import type { BeforeAgentStartEvent, ContextEvent, ExtensionHandler, InputEvent, InputEventResult, } from "@earendil-works/pi-coding-agent"; import { continuationGoalIdFromPrompt } from "./prompts.js"; import { applyQueuedGoalProviderContextRewrites, extensionQueuedGoalWorkMessageId } from "./queued-goal-work.js"; import { isCommandResumeQueuedGoalMessage } from "./queued-goal-messages.js"; import { applyStaleQueuedWorkEffects } from "./goal-runtime-event-utils.js"; import type { ContextEventResult, GoalRuntimeInputContextHandlerContext, MessageStartEvent, QueuedGoalWorkMessageIdResolver, } from "./goal-runtime-event-handler-types.js"; export function createInputContextEventHandlers( deps: GoalRuntimeInputContextHandlerContext, queuedGoalWorkMessageIdForRuntime: QueuedGoalWorkMessageIdResolver, ) { const { runtimeState, stateController, continuation, recoveryRuntime, status, resetErrorRecovery } = deps; return { onInput: (async (event, ctx) => { continuation.clearPassthroughContinuationInput(); const continuationGoalId = continuationGoalIdFromPrompt(event.text); if (event.source !== "extension") { recoveryRuntime.onUserInput(); applyStaleQueuedWorkEffects( runtimeState.staleQueuedWorkGuard.planUserInputClearAbort().effects, ctx, deps, ); if (continuationGoalId !== null) { continuation.notePassthroughContinuationInput(event.text); } return undefined; } if (continuationGoalId === null) { return undefined; } applyStaleQueuedWorkEffects( runtimeState.staleQueuedWorkGuard.planExtensionContinuationClearAbort().effects, ctx, deps, ); if (stateController.isCurrentActiveGoalId(continuationGoalId)) { continuation.markContinuationQueued(continuationGoalId); return { action: "continue" } as const; } continuation.clearContinuationStateFor(continuationGoalId); status.refreshUi(ctx); return { action: "handled" } as const; }) satisfies ExtensionHandler, onContext: (async (event, ctx) => { const { messages, changed } = applyQueuedGoalProviderContextRewrites(event.messages, { goal: stateController.getGoal(), resolveStaleQueuedGoalWorkMessageId: queuedGoalWorkMessageIdForRuntime, resolveActiveContinuationQueuedGoalWorkMessageId: extensionQueuedGoalWorkMessageId, }); const contextAbortPlan = runtimeState.staleQueuedWorkGuard.planContextAbort( runtimeState.currentTurnIndex, ); if (contextAbortPlan !== null) { applyStaleQueuedWorkEffects(contextAbortPlan.effects, ctx, deps); } return changed ? { messages } : undefined; }) satisfies ExtensionHandler, onBeforeAgentStart: (async (event, ctx) => { const continuationGoalId = continuation.continuationGoalIdFromRuntimePrompt(event.prompt); if (continuationGoalId !== null) { continuation.clearContinuationStateFor(continuationGoalId); if (!stateController.isCurrentActiveGoalId(continuationGoalId)) { status.refreshUi(ctx); return undefined; } applyStaleQueuedWorkEffects( runtimeState.staleQueuedWorkGuard.planBeforeAgentStartClearAbort().effects, ctx, deps, ); } else { applyStaleQueuedWorkEffects( runtimeState.staleQueuedWorkGuard.planBeforeAgentStartClearAbort().effects, ctx, deps, ); continuation.clearContinuationState(); } return undefined; }) satisfies ExtensionHandler, onMessageStart: (async (event, _ctx) => { if (event.message.role === "user") { stateController.persistHostOverflowUserReset(false); } const queuedGoalId = queuedGoalWorkMessageIdForRuntime(event.message); if (queuedGoalId === null) { if (event.message.role === "user" || event.message.role === "custom") { runtimeState.staleQueuedWorkGuard.noteRunnableWorkStarted(); continuation.clearContinuationState(); } return; } continuation.clearContinuationStateFor(queuedGoalId); if (stateController.isCurrentActiveGoalId(queuedGoalId)) { runtimeState.staleQueuedWorkGuard.noteRunnableWorkStarted(); if (isCommandResumeQueuedGoalMessage(event.message)) { resetErrorRecovery(); } return; } runtimeState.staleQueuedWorkGuard.noteStaleWorkStarted(queuedGoalId); }) satisfies ExtensionHandler, }; }