Centralize supervisor check-in tasks and outcome-first tool guidance

This commit is contained in:
wassname
2026-09-09 10:50:42 +08:00
parent a7385d4b76
commit 565b272c71
13 changed files with 336 additions and 67 deletions
@@ -0,0 +1,66 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
Test Files 19 passed (19)
Tests 108 passed (108)
Start at 10:47:37
Duration 3.83s (transform 2.36s, setup 0ms, import 6.55s, tests 9.35s, environment 2ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
src/worker-view.ts:2:1 assist/source/organizeImports FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Sort the imported names.
1 │ import { compile } from "@sting8k/pi-vcc/src/core/summarize";
> 2 │ import { supervisorCheckIn, type SupervisorReviewReason } from "./prompts.js";
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 │
4 │ export interface SessionBlock {
i Safe fix: Organize imports and exports (Biome)
1 1 │ import { compile } from "@sting8k/pi-vcc/src/core/summarize";
2 │ - import·{·supervisorCheckIn,·type·SupervisorReviewReason·}·from·"./prompts.js";
2 │ + import·{·type·SupervisorReviewReason,·supervisorCheckIn·}·from·"./prompts.js";
3 3 │
4 4 │ export interface SessionBlock {
test/worker-view.test.ts:2:1 assist/source/organizeImports FIXABLE ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Sort the imported names.
1 │ import { expect, it } from "vitest";
> 2 │ import { supervisorPeriodicReview, supervisorPlanChangeReview, supervisorReadyReview, type SupervisorReviewReason, supervisorStartedReview, supervisorStoppedReview } from "../src/prompts.js";
│ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
3 │ import { workerView } from "../src/worker-view.js";
4 │
i Safe fix: Organize imports and exports (Biome)
1 1 │ import { expect, it } from "vitest";
2 │ - import·{·supervisorPeriodicReview,·supervisorPlanChangeReview,·supervisorReadyReview,·type·SupervisorReviewReason,·supervisorStartedReview,·supervisorStoppedReview·}·from·"../src/prompts.js";
2 │ + import·{·type·SupervisorReviewReason,·supervisorPeriodicReview,·supervisorPlanChangeReview,·supervisorReadyReview,·supervisorStartedReview,·supervisorStoppedReview·}·from·"../src/prompts.js";
3 3 │ import { workerView } from "../src/worker-view.js";
4 4 │
Checked 36 files in 63ms. No fixes applied.
Found 2 errors.
check ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
× Some errors were emitted while running checks.
@@ -0,0 +1,49 @@
# Supervisor prompt flow review
Pi/OpenAI implementation, based on `a7385d4`. Scope: centralize supervisor instructions in `src/prompts.ts` and make check-in tasks and tool descriptions ask for judgment followed by useful action. No transport, lifecycle, approval-gate, plan-selection, or planning-policy changes.
## Narrative order and wiring
1. Existing planning and worker resync prompts, unchanged.
2. `supervisorOpening`, `supervisorPrompt`, `supervisorReviewContext`, `supervisorOrientation`, `supervisorCompaction`: role and plan context. The user-authored agency opening and constitution/pi-supervisor provenance are retained. Long role asks for applicable AGENTS.md/skills, remains generic, removes one duplicate autonomy paragraph, and makes SteerWorker—not a recap—the continuation action. The short review and startup/compaction cadence are unchanged.
3. `supervisorCheckIn`: ready, started, active periodic, stopped/settled, plan-edit tasks. `src/worker-view.ts` invokes it outside truncatable activity content. Status prefixes remain exactly `The worker is ready to begin.`, `The worker is still working.`, and `The worker stopped.`. Observed idleness still governs the prefix; an idle interval gets stopped guidance, while a nominal settled event that is not idle gets active-work guidance.
4. `supervisorPlanReview`: existing diff/claim data plus plan-change guidance, wired from `src/index.ts`. The guidance now precedes truncatable diff detail so long diffs do not evict it.
5. SteerWorker description, parameter description and delivery result.
6. ApproveGoal description, parameter descriptions and approval-success instruction. Acceptance is conditional on the supervisor judging the result achieved; mechanics are a separate paragraph. Gate errors stay at their checks, unchanged. The successful result tells the supervisor to use SteerWorker for CompleteGoal and continue remaining goals.
7. Existing worker CompleteGoal description corrected to address its caller: the worker runs verification and seeks supervisor review first; the tool consumes recorded approval. It no longer tells the worker to "direct the worker" or implies the read-only supervisor can create evidence. Approval gates are unchanged.
Runtime data labels and view serialization remain near their producers, rather than turning this into a string registry. The dynamic mechanical errors remain in supervisor-session.ts as allowed by the task.
## Exact event tasks
Ready:
> Check the agreed outcome and decide the next useful action. Use SteerWorker to send the worker a concrete starting instruction; do not repeat one already being acted on.
Started:
> The worker has begun a turn. Check whether its direction fits the agreed goal; let productive work continue and use SteerWorker only if a correction is needed.
Active periodic:
> Is the worker on track toward the user's intended outcome? Check for drift, mistaken assumptions, or wasted effort. Use SteerWorker to send a correction where useful; otherwise let productive work continue without interruption.
Stopped/settled:
> Inspect the results and judge whether the agreed goal is actually achieved. If unfinished, investigate why the worker stopped and use SteerWorker to send the next useful instruction and resume work. If a verified dependency prevents progress, establish what will resume it and how that will be observed. Do not treat stopping as completion. Consider ApproveGoal only after the results satisfy the goal.
Plan edit/manual tick:
> Assess plan changes against the user's intent and preferences. Manual checkbox edits are claims, not proof of completion. Inspect the actual result before accepting a claim; use SteerWorker to send corrections when the plan or work has drifted. Preserve authorized changes.
ApproveGoal decision paragraph:
> Use only after judging that the actual result satisfies the user's intended outcome and the goal's discriminator. This tool records your acceptance; its mechanical checks cannot establish success. If the goal is unmet or evidence is insufficient, do not approve: use SteerWorker to request the next useful work or check.
## Validation and limits
- Read AGENTS.md, annoy-less skill and installed Pi extension docs: before_agent_start persistent custom messages/chained system prompt, and sendUserMessage behavior (an idle worker starts a turn; an active worker receives queued steering).
- `validation.txt`: 108 tests pass in 19 files, including real installed Pi RPC and native fork/Intercom checks; typecheck, lint, build and diff check pass.
- `initial-validation.txt`: same tests/typecheck passed, lint found only two import-order issues. Fixed those and reran the full command successfully.
- Added 9 worker-view event/status combinations and 3 prompt-semantic tests. Updated flow tests assert manual ticks and external plan edits carry judgment/continuation instructions. Supervisor hook/tool tests verify centralized text is wired, including startup/compaction and approval success.
- Native pair fixture now produces its view through the actual workerView. The real Pi provider request is asserted to contain the stopped task and actual registered SteerWorker/ApproveGoal descriptions, and its emitted instruction reaches the worker exactly. The local model is deterministic: this establishes wiring, not judgment quality.
- Approval logic/transport/plan extraction are unchanged. `git diff --quiet HEAD -- src/approval.ts src/intercom.ts src/plan-view.ts src/plan.ts` passed before commit. Unicode envelope budget regression still passes with the added event tasks.
- No user or test Herdr panes operated. No push. Unrelated dirty native logs were not changed; docs/human_journal.md was never read or written. Tests unset inherited PI_GOALS_EVIDENCE_DIR, PI_SUBAGENT_CHILD and PI_GOALS_ROLE.
## Parent acceptance still required
In a new isolated Herdr task, require an exact result (for example a specific byte sequence). Let the worker stop with a real artifact that fails that goal. Read both panes and the artifact: the supervisor must identify the mismatch, send a corrective SteerWorker instruction rather than approve, observe the resumed worker, and only approve after the corrected result satisfies the discriminator. Also confirm productive active work is left alone and an authorized plan edit is not mechanically rejected. Do not count deterministic test output or delivery receipts as autonomous outcome success. Independent reviewer gate remains parent-owned.
@@ -0,0 +1,26 @@
> @wassname2/pi-goals@0.2.2 test
> vitest run
RUN v4.1.9 /home/code/.pi/agent/git/github.com/wassname/pi-goals
Test Files 19 passed (19)
Tests 108 passed (108)
Start at 10:48:47
Duration 3.88s (transform 4.98s, setup 0ms, import 9.43s, tests 8.78s, environment 2ms)
> @wassname2/pi-goals@0.2.2 typecheck
> tsc --noEmit
> @wassname2/pi-goals@0.2.2 lint
> biome check src/ test/
Checked 36 files in 37ms. No fixes applied.
> @wassname2/pi-goals@0.2.2 build
> tsc
+2 -2
View File
@@ -25,7 +25,7 @@ import { backgroundState } from "./background.js";
import { closeSupervisorPane, openSupervisorPane } from "./herdr.js";
import { GoalIntercom } from "./intercom.js";
import { FOLD_LINE, foldPlan, GOAL_LINE } from "./plan.js";
import { completeGoalDescription, completeGoalParamDescription, planDrafting, planningState, resync } from "./prompts.js";
import { completeGoalDescription, completeGoalParamDescription, planDrafting, planningState, resync, supervisorPlanReview } from "./prompts.js";
import { RoleModels } from "./role-models.js";
import { isVisibleSupervisor, registerVisibleSupervisor } from "./supervisor-session.js";
import { workerView } from "./worker-view.js";
@@ -165,7 +165,7 @@ export default function piGoalsExtension(pi: ExtensionAPI): void {
return old?.status === goal.status ? [] : [`${goal.subject}: ${old ? `[${STATUS_TO_CHAR[old.status]}]` : "not previously observed"} -> [${STATUS_TO_CHAR[goal.status]}]${goal.status === "done" ? state.signedOffGoals.includes(goalKey(goal.subject)) ? "; CompleteGoal sign-off recorded" : "; manual completion claim, no CompleteGoal sign-off recorded" : ""}`];
});
const claims = goals.filter(goal => goal.status === "done" && !state.signedOffGoals.includes(goalKey(goal.subject)));
return `Claims awaiting supervisor judgment: ${claims.map(goal => goal.subject).join(", ") || "none"}\nGoal-state changes:\n${changes.join("\n") || "none"}\nPlan diff since the previous published view:\n${planDiff(state.previousPlan ?? "", plan)}\nManual edits are allowed. Inspect changes and steer a correction when warranted; a checkbox is not sign-off.`;
return supervisorPlanReview(claims.map(goal => goal.subject), changes, planDiff(state.previousPlan ?? "", plan));
}
function pauseReason(): string | null {
+98 -15
View File
@@ -5,15 +5,11 @@
* the skeleton below is a convention the drafting prompt teaches. The main session implements it,
* while a visible forked Pi session supervises through pi-intercom.
*
* THE FOLD: everything above "## Log" is the short current-goal section. Everything below it
* (Log, Learnings, Appendix) is durable memory: unlimited, read on demand, and sent in full at
* session start and after compaction.
* The worker resync receives the whole plan. Supervisor reviews receive outcome/preferences/goals;
* startup and compaction add the full active plan before appendices/history (see plan-view.ts).
*
* Flow:
* SETUP (plan mode) 1. planDrafting — draft goals into the plan file (read-only), sent once
* EXEC, after compact 2. resync — the WHOLE file back, once
* SIGN-OFF, worker-side 3. completeGoal* — the one blessed tool's description
* SUPERVISION supervisor-session.ts — visible read-only supervisor
* Flow: planning → worker resync → supervisor orientation → check-ins → steering → approval →
* worker sign-off. Dynamic gate errors stay beside their checks; these prompts ask for judgment.
*
* The goal's test is the DISCRIMINATOR: the concrete observation that tells real success from the
* named subtle failure mode. Evidence is empty at planning and filled at sign-off.
@@ -176,22 +172,109 @@ ${plan}
}
/* ─────────────────────────────────────────────────────────────────────────
* 3. completeGoal — SIGN-OFF, agent-side: the one blessed tool
* 3. Supervisor orientation: short each review, full at startup/after compaction.
* ──────────────────────────────────────────────────────────────────────── */
export function supervisorOpening(planPath: string): string {
return `Your job is to be a diligent supervisor, autonomously extending the user's agency by correctly understanding their goals and preferences. Supervise the worker according to ${planPath}, which the user helped write.`;
}
// Pi/OpenAI: User intent/autonomy adapted from https://www.anthropic.com/constitution; outcome focus from @monotykamary/pi-supervisor.
export function supervisorPrompt(planPath: string): string {
return `${supervisorOpening(planPath)}
At startup and after compaction, read the applicable AGENTS.md instructions and relevant skills to understand the user's goals, preferences, and working standards. Do not assume a particular project or workflow. Read the plan's appendices when needed.
Understand the user's immediate request without interpreting it too literally or too liberally. Consider their final goals and the background standards and preferences the work should meet. Use good planning, taste, context, and high-level perspective. Infer ordinary implementation details, but do not silently replace the agreed outcome or invent restrictions.
Protect the user's epistemic autonomy and rational agency. Make consequential uncertainty and disagreement visible. Respect their authorized decisions without requiring them to justify reasonable preferences; voice concerns without substituting your preferences for theirs.
You are the visible pi-goals supervisor for ${planPath}. You are a stronger, read-only reviewer. The other Pi session is the implementation worker and keeps the full conversation. You keep the high-level intent from the compacted planning conversation and worker views. The complete plan at ${planPath} is the source of truth; read it directly after every compaction.
Supervise autonomously until the agreed goal is achieved and you have inspected the actual result. Use judgment: identify the missing user-visible result, decide the next useful action, and supervise it through to delivery. Approval records support this work; they are not the outcome. Seek justified confidence, not certainty at any cost. Investigate uncertainty with the cheapest useful check, then decide. Never repeat a steer that had no effect: inspect what happened and change the approach. Do not prolong completed work for optional polish.
The worker stopping is not a reason for you to stop. Treat "blocked", "waiting", "impossible", and "already done" as claims to investigate, not conclusions to repeat. Check the evidence and whether the claimed dependency is real. Consider mistaken assumptions, bugs, and other authorized ways forward. If progress stalls, diagnose why and use SteerWorker to send a useful next instruction instead of repeating status checks. Keep independent work moving when it does not depend on the blocker. A verified external dependency may require waiting or a human decision, but it does not make an unfinished goal complete.
Keep authorized work moving. Resolve technical choices within the agreed scope yourself. If idle with unfinished goals, use SteerWorker to resume useful work; a recap alone does not restart the worker. If useful work is running, do not invent work or repeat an instruction already awaiting execution. Waiting is warranted when a verified dependency remains; identify what event will resume progress and how it will be observed. Escalate only a specific unresolved human decision, permission, credential, or spending need after checking what is already authorized. Do not dismiss genuine limits or expand scope to avoid reporting a blocker.
At each review, give a brief visible recap of how work is tracking against the goal: what the evidence shows and your judgment about the next step. Add perspective rather than repeating status. Distinguish observations from guesses. Keep routine recaps short, but do not suppress useful explanation or thinking. Do not edit files or execute the worker's work.
Ground consequential judgments in verbatim evidence with a source path or link and enough surrounding context to check the interpretation. Keep the observation separate from your inference. A worker summary is a claim, not an independent observation; repeated summaries of one result are not independent evidence. Say what evidence would change your mind. Missing evidence stays unknown until you inspect where it should be.
Check the actual deliverable against the user's goal. Passing tests, a confident summary, or a checked box alone do not establish success. Investigate contradictions and surprising results; choose checks that distinguish plausible explanations. Review plan changes for drift from the user's intent and steer corrections when needed.
Only if the evidence establishes completion, use ApproveGoal and direct the worker to CompleteGoal. Otherwise send the next useful instruction with SteerWorker, or explain the verified dependency preventing progress. Follow the tools' requirements without letting bookkeeping replace delivery. Once the agreed work is complete, give a short assessment and stop. -- Pi/OpenAI`;
}
export function supervisorReviewContext(planPath: string, shortPlan: string): string {
return `${supervisorOpening(planPath)}\n\nCurrent agreed plan (reread for every review):\n${shortPlan}\n\nJudge progress against this outcome and its discriminators. A completed artifact or task is not completion unless it satisfies the agreed goal.`;
}
export function supervisorOrientation(planPath: string, fullPlan: string): string {
return `${supervisorPrompt(planPath)}\n\nFull active plan:\n${fullPlan}`;
}
export function supervisorCompaction(planPath: string, initial: boolean): string {
return initial
? `Preserve the user's high-level intent, decisions, unresolved risks, and the supervisor's remit. The canonical plan is ${planPath}; it remains available directly and must not be replaced by this summary.`
: `Keep the user's high-level intent, current plan state, unresolved risks, approval decisions, and the supervisor's own concise findings. Remove old worker views and implementation detail. The canonical plan remains ${planPath}.`;
}
/* 4. Check-ins: decide whether work is on track, then act when needed. */
export type SupervisorReviewReason = "ready" | "settled" | "turns" | "interval" | "started" | "plan";
export const supervisorReadyReview = "Check the agreed outcome and decide the next useful action. Use SteerWorker to send the worker a concrete starting instruction; do not repeat one already being acted on.";
export const supervisorStartedReview = "The worker has begun a turn. Check whether its direction fits the agreed goal; let productive work continue and use SteerWorker only if a correction is needed.";
export const supervisorPeriodicReview = "Is the worker on track toward the user's intended outcome? Check for drift, mistaken assumptions, or wasted effort. Use SteerWorker to send a correction where useful; otherwise let productive work continue without interruption.";
export const supervisorStoppedReview = "Inspect the results and judge whether the agreed goal is actually achieved. If unfinished, investigate why the worker stopped and use SteerWorker to send the next useful instruction and resume work. If a verified dependency prevents progress, establish what will resume it and how that will be observed. Do not treat stopping as completion. Consider ApproveGoal only after the results satisfy the goal.";
export const supervisorPlanChangeReview = "Assess plan changes against the user's intent and preferences. Manual checkbox edits are claims, not proof of completion. Inspect the actual result before accepting a claim; use SteerWorker to send corrections when the plan or work has drifted. Preserve authorized changes.";
export function supervisorCheckIn(reason: SupervisorReviewReason, idle: boolean): string {
// These status prefixes are also read by approval checks; keep them unchanged.
const state = reason === "ready" ? "is ready to begin" : idle ? "stopped" : "is still working";
const task = reason === "ready" ? supervisorReadyReview : idle ? supervisorStoppedReview : reason === "started" ? supervisorStartedReview : supervisorPeriodicReview;
return `The worker ${state}.\n\n${reason === "plan" ? `${supervisorPlanChangeReview}\n\n` : ""}${task}`;
}
export function supervisorPlanReview(claims: string[], changes: string[], diff: string): string {
return `${supervisorPlanChangeReview}\nClaims awaiting supervisor judgment: ${claims.join(", ") || "none"}\nGoal-state changes:\n${changes.join("\n") || "none"}\nPlan diff since the previous published view:\n${diff}`;
}
/* 5. Steering: a visible message is an assessment; this tool sends an actionable instruction. */
export const steerWorkerDescription = "Send one concrete instruction to the implementation worker. Use it to resume useful work after a stop, request a needed check, or correct drift toward the agreed goal. A recap alone does not send an instruction. Do not interrupt productive work or repeat ineffective steering without changing the approach.";
export const steerWorkerInstructionDescription = "The next useful action and its purpose toward the agreed goal; include the check or result needed to assess progress.";
export function workerInstructionSent(id: string): string {
return `Worker instruction ${id} sent through pi-intercom. Receipt and execution are not confirmed by this result.`;
}
/* 6. Approval: the supervisor's acceptance action AFTER judgment, not a request to judge. */
export const approveGoalDescription = "Use only after judging that the actual result satisfies the user's intended outcome and the goal's discriminator. This tool records your acceptance; its mechanical checks cannot establish success. If the goal is unmet or evidence is insufficient, do not approve: use SteerWorker to request the next useful work or check.\n\nRequirements: inspect the current goal, repository, evidence, and a saved nonempty verification-output file, with a current stopped worker view and no active work. force overrides only dirty-worktree rejection and requires a reason; later Git/content changes invalidate approval.";
export const approveGoalParameters = {
goal: "Exact text after goal: in the plan, whose intended outcome you have judged achieved.",
verifyOutputPath: "Nonempty repository-relative file containing the verification output you inspected against the goal's discriminator.",
force: "Accept this exact inspected dirty worktree, without bypassing any other approval gate.",
reason: "Required with force:true. Why accepting this inspected worktree state is justified.",
};
export function goalApprovalRecorded(goal: string, forced?: { reason: string; path: string }): string {
return `Approval recorded for "${goal}".${forced ? ` Forced worktree acceptance: ${forced.reason}. Exact status and content fingerprints saved in ${forced.path}; changes require fresh review.` : ""} Use SteerWorker to tell the worker to call CompleteGoal with this exact goal text. Continue supervising any remaining goals.`;
}
/* 7. Worker sign-off: consume the supervisor's recorded approval. */
export const completeGoalDescription =
"Sign off a goal once its discriminator is satisfied. First fill the goal's evidence: list in the " +
"Worker-only sign-off after the visible supervisor has judged the goal achieved and recorded approval. " +
"If approval is absent, provide the result and evidence for review rather than calling this tool. " +
"First fill the goal's evidence: list in the " +
"plan file: each item pairs a durable artifact with a short read of it (a quoted+linked log, a " +
"table plus how to read it, a metric plus what it shows -- not a bare claim). Quote verbatim from " +
"output you actually observed; never reconstruct numbers from memory. If you couldn't see an " +
"output, rerun it or write that you couldn't -- an honest gap beats a plausible fabrication. If " +
"the goal names a verify: command, direct the worker to run it and save its output to a file cited " +
"in the evidence. The supervisor may run an allowed read-only verification command, but must not " +
"create the evidence file itself. The visible supervisor must reject a claimed pass with no saved " +
"output. The read must show success POSITIVELY happened, not just that failures were avoided. The " +
"the goal names a verify: command, run it and save its output to a file cited in the evidence. " +
"The visible supervisor reads the actual result and saved output to judge whether the discriminator " +
"is satisfied, not merely whether tasks finished or files exist. The read must show success " +
"POSITIVELY happened, not just that failures were avoided. The " +
"supervisor records an approval checkpoint only after it inspected the current plan, repository, " +
"evidence, verify output, and a stopped worker view with no active work. Then the worker calls this " +
"tool with the exact goal text. This tool independently checks that checkpoint " +
"against the exact current goal block, HEAD/tree, and clean worktree before it appends the sign-off to " +
"against the exact current goal block, HEAD/tree, and approved repository state before it appends the sign-off to " +
"## Log and ticks the goal [x]. If any check differs, it fails closed and requires a fresh supervisor review.";
export const completeGoalParamDescription = "The goal's text: the line after 'goal:' in the plan file.";
+14 -44
View File
@@ -6,6 +6,7 @@ import { Type } from "typebox";
import { approvalPath, goalBlock, hashGoalBlock, repositoryState, verifyOutputPath, writeApproval } from "./approval.js";
import { GoalIntercom } from "./intercom.js";
import { planViews } from "./plan-view.js";
import { approveGoalDescription, approveGoalParameters, goalApprovalRecorded, steerWorkerDescription, steerWorkerInstructionDescription, supervisorCompaction, supervisorOrientation, supervisorReviewContext, workerInstructionSent } from "./prompts.js";
import { RoleModels } from "./role-models.js";
const BOOTSTRAPPED = "pi-goals-visible-supervisor-v2";
@@ -67,37 +68,6 @@ function latestWorkerView(ctx: ExtensionContext): string | null {
return null;
}
function supervisorOpening(settings: SupervisorConfig): string {
return `Your job is to be a diligent supervisor, autonomously extending the user's agency by correctly understanding their goals and preferences. Supervise the worker according to ${settings.planPath}, which the user helped write.`;
}
// Pi/OpenAI: User intent/autonomy adapted from https://www.anthropic.com/constitution; outcome focus from @monotykamary/pi-supervisor.
function supervisorPrompt(settings: SupervisorConfig): string {
return `${supervisorOpening(settings)}
At startup and after compaction, read the applicable AGENTS.md instructions and relevant skills to understand the user's goals, preferences, and working standards. Do not assume a particular project or workflow. Read the plan's appendices when needed.
Understand the user's immediate request without interpreting it too literally or too liberally. Consider their final goals and the background standards and preferences the work should meet. Use good planning, taste, context, and high-level perspective. Infer ordinary implementation details, but do not silently replace the agreed outcome or invent restrictions.
Protect the user's epistemic autonomy and rational agency. Make consequential uncertainty and disagreement visible. Respect their authorized decisions without requiring them to justify reasonable preferences; voice concerns without substituting your preferences for theirs.
You are the visible pi-goals supervisor for ${settings.planPath}. You are a stronger, read-only reviewer. The other Pi session is the implementation worker and keeps the full conversation. You keep the high-level intent from the compacted planning conversation and worker views. The complete plan at ${settings.planPath} is the source of truth; read it directly after every compaction.
Your job is to supervise the worker autonomously until the agreed goal is achieved. Use judgment: identify the missing user-visible result, decide the next useful action, and supervise it through to delivery. Approval records support this work; they are not the outcome. Seek justified confidence, not certainty at any cost. Investigate uncertainty with the cheapest useful check, then decide. Never repeat a steer that had no effect: inspect what happened and change the approach. When the worker is idle and the goal is unfinished, steer a concrete next action unless a verified dependency or required human decision prevents progress. Do not prolong completed work for optional polish.
Supervise autonomously until the agreed goal is achieved and you have inspected the actual result. The worker stopping is not a reason for you to stop. Treat "blocked", "waiting", "impossible", and "already done" as claims to investigate, not conclusions to repeat. Check the evidence and whether the claimed dependency is real. Consider mistaken assumptions, bugs, and other authorized ways forward. If progress stalls, diagnose why and steer a useful next action instead of repeating status checks. Keep independent work moving when it does not depend on the blocker. A verified external dependency may require waiting or a human decision, but it does not make an unfinished goal complete.
Keep authorized work moving. Resolve technical choices within the agreed scope yourself. If idle with unfinished goals, use SteerWorker for a concrete next step or diagnostic check. If useful work is running, do not invent work or repeat an instruction already awaiting execution. Waiting is warranted when a verified dependency remains; identify what event will resume progress and how it will be observed. Escalate only a specific unresolved human decision, permission, credential, or spending need after checking what is already authorized. Do not dismiss genuine limits or expand scope to avoid reporting a blocker.
At each review, give a brief visible recap of how work is tracking against the goal: what the evidence shows and your judgment about the next step. Add perspective rather than repeating status. Distinguish observations from guesses. Keep routine recaps short, but do not suppress useful explanation or thinking. Do not edit files or execute the worker's work.
Ground consequential judgments in verbatim evidence with a source path or link and enough surrounding context to check the interpretation. Keep the observation separate from your inference. A worker summary is a claim, not an independent observation; repeated summaries of one result are not independent evidence. Say what evidence would change your mind. Missing evidence stays unknown until you inspect where it should be.
Check the actual deliverable against the user's goal. Passing tests, a confident summary, or a checked box alone do not establish success. Investigate contradictions and surprising results; choose checks that distinguish plausible explanations. Review plan changes for drift from the user's intent and steer corrections when needed.
When the evidence establishes completion, use ApproveGoal and direct the worker to CompleteGoal. Follow the tools' requirements without letting bookkeeping replace delivery. Once the agreed work is complete, give a short assessment and stop. -- Pi/OpenAI`;
}
export function isVisibleSupervisor(): boolean {
return process.env.PI_GOALS_ROLE === "supervisor";
}
@@ -141,7 +111,7 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
}
compacting = true;
ctx.compact({
customInstructions: `Preserve the user's high-level intent, decisions, unresolved risks, and the supervisor's remit. The canonical plan is ${settings.planPath}; it remains available directly and must not be replaced by this summary.`,
customInstructions: supervisorCompaction(settings.planPath, true),
onComplete: () => {
compacting = false;
if (intercom.ended) return;
@@ -183,10 +153,10 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
});
pi.on("before_agent_start", async (_event, ctx) => {
const plan = planViews(readFileSync(settings.planPath, "utf8"));
const message = repeatFullPrompt ? { customType: "pi-goals-supervisor-role", content: `${supervisorPrompt(settings)}\n\nFull active plan:\n${plan.long}`, display: true } : undefined;
const message = repeatFullPrompt ? { customType: "pi-goals-supervisor-role", content: supervisorOrientation(settings.planPath, plan.long), display: true } : undefined;
repeatFullPrompt = false;
return {
systemPrompt: `${ctx.getSystemPrompt()}\n\n${supervisorOpening(settings)}\n\nCurrent agreed plan (reread for every review):\n${plan.short}\n\nJudge progress against this outcome and its discriminators. A completed artifact or task is not completion unless it satisfies the agreed goal.`,
systemPrompt: `${ctx.getSystemPrompt()}\n\n${supervisorReviewContext(settings.planPath, plan.short)}`,
...(message ? { message } : {}),
};
});
@@ -201,7 +171,7 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
if (typeof usage?.tokens !== "number" || usage.tokens < COMPACT_AT_TOKENS) return;
compacting = true;
ctx.compact({
customInstructions: `Keep the user's high-level intent, current plan state, unresolved risks, approval decisions, and the supervisor's own concise findings. Remove old worker views and implementation detail. The canonical plan remains ${settings.planPath}.`,
customInstructions: supervisorCompaction(settings.planPath, false),
onComplete: () => {
compacting = false;
if (intercom.ended) return;
@@ -219,8 +189,8 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
name: "SteerWorker",
label: "Steer worker",
executionMode: "sequential",
description: "Write one concrete instruction for the implementation worker.",
parameters: Type.Object({ instruction: Type.String({ description: "Concrete next instruction for the worker." }) }),
description: steerWorkerDescription,
parameters: Type.Object({ instruction: Type.String({ description: steerWorkerInstructionDescription }) }),
renderCall(args, theme) {
return new Text(`${theme.fg("toolTitle", "Supervisor → worker")}\n${args.instruction ?? ""}`, 0, 0);
},
@@ -229,7 +199,7 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
const instruction = params.instruction.trim();
if (!instruction) return result("A worker instruction cannot be empty.", true);
const id = intercom.steer(instruction);
return result(`Worker instruction ${id} sent through pi-intercom. Receipt and execution are not confirmed by this result.`);
return result(workerInstructionSent(id));
},
});
@@ -237,12 +207,12 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
name: "ApproveGoal",
label: "Approve goal",
executionMode: "sequential",
description: "Record approval after inspecting the current goal, repository, evidence, and a saved nonempty verification-output file, with a stopped worker view and no active work. force overrides only dirty-worktree rejection and requires a reason; later Git/content changes invalidate it.",
description: approveGoalDescription,
parameters: Type.Object({
goal: Type.String({ description: "Exact text after goal: in the plan." }),
verifyOutputPath: Type.String({ description: "Nonempty repository-relative file containing the verification output you inspected." }),
force: Type.Optional(Type.Boolean({ description: "Accept this exact inspected dirty worktree, without bypassing any other approval gate." })),
reason: Type.Optional(Type.String({ description: "Required with force:true. Why accepting these inspected worktree changes is justified." })),
goal: Type.String({ description: approveGoalParameters.goal }),
verifyOutputPath: Type.String({ description: approveGoalParameters.verifyOutputPath }),
force: Type.Optional(Type.Boolean({ description: approveGoalParameters.force })),
reason: Type.Optional(Type.String({ description: approveGoalParameters.reason })),
}),
async execute(_id, params, _signal, _onUpdate, ctx) {
if (modelError) return result(`Supervisor paused: ${modelError} Use /model, then /goals reconnect.`, true);
@@ -280,7 +250,7 @@ export function registerVisibleSupervisor(pi: ExtensionAPI): void {
cleanWorktree: repository.cleanWorktree, ...(force ? { force: { reason: reason!, worktree: repository.worktree! } } : {}), inspected: { plan: true, repository: true, evidence: true, verifyOutput: true }, verifyOutputPath: verifiedOutput,
supervisor: { sessionId: ctx.sessionManager.getSessionId(), runId: null }, timestamp: new Date().toISOString(),
});
return result(`Approval recorded for "${params.goal}".${force ? ` Forced worktree acceptance: ${reason}. Exact status and content fingerprints saved in ${path}; changes require fresh review.` : ""} Now steer the worker to call CompleteGoal.`);
return result(goalApprovalRecorded(params.goal, force ? { reason: reason!, path } : undefined));
},
});
}
+3 -3
View File
@@ -1,4 +1,5 @@
import { compile } from "@sting8k/pi-vcc/src/core/summarize";
import { type SupervisorReviewReason, supervisorCheckIn } from "./prompts.js";
export interface SessionBlock {
type?: string;
@@ -87,7 +88,7 @@ export interface ViewContext {
planReview?: string;
}
export function workerView(entries: SessionEntry[], reason: "ready" | "settled" | "turns" | "interval" | "started" | "plan", idle: boolean, context: ViewContext): string {
export function workerView(entries: SessionEntry[], reason: SupervisorReviewReason, idle: boolean, context: ViewContext): string {
const compactAt = entries.map(entry => entry.type).lastIndexOf("compaction");
const since = context.since ? entries.findIndex(entry => entry.id === context.since) : -1;
const from = since >= compactAt ? since + 1 : compactAt + 1;
@@ -95,6 +96,5 @@ export function workerView(entries: SessionEntry[], reason: "ready" | "settled"
const recent = compiledView(fresh.flatMap(entry => entry.type === "message" && entry.message ? [entry.message] : []));
const summary = since < compactAt ? entries[compactAt]?.summary : undefined;
const outstanding = outstandingTools(entries.slice(compactAt + 1));
const state = reason === "ready" ? "is ready to begin" : idle ? "stopped" : "is still working";
return `The worker ${state}.\n\nreview trigger: ${reason}\nsource session: ${bounded(context.sourceSession, 800)}\nworker model: ${bounded(context.model, 300)}${context.contextPercent == null ? "" : `; context used: ${context.contextPercent}%`}\nlatest human direction:\n${bounded(context.latestDirection || "not recorded", 1800)}\ntool calls with no result: ${bounded(outstanding.join(", ") || "none", 500)}\ntracked background work: ${bounded(context.background, 800)}\n\n${context.planReview ? `Plan review:\n${bounded(context.planReview, 1800)}\n\n` : ""}${summary ? `compaction summary (worker account, not independent evidence):\n${bounded(summary, 2500)}\n\n` : ""}new worker overview${since === -1 ? " (initial or reset view)" : " since the last acknowledged view"} (VCC algorithmic compression; local # refs index new messages; tool-result bodies omitted; inspect source for evidence):\n${recent}`;
return `${supervisorCheckIn(reason, idle)}\n\nreview trigger: ${reason}\nsource session: ${bounded(context.sourceSession, 800)}\nworker model: ${bounded(context.model, 300)}${context.contextPercent == null ? "" : `; context used: ${context.contextPercent}%`}\nlatest human direction:\n${bounded(context.latestDirection || "not recorded", 1800)}\ntool calls with no result: ${bounded(outstanding.join(", ") || "none", 500)}\ntracked background work: ${bounded(context.background, 800)}\n\n${context.planReview ? `Plan review:\n${bounded(context.planReview, 1800)}\n\n` : ""}${summary ? `compaction summary (worker account, not independent evidence):\n${bounded(summary, 2500)}\n\n` : ""}new worker overview${since === -1 ? " (initial or reset view)" : " since the last acknowledged view"} (VCC algorithmic compression; local # refs index new messages; tool-result bodies omitted; inspect source for evidence):\n${recent}`;
}
+5 -1
View File
@@ -1,5 +1,6 @@
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
import { GoalIntercom } from "../../src/intercom.js";
import { workerView } from "../../src/worker-view.js";
export default function worker(pi: ExtensionAPI): void {
const link = new GoalIntercom(pi);
@@ -7,7 +8,10 @@ export default function worker(pi: ExtensionAPI): void {
pi.on("session_start", async (_event, ctx) => {
link.configure("native-pair-test", "worker", ctx);
void link.waitReady(8000).then(() => {
link.view("The worker stopped.\n\nThe saved plan needs a check of the actual outputs.", "settled", undefined, true);
link.view(workerView(ctx.sessionManager.getBranch(), "settled", true, {
sourceSession: ctx.sessionManager.getSessionFile()!, latestDirection: "Inspect actual outputs.",
model: "offline/test", background: "No tracked work in this fixture.",
}), "settled", undefined, true);
}).catch(error => { if (!link.ended) ctx.ui.notify(String(error), "error"); });
});
}
+3
View File
@@ -114,6 +114,8 @@ describe("/goals flow", () => {
const count = views().length;
expect(flow.entries.at(-1)?.data).toMatchObject({ phase: "working", signedOffGoals: [] });
expect(views().at(-1)?.text).toContain("make the file: [/] -> [x]; manual completion claim, no CompleteGoal sign-off recorded");
expect(views().at(-1)?.text).toContain("use SteerWorker to send the next useful instruction and resume work");
expect(views().at(-1)?.text).toContain("Manual checkbox edits are claims, not proof of completion");
expect(readFileSync(path, "utf8")).toContain("[x] goal:");
expect(flow.ctx.ui.setStatus).toHaveBeenLastCalledWith("pi-goals", expect.stringContaining("0/1 goals · 1 claimed, awaiting review"));
expect(flow.ctx.ui.setWidget).toHaveBeenLastCalledWith("pi-goals-widget", [expect.stringContaining("claimed complete; awaiting supervisor review")]);
@@ -142,6 +144,7 @@ describe("/goals flow", () => {
await vi.waitFor(() => {
const view = flow.transport.sent.filter(message => message.kind === "view").at(-1);
expect(view?.reason).toBe("plan");
expect(view?.text).toContain("Assess plan changes against the user's intent and preferences");
expect(view?.text).toContain("- - discriminator: output exists");
expect(view?.text).toContain("+ - discriminator: output contains exact required bytes");
});
+10 -1
View File
@@ -5,6 +5,7 @@ import { createServer } from "node:http";
import { tmpdir } from "node:os";
import { join, resolve } from "node:path";
import { expect, it } from "vitest";
import { approveGoalDescription, steerWorkerDescription, supervisorStoppedReview } from "../src/prompts.js";
// Pi/OpenAI: RPC drives test inputs only; the two sessions communicate exclusively through Intercom.
class Driver {
@@ -48,13 +49,17 @@ it("runs a forked Pi supervisor and receives its exact instruction in another Pi
let workerFile: string | undefined;
let supervisorFile: string | undefined;
let supervisorTools: string[] = [];
let supervisorRequest: any;
const server = createServer(async (request, response) => {
let body = "";
for await (const chunk of request) body += chunk;
const input = JSON.parse(body);
const latest = input.messages.filter((message: any) => !JSON.stringify(message.content).includes("Full active plan:")).at(-1);
const steer = latest.role === "user" && JSON.stringify(latest.content).includes("The worker stopped.");
if (steer) supervisorTools = input.tools.map((tool: any) => tool.function.name);
if (steer) {
supervisorRequest = input;
supervisorTools = input.tools.map((tool: any) => tool.function.name);
}
response.writeHead(200, { "content-type": "text/event-stream" });
const delta = steer ? { tool_calls: [{ index: 0, id: "test-steer", type: "function", function: { name: "SteerWorker", arguments: JSON.stringify({ instruction: advice }) } }] } : { content: "Test context retained. Actual outputs still need inspection." };
response.write(`data: ${JSON.stringify({ choices: [{ index: 0, delta, finish_reason: null }] })}\n\n`);
@@ -97,6 +102,10 @@ it("runs a forked Pi supervisor and receives its exact instruction in another Pi
expect(supervisorTools).toContain("SteerWorker");
expect(supervisorTools).not.toContain("intercom");
expect(supervisorTools).not.toContain("bash");
expect(JSON.stringify(supervisorRequest.messages)).toContain(supervisorStoppedReview);
const description = (name: string) => supervisorRequest.tools.find((tool: any) => tool.function.name === name).function.description;
expect(description("SteerWorker")).toBe(steerWorkerDescription);
expect(description("ApproveGoal")).toBe(approveGoalDescription);
supervisor.send({ type: "get_state", id: "supervisor-state" });
const supervisorState = await supervisor.wait(message => message.type === "response" && message.id === "supervisor-state");
supervisorFile = supervisorState.data.sessionFile;
+30 -1
View File
@@ -1,5 +1,34 @@
import { describe, expect, it } from "vitest";
import { completeGoalDescription, planDrafting, planningState, resync } from "../src/prompts.js";
import { approveGoalDescription, completeGoalDescription, goalApprovalRecorded, planDrafting, planningState, resync, steerWorkerDescription, supervisorPeriodicReview, supervisorPlanChangeReview, supervisorReadyReview, supervisorStartedReview, supervisorStoppedReview } from "../src/prompts.js";
describe("supervisor event tasks", () => {
it("asks a ready or stopped worker to resume through SteerWorker rather than only review", () => {
expect(supervisorReadyReview).toContain("Use SteerWorker");
expect(supervisorStoppedReview).toContain("judge whether the agreed goal is actually achieved");
expect(supervisorStoppedReview).toContain("use SteerWorker to send the next useful instruction and resume work");
expect(supervisorStoppedReview).toContain("verified dependency");
expect(supervisorStoppedReview).toContain("only after the results satisfy the goal");
expect(steerWorkerDescription).toContain("A recap alone does not send an instruction");
});
it("asks if active work is on track and keeps productive work uninterrupted", () => {
expect(supervisorPeriodicReview).toContain("Is the worker on track");
expect(supervisorPeriodicReview).toContain("let productive work continue without interruption");
expect(supervisorStartedReview).toContain("only if a correction is needed");
expect(supervisorPlanChangeReview).toContain("claims, not proof of completion");
expect(supervisorPlanChangeReview).toContain("Preserve authorized changes");
});
it("defines approval as acceptance after outcome judgment, with mechanics separate", () => {
expect(approveGoalDescription).toMatch(/^Use only after judging that the actual result satisfies/);
expect(approveGoalDescription).toContain("mechanical checks cannot establish success");
expect(approveGoalDescription).toContain("If the goal is unmet or evidence is insufficient, do not approve");
expect(approveGoalDescription).toContain("\n\nRequirements:");
expect(goalApprovalRecorded("repair")).toContain("Use SteerWorker to tell the worker to call CompleteGoal with this exact goal text");
expect(completeGoalDescription).toContain("Worker-only sign-off");
expect(completeGoalDescription).not.toContain("direct the worker to run it");
});
});
describe("planning prompt", () => {
it("requires fact finding or a focused question before a goal", () => {
+10
View File
@@ -6,6 +6,7 @@ import { stripVTControlCharacters } from "node:util";
import { AssistantMessageComponent, type ExtensionAPI, initTheme, ToolExecutionComponent } from "@earendil-works/pi-coding-agent";
import { afterEach, describe, expect, it, vi } from "vitest";
import { approvalPath } from "../src/approval.js";
import { approveGoalDescription, approveGoalParameters, goalApprovalRecorded, steerWorkerDescription, steerWorkerInstructionDescription, supervisorCompaction, supervisorOrientation, supervisorReviewContext } from "../src/prompts.js";
import { registerVisibleSupervisor } from "../src/supervisor-session.js";
import { intercomFixture } from "./intercom-fixture.js";
@@ -139,6 +140,9 @@ describe("visible supervisor session", () => {
expect(systemPrompt).toContain("discriminator: beats random");
expect(systemPrompt).not.toContain("old history");
expect(first.message.customType).toBe("pi-goals-supervisor-role");
const activePlan = "# Outcome\nBeat random\n1. [ ] goal: repair\n - discriminator: beats random";
expect(first.systemPrompt).toBe(`base\n\n${supervisorReviewContext(join(cwd, "plan.md"), activePlan)}`);
expect(first.message.content).toBe(supervisorOrientation(join(cwd, "plan.md"), activePlan));
const review = async () => runtime.hooks.get("before_agent_start")({}, runtime.ctx);
const next = await review();
expect(next.message).toBeUndefined();
@@ -186,6 +190,7 @@ describe("visible supervisor session", () => {
await runtime.hooks.get("session_start")({}, runtime.ctx);
await new Promise((resolve) => setImmediate(resolve));
expect(runtime.ctx.compact).toHaveBeenCalledOnce();
expect(runtime.ctx.compact.mock.calls[0][0].customInstructions).toBe(supervisorCompaction(join(cwd, ".pi/plan/worker-v1.md"), true));
expect(runtime.ready()).toBe(false);
complete!();
expect(runtime.ready()).toBe(true);
@@ -208,6 +213,10 @@ describe("visible supervisor session", () => {
try {
const runtime = setup(cwd, join(cwd, "plan.md"));
await runtime.start();
expect(runtime.tools.get("SteerWorker").description).toBe(steerWorkerDescription);
expect(runtime.tools.get("SteerWorker").parameters.properties.instruction.description).toBe(steerWorkerInstructionDescription);
expect(runtime.tools.get("ApproveGoal").description).toBe(approveGoalDescription);
expect(runtime.tools.get("ApproveGoal").parameters.properties.goal.description).toBe(approveGoalParameters.goal);
const steered = await runtime.tools.get("SteerWorker").execute("id", { instruction: "Run the saved verification." });
expect(steered.isError).toBe(false);
expect(runtime.transport.sent.filter(message => message.kind === "steer")).toMatchObject([{ text: "Run the saved verification." }]);
@@ -240,6 +249,7 @@ describe("visible supervisor session", () => {
writeFileSync(planPath, originalPlan);
const approved = await runtime.tools.get("ApproveGoal").execute("id", { goal: "make the file", verifyOutputPath: "verify.txt" }, undefined, undefined, runtime.ctx);
expect(approved.isError).toBe(false);
expect(approved.content[0].text).toBe(goalApprovalRecorded("make the file"));
expect(existsSync(approvalPath(cwd, "worker-session", "make the file"))).toBe(true);
runtime.view("second", "The worker is still working.", "started");
const stale = await runtime.tools.get("ApproveGoal").execute("id", { goal: "make the file", verifyOutputPath: "verify.txt" }, undefined, undefined, runtime.ctx);
+20
View File
@@ -1,9 +1,29 @@
import { expect, it } from "vitest";
import { type SupervisorReviewReason, supervisorPeriodicReview, supervisorPlanChangeReview, supervisorReadyReview, supervisorStartedReview, supervisorStoppedReview } from "../src/prompts.js";
import { workerView } from "../src/worker-view.js";
const context = { sourceSession: "/sessions/worker.jsonl", latestDirection: "Modal uses a remote GPU.", model: "provider/worker", background: "processes: 0; subagents: 0" };
const entry = (id: string, text: string) => ({ id, type: "message", message: { role: "assistant", content: text } });
it.each<[SupervisorReviewReason, boolean, string, string]>([
["ready", true, "The worker is ready to begin.", supervisorReadyReview],
["started", false, "The worker is still working.", supervisorStartedReview],
["turns", false, "The worker is still working.", supervisorPeriodicReview],
["interval", false, "The worker is still working.", supervisorPeriodicReview],
["settled", true, "The worker stopped.", supervisorStoppedReview],
["interval", true, "The worker stopped.", supervisorStoppedReview],
["settled", false, "The worker is still working.", supervisorPeriodicReview],
["plan", true, "The worker stopped.", supervisorStoppedReview],
["plan", false, "The worker is still working.", supervisorPeriodicReview],
])("wires %s (idle=%s) to its review task without changing status prefixes", (reason, idle, prefix, task) => {
const view = workerView([entry("claim", "The plot is complete but the result does not beat random.")], reason, idle, context);
expect(view.startsWith(`${prefix}\n\n`)).toBe(true);
expect(view).toContain(task);
expect(view).toContain(`review trigger: ${reason}`);
if (reason === "plan") expect(view).toContain(supervisorPlanChangeReview);
if (!idle) expect(view).not.toContain(supervisorStoppedReview);
});
it("keeps human direction and source location while sending only new messages", () => {
const view = workerView([entry("old", "old detail"), entry("new", "new result")], "interval", true, { ...context, since: "old" });
expect(view).toContain(context.latestDirection);