feat: replace edgePrompt null check with isFirstVisit (Phase 2)

- Add isFirstVisit: boolean to AgentContext
- Compute from steps history: !steps.some(s => s.role === role)
- hermes.ts: use isFirstVisit for first-entry vs re-entry logic
- buildInitialPrompt: always append edgePrompt as Moderator Instruction
- edgePrompt is never blanked — always the real moderator instruction
- New tests for first-visit, re-entry, and fallback scenarios

Refs #405, #407, #404
This commit is contained in:
2026-05-23 04:54:11 +00:00
parent 2a6bce4918
commit 4b45f4e6d1
5 changed files with 92 additions and 4 deletions
@@ -142,6 +142,7 @@ export async function buildContext(threadId: ThreadId, role: string): Promise<Ag
const steps = await buildHistory(store, chain.stepsNewestFirst);
const edgePrompt = readEdgePrompt();
const isFirstVisit = !steps.some((s) => s.role === role);
return {
threadId,
@@ -152,6 +153,7 @@ export async function buildContext(threadId: ThreadId, role: string): Promise<Ag
store,
outputFormatInstruction: "",
edgePrompt,
isFirstVisit,
};
}
@@ -189,6 +191,7 @@ export async function buildContextWithMeta(
const steps = await buildHistory(store, chain.stepsNewestFirst);
const edgePrompt = readEdgePrompt();
const isFirstVisit = !steps.some((s) => s.role === role);
return {
threadId,
@@ -199,6 +202,7 @@ export async function buildContextWithMeta(
store,
outputFormatInstruction: "",
edgePrompt,
isFirstVisit,
meta: { storageRoot, store, schemas, headHash, chain },
};
}
+5 -1
View File
@@ -14,9 +14,13 @@ export type AgentContext = ModeratorContext & {
outputFormatInstruction: string;
/**
* Edge prompt from the graph transition that led to this role (UWF_EDGE_PROMPT).
* Phase 2 will use visit history to choose full role definition vs continuation.
* Always the real moderator instruction for this step.
*/
edgePrompt: string;
/**
* True when the current role has not appeared in steps history before this invocation.
*/
isFirstVisit: boolean;
};
export type AgentRunResult = {