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;
});
}