import { randomUUID } from "node:crypto"; import { Type } from "@earendil-works/pi-ai"; import type { ExtensionAPI, ExtensionContext, Theme } from "@earendil-works/pi-coding-agent"; import { Text } from "@earendil-works/pi-tui"; import { runGoalCompletionAuditor } from "./goal-auditor.ts"; import { GOAL_AUDIT_REJECTION_REPORT_MAX_LENGTH, GOAL_COMPLETION_AUDITOR_REPORT_MAX_LENGTH, GOAL_COMPLETION_SUMMARY_MAX_LENGTH, GOAL_CONTINUATION_MESSAGE, GOAL_OBJECTIVE_MAX_LENGTH, GOAL_PROPOSAL_COMMENT_MAX_LENGTH, GOAL_PAUSE_REASON_MAX_LENGTH, GOAL_PAUSE_SUGGESTED_ACTION_MAX_LENGTH, GOAL_PROPOSAL_EVENT, GOAL_AUDIT_EVENT, GOAL_AUDIT_EVENT_VERSION, GOAL_PROPOSAL_REVISION_ENTRY, GOAL_RECEIPT_ENTRY, GOAL_SCHEMA_VERSION, GOAL_STATE_ENTRY, GOAL_STATE_EVENT, GOAL_STATE_REQUEST_EVENT, isGoalState, parseGoalState, type Goal, type GoalProposal, type GoalState, } from "./goal-contract.ts"; import { LEGACY_MIGRATION_ENTRY, findLegacyGoalCandidates, planLegacyMigration, writeLegacyMigration, type LegacyGoalCandidate, } from "./legacy-migration.ts"; import { GOAL_TRANSCRIPT_EVENT, createGoalTranscriptEvent, type GoalTranscriptEvent, type GoalTranscriptEventInput, } from "./goal-transcript-events.ts"; import { GoalWidget } from "./goal-widget.ts"; export * from "./goal-contract.ts"; export * from "./goal-transcript-events.ts"; export * from "./legacy-migration.ts"; const GOAL_CONTINUATION_TEXT = "Continue the Goal."; const REQUIRED_PI_CODING_AGENT_VERSION = "0.84.1"; type IdleExtensionContext = ExtensionContext & { onIdle(callback: () => void): () => void; }; function requireIdleSupport(ctx: ExtensionContext): asserts ctx is IdleExtensionContext { if (typeof (ctx as ExtensionContext & { onIdle?: unknown }).onIdle !== "function") { throw new Error(`@fractaal/pi-goal-x requires @earendil-works/pi-coding-agent >= ${REQUIRED_PI_CODING_AGENT_VERSION}; this runtime does not provide ctx.onIdle.`); } } function nowIso(): string { return new Date().toISOString(); } function boundedRequiredText(value: string, label: string, maxLength: number): string { const trimmed = value.trim(); if (!trimmed) throw new Error(`${label} requires non-empty text.`); if (trimmed.length > maxLength) throw new Error(`${label} exceeds the ${maxLength}-character producer state bound.`); return trimmed; } function boundedOptionalText(value: string | undefined, label: string, maxLength: number): string | undefined { const trimmed = value?.trim(); if (!trimmed) return undefined; if (trimmed.length > maxLength) throw new Error(`${label} exceeds the ${maxLength}-character producer state bound.`); return trimmed; } function emptyState(): GoalState { return { schemaVersion: GOAL_SCHEMA_VERSION, revision: 0, goal: null }; } function loadProposalRevision(ctx: ExtensionContext): number { const branch = ctx.sessionManager.getBranch(); for (let index = branch.length - 1; index >= 0; index -= 1) { const entry = branch[index] as { type?: string; customType?: string; data?: unknown }; if (entry.type !== "custom" || entry.customType !== GOAL_PROPOSAL_REVISION_ENTRY) continue; const revision = entry.data !== null && typeof entry.data === "object" ? (entry.data as { revision?: unknown }).revision : undefined; if (typeof revision !== "number" || !Number.isSafeInteger(revision) || revision < 0) { throw new Error(`Invalid ${GOAL_PROPOSAL_REVISION_ENTRY} at the active branch leaf; refusing to reset the event revision.`); } return revision; } return 0; } function loadGoalState(ctx: ExtensionContext): GoalState | null { const branch = ctx.sessionManager.getBranch(); for (let index = branch.length - 1; index >= 0; index -= 1) { const entry = branch[index] as { type?: string; customType?: string; data?: unknown }; if (entry.type !== "custom" || entry.customType !== GOAL_STATE_ENTRY) continue; const parsed = parseGoalState(entry.data); if (!parsed) throw new Error(`Invalid ${GOAL_STATE_ENTRY} snapshot at the active branch leaf; refusing to fall back to older Goal state.`); return parsed; } return null; } function hasMigrationMarker(ctx: ExtensionContext, status?: string): boolean { return ctx.sessionManager.getBranch().some((item) => { const entry = item as { type?: string; customType?: string; data?: unknown }; if (entry.type !== "custom" || entry.customType !== LEGACY_MIGRATION_ENTRY) return false; if (!status) return true; return entry.data !== null && typeof entry.data === "object" && (entry.data as { status?: unknown }).status === status; }); } function assistantTokens(message: unknown): number { if (message === null || typeof message !== "object") return 0; const raw = message as { role?: unknown; usage?: { input?: unknown; output?: unknown } }; if (raw.role !== "assistant") return 0; const input = typeof raw.usage?.input === "number" && Number.isFinite(raw.usage.input) ? raw.usage.input : 0; const output = typeof raw.usage?.output === "number" && Number.isFinite(raw.usage.output) ? raw.usage.output : 0; return Math.max(0, Math.trunc(input)) + Math.max(0, Math.trunc(output)); } function renderGoalSystemPrompt(state: GoalState): string { const goal = state.goal; if (!goal) return ""; const lines = [ `[PI GOAL ${goal.status.toUpperCase()}]`, "", goal.objective.replace(/<\/?goal_objective>/gi, (tag) => tag.replaceAll("<", "<").replaceAll(">", ">")), "", ]; if (goal.status === "active") { lines.push("Keep this objective in force. Continue with concrete work; call pause_goal for a real blocker, abandon_goal if it should be abandoned, or complete_goal only after the objective is genuinely complete."); } else if (goal.status === "paused") { lines.push(`The Goal is paused: ${goal.pause?.reason ?? "no reason recorded"}. Do not resume substantive Goal work until resume_goal is called.`); if (goal.pause?.suggestedAction) lines.push(`Suggested unblock action: ${goal.pause.suggestedAction}`); } else { lines.push("The Goal passed its independent audit. Write one normal final response now and do not call tools."); } if (goal.lastAuditRejection) lines.push(`Latest auditor objection: ${goal.lastAuditRejection.report}`); return lines.join("\n"); } function stateText(state: GoalState): string { const goal = state.goal; if (!goal) return "No Goal is active on this branch."; const lines = [`Goal ${goal.status}: ${goal.objective}`, `Revision: ${state.revision}`, `Auto-continue: ${goal.autoContinue ? "on" : "off"}`]; if (goal.pause) lines.push(`Reason: ${goal.pause.reason}`); if (goal.pause?.suggestedAction) lines.push(`Suggested action: ${goal.pause.suggestedAction}`); if (goal.lastAuditRejection) lines.push(`Latest audit rejection: ${goal.lastAuditRejection.report}`); return lines.join("\n"); } export default function goalExtension( pi: ExtensionAPI, dependencies: { runCompletionAuditor?: typeof runGoalCompletionAuditor } = {}, ): void { let state = emptyState(); let proposal: GoalProposal = { schemaVersion: GOAL_SCHEMA_VERSION, revision: 0, proposal: null }; let proposalSequence = 0; let lastAccountedAt: number | null = null; let auditing = false; let auditingGoalId: string | null = null; let widget: GoalWidget | null = null; let widgetContext: ExtensionContext | null = null; let migrationCandidates: LegacyGoalCandidate[] = []; let idleContinuationCancel: (() => void) | undefined; function emitState(): void { pi.events.emit(GOAL_STATE_EVENT, structuredClone(state)); } function emitProposal(): void { pi.events.emit(GOAL_PROPOSAL_EVENT, structuredClone(proposal)); } function emitAuditState(active: boolean, goalId: string): void { if (auditing === active && (!active || auditingGoalId === goalId)) return; auditing = active; auditingGoalId = active ? goalId : null; pi.events.emit(GOAL_AUDIT_EVENT, { version: GOAL_AUDIT_EVENT_VERSION, goalId, active, emittedAt: nowIso(), }); widget?.update(); } function updateWidget(ctx: ExtensionContext): void { widgetContext = ctx; if (!ctx.hasUI || !state.goal) { ctx.ui.setWidget("pi-goal", undefined); widget = null; return; } if (widget) { widget.update(); return; } ctx.ui.setWidget("pi-goal", (tui, theme) => { widget = new GoalWidget(tui, theme, () => state, () => auditing); return widget; }, { placement: "aboveEditor" }); } function persist(nextGoal: Goal | null, ctx: ExtensionContext): void { requireIdleSupport(ctx); const nextState = { schemaVersion: GOAL_SCHEMA_VERSION, revision: state.revision + 1, goal: nextGoal ? structuredClone(nextGoal) : null, }; if (!isGoalState(nextState)) throw new Error("Goal mutation exceeds the exported producer state contract."); state = nextState; pi.appendEntry(GOAL_STATE_ENTRY, state); emitState(); updateWidget(ctx); } function publishReceipt(input: GoalTranscriptEventInput): GoalTranscriptEvent { const receipt = createGoalTranscriptEvent(input, nowIso()); pi.appendEntry(GOAL_RECEIPT_ENTRY, receipt); pi.events.emit(GOAL_TRANSCRIPT_EVENT, receipt); return receipt; } function goalFields(goal: Goal | null): Pick { return goal ? { goalId: goal.id, objective: goal.objective, autoContinue: goal.autoContinue } : {}; } function nextProposalRevision(): number { proposalSequence += 1; pi.appendEntry(GOAL_PROPOSAL_REVISION_ENTRY, { schemaVersion: GOAL_SCHEMA_VERSION, revision: proposalSequence }); return proposalSequence; } function setProposal(kind: "create" | "tweak", objective: string, currentObjective?: string): void { const boundedObjective = boundedRequiredText(objective, "Goal objective", GOAL_OBJECTIVE_MAX_LENGTH); const boundedCurrentObjective = boundedOptionalText(currentObjective, "Current Goal objective", GOAL_OBJECTIVE_MAX_LENGTH); proposal = { schemaVersion: GOAL_SCHEMA_VERSION, revision: nextProposalRevision(), proposal: { kind, objective: boundedObjective, ...(boundedCurrentObjective ? { currentObjective: boundedCurrentObjective } : {}) }, }; emitProposal(); } function clearProposal(): void { proposal = { schemaVersion: GOAL_SCHEMA_VERSION, revision: nextProposalRevision(), proposal: null }; emitProposal(); } function cancelContinuation(): void { idleContinuationCancel?.(); idleContinuationCancel = undefined; } function continueGoal(): void { const goal = state.goal; if (!goal || goal.status !== "active" || !goal.autoContinue) return; pi.sendMessage({ customType: GOAL_CONTINUATION_MESSAGE, content: GOAL_CONTINUATION_TEXT, display: false, }, { deliverAs: "followUp", triggerTurn: true }); } function requestContinuation(ctx: ExtensionContext): void { if (!state.goal || state.goal.status !== "active" || !state.goal.autoContinue || idleContinuationCancel) return; requireIdleSupport(ctx); idleContinuationCancel = ctx.onIdle(() => { idleContinuationCancel = undefined; continueGoal(); }); } function currentGoal(requiredStatus?: "active" | "paused-or-active"): Goal { const goal = state.goal; if (!goal) throw new Error("No Goal is active on this branch."); if (requiredStatus === "active" && goal.status !== "active") throw new Error(`The Goal is ${goal.status}, not active.`); if (requiredStatus === "paused-or-active" && goal.status === "complete") throw new Error("The Goal is already complete and awaiting final settlement."); return goal; } type GoalProposalDecision = { confirmed: boolean; comment?: string }; type ConfirmWithInputUI = { confirmWithInput?: (options: { title: string; message: string; messageFormat: "markdown"; inputLabel: string; inputPlaceholder: string; }) => Promise<{ confirmed: boolean; input?: string }>; }; function proposalResultText(text: string, comment?: string): string { return comment ? `${text}\n\nUser comment: "${comment}"` : text; } async function confirmProposal(ctx: ExtensionContext, title: string, objective: string): Promise { if (!ctx.hasUI) throw new Error("Goal proposal requires an interactive user confirmation surface."); const ui = ctx.ui as typeof ctx.ui & ConfirmWithInputUI; if (ui.confirmWithInput) { const result = await ui.confirmWithInput({ title, message: objective, messageFormat: "markdown", inputLabel: "Comments or reservations (optional)", inputPlaceholder: "Write additional comments or reservations here…", }); return { confirmed: result.confirmed, comment: boundedOptionalText(result.input, "Goal proposal comment", GOAL_PROPOSAL_COMMENT_MAX_LENGTH), }; } return { confirmed: await ctx.ui.confirm(title, objective) }; } function pause(ctx: ExtensionContext, reason: string, suggestedAction?: string): Goal { const goal = currentGoal("active"); const trimmedReason = boundedRequiredText(reason, "Goal pause reason", GOAL_PAUSE_REASON_MAX_LENGTH); const trimmedSuggestedAction = boundedOptionalText(suggestedAction, "Goal pause suggested action", GOAL_PAUSE_SUGGESTED_ACTION_MAX_LENGTH); const next: Goal = { ...goal, status: "paused", autoContinue: false, updatedAt: nowIso(), pause: { reason: trimmedReason, ...(trimmedSuggestedAction ? { suggestedAction: trimmedSuggestedAction } : {}) }, }; persist(next, ctx); publishReceipt({ kind: "goal_paused", level: "warning", ...goalFields(next), reason: trimmedReason, suggestedAction: trimmedSuggestedAction, tuiMessage: `Goal paused: ${trimmedReason}` }); return next; } function resume(ctx: ExtensionContext): Goal { requireIdleSupport(ctx); const goal = currentGoal("paused-or-active"); if (goal.status === "active") throw new Error("The Goal is already active."); const { pause: _pause, ...resumedGoal } = goal; const next: Goal = { ...resumedGoal, status: "active", autoContinue: true, updatedAt: nowIso() }; persist(next, ctx); publishReceipt({ kind: "goal_resumed", level: "info", ...goalFields(next), tuiMessage: "Goal resumed." }); requestContinuation(ctx); return next; } function abandon(ctx: ExtensionContext, reason: string): Goal { const goal = currentGoal("paused-or-active"); const trimmedReason = reason.trim(); if (!trimmedReason) throw new Error("abandon_goal requires a non-empty reason."); persist(null, ctx); publishReceipt({ kind: "goal_abandoned", level: "warning", ...goalFields(goal), reason: trimmedReason, tuiMessage: `Goal abandoned: ${trimmedReason}` }); return goal; } function loadOrMigrate(ctx: ExtensionContext): void { const loaded = loadGoalState(ctx); if (loaded) { state = loaded; migrationCandidates = []; return; } state = emptyState(); if (hasMigrationMarker(ctx, "complete")) return; const plan = planLegacyMigration(ctx); if (plan.kind === "migrate") { writeLegacyMigration(pi, plan); state = plan.goal; migrationCandidates = []; return; } if (plan.kind === "ambiguous") { migrationCandidates = plan.candidates; if (!hasMigrationMarker(ctx, "selection_required")) { pi.appendEntry(LEGACY_MIGRATION_ENTRY, { schemaVersion: 1, status: "selection_required", candidateIds: plan.candidates.map((item) => item.id), sourcePreserved: true, }); } } } pi.events.on(GOAL_STATE_REQUEST_EVENT, () => { emitState(); emitProposal(); }); const currentPi = pi as unknown as { registerEntryRenderer(customType: string, renderer: (entry: { data: T }, options: { expanded: boolean }, theme: Theme) => Text): void; }; currentPi.registerEntryRenderer(GOAL_RECEIPT_ENTRY, (entry, _options, theme) => { const receipt = entry.data; const label = receipt.kind.replace(/^goal_/, "Goal ").replaceAll("_", " "); const message = receipt.message ?? receipt.reason ?? receipt.changeSummary ?? receipt.completionSummary ?? receipt.objective ?? ""; return new Text(`${theme.fg(receipt.level === "error" ? "error" : receipt.level === "warning" ? "warning" : "accent", theme.bold(label))}${message ? `\n${theme.fg("muted", message)}` : ""}`, 0, 0); }); pi.registerTool({ name: "propose_goal", label: "Propose Goal", description: "Propose one Goal after ordinary conversation has made the objective clear. User confirmation creates and starts it.", promptSnippet: "Propose one confirmed Goal from an aligned objective.", promptGuidelines: ["Use Markdown to create your Goal proposal.", "Use propose_goal only after normal conversation has made a concrete objective clear enough for user confirmation."], parameters: Type.Object({ objective: Type.String({ minLength: 1, maxLength: GOAL_OBJECTIVE_MAX_LENGTH, description: "The complete Goal contract. Markdown is allowed." }) }, { additionalProperties: false }), executionMode: "sequential", async execute(_id, params, _signal, _update, ctx) { requireIdleSupport(ctx); if (state.goal) throw new Error("A Goal already exists. Use tweak_goal, pause_goal, abandon_goal, or complete_goal."); const objective = boundedRequiredText(params.objective, "Goal objective", GOAL_OBJECTIVE_MAX_LENGTH); setProposal("create", objective); let decision: GoalProposalDecision; try { decision = await confirmProposal(ctx, "Confirm Goal", objective); } finally { clearProposal(); } if (!decision.confirmed) return { content: [{ type: "text", text: proposalResultText("Goal proposal declined. Continue the ordinary conversation and propose again only after the user asks for a change.", decision.comment) }], details: state }; const timestamp = nowIso(); const goal: Goal = { id: randomUUID(), objective, status: "active", autoContinue: true, usage: { tokensUsed: 0, activeSeconds: 0 }, createdAt: timestamp, updatedAt: timestamp }; persist(goal, ctx); publishReceipt({ kind: "goal_started", level: "info", ...goalFields(goal), tuiMessage: "Goal started." }); requestContinuation(ctx); return { content: [{ type: "text", text: proposalResultText("Goal confirmed and started. Autonomous continuation is active.", decision.comment) }], details: state, terminate: true }; }, }); pi.registerTool({ name: "tweak_goal", label: "Tweak Goal", description: "Propose a complete revised objective for the current Goal. The revision applies only after user confirmation.", promptSnippet: "Propose a confirmed revision to the current Goal objective.", promptGuidelines: ["Use Markdown to create your Goal proposal.", "Use tweak_goal when user feedback changes the current Goal contract; pass the complete revised objective, not a patch."], parameters: Type.Object({ objective: Type.String({ minLength: 1, maxLength: GOAL_OBJECTIVE_MAX_LENGTH }) }, { additionalProperties: false }), executionMode: "sequential", async execute(_id, params, _signal, _update, ctx) { requireIdleSupport(ctx); const goal = currentGoal("paused-or-active"); const objective = boundedRequiredText(params.objective, "Goal objective", GOAL_OBJECTIVE_MAX_LENGTH); setProposal("tweak", objective, goal.objective); let decision: GoalProposalDecision; try { decision = await confirmProposal(ctx, "Confirm Goal revision", `## Current Goal\n\n${goal.objective}\n\n## Revised Goal\n\n${objective}`); } finally { clearProposal(); } if (!decision.confirmed) return { content: [{ type: "text", text: proposalResultText("Goal revision declined. The current Goal is unchanged.", decision.comment) }], details: state }; const { lastAuditRejection: _lastAuditRejection, ...revisedGoal } = goal; const next: Goal = { ...revisedGoal, objective, updatedAt: nowIso() }; persist(next, ctx); publishReceipt({ kind: "goal_updated", level: "info", ...goalFields(next), changeSummary: "Goal objective revised with user confirmation.", tuiMessage: "Goal updated." }); if (next.status === "active") requestContinuation(ctx); return { content: [{ type: "text", text: proposalResultText("Goal revision confirmed.", decision.comment) }], details: state, terminate: true }; }, }); pi.registerTool({ name: "pause_goal", label: "Pause Goal", description: "Pause an active Goal at a real blocker and record the reason and optional unblock action.", promptSnippet: "Pause the active Goal with a concrete blocker.", parameters: Type.Object({ reason: Type.String({ minLength: 1, maxLength: GOAL_PAUSE_REASON_MAX_LENGTH }), suggestedAction: Type.Optional(Type.String({ minLength: 1, maxLength: GOAL_PAUSE_SUGGESTED_ACTION_MAX_LENGTH })), }, { additionalProperties: false }), executionMode: "sequential", async execute(_id, params, _signal, _update, ctx) { const next = pause(ctx, params.reason, params.suggestedAction); return { content: [{ type: "text", text: `Goal paused: ${next.pause?.reason}` }], details: state, terminate: true }; }, }); pi.registerTool({ name: "resume_goal", label: "Resume Goal", description: "Resume the paused Goal from its exact current state and restart autonomous continuation.", promptSnippet: "Resume the paused Goal.", parameters: Type.Object({}, { additionalProperties: false }), executionMode: "sequential", async execute(_id, _params, _signal, _update, ctx) { resume(ctx); return { content: [{ type: "text", text: "Goal resumed. Autonomous continuation is active." }], details: state, terminate: true }; }, }); pi.registerTool({ name: "abandon_goal", label: "Abandon Goal", description: "Abandon the active or paused Goal without marking it complete.", promptSnippet: "Abandon the Goal with a concrete reason.", parameters: Type.Object({ reason: Type.String({ minLength: 1 }) }, { additionalProperties: false }), executionMode: "sequential", async execute(_id, params, _signal, _update, ctx) { abandon(ctx, params.reason); return { content: [{ type: "text", text: `Goal abandoned: ${params.reason.trim()}` }], details: state, terminate: true }; }, }); pi.registerTool({ name: "complete_goal", label: "Complete Goal", description: "Request independent audit of the active or paused Goal. Approval permits one final prose response, then archival.", promptSnippet: "Submit genuinely complete Goal work for independent audit.", promptGuidelines: ["Use complete_goal only when the complete Goal objective is satisfied; the summary is an audit claim, not proof."], parameters: Type.Object({ summary: Type.String({ minLength: 1, maxLength: GOAL_COMPLETION_SUMMARY_MAX_LENGTH, description: "Concise completion claim and available verification evidence." }) }, { additionalProperties: false }), executionMode: "sequential", async execute(_id, params, signal, _update, ctx) { const target = structuredClone(currentGoal("paused-or-active")); const summary = boundedRequiredText(params.summary, "Goal completion summary", GOAL_COMPLETION_SUMMARY_MAX_LENGTH); const auditor = await (async () => { try { emitAuditState(true, target.id); return await (dependencies.runCompletionAuditor ?? runGoalCompletionAuditor)({ ctx, goal: target, completionSummary: summary, signal }); } finally { emitAuditState(false, target.id); } })(); if (state.goal?.id !== target.id || state.goal.updatedAt !== target.updatedAt) throw new Error("Goal changed while the completion audit was running; audit result discarded."); if (!auditor.approved) { const report = boundedRequiredText( auditor.output.trim() || auditor.error || "The independent auditor did not approve completion.", "Goal audit rejection report", GOAL_AUDIT_REJECTION_REPORT_MAX_LENGTH, ); const { pause: _pause, ...rejectedGoal } = target; const next: Goal = { ...rejectedGoal, status: "active", autoContinue: true, updatedAt: nowIso(), lastAuditRejection: { rejectedAt: nowIso(), report } }; persist(next, ctx); publishReceipt({ kind: "goal_completion_rejected", level: auditor.error ? "error" : "warning", ...goalFields(next), reason: auditor.error ?? "Rejected by independent auditor.", auditorReport: report, message: "Goal completion rejected by independent auditor.", tuiMessage: `Goal completion rejected.\n${report}` }); return { content: [{ type: "text", text: `Goal completion rejected. Address these objections before retrying:\n\n${report}` }], details: state }; } const auditorReport = boundedRequiredText(auditor.output, "Goal completion auditor report", GOAL_COMPLETION_AUDITOR_REPORT_MAX_LENGTH); const { pause: _pause, lastAuditRejection: _lastAuditRejection, ...auditedGoal } = target; const completed: Goal = { ...auditedGoal, status: "complete", autoContinue: false, updatedAt: nowIso(), completion: { approvedAt: nowIso(), summary, auditorReport }, }; persist(completed, ctx); return { content: [{ type: "text", text: `Goal audit approved.\n\n${auditor.output}\n\nWrite one normal final response now: explain what was completed, what changed or was produced, what was verified, and the final state or relevant next step. Do not call tools.` }], details: state, }; }, }); pi.registerCommand("goal", { description: "Discuss a Goal in normal conversation; the model proposes it once aligned.", handler: async (args, ctx) => { const topic = args.trim(); if (!topic) { ctx.ui.setEditorText(state.goal ? "I want to revise the current Goal: " : "I want to set a Goal: "); return; } pi.sendUserMessage(state.goal ? `I want to revise the current Goal: ${topic}. Discuss this with me normally, then use tweak_goal once we are aligned.` : `I want to set a Goal: ${topic}. Discuss this with me normally, then use propose_goal once we are aligned.`); }, }); pi.registerCommand("goal-status", { description: "Show the current Goal state.", handler: async (_args, ctx) => ctx.ui.notify(stateText(state), "info") }); pi.registerCommand("goal-pause", { description: "Pause the active Goal.", handler: async (args, ctx) => { pause(ctx, args.trim() || "Paused by user."); }, }); pi.registerCommand("goal-resume", { description: "Resume the paused Goal.", handler: async (_args, ctx) => { resume(ctx); } }); pi.registerCommand("goal-abandon", { description: "Abandon the active or paused Goal.", handler: async (args, ctx) => { abandon(ctx, args.trim() || "Abandoned by user."); }, }); pi.registerCommand("goal-migrate", { description: "Choose a legacy Goal when migration found multiple open candidates.", handler: async (_args, ctx) => { requireIdleSupport(ctx); if (loadGoalState(ctx) || hasMigrationMarker(ctx, "complete")) { ctx.ui.notify("Legacy migration is already complete or this branch already has new Goal state.", "info"); return; } if (migrationCandidates.length === 0) migrationCandidates = findLegacyGoalCandidates(ctx).candidates; if (migrationCandidates.length === 0) { ctx.ui.notify("No legacy Goals require migration.", "info"); return; } if (!ctx.hasUI) { ctx.ui.notify(`Legacy Goal selection required: ${migrationCandidates.map((item) => item.id).join(", ")}`, "warning"); return; } const labels = migrationCandidates.map((item) => `${item.id}: ${item.objective.replace(/\s+/g, " ").slice(0, 100)}`); const selected = await ctx.ui.select("Migrate which legacy Goal?", labels); const selectedIndex = selected ? labels.indexOf(selected) : -1; if (selectedIndex < 0) return; const plan = planLegacyMigration(ctx, migrationCandidates[selectedIndex]?.id); if (plan.kind !== "migrate") throw new Error("Legacy Goal selection could not be migrated."); writeLegacyMigration(pi, plan); state = plan.goal; migrationCandidates = []; emitState(); updateWidget(ctx); requestContinuation(ctx); }, }); pi.on("before_agent_start", (event) => { lastAccountedAt = state.goal?.status === "active" ? Date.now() : null; const goalPrompt = renderGoalSystemPrompt(state); if (!goalPrompt) return; return { systemPrompt: `${event.systemPrompt}\n\n${goalPrompt}` }; }); pi.on("tool_call", () => { if (state.goal?.status === "complete") return { block: true, reason: "The Goal is complete. Write the final user-facing response without calling tools." }; }); pi.on("agent_end", (event, ctx) => { const assistant = [...event.messages].reverse().find((message) => message.role === "assistant"); if (!assistant) return; if (assistant.stopReason === "error" || assistant.stopReason === "aborted") { cancelContinuation(); return; } const goal = state.goal; if (!goal || goal.status !== "active" || !goal.autoContinue) return; if (assistant.stopReason !== "stop" && assistant.stopReason !== "length" && assistant.stopReason !== "toolUse") return; requestContinuation(ctx); }); pi.on("turn_end", (event, ctx) => { const goal = state.goal; if (!goal || goal.status !== "active") return; const now = Date.now(); const elapsed = lastAccountedAt === null ? 0 : Math.max(0, Math.floor((now - lastAccountedAt) / 1000)); lastAccountedAt = now; const tokens = assistantTokens(event.message); if (elapsed === 0 && tokens === 0) return; persist({ ...goal, usage: { tokensUsed: goal.usage.tokensUsed + tokens, activeSeconds: goal.usage.activeSeconds + elapsed }, updatedAt: nowIso() }, ctx); }); pi.on("session_start", (_event, ctx) => { requireIdleSupport(ctx); loadOrMigrate(ctx); proposalSequence = loadProposalRevision(ctx); proposal = { schemaVersion: GOAL_SCHEMA_VERSION, revision: proposalSequence, proposal: null }; emitState(); emitProposal(); updateWidget(ctx); if (migrationCandidates.length > 1) ctx.ui.notify("Multiple legacy Goals need selection. Run /goal-migrate; no Goal was guessed and all legacy sources remain unchanged.", "warning"); requestContinuation(ctx); }); pi.on("session_tree", (_event, ctx) => { requireIdleSupport(ctx); loadOrMigrate(ctx); proposalSequence = loadProposalRevision(ctx); proposal = { schemaVersion: GOAL_SCHEMA_VERSION, revision: proposalSequence, proposal: null }; emitState(); emitProposal(); updateWidget(ctx); requestContinuation(ctx); }); pi.on("session_compact", (_event, ctx) => { requireIdleSupport(ctx); pi.appendEntry(GOAL_STATE_ENTRY, state); emitState(); updateWidget(ctx); }); pi.on("agent_settled", (_event, ctx) => { const completed = state.goal?.status === "complete" ? state.goal : null; if (!completed) return; persist(null, ctx); publishReceipt({ kind: "goal_completed", level: "info", ...goalFields(completed), completionSummary: completed.completion?.summary, auditorReport: completed.completion?.auditorReport, message: "Goal completed.", tuiMessage: "Goal completed.", }); }); pi.on("session_shutdown", () => { cancelContinuation(); if (auditing && auditingGoalId) emitAuditState(false, auditingGoalId); widget = null; widgetContext = null; }); }