@caupulican/pi-adaptative 0.96.0 → 0.96.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/core/agent-session.d.ts +3 -3
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +17 -6
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/delegation/sanitized-context-fork.d.ts.map +1 -1
  7. package/dist/core/delegation/sanitized-context-fork.js +2 -15
  8. package/dist/core/delegation/sanitized-context-fork.js.map +1 -1
  9. package/dist/core/delegation/worker-retry-policy.d.ts.map +1 -1
  10. package/dist/core/delegation/worker-retry-policy.js +12 -4
  11. package/dist/core/delegation/worker-retry-policy.js.map +1 -1
  12. package/dist/core/foreground-recovery-controller.d.ts +1 -0
  13. package/dist/core/foreground-recovery-controller.d.ts.map +1 -1
  14. package/dist/core/foreground-recovery-controller.js +30 -13
  15. package/dist/core/foreground-recovery-controller.js.map +1 -1
  16. package/dist/core/goal-loop-controller.d.ts +2 -2
  17. package/dist/core/goal-loop-controller.js +2 -2
  18. package/dist/core/goal-loop-controller.js.map +1 -1
  19. package/dist/core/goals/compact-goal-context.d.ts.map +1 -1
  20. package/dist/core/goals/compact-goal-context.js +12 -8
  21. package/dist/core/goals/compact-goal-context.js.map +1 -1
  22. package/dist/core/goals/goal-continuation-controller.d.ts +3 -3
  23. package/dist/core/goals/goal-continuation-controller.js +14 -15
  24. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  25. package/dist/core/goals/goal-continuation-defaults.d.ts +3 -3
  26. package/dist/core/goals/goal-continuation-defaults.js +3 -3
  27. package/dist/core/goals/goal-continuation-defaults.js.map +1 -1
  28. package/dist/core/goals/goal-lifecycle.d.ts +2 -0
  29. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
  30. package/dist/core/goals/goal-lifecycle.js +22 -0
  31. package/dist/core/goals/goal-lifecycle.js.map +1 -1
  32. package/dist/core/goals/goal-session-controller.d.ts +8 -2
  33. package/dist/core/goals/goal-session-controller.d.ts.map +1 -1
  34. package/dist/core/goals/goal-session-controller.js +22 -3
  35. package/dist/core/goals/goal-session-controller.js.map +1 -1
  36. package/dist/core/goals/goal-state.d.ts.map +1 -1
  37. package/dist/core/goals/goal-state.js +1 -7
  38. package/dist/core/goals/goal-state.js.map +1 -1
  39. package/dist/core/goals/goal-tool-core.js +1 -1
  40. package/dist/core/goals/goal-tool-core.js.map +1 -1
  41. package/dist/core/message-phase.d.ts +8 -0
  42. package/dist/core/message-phase.d.ts.map +1 -0
  43. package/dist/core/message-phase.js +48 -0
  44. package/dist/core/message-phase.js.map +1 -0
  45. package/dist/core/model-resolver.js +1 -1
  46. package/dist/core/model-resolver.js.map +1 -1
  47. package/dist/core/models/perf-profile.d.ts +1 -0
  48. package/dist/core/models/perf-profile.d.ts.map +1 -1
  49. package/dist/core/models/perf-profile.js +12 -3
  50. package/dist/core/models/perf-profile.js.map +1 -1
  51. package/dist/core/package-manager.d.ts +1 -1
  52. package/dist/core/package-manager.d.ts.map +1 -1
  53. package/dist/core/package-manager.js +2 -21
  54. package/dist/core/package-manager.js.map +1 -1
  55. package/dist/core/settings-manager.d.ts +5 -3
  56. package/dist/core/settings-manager.d.ts.map +1 -1
  57. package/dist/core/settings-manager.js +44 -12
  58. package/dist/core/settings-manager.js.map +1 -1
  59. package/dist/core/tools/goal.js +2 -2
  60. package/dist/core/tools/goal.js.map +1 -1
  61. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  62. package/dist/modes/interactive/components/assistant-message.js +5 -3
  63. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  64. package/dist/modes/interactive/components/custom-message.js +7 -2
  65. package/dist/modes/interactive/components/custom-message.js.map +1 -1
  66. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  67. package/dist/modes/interactive/components/settings-selector.js +2 -2
  68. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  69. package/dist/modes/interactive/interactive-event-controller.d.ts.map +1 -1
  70. package/dist/modes/interactive/interactive-event-controller.js +9 -0
  71. package/dist/modes/interactive/interactive-event-controller.js.map +1 -1
  72. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  73. package/dist/modes/interactive/session-flow-commands.js +9 -2
  74. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  75. package/docs/sessions.md +1 -1
  76. package/docs/tool-repair.md +4 -3
  77. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  78. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  79. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  80. package/examples/extensions/sandbox/package-lock.json +2 -2
  81. package/examples/extensions/sandbox/package.json +1 -1
  82. package/examples/extensions/with-deps/package-lock.json +2 -2
  83. package/examples/extensions/with-deps/package.json +1 -1
  84. package/npm-shrinkwrap.json +12 -12
  85. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"sanitized-context-fork.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/sanitized-context-fork.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAOpF,eAAO,MAAM,wCAAwC,kHAC2D,CAAC;AACjH,eAAO,MAAM,wCAAwC,qBAAqB,CAAC;AAE3E,MAAM,MAAM,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvH,MAAM,MAAM,2BAA2B,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAezE,gGAAgG;AAChG,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB,CAQrF;AAiMD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,IAAI,EAAE,wBAAwB,GAC5B,2BAA2B,EAAE,CAyE/B"}
1
+ {"version":3,"file":"sanitized-context-fork.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/sanitized-context-fork.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAe,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAQpF,eAAO,MAAM,wCAAwC,kHAC2D,CAAC;AACjH,eAAO,MAAM,wCAAwC,qBAAqB,CAAC;AAE3E,MAAM,MAAM,wBAAwB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvH,MAAM,MAAM,2BAA2B,GAAG,WAAW,GAAG,gBAAgB,CAAC;AAezE,gGAAgG;AAChG,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,wBAAwB,CAQrF;AAqLD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACzC,QAAQ,EAAE,SAAS,YAAY,EAAE,EACjC,IAAI,EAAE,wBAAwB,GAC5B,2BAA2B,EAAE,CAyE/B"}
@@ -1,3 +1,4 @@
1
+ import { isAssistantCommentary } from "../message-phase.js";
1
2
  import { MAX_WORKER_CONTEXT_FORK_BYTES, MAX_WORKER_CONTEXT_FORK_MESSAGES, MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS, } from "../orchestration/worker-context-fork-reference.js";
2
3
  export const SANITIZED_CONTEXT_FORK_COMPACTION_PREFIX = "The parent conversation history before this point was compacted into the following checkpoint:\n\n<summary>\n";
3
4
  export const SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX = "\n</summary>\n\n";
@@ -20,20 +21,6 @@ export function parseSanitizedContextForkMode(value) {
20
21
  throw invalidMode();
21
22
  return { kind: "last_user_turns", count };
22
23
  }
23
- function hasCommentaryPhase(textSignature) {
24
- if (!textSignature?.startsWith("{"))
25
- return false;
26
- try {
27
- const parsed = JSON.parse(textSignature);
28
- if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
29
- return false;
30
- const phase = Object.getOwnPropertyDescriptor(parsed, "phase");
31
- return phase !== undefined && "value" in phase && phase.value === "commentary";
32
- }
33
- catch {
34
- return false;
35
- }
36
- }
37
24
  function sanitizedTextBlocks(content, dropCommentary) {
38
25
  if (content.length > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS)
39
26
  return { kind: "oversized" };
@@ -42,7 +29,7 @@ function sanitizedTextBlocks(content, dropCommentary) {
42
29
  for (const block of content) {
43
30
  if (block.type !== "text" || !block.text.trim())
44
31
  continue;
45
- if (dropCommentary && hasCommentaryPhase(block.textSignature))
32
+ if (dropCommentary && isAssistantCommentary(block))
46
33
  continue;
47
34
  textBytes += Buffer.byteLength(block.text, "utf-8");
48
35
  if (textBytes > MAX_WORKER_CONTEXT_FORK_BYTES)
@@ -1 +1 @@
1
- {"version":3,"file":"sanitized-context-fork.js","sourceRoot":"","sources":["../../../src/core/delegation/sanitized-context-fork.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { AssistantMessage, TextContent, UserMessage } from \"@caupulican/pi-ai\";\nimport {\n\tMAX_WORKER_CONTEXT_FORK_BYTES,\n\tMAX_WORKER_CONTEXT_FORK_MESSAGES,\n\tMAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS,\n} from \"../orchestration/worker-context-fork-reference.ts\";\n\nexport const SANITIZED_CONTEXT_FORK_COMPACTION_PREFIX =\n\t\"The parent conversation history before this point was compacted into the following checkpoint:\\n\\n<summary>\\n\";\nexport const SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX = \"\\n</summary>\\n\\n\";\n\nexport type SanitizedContextForkMode = { kind: \"none\" } | { kind: \"all\" } | { kind: \"last_user_turns\"; count: number };\n\nexport type SanitizedContextForkMessage = UserMessage | AssistantMessage;\n\ntype ContextTextCandidate = AssistantMessage[\"content\"][number] | Exclude<UserMessage[\"content\"], string>[number];\n\ntype SanitizedCompactionCheckpoint = { kind: \"valid\"; text: string } | { kind: \"invalid\" };\ntype SanitizedMessageResult<T> = { kind: \"ok\"; message: T } | { kind: \"drop\" } | { kind: \"oversized\" };\ntype UserBoundaryKind = \"eligible\" | \"worker_control\" | \"unsupported\" | \"oversized\";\n\nconst WORKER_CONTROL_PREFIX = /^\\[Worker control worker-message-[^\\]\\s]+(?: [^\\]]+)?\\]\\r?\\n/;\nconst MAX_WORKER_CONTROL_PREFIX_CHARS = 2048;\n\nfunction invalidMode(): TypeError {\n\treturn new TypeError(\"Context fork mode must be none, all, or a positive safe-integer string.\");\n}\n\n/** Parse the eventual tool-facing `fork_turns` wire value without choosing a default policy. */\nexport function parseSanitizedContextForkMode(value: string): SanitizedContextForkMode {\n\tconst normalized = value.trim().toLowerCase();\n\tif (normalized === \"none\") return { kind: \"none\" };\n\tif (normalized === \"all\") return { kind: \"all\" };\n\tif (!/^\\d+$/.test(normalized)) throw invalidMode();\n\tconst count = Number(normalized);\n\tif (!Number.isSafeInteger(count) || count <= 0) throw invalidMode();\n\treturn { kind: \"last_user_turns\", count };\n}\n\nfunction hasCommentaryPhase(textSignature: string | undefined): boolean {\n\tif (!textSignature?.startsWith(\"{\")) return false;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(textSignature);\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return false;\n\t\tconst phase = Object.getOwnPropertyDescriptor(parsed, \"phase\");\n\t\treturn phase !== undefined && \"value\" in phase && phase.value === \"commentary\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\nfunction sanitizedTextBlocks(\n\tcontent: readonly ContextTextCandidate[],\n\tdropCommentary: boolean,\n): { kind: \"ok\"; blocks: TextContent[] } | { kind: \"oversized\" } {\n\tif (content.length > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS) return { kind: \"oversized\" };\n\tconst blocks: TextContent[] = [];\n\tlet textBytes = 0;\n\tfor (const block of content) {\n\t\tif (block.type !== \"text\" || !block.text.trim()) continue;\n\t\tif (dropCommentary && hasCommentaryPhase(block.textSignature)) continue;\n\t\ttextBytes += Buffer.byteLength(block.text, \"utf-8\");\n\t\tif (textBytes > MAX_WORKER_CONTEXT_FORK_BYTES) return { kind: \"oversized\" };\n\t\tblocks.push({ type: \"text\", text: block.text });\n\t}\n\treturn { kind: \"ok\", blocks };\n}\n\nfunction isWorkerControlUserMessage(message: UserMessage): boolean {\n\tif (typeof message.content === \"string\") {\n\t\tconst newline = message.content.indexOf(\"\\n\", 0);\n\t\tconst prefixEnd = newline >= 0 ? newline + 1 : MAX_WORKER_CONTROL_PREFIX_CHARS;\n\t\treturn WORKER_CONTROL_PREFIX.test(message.content.slice(0, Math.min(prefixEnd, MAX_WORKER_CONTROL_PREFIX_CHARS)));\n\t}\n\tlet prefix = \"\";\n\tfor (const block of message.content) {\n\t\tif (block.type !== \"text\") continue;\n\t\tconst remaining = MAX_WORKER_CONTROL_PREFIX_CHARS - prefix.length;\n\t\tif (remaining <= 0) return false;\n\t\tconst newline = block.text.indexOf(\"\\n\");\n\t\tconst blockPrefixEnd = newline >= 0 ? newline + 1 : block.text.length;\n\t\tprefix += block.text.slice(0, Math.min(blockPrefixEnd, remaining));\n\t\tif (newline >= 0) break;\n\t}\n\treturn WORKER_CONTROL_PREFIX.test(prefix);\n}\n\nfunction userBoundaryKind(message: UserMessage): UserBoundaryKind {\n\tif (isWorkerControlUserMessage(message)) return \"worker_control\";\n\tif (typeof message.content === \"string\") {\n\t\tif (!message.content.trim()) return \"unsupported\";\n\t\treturn Buffer.byteLength(message.content, \"utf-8\") > MAX_WORKER_CONTEXT_FORK_BYTES ? \"oversized\" : \"eligible\";\n\t}\n\tif (message.content.length > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS) return \"oversized\";\n\tlet hasText = false;\n\tlet textBytes = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type !== \"text\" || !block.text.trim()) continue;\n\t\thasText = true;\n\t\ttextBytes += Buffer.byteLength(block.text, \"utf-8\");\n\t\tif (textBytes > MAX_WORKER_CONTEXT_FORK_BYTES) return \"oversized\";\n\t}\n\treturn hasText ? \"eligible\" : \"unsupported\";\n}\n\nfunction sanitizeUserMessage(message: UserMessage): SanitizedMessageResult<UserMessage> {\n\tconst boundary = userBoundaryKind(message);\n\tif (boundary === \"worker_control\" || boundary === \"unsupported\") return { kind: \"drop\" };\n\tif (boundary === \"oversized\") return { kind: \"oversized\" };\n\tif (typeof message.content === \"string\") {\n\t\treturn { kind: \"ok\", message: { role: \"user\", content: message.content, timestamp: message.timestamp } };\n\t}\n\tconst sanitized = sanitizedTextBlocks(message.content, false);\n\tif (sanitized.kind === \"oversized\") return sanitized;\n\tif (sanitized.blocks.length === 0) return { kind: \"drop\" };\n\treturn { kind: \"ok\", message: { role: \"user\", content: sanitized.blocks, timestamp: message.timestamp } };\n}\n\nfunction sanitizeCompactionCheckpoint(\n\tmessage: Extract<AgentMessage, { role: \"compactionSummary\" }>,\n): SanitizedCompactionCheckpoint {\n\tif (typeof message.summary !== \"string\" || !message.summary.trim()) return { kind: \"invalid\" };\n\tconst wrapperBytes = Buffer.byteLength(\n\t\tSANITIZED_CONTEXT_FORK_COMPACTION_PREFIX + SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX,\n\t\t\"utf-8\",\n\t);\n\tif (Buffer.byteLength(message.summary, \"utf-8\") > MAX_WORKER_CONTEXT_FORK_BYTES - wrapperBytes) {\n\t\treturn { kind: \"invalid\" };\n\t}\n\treturn {\n\t\tkind: \"valid\",\n\t\ttext: SANITIZED_CONTEXT_FORK_COMPACTION_PREFIX + message.summary + SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX,\n\t};\n}\n\nfunction attachCompactionCheckpoint(\n\tmessage: UserMessage,\n\tcheckpoint: Extract<SanitizedCompactionCheckpoint, { kind: \"valid\" }>,\n): UserMessage {\n\tconst checkpointBlock: TextContent = { type: \"text\", text: checkpoint.text };\n\treturn {\n\t\trole: \"user\",\n\t\tcontent:\n\t\t\ttypeof message.content === \"string\"\n\t\t\t\t? [checkpointBlock, { type: \"text\", text: message.content }]\n\t\t\t\t: [checkpointBlock, ...message.content],\n\t\ttimestamp: message.timestamp,\n\t};\n}\n\n/**\n * Resolve each durable compaction replacement onto its following real user turn. The map is capped\n * at the maximum output size: an older association cannot be selected once that many newer mapped\n * user messages exist, even when every selected turn contains only its user message.\n */\nfunction compactionCheckpointsByUserIndex(\n\tmessages: readonly AgentMessage[],\n): ReadonlyMap<number, SanitizedCompactionCheckpoint> {\n\tconst checkpoints = new Map<number, SanitizedCompactionCheckpoint>();\n\tlet pending: SanitizedCompactionCheckpoint | undefined;\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index]!;\n\t\tif (message.role === \"compactionSummary\") {\n\t\t\tpending = sanitizeCompactionCheckpoint(message);\n\t\t\tcontinue;\n\t\t}\n\t\tif (message.role !== \"user\" || !pending) continue;\n\t\tconst boundary = userBoundaryKind(message);\n\t\tif (boundary === \"worker_control\") continue;\n\t\tif (boundary === \"eligible\") checkpoints.set(index, pending);\n\t\tpending = undefined;\n\t\tif (checkpoints.size > MAX_WORKER_CONTEXT_FORK_MESSAGES) {\n\t\t\tconst oldest = checkpoints.keys().next().value;\n\t\t\tif (oldest !== undefined) checkpoints.delete(oldest);\n\t\t}\n\t}\n\treturn checkpoints;\n}\n\nfunction sanitizeAssistantMessage(message: AssistantMessage): SanitizedMessageResult<AssistantMessage> {\n\t// A length stop, tool request, failure, or abort is not a complete assistant answer.\n\tif (message.stopReason !== \"stop\") return { kind: \"drop\" };\n\tconst sanitized = sanitizedTextBlocks(message.content, true);\n\tif (sanitized.kind === \"oversized\") return sanitized;\n\tif (sanitized.blocks.length === 0) return { kind: \"drop\" };\n\treturn {\n\t\tkind: \"ok\",\n\t\tmessage: {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: sanitized.blocks,\n\t\t\tapi: message.api,\n\t\t\tprovider: message.provider,\n\t\t\tmodel: message.model,\n\t\t\tusage: {\n\t\t\t\tinput: message.usage.input,\n\t\t\t\toutput: message.usage.output,\n\t\t\t\tcacheRead: message.usage.cacheRead,\n\t\t\t\tcacheWrite: message.usage.cacheWrite,\n\t\t\t\ttotalTokens: message.usage.totalTokens,\n\t\t\t\tcost: {\n\t\t\t\t\tinput: message.usage.cost.input,\n\t\t\t\t\toutput: message.usage.cost.output,\n\t\t\t\t\tcacheRead: message.usage.cost.cacheRead,\n\t\t\t\t\tcacheWrite: message.usage.cost.cacheWrite,\n\t\t\t\t\ttotal: message.usage.cost.total,\n\t\t\t\t},\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: message.timestamp,\n\t\t},\n\t};\n}\n\nfunction serializedBytes(messages: readonly SanitizedContextForkMessage[]): number {\n\treturn Buffer.byteLength(JSON.stringify(messages), \"utf-8\");\n}\n\nfunction textBlockCount(message: SanitizedContextForkMessage): number {\n\treturn typeof message.content === \"string\" ? 1 : message.content.length;\n}\n\nfunction requestedTurnCount(mode: SanitizedContextForkMode): number {\n\tif (mode.kind === \"none\") return 0;\n\tif (mode.kind === \"all\") return Number.POSITIVE_INFINITY;\n\tif (!Number.isSafeInteger(mode.count) || mode.count <= 0) {\n\t\tthrow new TypeError(\"Last-N context fork count must be a positive safe integer.\");\n\t}\n\treturn mode.count;\n}\n\n/**\n * Select a bounded suffix of complete, sanitized user turns.\n *\n * Selection walks backward so an arbitrarily long source transcript never creates an unbounded\n * second projection. Bounds drop whole oldest turns; no message text is truncated. The result is a\n * detached chronological copy containing no tool protocol, tool results, reasoning, provider\n * signatures, custom/system/developer messages, mailbox controls, or incomplete assistant output.\n */\nexport function selectSanitizedContextFork(\n\tmessages: readonly AgentMessage[],\n\tmode: SanitizedContextForkMode,\n): SanitizedContextForkMessage[] {\n\tconst maxTurns = requestedTurnCount(mode);\n\tif (maxTurns === 0) return [];\n\tconst compactionCheckpoints = compactionCheckpointsByUserIndex(messages);\n\n\tlet selected: SanitizedContextForkMessage[] = [];\n\tlet selectedTurns = 0;\n\tlet selectedTextBlocks = 0;\n\tlet reversedAssistantSuffix: AssistantMessage[] = [];\n\tlet reversedAssistantTextBlocks = 0;\n\tlet currentTurnOversized = false;\n\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst source = messages[index]!;\n\t\tif (source.role === \"assistant\") {\n\t\t\tconst sanitized = sanitizeAssistantMessage(source);\n\t\t\tif (sanitized.kind === \"oversized\") {\n\t\t\t\tcurrentTurnOversized = true;\n\t\t\t\treversedAssistantSuffix = [];\n\t\t\t\treversedAssistantTextBlocks = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sanitized.kind === \"drop\") continue;\n\t\t\tif (currentTurnOversized) continue;\n\t\t\tconst candidate = [sanitized.message, ...reversedAssistantSuffix];\n\t\t\tconst candidateTextBlocks = textBlockCount(sanitized.message) + reversedAssistantTextBlocks;\n\t\t\tif (\n\t\t\t\tcandidate.length >= MAX_WORKER_CONTEXT_FORK_MESSAGES ||\n\t\t\t\tserializedBytes(candidate) >= MAX_WORKER_CONTEXT_FORK_BYTES ||\n\t\t\t\tcandidateTextBlocks >= MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS\n\t\t\t) {\n\t\t\t\tcurrentTurnOversized = true;\n\t\t\t\treversedAssistantSuffix = [];\n\t\t\t\treversedAssistantTextBlocks = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treversedAssistantSuffix = candidate;\n\t\t\treversedAssistantTextBlocks = candidateTextBlocks;\n\t\t\tcontinue;\n\t\t}\n\t\tif (source.role !== \"user\") continue;\n\t\tconst sanitized = sanitizeUserMessage(source);\n\t\tif (sanitized.kind === \"drop\") {\n\t\t\treversedAssistantSuffix = [];\n\t\t\treversedAssistantTextBlocks = 0;\n\t\t\tcurrentTurnOversized = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (sanitized.kind === \"oversized\") break;\n\n\t\tconst checkpoint = compactionCheckpoints.get(index);\n\t\tif (checkpoint?.kind === \"invalid\") break;\n\t\tconst userMessage = checkpoint ? attachCompactionCheckpoint(sanitized.message, checkpoint) : sanitized.message;\n\t\tif (currentTurnOversized) break;\n\t\tconst turn: SanitizedContextForkMessage[] = [userMessage, ...reversedAssistantSuffix];\n\t\tconst turnTextBlocks = textBlockCount(userMessage) + reversedAssistantTextBlocks;\n\t\tconst candidate = [...turn, ...selected];\n\t\tif (\n\t\t\tcandidate.length > MAX_WORKER_CONTEXT_FORK_MESSAGES ||\n\t\t\tserializedBytes(candidate) > MAX_WORKER_CONTEXT_FORK_BYTES ||\n\t\t\tturnTextBlocks + selectedTextBlocks > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS\n\t\t) {\n\t\t\tbreak;\n\t\t}\n\t\tselected = candidate;\n\t\tselectedTurns += 1;\n\t\tselectedTextBlocks += turnTextBlocks;\n\t\tif (selectedTurns >= maxTurns) break;\n\t\treversedAssistantSuffix = [];\n\t\treversedAssistantTextBlocks = 0;\n\t}\n\n\treturn selected;\n}\n"]}
1
+ {"version":3,"file":"sanitized-context-fork.js","sourceRoot":"","sources":["../../../src/core/delegation/sanitized-context-fork.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AgentMessage } from \"@caupulican/pi-agent-core\";\nimport type { AssistantMessage, TextContent, UserMessage } from \"@caupulican/pi-ai\";\nimport { isAssistantCommentary } from \"../message-phase.ts\";\nimport {\n\tMAX_WORKER_CONTEXT_FORK_BYTES,\n\tMAX_WORKER_CONTEXT_FORK_MESSAGES,\n\tMAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS,\n} from \"../orchestration/worker-context-fork-reference.ts\";\n\nexport const SANITIZED_CONTEXT_FORK_COMPACTION_PREFIX =\n\t\"The parent conversation history before this point was compacted into the following checkpoint:\\n\\n<summary>\\n\";\nexport const SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX = \"\\n</summary>\\n\\n\";\n\nexport type SanitizedContextForkMode = { kind: \"none\" } | { kind: \"all\" } | { kind: \"last_user_turns\"; count: number };\n\nexport type SanitizedContextForkMessage = UserMessage | AssistantMessage;\n\ntype ContextTextCandidate = AssistantMessage[\"content\"][number] | Exclude<UserMessage[\"content\"], string>[number];\n\ntype SanitizedCompactionCheckpoint = { kind: \"valid\"; text: string } | { kind: \"invalid\" };\ntype SanitizedMessageResult<T> = { kind: \"ok\"; message: T } | { kind: \"drop\" } | { kind: \"oversized\" };\ntype UserBoundaryKind = \"eligible\" | \"worker_control\" | \"unsupported\" | \"oversized\";\n\nconst WORKER_CONTROL_PREFIX = /^\\[Worker control worker-message-[^\\]\\s]+(?: [^\\]]+)?\\]\\r?\\n/;\nconst MAX_WORKER_CONTROL_PREFIX_CHARS = 2048;\n\nfunction invalidMode(): TypeError {\n\treturn new TypeError(\"Context fork mode must be none, all, or a positive safe-integer string.\");\n}\n\n/** Parse the eventual tool-facing `fork_turns` wire value without choosing a default policy. */\nexport function parseSanitizedContextForkMode(value: string): SanitizedContextForkMode {\n\tconst normalized = value.trim().toLowerCase();\n\tif (normalized === \"none\") return { kind: \"none\" };\n\tif (normalized === \"all\") return { kind: \"all\" };\n\tif (!/^\\d+$/.test(normalized)) throw invalidMode();\n\tconst count = Number(normalized);\n\tif (!Number.isSafeInteger(count) || count <= 0) throw invalidMode();\n\treturn { kind: \"last_user_turns\", count };\n}\n\nfunction sanitizedTextBlocks(\n\tcontent: readonly ContextTextCandidate[],\n\tdropCommentary: boolean,\n): { kind: \"ok\"; blocks: TextContent[] } | { kind: \"oversized\" } {\n\tif (content.length > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS) return { kind: \"oversized\" };\n\tconst blocks: TextContent[] = [];\n\tlet textBytes = 0;\n\tfor (const block of content) {\n\t\tif (block.type !== \"text\" || !block.text.trim()) continue;\n\t\tif (dropCommentary && isAssistantCommentary(block)) continue;\n\t\ttextBytes += Buffer.byteLength(block.text, \"utf-8\");\n\t\tif (textBytes > MAX_WORKER_CONTEXT_FORK_BYTES) return { kind: \"oversized\" };\n\t\tblocks.push({ type: \"text\", text: block.text });\n\t}\n\treturn { kind: \"ok\", blocks };\n}\n\nfunction isWorkerControlUserMessage(message: UserMessage): boolean {\n\tif (typeof message.content === \"string\") {\n\t\tconst newline = message.content.indexOf(\"\\n\", 0);\n\t\tconst prefixEnd = newline >= 0 ? newline + 1 : MAX_WORKER_CONTROL_PREFIX_CHARS;\n\t\treturn WORKER_CONTROL_PREFIX.test(message.content.slice(0, Math.min(prefixEnd, MAX_WORKER_CONTROL_PREFIX_CHARS)));\n\t}\n\tlet prefix = \"\";\n\tfor (const block of message.content) {\n\t\tif (block.type !== \"text\") continue;\n\t\tconst remaining = MAX_WORKER_CONTROL_PREFIX_CHARS - prefix.length;\n\t\tif (remaining <= 0) return false;\n\t\tconst newline = block.text.indexOf(\"\\n\");\n\t\tconst blockPrefixEnd = newline >= 0 ? newline + 1 : block.text.length;\n\t\tprefix += block.text.slice(0, Math.min(blockPrefixEnd, remaining));\n\t\tif (newline >= 0) break;\n\t}\n\treturn WORKER_CONTROL_PREFIX.test(prefix);\n}\n\nfunction userBoundaryKind(message: UserMessage): UserBoundaryKind {\n\tif (isWorkerControlUserMessage(message)) return \"worker_control\";\n\tif (typeof message.content === \"string\") {\n\t\tif (!message.content.trim()) return \"unsupported\";\n\t\treturn Buffer.byteLength(message.content, \"utf-8\") > MAX_WORKER_CONTEXT_FORK_BYTES ? \"oversized\" : \"eligible\";\n\t}\n\tif (message.content.length > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS) return \"oversized\";\n\tlet hasText = false;\n\tlet textBytes = 0;\n\tfor (const block of message.content) {\n\t\tif (block.type !== \"text\" || !block.text.trim()) continue;\n\t\thasText = true;\n\t\ttextBytes += Buffer.byteLength(block.text, \"utf-8\");\n\t\tif (textBytes > MAX_WORKER_CONTEXT_FORK_BYTES) return \"oversized\";\n\t}\n\treturn hasText ? \"eligible\" : \"unsupported\";\n}\n\nfunction sanitizeUserMessage(message: UserMessage): SanitizedMessageResult<UserMessage> {\n\tconst boundary = userBoundaryKind(message);\n\tif (boundary === \"worker_control\" || boundary === \"unsupported\") return { kind: \"drop\" };\n\tif (boundary === \"oversized\") return { kind: \"oversized\" };\n\tif (typeof message.content === \"string\") {\n\t\treturn { kind: \"ok\", message: { role: \"user\", content: message.content, timestamp: message.timestamp } };\n\t}\n\tconst sanitized = sanitizedTextBlocks(message.content, false);\n\tif (sanitized.kind === \"oversized\") return sanitized;\n\tif (sanitized.blocks.length === 0) return { kind: \"drop\" };\n\treturn { kind: \"ok\", message: { role: \"user\", content: sanitized.blocks, timestamp: message.timestamp } };\n}\n\nfunction sanitizeCompactionCheckpoint(\n\tmessage: Extract<AgentMessage, { role: \"compactionSummary\" }>,\n): SanitizedCompactionCheckpoint {\n\tif (typeof message.summary !== \"string\" || !message.summary.trim()) return { kind: \"invalid\" };\n\tconst wrapperBytes = Buffer.byteLength(\n\t\tSANITIZED_CONTEXT_FORK_COMPACTION_PREFIX + SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX,\n\t\t\"utf-8\",\n\t);\n\tif (Buffer.byteLength(message.summary, \"utf-8\") > MAX_WORKER_CONTEXT_FORK_BYTES - wrapperBytes) {\n\t\treturn { kind: \"invalid\" };\n\t}\n\treturn {\n\t\tkind: \"valid\",\n\t\ttext: SANITIZED_CONTEXT_FORK_COMPACTION_PREFIX + message.summary + SANITIZED_CONTEXT_FORK_COMPACTION_SUFFIX,\n\t};\n}\n\nfunction attachCompactionCheckpoint(\n\tmessage: UserMessage,\n\tcheckpoint: Extract<SanitizedCompactionCheckpoint, { kind: \"valid\" }>,\n): UserMessage {\n\tconst checkpointBlock: TextContent = { type: \"text\", text: checkpoint.text };\n\treturn {\n\t\trole: \"user\",\n\t\tcontent:\n\t\t\ttypeof message.content === \"string\"\n\t\t\t\t? [checkpointBlock, { type: \"text\", text: message.content }]\n\t\t\t\t: [checkpointBlock, ...message.content],\n\t\ttimestamp: message.timestamp,\n\t};\n}\n\n/**\n * Resolve each durable compaction replacement onto its following real user turn. The map is capped\n * at the maximum output size: an older association cannot be selected once that many newer mapped\n * user messages exist, even when every selected turn contains only its user message.\n */\nfunction compactionCheckpointsByUserIndex(\n\tmessages: readonly AgentMessage[],\n): ReadonlyMap<number, SanitizedCompactionCheckpoint> {\n\tconst checkpoints = new Map<number, SanitizedCompactionCheckpoint>();\n\tlet pending: SanitizedCompactionCheckpoint | undefined;\n\tfor (let index = 0; index < messages.length; index++) {\n\t\tconst message = messages[index]!;\n\t\tif (message.role === \"compactionSummary\") {\n\t\t\tpending = sanitizeCompactionCheckpoint(message);\n\t\t\tcontinue;\n\t\t}\n\t\tif (message.role !== \"user\" || !pending) continue;\n\t\tconst boundary = userBoundaryKind(message);\n\t\tif (boundary === \"worker_control\") continue;\n\t\tif (boundary === \"eligible\") checkpoints.set(index, pending);\n\t\tpending = undefined;\n\t\tif (checkpoints.size > MAX_WORKER_CONTEXT_FORK_MESSAGES) {\n\t\t\tconst oldest = checkpoints.keys().next().value;\n\t\t\tif (oldest !== undefined) checkpoints.delete(oldest);\n\t\t}\n\t}\n\treturn checkpoints;\n}\n\nfunction sanitizeAssistantMessage(message: AssistantMessage): SanitizedMessageResult<AssistantMessage> {\n\t// A length stop, tool request, failure, or abort is not a complete assistant answer.\n\tif (message.stopReason !== \"stop\") return { kind: \"drop\" };\n\tconst sanitized = sanitizedTextBlocks(message.content, true);\n\tif (sanitized.kind === \"oversized\") return sanitized;\n\tif (sanitized.blocks.length === 0) return { kind: \"drop\" };\n\treturn {\n\t\tkind: \"ok\",\n\t\tmessage: {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: sanitized.blocks,\n\t\t\tapi: message.api,\n\t\t\tprovider: message.provider,\n\t\t\tmodel: message.model,\n\t\t\tusage: {\n\t\t\t\tinput: message.usage.input,\n\t\t\t\toutput: message.usage.output,\n\t\t\t\tcacheRead: message.usage.cacheRead,\n\t\t\t\tcacheWrite: message.usage.cacheWrite,\n\t\t\t\ttotalTokens: message.usage.totalTokens,\n\t\t\t\tcost: {\n\t\t\t\t\tinput: message.usage.cost.input,\n\t\t\t\t\toutput: message.usage.cost.output,\n\t\t\t\t\tcacheRead: message.usage.cost.cacheRead,\n\t\t\t\t\tcacheWrite: message.usage.cost.cacheWrite,\n\t\t\t\t\ttotal: message.usage.cost.total,\n\t\t\t\t},\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: message.timestamp,\n\t\t},\n\t};\n}\n\nfunction serializedBytes(messages: readonly SanitizedContextForkMessage[]): number {\n\treturn Buffer.byteLength(JSON.stringify(messages), \"utf-8\");\n}\n\nfunction textBlockCount(message: SanitizedContextForkMessage): number {\n\treturn typeof message.content === \"string\" ? 1 : message.content.length;\n}\n\nfunction requestedTurnCount(mode: SanitizedContextForkMode): number {\n\tif (mode.kind === \"none\") return 0;\n\tif (mode.kind === \"all\") return Number.POSITIVE_INFINITY;\n\tif (!Number.isSafeInteger(mode.count) || mode.count <= 0) {\n\t\tthrow new TypeError(\"Last-N context fork count must be a positive safe integer.\");\n\t}\n\treturn mode.count;\n}\n\n/**\n * Select a bounded suffix of complete, sanitized user turns.\n *\n * Selection walks backward so an arbitrarily long source transcript never creates an unbounded\n * second projection. Bounds drop whole oldest turns; no message text is truncated. The result is a\n * detached chronological copy containing no tool protocol, tool results, reasoning, provider\n * signatures, custom/system/developer messages, mailbox controls, or incomplete assistant output.\n */\nexport function selectSanitizedContextFork(\n\tmessages: readonly AgentMessage[],\n\tmode: SanitizedContextForkMode,\n): SanitizedContextForkMessage[] {\n\tconst maxTurns = requestedTurnCount(mode);\n\tif (maxTurns === 0) return [];\n\tconst compactionCheckpoints = compactionCheckpointsByUserIndex(messages);\n\n\tlet selected: SanitizedContextForkMessage[] = [];\n\tlet selectedTurns = 0;\n\tlet selectedTextBlocks = 0;\n\tlet reversedAssistantSuffix: AssistantMessage[] = [];\n\tlet reversedAssistantTextBlocks = 0;\n\tlet currentTurnOversized = false;\n\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tconst source = messages[index]!;\n\t\tif (source.role === \"assistant\") {\n\t\t\tconst sanitized = sanitizeAssistantMessage(source);\n\t\t\tif (sanitized.kind === \"oversized\") {\n\t\t\t\tcurrentTurnOversized = true;\n\t\t\t\treversedAssistantSuffix = [];\n\t\t\t\treversedAssistantTextBlocks = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (sanitized.kind === \"drop\") continue;\n\t\t\tif (currentTurnOversized) continue;\n\t\t\tconst candidate = [sanitized.message, ...reversedAssistantSuffix];\n\t\t\tconst candidateTextBlocks = textBlockCount(sanitized.message) + reversedAssistantTextBlocks;\n\t\t\tif (\n\t\t\t\tcandidate.length >= MAX_WORKER_CONTEXT_FORK_MESSAGES ||\n\t\t\t\tserializedBytes(candidate) >= MAX_WORKER_CONTEXT_FORK_BYTES ||\n\t\t\t\tcandidateTextBlocks >= MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS\n\t\t\t) {\n\t\t\t\tcurrentTurnOversized = true;\n\t\t\t\treversedAssistantSuffix = [];\n\t\t\t\treversedAssistantTextBlocks = 0;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\treversedAssistantSuffix = candidate;\n\t\t\treversedAssistantTextBlocks = candidateTextBlocks;\n\t\t\tcontinue;\n\t\t}\n\t\tif (source.role !== \"user\") continue;\n\t\tconst sanitized = sanitizeUserMessage(source);\n\t\tif (sanitized.kind === \"drop\") {\n\t\t\treversedAssistantSuffix = [];\n\t\t\treversedAssistantTextBlocks = 0;\n\t\t\tcurrentTurnOversized = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (sanitized.kind === \"oversized\") break;\n\n\t\tconst checkpoint = compactionCheckpoints.get(index);\n\t\tif (checkpoint?.kind === \"invalid\") break;\n\t\tconst userMessage = checkpoint ? attachCompactionCheckpoint(sanitized.message, checkpoint) : sanitized.message;\n\t\tif (currentTurnOversized) break;\n\t\tconst turn: SanitizedContextForkMessage[] = [userMessage, ...reversedAssistantSuffix];\n\t\tconst turnTextBlocks = textBlockCount(userMessage) + reversedAssistantTextBlocks;\n\t\tconst candidate = [...turn, ...selected];\n\t\tif (\n\t\t\tcandidate.length > MAX_WORKER_CONTEXT_FORK_MESSAGES ||\n\t\t\tserializedBytes(candidate) > MAX_WORKER_CONTEXT_FORK_BYTES ||\n\t\t\tturnTextBlocks + selectedTextBlocks > MAX_WORKER_CONTEXT_FORK_TEXT_BLOCKS\n\t\t) {\n\t\t\tbreak;\n\t\t}\n\t\tselected = candidate;\n\t\tselectedTurns += 1;\n\t\tselectedTextBlocks += turnTextBlocks;\n\t\tif (selectedTurns >= maxTurns) break;\n\t\treversedAssistantSuffix = [];\n\t\treversedAssistantTextBlocks = 0;\n\t}\n\n\treturn selected;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"worker-retry-policy.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-retry-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,uCAAuC,CAAC;AAE/G;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,wBAAwB,EAAE,WAKtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,mBAAmB,CAYtB"}
1
+ {"version":3,"file":"worker-retry-policy.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-retry-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAIN,KAAK,WAAW,EAChB,MAAM,uCAAuC,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,4BAA4B,IAAI,CAAC;AAE9C,eAAO,MAAM,wBAAwB,EAAE,WAKtC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,WAAW,EAAE,MAAM,CAAC;IACpB,iGAAiG;IACjG,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,GAAG,mBAAmB,CAkBtB"}
@@ -1,4 +1,4 @@
1
- import { classifyFailure, computeRetryDelayMs } from "@caupulican/pi-agent-core/reliability";
1
+ import { classifyFailure, computeRetryDelayMs, RetryDelayExceededError, } from "@caupulican/pi-agent-core/reliability";
2
2
  /**
3
3
  * Restart-durable, host-owned attempt ladder policy for delegated workers.
4
4
  *
@@ -33,9 +33,17 @@ export function evaluateWorkerRetry(args) {
33
33
  const classified = classifyFailure({ message: args.reasonDetail, provider: args.provider });
34
34
  if (!classified.retryable)
35
35
  return { retry: false, reason: `not_retryable_${classified.reason}` };
36
- const delayMs = computeRetryDelayMs(WORKER_TASK_RETRY_POLICY, args.retriesUsed + 1, {
37
- ...(classified.retryAfterMs !== undefined ? { retryAfterMs: classified.retryAfterMs } : {}),
38
- });
36
+ let delayMs;
37
+ try {
38
+ delayMs = computeRetryDelayMs(WORKER_TASK_RETRY_POLICY, args.retriesUsed + 1, {
39
+ ...(classified.retryAfterMs !== undefined ? { retryAfterMs: classified.retryAfterMs } : {}),
40
+ });
41
+ }
42
+ catch (error) {
43
+ if (error instanceof RetryDelayExceededError)
44
+ return { retry: false, reason: "retry_delay_exceeds_max" };
45
+ throw error;
46
+ }
39
47
  return { retry: true, reason: classified.reason, delayMs };
40
48
  }
41
49
  //# sourceMappingURL=worker-retry-policy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker-retry-policy.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-retry-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAoB,MAAM,uCAAuC,CAAC;AAE/G;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,wBAAwB,GAAgB;IACpD,WAAW,EAAE,4BAA4B;IACzC,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,MAAM;IAClB,WAAW,EAAE,GAAG;CAChB,CAAC;AAIF,MAAM,UAAU,mBAAmB,CAAC,IASnC;IACA,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IACpG,IAAI,IAAI,CAAC,UAAU,KAAK,kBAAkB;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IAC9G,IAAI,CAAC,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC7E,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,IAAI,4BAA4B,CAAC;IACzE,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,eAAe;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IACnG,MAAM,UAAU,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5F,IAAI,CAAC,UAAU,CAAC,SAAS;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;IACjG,MAAM,OAAO,GAAG,mBAAmB,CAAC,wBAAwB,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE;QACnF,GAAG,CAAC,UAAU,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC3F,CAAC,CAAC;IACH,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;AAC5D,CAAC","sourcesContent":["import { classifyFailure, computeRetryDelayMs, type RetryPolicy } from \"@caupulican/pi-agent-core/reliability\";\n\n/**\n * Restart-durable, host-owned attempt ladder policy for delegated workers.\n *\n * The budget model has always carried `maxAttempts`, but nothing drove a second attempt: a\n * failed worker terminalized immediately and \"retry\" meant the orchestrator model burning a\n * turn to re-delegate blind, losing the worker's transcript. The ladder makes retry a host\n * mechanism instead: a retryable bounded failure suspends the attempt (durable, fenced) and\n * re-enqueues it through the owner scheduler after backoff, resuming from the persisted\n * conversation exactly like restart recovery does.\n *\n * Retries are deliberately evidence-gated: only failures whose recorded detail classifies as\n * transient (network, 5xx, rate limits) are retried. A missing detail or an unknown\n * classification never retries — an undiagnosed failure repeated is spend without evidence.\n */\nexport const DEFAULT_WORKER_TASK_ATTEMPTS = 2;\n\nexport const WORKER_TASK_RETRY_POLICY: RetryPolicy = {\n\tmaxAttempts: DEFAULT_WORKER_TASK_ATTEMPTS,\n\tbaseDelayMs: 5_000,\n\tmaxDelayMs: 60_000,\n\tjitterRatio: 0.2,\n};\n\nexport type WorkerRetryDecision = { retry: true; reason: string; delayMs: number } | { retry: false; reason: string };\n\nexport function evaluateWorkerRetry(args: {\n\tlaneStatus: string;\n\treasonCode: string;\n\treasonDetail?: string;\n\tprovider: string;\n\t/** Restart-durable ladder retries already consumed for this attempt. */\n\tretriesUsed: number;\n\t/** Grant budget ceiling for total attempts; defaults to {@link DEFAULT_WORKER_TASK_ATTEMPTS}. */\n\tmaxAttempts?: number;\n}): WorkerRetryDecision {\n\tif (args.laneStatus !== \"failed\") return { retry: false, reason: `lane_status_${args.laneStatus}` };\n\tif (args.reasonCode !== \"completion_error\") return { retry: false, reason: `reason_code_${args.reasonCode}` };\n\tif (!args.reasonDetail) return { retry: false, reason: \"no_failure_detail\" };\n\tconst attemptsAllowed = args.maxAttempts ?? DEFAULT_WORKER_TASK_ATTEMPTS;\n\tif (args.retriesUsed + 1 >= attemptsAllowed) return { retry: false, reason: \"attempts_exhausted\" };\n\tconst classified = classifyFailure({ message: args.reasonDetail, provider: args.provider });\n\tif (!classified.retryable) return { retry: false, reason: `not_retryable_${classified.reason}` };\n\tconst delayMs = computeRetryDelayMs(WORKER_TASK_RETRY_POLICY, args.retriesUsed + 1, {\n\t\t...(classified.retryAfterMs !== undefined ? { retryAfterMs: classified.retryAfterMs } : {}),\n\t});\n\treturn { retry: true, reason: classified.reason, delayMs };\n}\n"]}
1
+ {"version":3,"file":"worker-retry-policy.js","sourceRoot":"","sources":["../../../src/core/delegation/worker-retry-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EACN,eAAe,EACf,mBAAmB,EACnB,uBAAuB,GAEvB,MAAM,uCAAuC,CAAC;AAE/C;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,CAAC,CAAC;AAE9C,MAAM,CAAC,MAAM,wBAAwB,GAAgB;IACpD,WAAW,EAAE,4BAA4B;IACzC,WAAW,EAAE,KAAK;IAClB,UAAU,EAAE,MAAM;IAClB,WAAW,EAAE,GAAG;CAChB,CAAC;AAIF,MAAM,UAAU,mBAAmB,CAAC,IASnC;IACA,IAAI,IAAI,CAAC,UAAU,KAAK,QAAQ;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IACpG,IAAI,IAAI,CAAC,UAAU,KAAK,kBAAkB;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,IAAI,CAAC,UAAU,EAAE,EAAE,CAAC;IAC9G,IAAI,CAAC,IAAI,CAAC,YAAY;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC;IAC7E,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,IAAI,4BAA4B,CAAC;IACzE,IAAI,IAAI,CAAC,WAAW,GAAG,CAAC,IAAI,eAAe;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,oBAAoB,EAAE,CAAC;IACnG,MAAM,UAAU,GAAG,eAAe,CAAC,EAAE,OAAO,EAAE,IAAI,CAAC,YAAY,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5F,IAAI,CAAC,UAAU,CAAC,SAAS;QAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,iBAAiB,UAAU,CAAC,MAAM,EAAE,EAAE,CAAC;IACjG,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACJ,OAAO,GAAG,mBAAmB,CAAC,wBAAwB,EAAE,IAAI,CAAC,WAAW,GAAG,CAAC,EAAE;YAC7E,GAAG,CAAC,UAAU,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,YAAY,EAAE,UAAU,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC3F,CAAC,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,IAAI,KAAK,YAAY,uBAAuB;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC;QACzG,MAAM,KAAK,CAAC;IACb,CAAC;IACD,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,OAAO,EAAE,CAAC;AAC5D,CAAC","sourcesContent":["import {\n\tclassifyFailure,\n\tcomputeRetryDelayMs,\n\tRetryDelayExceededError,\n\ttype RetryPolicy,\n} from \"@caupulican/pi-agent-core/reliability\";\n\n/**\n * Restart-durable, host-owned attempt ladder policy for delegated workers.\n *\n * The budget model has always carried `maxAttempts`, but nothing drove a second attempt: a\n * failed worker terminalized immediately and \"retry\" meant the orchestrator model burning a\n * turn to re-delegate blind, losing the worker's transcript. The ladder makes retry a host\n * mechanism instead: a retryable bounded failure suspends the attempt (durable, fenced) and\n * re-enqueues it through the owner scheduler after backoff, resuming from the persisted\n * conversation exactly like restart recovery does.\n *\n * Retries are deliberately evidence-gated: only failures whose recorded detail classifies as\n * transient (network, 5xx, rate limits) are retried. A missing detail or an unknown\n * classification never retries — an undiagnosed failure repeated is spend without evidence.\n */\nexport const DEFAULT_WORKER_TASK_ATTEMPTS = 2;\n\nexport const WORKER_TASK_RETRY_POLICY: RetryPolicy = {\n\tmaxAttempts: DEFAULT_WORKER_TASK_ATTEMPTS,\n\tbaseDelayMs: 5_000,\n\tmaxDelayMs: 60_000,\n\tjitterRatio: 0.2,\n};\n\nexport type WorkerRetryDecision = { retry: true; reason: string; delayMs: number } | { retry: false; reason: string };\n\nexport function evaluateWorkerRetry(args: {\n\tlaneStatus: string;\n\treasonCode: string;\n\treasonDetail?: string;\n\tprovider: string;\n\t/** Restart-durable ladder retries already consumed for this attempt. */\n\tretriesUsed: number;\n\t/** Grant budget ceiling for total attempts; defaults to {@link DEFAULT_WORKER_TASK_ATTEMPTS}. */\n\tmaxAttempts?: number;\n}): WorkerRetryDecision {\n\tif (args.laneStatus !== \"failed\") return { retry: false, reason: `lane_status_${args.laneStatus}` };\n\tif (args.reasonCode !== \"completion_error\") return { retry: false, reason: `reason_code_${args.reasonCode}` };\n\tif (!args.reasonDetail) return { retry: false, reason: \"no_failure_detail\" };\n\tconst attemptsAllowed = args.maxAttempts ?? DEFAULT_WORKER_TASK_ATTEMPTS;\n\tif (args.retriesUsed + 1 >= attemptsAllowed) return { retry: false, reason: \"attempts_exhausted\" };\n\tconst classified = classifyFailure({ message: args.reasonDetail, provider: args.provider });\n\tif (!classified.retryable) return { retry: false, reason: `not_retryable_${classified.reason}` };\n\tlet delayMs: number;\n\ttry {\n\t\tdelayMs = computeRetryDelayMs(WORKER_TASK_RETRY_POLICY, args.retriesUsed + 1, {\n\t\t\t...(classified.retryAfterMs !== undefined ? { retryAfterMs: classified.retryAfterMs } : {}),\n\t\t});\n\t} catch (error) {\n\t\tif (error instanceof RetryDelayExceededError) return { retry: false, reason: \"retry_delay_exceeds_max\" };\n\t\tthrow error;\n\t}\n\treturn { retry: true, reason: classified.reason, delayMs };\n}\n"]}
@@ -50,6 +50,7 @@ export declare class ForegroundRecoveryController {
50
50
  private readonly idleWaiters;
51
51
  private readonly deps;
52
52
  constructor(deps: ForegroundRecoveryControllerDeps);
53
+ private getRetryPolicy;
53
54
  get attempt(): number;
54
55
  get isRetrying(): boolean;
55
56
  get isRunActive(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"foreground-recovery-controller.d.ts","sourceRoot":"","sources":["../../src/core/foreground-recovery-controller.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"foreground-recovery-controller.d.ts","sourceRoot":"","sources":["../../src/core/foreground-recovery-controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,KAAK,EAAkB,MAAM,iCAAiC,CAAC;AAS7E,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAC1E,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,KAAK,uBAAuB,GACzB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,kBAAkB,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACzG;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF,QAAA,MAAM,+BAA+B,EAAE,OAAO,MAA4C,CAAC;AAE3F,yFAAyF;AACzF,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,CAAC,+BAA+B,CAAC,EAAE,IAAI,CAAC;CACjD;AAED,MAAM,WAAW,gCAAgC;IAChD,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,aAAa,EAAE,qBAAqB,CAAC;IACrC,gBAAgB,IAAI,MAAM,CAAC;IAC3B,IAAI,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI,CAAC;IAC3C,eAAe,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7D,qBAAqB,IAAI,IAAI,CAAC;IAC9B,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,OAAO,CAAC;CAC7B;AAED,iGAAiG;AACjG,qBAAa,4BAA4B;IACxC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkB;IACxC,OAAO,CAAC,QAAQ,CAAC,eAAe,CAA4B;IAC5D,OAAO,CAAC,oBAAoB,CAA+B;IAC3D,OAAO,CAAC,yBAAyB,CAAqB;IACtD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,eAAe,CAAwC;IAC/D,OAAO,CAAC,cAAc,CAAoB;IAC1C,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IACrD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IAExD,YAAY,IAAI,EAAE,gCAAgC,EAmBjD;IAED,OAAO,CAAC,cAAc;IAatB,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED,IAAI,UAAU,IAAI,OAAO,CAExB;IAED,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,IAAI,MAAM,IAAI,OAAO,CAQpB;IAED,mGAAmG;IACnG,oBAAoB,IAAI,yBAAyB,GAAG,SAAS,CAK5D;IAED,oFAAoF;IAC9E,iBAAiB,IAAI,OAAO,CAAC,yBAAyB,CAAC,CAO5D;IAED,cAAc,CAAC,KAAK,EAAE,yBAAyB,GAAG,SAAS,GAAG,OAAO,CAEpE;IAED,iBAAiB,CAAC,KAAK,EAAE,yBAAyB,GAAG,IAAI,CAQxD;IAEK,cAAc,CACnB,QAAQ,EAAE,YAAY,GAAG,YAAY,EAAE,EACvC,eAAe,CAAC,EAAE,yBAAyB,GACzC,OAAO,CAAC,IAAI,CAAC,CAEf;IAED,qGAAqG;IAC/F,oBAAoB,CAAC,eAAe,CAAC,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAErF;YAEa,iBAAiB;IAiD/B,eAAe,IAAI,IAAI,CAEtB;IAEK,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAUjC;IAED,QAAQ,IAAI,IAAI,CAIf;IAED,OAAO,CAAC,kBAAkB;IAM1B,UAAU,IAAI,IAAI,CAEjB;IAED,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAErC;IAED,iBAAiB,IAAI,yBAAyB,CAE7C;IAED,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAShD;IAED,sBAAsB,CAAC,KAAK,EAAE,OAAO,CAAC,UAAU,EAAE;QAAE,IAAI,EAAE,WAAW,CAAA;KAAE,CAAC,GAAG,OAAO,CAmBjF;IAEK,kBAAkB,IAAI,OAAO,CAAC,OAAO,CAAC,CAiC3C;IAED,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,sBAAsB;CAQ9B"}
@@ -1,5 +1,5 @@
1
1
  import { AgentBusyError } from "@caupulican/pi-agent-core/agent";
2
- import { classifyFailure, DEFAULT_RETRY_POLICY, RetryController, } from "@caupulican/pi-agent-core/reliability";
2
+ import { classifyFailure, computeRetryDelayMs, DEFAULT_RETRY_POLICY, RetryController, RetryDelayExceededError, } from "@caupulican/pi-agent-core/reliability";
3
3
  import { isContextOverflow } from "@caupulican/pi-ai/overflow";
4
4
  import { BillingFailoverController, ExhaustedProviderRegistry } from "./billing-failover-controller.js";
5
5
  const foregroundSubmissionLeaseMarker = Symbol("foregroundSubmissionLease");
@@ -9,16 +9,7 @@ export class ForegroundRecoveryController {
9
9
  this.activeRuns = 0;
10
10
  this.idleWaiters = new Set();
11
11
  this.deps = deps;
12
- this.retry = new RetryController(deps.agent, () => {
13
- const retry = deps.settingsManager.getRetrySettings();
14
- return {
15
- enabled: retry.enabled,
16
- maxAttempts: retry.maxRetries,
17
- baseDelayMs: retry.baseDelayMs,
18
- maxDelayMs: DEFAULT_RETRY_POLICY.maxDelayMs,
19
- jitterRatio: 0,
20
- };
21
- }, {
12
+ this.retry = new RetryController(deps.agent, () => this.getRetryPolicy(), {
22
13
  onRetryStart: (info) => deps.emit({ type: "auto_retry_start", ...info }),
23
14
  onRetryEnd: (info) => deps.emit({ type: "auto_retry_end", ...info }),
24
15
  }, deps.getContextWindow);
@@ -31,6 +22,18 @@ export class ForegroundRecoveryController {
31
22
  recordFailure: (record) => deps.failureCorpus.record(record),
32
23
  });
33
24
  }
25
+ getRetryPolicy() {
26
+ const retry = this.deps.settingsManager.getRetrySettings();
27
+ const providerRetry = this.deps.settingsManager.getProviderRetrySettings();
28
+ return {
29
+ enabled: retry.enabled,
30
+ maxAttempts: retry.maxRetries,
31
+ baseDelayMs: retry.baseDelayMs,
32
+ maxDelayMs: DEFAULT_RETRY_POLICY.maxDelayMs,
33
+ maxRetryAfterMs: providerRetry.maxRetryDelayMs,
34
+ jitterRatio: 0,
35
+ };
36
+ }
34
37
  get attempt() {
35
38
  return this.retry.attempt;
36
39
  }
@@ -191,8 +194,22 @@ export class ForegroundRecoveryController {
191
194
  return false;
192
195
  for (let index = event.messages.length - 1; index >= 0; index--) {
193
196
  const message = event.messages[index];
194
- if (message.role === "assistant")
195
- return this.classifyAssistantError(message)?.retryable ?? false;
197
+ if (message.role !== "assistant")
198
+ continue;
199
+ const classified = this.classifyAssistantError(message);
200
+ if (!classified?.retryable)
201
+ return false;
202
+ try {
203
+ computeRetryDelayMs(this.getRetryPolicy(), this.retry.attempt + 1, {
204
+ retryAfterMs: classified.retryAfterMs,
205
+ });
206
+ return true;
207
+ }
208
+ catch (error) {
209
+ if (error instanceof RetryDelayExceededError)
210
+ return false;
211
+ throw error;
212
+ }
196
213
  }
197
214
  return false;
198
215
  }
@@ -1 +1 @@
1
- {"version":3,"file":"foreground-recovery-controller.js","sourceRoot":"","sources":["../../src/core/foreground-recovery-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Agent, AgentBusyError } from \"@caupulican/pi-agent-core/agent\";\nimport {\n\ttype ClassifiedError,\n\tclassifyFailure,\n\tDEFAULT_RETRY_POLICY,\n\tRetryController,\n} from \"@caupulican/pi-agent-core/reliability\";\nimport type { AgentEvent, AgentMessage } from \"@caupulican/pi-agent-core/types\";\nimport type { AssistantMessage } from \"@caupulican/pi-ai\";\nimport { isContextOverflow } from \"@caupulican/pi-ai/overflow\";\nimport { BillingFailoverController, ExhaustedProviderRegistry } from \"./billing-failover-controller.ts\";\nimport type { FailureCorpusRecorder } from \"./failure-corpus.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport type { ModelRouterFailoverStatus } from \"./model-router/status.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\ntype ForegroundRecoveryEvent =\n\t| { type: \"warning\"; message: string }\n\t| { type: \"auto_retry_start\"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }\n\t| { type: \"auto_retry_end\"; success: boolean; attempt: number; finalError?: string };\n\nconst foregroundSubmissionLeaseMarker: unique symbol = Symbol(\"foregroundSubmissionLease\");\n\n/** Identity-bound authority to prepare and execute one logical foreground submission. */\nexport interface ForegroundSubmissionLease {\n\treadonly [foregroundSubmissionLeaseMarker]: true;\n}\n\nexport interface ForegroundRecoveryControllerDeps {\n\tagent: Agent;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tfailureCorpus: FailureCorpusRecorder;\n\tgetContextWindow(): number;\n\temit(event: ForegroundRecoveryEvent): void;\n\tcheckCompaction(message: AssistantMessage): Promise<boolean>;\n\tonSuccessfulAssistant(): void;\n\tprepareRun(): Promise<void>;\n\tafterRun(): Promise<void>;\n\tisCompacting?: () => boolean;\n}\n\n/** Owns the complete logical foreground run plus retry/failover/compaction recovery ordering. */\nexport class ForegroundRecoveryController {\n\tprivate readonly retry: RetryController;\n\tprivate readonly billingFailover: BillingFailoverController;\n\tprivate lastAssistantMessage: AssistantMessage | undefined;\n\tprivate pendingCompactionRetryKey: string | undefined;\n\tprivate activeRuns = 0;\n\tprivate submissionLease: ForegroundSubmissionLease | undefined;\n\tprivate shutdownReason: Error | undefined;\n\tprivate readonly idleWaiters = new Set<() => void>();\n\tprivate readonly deps: ForegroundRecoveryControllerDeps;\n\n\tconstructor(deps: ForegroundRecoveryControllerDeps) {\n\t\tthis.deps = deps;\n\t\tthis.retry = new RetryController(\n\t\t\tdeps.agent,\n\t\t\t() => {\n\t\t\t\tconst retry = deps.settingsManager.getRetrySettings();\n\t\t\t\treturn {\n\t\t\t\t\tenabled: retry.enabled,\n\t\t\t\t\tmaxAttempts: retry.maxRetries,\n\t\t\t\t\tbaseDelayMs: retry.baseDelayMs,\n\t\t\t\t\tmaxDelayMs: DEFAULT_RETRY_POLICY.maxDelayMs,\n\t\t\t\t\tjitterRatio: 0,\n\t\t\t\t};\n\t\t\t},\n\t\t\t{\n\t\t\t\tonRetryStart: (info) => deps.emit({ type: \"auto_retry_start\", ...info }),\n\t\t\t\tonRetryEnd: (info) => deps.emit({ type: \"auto_retry_end\", ...info }),\n\t\t\t},\n\t\t\tdeps.getContextWindow,\n\t\t);\n\t\tthis.billingFailover = new BillingFailoverController({\n\t\t\tagent: deps.agent,\n\t\t\tmodelRegistry: deps.modelRegistry,\n\t\t\texhausted: new ExhaustedProviderRegistry(),\n\t\t\tsubscriptionHop: deps.settingsManager.getFailoverSettings().subscriptionHop,\n\t\t\temit: (event) => deps.emit(event),\n\t\t\trecordFailure: (record) => deps.failureCorpus.record(record),\n\t\t});\n\t}\n\n\tget attempt(): number {\n\t\treturn this.retry.attempt;\n\t}\n\n\tget isRetrying(): boolean {\n\t\treturn this.retry.isRetrying;\n\t}\n\n\tget isRunActive(): boolean {\n\t\treturn this.activeRuns > 0;\n\t}\n\n\tget isBusy(): boolean {\n\t\treturn (\n\t\t\tthis.submissionLease !== undefined ||\n\t\t\tthis.isRunActive ||\n\t\t\tthis.deps.agent.state.isStreaming ||\n\t\t\tthis.isRetrying ||\n\t\t\tthis.deps.isCompacting?.() === true\n\t\t);\n\t}\n\n\t/** Atomically reserve the full foreground lifecycle, including asynchronous prompt preparation. */\n\ttryAcquireSubmission(): ForegroundSubmissionLease | undefined {\n\t\tif (this.shutdownReason || this.isBusy) return undefined;\n\t\tconst lease: ForegroundSubmissionLease = { [foregroundSubmissionLeaseMarker]: true };\n\t\tthis.submissionLease = lease;\n\t\treturn lease;\n\t}\n\n\t/** Wait until foreground ownership can be acquired without a check-then-act gap. */\n\tasync acquireSubmission(): Promise<ForegroundSubmissionLease> {\n\t\twhile (true) {\n\t\t\tif (this.shutdownReason) throw this.shutdownReason;\n\t\t\tconst lease = this.tryAcquireSubmission();\n\t\t\tif (lease) return lease;\n\t\t\tawait this.waitForIdle();\n\t\t}\n\t}\n\n\townsSubmission(lease: ForegroundSubmissionLease | undefined): boolean {\n\t\treturn lease !== undefined && lease === this.submissionLease;\n\t}\n\n\treleaseSubmission(lease: ForegroundSubmissionLease): void {\n\t\tif (!this.ownsSubmission(lease)) {\n\t\t\tthrow new Error(\"Cannot release foreground submission authority owned by another caller\");\n\t\t}\n\t\tthis.submissionLease = undefined;\n\t\tif (this.activeRuns === 0) {\n\t\t\tthis.resolveIdleWaiters();\n\t\t}\n\t}\n\n\tasync runAgentPrompt(\n\t\tmessages: AgentMessage | AgentMessage[],\n\t\tsubmissionLease?: ForegroundSubmissionLease,\n\t): Promise<void> {\n\t\tawait this.runAgentExecution(\"prompt\", messages, submissionLease);\n\t}\n\n\t/** Continue from the already canonical agent history without replaying the original user message. */\n\tasync runAgentContinuation(submissionLease?: ForegroundSubmissionLease): Promise<void> {\n\t\tawait this.runAgentExecution(\"continue\", undefined, submissionLease);\n\t}\n\n\tprivate async runAgentExecution(\n\t\tmode: \"prompt\" | \"continue\",\n\t\tmessages: AgentMessage | AgentMessage[] | undefined,\n\t\tsubmissionLease?: ForegroundSubmissionLease,\n\t): Promise<void> {\n\t\tlet lease = submissionLease;\n\t\tlet releaseLease = false;\n\t\tif (lease) {\n\t\t\tif (!this.ownsSubmission(lease)) {\n\t\t\t\tthrow new AgentBusyError(\"Foreground submission authority is no longer active.\");\n\t\t\t}\n\t\t} else {\n\t\t\tlease = this.tryAcquireSubmission();\n\t\t\tif (!lease) throw new AgentBusyError(\"Agent is already processing.\");\n\t\t\treleaseLease = true;\n\t\t}\n\t\tif (this.activeRuns > 0) {\n\t\t\tif (releaseLease && lease) this.releaseSubmission(lease);\n\t\t\tthrow new AgentBusyError(\"Agent is already processing.\");\n\t\t}\n\n\t\tthis.activeRuns++;\n\t\ttry {\n\t\t\tconst maxGoalLoopRounds = this.deps.settingsManager.getAutonomySettings().maxStallTurns;\n\t\t\tawait this.deps.prepareRun();\n\t\t\tlet goalLoopRounds = 1;\n\t\t\tif (mode === \"prompt\") {\n\t\t\t\tif (!messages) throw new Error(\"Foreground prompt execution requires messages.\");\n\t\t\t\tawait this.deps.agent.prompt(messages);\n\t\t\t} else {\n\t\t\t\tawait this.deps.agent.continue();\n\t\t\t}\n\t\t\twhile ((maxGoalLoopRounds === 0 || goalLoopRounds < maxGoalLoopRounds) && (await this.handlePostAgentRun())) {\n\t\t\t\tawait this.deps.agent.continue();\n\t\t\t\tgoalLoopRounds++;\n\t\t\t}\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait this.deps.afterRun();\n\t\t\t} finally {\n\t\t\t\tthis.activeRuns--;\n\t\t\t\tif (releaseLease && lease && this.ownsSubmission(lease)) this.releaseSubmission(lease);\n\t\t\t\tif (this.activeRuns === 0 && this.submissionLease === undefined) {\n\t\t\t\t\tthis.resolveIdleWaiters();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\twakeIdleWaiters(): void {\n\t\tthis.resolveIdleWaiters();\n\t}\n\n\tasync waitForIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tif (this.shutdownReason) return;\n\t\t\tif (this.submissionLease !== undefined || this.activeRuns > 0 || this.deps.isCompacting?.() === true) {\n\t\t\t\tawait new Promise<void>((resolve) => this.idleWaiters.add(resolve));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.deps.agent.waitForIdle();\n\t\t\tif (!this.isBusy) return;\n\t\t}\n\t}\n\n\tshutdown(): void {\n\t\tthis.shutdownReason ??= new Error(\"Session disposed before foreground submission authority was acquired\");\n\t\tfor (const resolve of this.idleWaiters) resolve();\n\t\tthis.idleWaiters.clear();\n\t}\n\n\tprivate resolveIdleWaiters(): void {\n\t\tif (this.submissionLease !== undefined || this.activeRuns > 0) return;\n\t\tfor (const resolve of this.idleWaiters) resolve();\n\t\tthis.idleWaiters.clear();\n\t}\n\n\tabortRetry(): void {\n\t\tthis.retry.abort();\n\t}\n\n\tisModelExhausted(ref: string): boolean {\n\t\treturn this.billingFailover.isExhausted(ref);\n\t}\n\n\tgetFailoverStatus(): ModelRouterFailoverStatus {\n\t\treturn this.billingFailover.getStatus();\n\t}\n\n\tobserveAssistant(message: AssistantMessage): void {\n\t\tthis.lastAssistantMessage = message;\n\t\tif (message.stopReason === \"error\") return;\n\t\tif (message.stopReason === \"aborted\") {\n\t\t\tthis.finishRetry(false, message.errorMessage ?? \"Retry aborted\");\n\t\t\treturn;\n\t\t}\n\t\tthis.deps.onSuccessfulAssistant();\n\t\tthis.finishRetry(true);\n\t}\n\n\twillRetryAfterAgentEnd(event: Extract<AgentEvent, { type: \"agent_end\" }>): boolean {\n\t\tconst settings = this.deps.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled || this.retry.attempt >= settings.maxRetries) return false;\n\t\tfor (let index = event.messages.length - 1; index >= 0; index--) {\n\t\t\tconst message = event.messages[index];\n\t\t\tif (message.role === \"assistant\") return this.classifyAssistantError(message)?.retryable ?? false;\n\t\t}\n\t\treturn false;\n\t}\n\n\tasync handlePostAgentRun(): Promise<boolean> {\n\t\tconst message = this.lastAssistantMessage;\n\t\tthis.lastAssistantMessage = undefined;\n\t\tif (!message) return false;\n\n\t\tconst classified = this.classifyAssistantError(message);\n\t\tif (classified) {\n\t\t\tthis.deps.failureCorpus.record({\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodelId: message.model,\n\t\t\t\tmessage: message.errorMessage ?? \"\",\n\t\t\t\tclassified,\n\t\t\t});\n\t\t}\n\t\tconst compactionRetryKey =\n\t\t\tclassified?.retryable && classified.shouldCompact\n\t\t\t\t? `${message.provider}\\u0000${message.model}\\u0000${classified.reason}\\u0000${message.errorMessage ?? \"\"}`\n\t\t\t\t: undefined;\n\t\tconst repeatedCompactionFailure =\n\t\t\tcompactionRetryKey !== undefined && compactionRetryKey === this.pendingCompactionRetryKey;\n\t\tif (!repeatedCompactionFailure) this.pendingCompactionRetryKey = undefined;\n\t\tif (repeatedCompactionFailure && (await this.deps.checkCompaction(message))) {\n\t\t\treturn true;\n\t\t}\n\t\tif (classified?.retryable && (await this.retry.prepareRetry(message))) {\n\t\t\tthis.pendingCompactionRetryKey = compactionRetryKey;\n\t\t\treturn true;\n\t\t}\n\t\tif (await this.billingFailover.handleAssistantError(message, classified)) return false;\n\n\t\tif (message.stopReason === \"error\") this.finishRetry(false, message.errorMessage);\n\t\tif (await this.deps.checkCompaction(message)) return true;\n\t\treturn this.deps.agent.hasQueuedMessages();\n\t}\n\n\tprivate finishRetry(success: boolean, finalError?: string): void {\n\t\tthis.pendingCompactionRetryKey = undefined;\n\t\tif (this.retry.attempt === 0) return;\n\t\tthis.deps.emit({ type: \"auto_retry_end\", success, attempt: this.retry.attempt, finalError });\n\t\tthis.retry.reset();\n\t}\n\n\tprivate classifyAssistantError(message: AssistantMessage): ClassifiedError | undefined {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return undefined;\n\t\treturn classifyFailure({\n\t\t\tmessage: message.errorMessage,\n\t\t\tcontextOverflow: isContextOverflow(message, this.deps.getContextWindow()),\n\t\t\tprovider: message.provider,\n\t\t});\n\t}\n}\n"]}
1
+ {"version":3,"file":"foreground-recovery-controller.js","sourceRoot":"","sources":["../../src/core/foreground-recovery-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import { type Agent, AgentBusyError } from \"@caupulican/pi-agent-core/agent\";\nimport {\n\ttype ClassifiedError,\n\tclassifyFailure,\n\tcomputeRetryDelayMs,\n\tDEFAULT_RETRY_POLICY,\n\tRetryController,\n\tRetryDelayExceededError,\n} from \"@caupulican/pi-agent-core/reliability\";\nimport type { AgentEvent, AgentMessage } from \"@caupulican/pi-agent-core/types\";\nimport type { AssistantMessage } from \"@caupulican/pi-ai\";\nimport { isContextOverflow } from \"@caupulican/pi-ai/overflow\";\nimport { BillingFailoverController, ExhaustedProviderRegistry } from \"./billing-failover-controller.ts\";\nimport type { FailureCorpusRecorder } from \"./failure-corpus.ts\";\nimport type { ModelRegistry } from \"./model-registry.ts\";\nimport type { ModelRouterFailoverStatus } from \"./model-router/status.ts\";\nimport type { SettingsManager } from \"./settings-manager.ts\";\n\ntype ForegroundRecoveryEvent =\n\t| { type: \"warning\"; message: string }\n\t| { type: \"auto_retry_start\"; attempt: number; maxAttempts: number; delayMs: number; errorMessage: string }\n\t| { type: \"auto_retry_end\"; success: boolean; attempt: number; finalError?: string };\n\nconst foregroundSubmissionLeaseMarker: unique symbol = Symbol(\"foregroundSubmissionLease\");\n\n/** Identity-bound authority to prepare and execute one logical foreground submission. */\nexport interface ForegroundSubmissionLease {\n\treadonly [foregroundSubmissionLeaseMarker]: true;\n}\n\nexport interface ForegroundRecoveryControllerDeps {\n\tagent: Agent;\n\tsettingsManager: SettingsManager;\n\tmodelRegistry: ModelRegistry;\n\tfailureCorpus: FailureCorpusRecorder;\n\tgetContextWindow(): number;\n\temit(event: ForegroundRecoveryEvent): void;\n\tcheckCompaction(message: AssistantMessage): Promise<boolean>;\n\tonSuccessfulAssistant(): void;\n\tprepareRun(): Promise<void>;\n\tafterRun(): Promise<void>;\n\tisCompacting?: () => boolean;\n}\n\n/** Owns the complete logical foreground run plus retry/failover/compaction recovery ordering. */\nexport class ForegroundRecoveryController {\n\tprivate readonly retry: RetryController;\n\tprivate readonly billingFailover: BillingFailoverController;\n\tprivate lastAssistantMessage: AssistantMessage | undefined;\n\tprivate pendingCompactionRetryKey: string | undefined;\n\tprivate activeRuns = 0;\n\tprivate submissionLease: ForegroundSubmissionLease | undefined;\n\tprivate shutdownReason: Error | undefined;\n\tprivate readonly idleWaiters = new Set<() => void>();\n\tprivate readonly deps: ForegroundRecoveryControllerDeps;\n\n\tconstructor(deps: ForegroundRecoveryControllerDeps) {\n\t\tthis.deps = deps;\n\t\tthis.retry = new RetryController(\n\t\t\tdeps.agent,\n\t\t\t() => this.getRetryPolicy(),\n\t\t\t{\n\t\t\t\tonRetryStart: (info) => deps.emit({ type: \"auto_retry_start\", ...info }),\n\t\t\t\tonRetryEnd: (info) => deps.emit({ type: \"auto_retry_end\", ...info }),\n\t\t\t},\n\t\t\tdeps.getContextWindow,\n\t\t);\n\t\tthis.billingFailover = new BillingFailoverController({\n\t\t\tagent: deps.agent,\n\t\t\tmodelRegistry: deps.modelRegistry,\n\t\t\texhausted: new ExhaustedProviderRegistry(),\n\t\t\tsubscriptionHop: deps.settingsManager.getFailoverSettings().subscriptionHop,\n\t\t\temit: (event) => deps.emit(event),\n\t\t\trecordFailure: (record) => deps.failureCorpus.record(record),\n\t\t});\n\t}\n\n\tprivate getRetryPolicy() {\n\t\tconst retry = this.deps.settingsManager.getRetrySettings();\n\t\tconst providerRetry = this.deps.settingsManager.getProviderRetrySettings();\n\t\treturn {\n\t\t\tenabled: retry.enabled,\n\t\t\tmaxAttempts: retry.maxRetries,\n\t\t\tbaseDelayMs: retry.baseDelayMs,\n\t\t\tmaxDelayMs: DEFAULT_RETRY_POLICY.maxDelayMs,\n\t\t\tmaxRetryAfterMs: providerRetry.maxRetryDelayMs,\n\t\t\tjitterRatio: 0,\n\t\t};\n\t}\n\n\tget attempt(): number {\n\t\treturn this.retry.attempt;\n\t}\n\n\tget isRetrying(): boolean {\n\t\treturn this.retry.isRetrying;\n\t}\n\n\tget isRunActive(): boolean {\n\t\treturn this.activeRuns > 0;\n\t}\n\n\tget isBusy(): boolean {\n\t\treturn (\n\t\t\tthis.submissionLease !== undefined ||\n\t\t\tthis.isRunActive ||\n\t\t\tthis.deps.agent.state.isStreaming ||\n\t\t\tthis.isRetrying ||\n\t\t\tthis.deps.isCompacting?.() === true\n\t\t);\n\t}\n\n\t/** Atomically reserve the full foreground lifecycle, including asynchronous prompt preparation. */\n\ttryAcquireSubmission(): ForegroundSubmissionLease | undefined {\n\t\tif (this.shutdownReason || this.isBusy) return undefined;\n\t\tconst lease: ForegroundSubmissionLease = { [foregroundSubmissionLeaseMarker]: true };\n\t\tthis.submissionLease = lease;\n\t\treturn lease;\n\t}\n\n\t/** Wait until foreground ownership can be acquired without a check-then-act gap. */\n\tasync acquireSubmission(): Promise<ForegroundSubmissionLease> {\n\t\twhile (true) {\n\t\t\tif (this.shutdownReason) throw this.shutdownReason;\n\t\t\tconst lease = this.tryAcquireSubmission();\n\t\t\tif (lease) return lease;\n\t\t\tawait this.waitForIdle();\n\t\t}\n\t}\n\n\townsSubmission(lease: ForegroundSubmissionLease | undefined): boolean {\n\t\treturn lease !== undefined && lease === this.submissionLease;\n\t}\n\n\treleaseSubmission(lease: ForegroundSubmissionLease): void {\n\t\tif (!this.ownsSubmission(lease)) {\n\t\t\tthrow new Error(\"Cannot release foreground submission authority owned by another caller\");\n\t\t}\n\t\tthis.submissionLease = undefined;\n\t\tif (this.activeRuns === 0) {\n\t\t\tthis.resolveIdleWaiters();\n\t\t}\n\t}\n\n\tasync runAgentPrompt(\n\t\tmessages: AgentMessage | AgentMessage[],\n\t\tsubmissionLease?: ForegroundSubmissionLease,\n\t): Promise<void> {\n\t\tawait this.runAgentExecution(\"prompt\", messages, submissionLease);\n\t}\n\n\t/** Continue from the already canonical agent history without replaying the original user message. */\n\tasync runAgentContinuation(submissionLease?: ForegroundSubmissionLease): Promise<void> {\n\t\tawait this.runAgentExecution(\"continue\", undefined, submissionLease);\n\t}\n\n\tprivate async runAgentExecution(\n\t\tmode: \"prompt\" | \"continue\",\n\t\tmessages: AgentMessage | AgentMessage[] | undefined,\n\t\tsubmissionLease?: ForegroundSubmissionLease,\n\t): Promise<void> {\n\t\tlet lease = submissionLease;\n\t\tlet releaseLease = false;\n\t\tif (lease) {\n\t\t\tif (!this.ownsSubmission(lease)) {\n\t\t\t\tthrow new AgentBusyError(\"Foreground submission authority is no longer active.\");\n\t\t\t}\n\t\t} else {\n\t\t\tlease = this.tryAcquireSubmission();\n\t\t\tif (!lease) throw new AgentBusyError(\"Agent is already processing.\");\n\t\t\treleaseLease = true;\n\t\t}\n\t\tif (this.activeRuns > 0) {\n\t\t\tif (releaseLease && lease) this.releaseSubmission(lease);\n\t\t\tthrow new AgentBusyError(\"Agent is already processing.\");\n\t\t}\n\n\t\tthis.activeRuns++;\n\t\ttry {\n\t\t\tconst maxGoalLoopRounds = this.deps.settingsManager.getAutonomySettings().maxStallTurns;\n\t\t\tawait this.deps.prepareRun();\n\t\t\tlet goalLoopRounds = 1;\n\t\t\tif (mode === \"prompt\") {\n\t\t\t\tif (!messages) throw new Error(\"Foreground prompt execution requires messages.\");\n\t\t\t\tawait this.deps.agent.prompt(messages);\n\t\t\t} else {\n\t\t\t\tawait this.deps.agent.continue();\n\t\t\t}\n\t\t\twhile ((maxGoalLoopRounds === 0 || goalLoopRounds < maxGoalLoopRounds) && (await this.handlePostAgentRun())) {\n\t\t\t\tawait this.deps.agent.continue();\n\t\t\t\tgoalLoopRounds++;\n\t\t\t}\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait this.deps.afterRun();\n\t\t\t} finally {\n\t\t\t\tthis.activeRuns--;\n\t\t\t\tif (releaseLease && lease && this.ownsSubmission(lease)) this.releaseSubmission(lease);\n\t\t\t\tif (this.activeRuns === 0 && this.submissionLease === undefined) {\n\t\t\t\t\tthis.resolveIdleWaiters();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\twakeIdleWaiters(): void {\n\t\tthis.resolveIdleWaiters();\n\t}\n\n\tasync waitForIdle(): Promise<void> {\n\t\twhile (true) {\n\t\t\tif (this.shutdownReason) return;\n\t\t\tif (this.submissionLease !== undefined || this.activeRuns > 0 || this.deps.isCompacting?.() === true) {\n\t\t\t\tawait new Promise<void>((resolve) => this.idleWaiters.add(resolve));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait this.deps.agent.waitForIdle();\n\t\t\tif (!this.isBusy) return;\n\t\t}\n\t}\n\n\tshutdown(): void {\n\t\tthis.shutdownReason ??= new Error(\"Session disposed before foreground submission authority was acquired\");\n\t\tfor (const resolve of this.idleWaiters) resolve();\n\t\tthis.idleWaiters.clear();\n\t}\n\n\tprivate resolveIdleWaiters(): void {\n\t\tif (this.submissionLease !== undefined || this.activeRuns > 0) return;\n\t\tfor (const resolve of this.idleWaiters) resolve();\n\t\tthis.idleWaiters.clear();\n\t}\n\n\tabortRetry(): void {\n\t\tthis.retry.abort();\n\t}\n\n\tisModelExhausted(ref: string): boolean {\n\t\treturn this.billingFailover.isExhausted(ref);\n\t}\n\n\tgetFailoverStatus(): ModelRouterFailoverStatus {\n\t\treturn this.billingFailover.getStatus();\n\t}\n\n\tobserveAssistant(message: AssistantMessage): void {\n\t\tthis.lastAssistantMessage = message;\n\t\tif (message.stopReason === \"error\") return;\n\t\tif (message.stopReason === \"aborted\") {\n\t\t\tthis.finishRetry(false, message.errorMessage ?? \"Retry aborted\");\n\t\t\treturn;\n\t\t}\n\t\tthis.deps.onSuccessfulAssistant();\n\t\tthis.finishRetry(true);\n\t}\n\n\twillRetryAfterAgentEnd(event: Extract<AgentEvent, { type: \"agent_end\" }>): boolean {\n\t\tconst settings = this.deps.settingsManager.getRetrySettings();\n\t\tif (!settings.enabled || this.retry.attempt >= settings.maxRetries) return false;\n\t\tfor (let index = event.messages.length - 1; index >= 0; index--) {\n\t\t\tconst message = event.messages[index];\n\t\t\tif (message.role !== \"assistant\") continue;\n\t\t\tconst classified = this.classifyAssistantError(message);\n\t\t\tif (!classified?.retryable) return false;\n\t\t\ttry {\n\t\t\t\tcomputeRetryDelayMs(this.getRetryPolicy(), this.retry.attempt + 1, {\n\t\t\t\t\tretryAfterMs: classified.retryAfterMs,\n\t\t\t\t});\n\t\t\t\treturn true;\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof RetryDelayExceededError) return false;\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t}\n\t\treturn false;\n\t}\n\n\tasync handlePostAgentRun(): Promise<boolean> {\n\t\tconst message = this.lastAssistantMessage;\n\t\tthis.lastAssistantMessage = undefined;\n\t\tif (!message) return false;\n\n\t\tconst classified = this.classifyAssistantError(message);\n\t\tif (classified) {\n\t\t\tthis.deps.failureCorpus.record({\n\t\t\t\tprovider: message.provider,\n\t\t\t\tmodelId: message.model,\n\t\t\t\tmessage: message.errorMessage ?? \"\",\n\t\t\t\tclassified,\n\t\t\t});\n\t\t}\n\t\tconst compactionRetryKey =\n\t\t\tclassified?.retryable && classified.shouldCompact\n\t\t\t\t? `${message.provider}\\u0000${message.model}\\u0000${classified.reason}\\u0000${message.errorMessage ?? \"\"}`\n\t\t\t\t: undefined;\n\t\tconst repeatedCompactionFailure =\n\t\t\tcompactionRetryKey !== undefined && compactionRetryKey === this.pendingCompactionRetryKey;\n\t\tif (!repeatedCompactionFailure) this.pendingCompactionRetryKey = undefined;\n\t\tif (repeatedCompactionFailure && (await this.deps.checkCompaction(message))) {\n\t\t\treturn true;\n\t\t}\n\t\tif (classified?.retryable && (await this.retry.prepareRetry(message))) {\n\t\t\tthis.pendingCompactionRetryKey = compactionRetryKey;\n\t\t\treturn true;\n\t\t}\n\t\tif (await this.billingFailover.handleAssistantError(message, classified)) return false;\n\n\t\tif (message.stopReason === \"error\") this.finishRetry(false, message.errorMessage);\n\t\tif (await this.deps.checkCompaction(message)) return true;\n\t\treturn this.deps.agent.hasQueuedMessages();\n\t}\n\n\tprivate finishRetry(success: boolean, finalError?: string): void {\n\t\tthis.pendingCompactionRetryKey = undefined;\n\t\tif (this.retry.attempt === 0) return;\n\t\tthis.deps.emit({ type: \"auto_retry_end\", success, attempt: this.retry.attempt, finalError });\n\t\tthis.retry.reset();\n\t}\n\n\tprivate classifyAssistantError(message: AssistantMessage): ClassifiedError | undefined {\n\t\tif (message.stopReason !== \"error\" || !message.errorMessage) return undefined;\n\t\treturn classifyFailure({\n\t\t\tmessage: message.errorMessage,\n\t\t\tcontextOverflow: isContextOverflow(message, this.deps.getContextWindow()),\n\t\t\tprovider: message.provider,\n\t\t});\n\t}\n}\n"]}
@@ -9,8 +9,8 @@
9
9
  * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token
10
10
  * budget on the goal. Each submitted pass still reports turn/wall-clock telemetry; provider usage
11
11
  * and spend are attributed at the response boundary. The host compares each pass's authoritative
12
- * progress revision and records unchanged passes as stalls, so a model cannot bypass the stall
13
- * limit by omitting a voluntary `no_progress` call.
12
+ * progress revision and records unchanged passes as stalls, so the continuation prompt can force
13
+ * a different recovery approach even when a model omits a voluntary `no_progress` call.
14
14
  */
15
15
  import type { GoalContinuationLoopOptions, GoalContinuationLoopResult, GoalContinuationOnceOptions, GoalContinuationOnceResult, PromptOptions } from "./agent-session-contracts.ts";
16
16
  import type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from "./goals/goal-runtime-snapshot.ts";
@@ -9,8 +9,8 @@
9
9
  * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token
10
10
  * budget on the goal. Each submitted pass still reports turn/wall-clock telemetry; provider usage
11
11
  * and spend are attributed at the response boundary. The host compares each pass's authoritative
12
- * progress revision and records unchanged passes as stalls, so a model cannot bypass the stall
13
- * limit by omitting a voluntary `no_progress` call.
12
+ * progress revision and records unchanged passes as stalls, so the continuation prompt can force
13
+ * a different recovery approach even when a model omits a voluntary `no_progress` call.
14
14
  */
15
15
  import { AgentBusyError } from "@caupulican/pi-agent-core/agent";
16
16
  import { buildGoalContinuationPrompt, GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE, } from "./goals/goal-continuation-prompt.js";
@@ -1 +1 @@
1
- {"version":3,"file":"goal-loop-controller.js","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AASjE,OAAO,EACN,2BAA2B,EAC3B,qCAAqC,GACrC,MAAM,qCAAqC,CAAC;AAC7C,OAAO,EAAE,wBAAwB,EAAE,MAAM,kCAAkC,CAAC;AAE5E,OAAO,EAAkB,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9E;;;;GAIG;AACH,SAAS,+BAA+B,CAAC,KAA4B;IACpE,IAAI,CAAC,KAAK,IAAI,CAAC,qBAAqB,CAAC,KAAK,CAAC,MAAM,CAAC;QAAE,OAAO,SAAS,CAAC;IACrE,IAAI,KAAK,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,KAAK,CAAC,WAAW,EAAE,CAAC;QACrF,OAAO,2BAA2B,KAAK,CAAC,UAAU,IAAI,CAAC,IAAI,KAAK,CAAC,WAAW,GAAG,CAAC;IACjF,CAAC;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,qBAAqB,CAAC,QAA6B;IAC3D,OAAO,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,0BAA0B,CAAC;AACrG,CAAC;AAyBD,MAAM,OAAO,kBAAkB;IAG9B,YAAY,IAA4B;QACvC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,OAAoC;QAC1D,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;QAE5F,IAAI,QAAQ,CAAC,YAAY,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;YACjD,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;QACvC,CAAC;QAED,MAAM,MAAM,GAAG,2BAA2B,EAAE,CAAC;QAC7C,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;YACvD,qBAAqB,EAAE,KAAK;YAC5B,oBAAoB,EAAE,KAAK;YAC3B,gBAAgB,EAAE,KAAK;YACvB,mBAAmB,EAAE,qCAAqC;YAC1D,eAAe,EAAE,QAAQ,CAAC,SAAS,EAAE,MAAM;SAC3C,CAAC,CAAC;QAEH,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,WAAW,EAAE,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,gBAAgB,CAAC,OAAoC;QAC1D,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,OAAO,CAAC,QAAQ,GAAG,CAAC,EAAE,CAAC;YACrE,MAAM,IAAI,KAAK,CAAC,oFAAoF,CAAC,CAAC;QACvG,CAAC;QACD,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,MAAM,oBAAoB,GAAG,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC;QACpC,MAAM,cAAc,GACnB,OAAO,OAAO,CAAC,mBAAmB,KAAK,QAAQ,IAAI,OAAO,CAAC,mBAAmB,GAAG,CAAC;YACjF,CAAC,CAAC,OAAO,CAAC,mBAAmB,GAAG,MAAM;YACtC,CAAC,CAAC,SAAS,CAAC;QACd,MAAM,SAAS,GAAG,GAAG,EAAE,CAAC;QACxB,MAAM,yBAAyB,GAAG,GAAG,EAAE,CAAC,cAAc,KAAK,SAAS,IAAI,GAAG,EAAE,GAAG,SAAS,IAAI,cAAc,CAAC;QAC5G,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,sBAAsB,CAAC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE,CAAC,CAAC;QAElG,IAAI,yBAAyB,EAAE,EAAE,CAAC;YACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,2BAA2B,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC;QAC/F,CAAC;QAED,OAAO,CAAC,oBAAoB,IAAI,cAAc,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;YACnE,MAAM,cAAc,GAAG,QAAQ,EAAE,CAAC;YAClC,IAAI,cAAc,CAAC,YAAY,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACvD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,qBAAqB,CAAC,cAAc,CAAC,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;YAC7G,CAAC;YAED,wFAAwF;YACxF,uEAAuE;YACvE,MAAM,sBAAsB,GAAG,+BAA+B,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;YACzF,IAAI,sBAAsB,EAAE,CAAC;gBAC5B,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,sBAAsB,CAAC,CAAC;gBACxD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,uBAAuB,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC;YAC3F,CAAC;YAED,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC;YAC5B,MAAM,UAAU,GAAG,cAAc,CAAC,SAAS,CAAC;YAC5C,IAAI,CAAC,UAAU,EAAE,CAAC;gBACjB,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,0BAA0B,EAAE,aAAa,EAAE,cAAc,EAAE,CAAC;YAClG,CAAC;YACD,MAAM,cAAc,GAAG;gBACtB,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,UAAU,CAAC,MAAM;gBACzB,gBAAgB,EAAE,UAAU,CAAC,gBAAgB,IAAI,CAAC;gBAClD,UAAU,EAAE,UAAU,CAAC,UAAU;aACjC,CAAC;YACF,IAAI,MAAkC,CAAC;YACvC,IAAI,CAAC;gBACJ,MAAM,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;YAC/C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBAChB,sFAAsF;gBACtF,oFAAoF;gBACpF,IAAI,KAAK,YAAY,cAAc;oBAAE,MAAM,KAAK,CAAC;gBACjD,IAAI,KAAK,YAAY,wBAAwB,EAAE,CAAC;oBAC/C,sFAAsF;oBACtF,wFAAwF;oBACxF,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,uBAAuB,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC;gBAC3F,CAAC;gBACD,cAAc,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,EAAE,GAAG,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC;gBAChG,IAAI,CAAC,IAAI,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC;gBAC/C,MAAM,KAAK,CAAC;YACb,CAAC;YACD,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;gBACtB,cAAc,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,EAAE,GAAG,cAAc,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC;YACjG,CAAC;YAED,IAAI,aAAa,GAAG,QAAQ,EAAE,CAAC;YAC/B,IAAI,aAAa,CAAC,SAAS,EAAE,MAAM,KAAK,gBAAgB,EAAE,CAAC;gBAC1D,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,uBAAuB,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;YAC9F,CAAC;YACD,MAAM,qBAAqB,GAAG,+BAA+B,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;YACvF,IAAI,qBAAqB,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,CAAC,qBAAqB,CAAC,qBAAqB,CAAC,CAAC;gBACvD,aAAa,GAAG,QAAQ,EAAE,CAAC;gBAC3B,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,uBAAuB,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;YAC9F,CAAC;YACD,IAAI,aAAa,CAAC,YAAY,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACtD,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,qBAAqB,CAAC,aAAa,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;YAC3G,CAAC;YACD,IAAI,MAAM,CAAC,WAAW,KAAK,aAAa,EAAE,CAAC;gBAC1C,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;YACzF,CAAC;YACD,IAAI,yBAAyB,EAAE,EAAE,CAAC;gBACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,2BAA2B,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC;YAClG,CAAC;QACF,CAAC;QAED,OAAO;YACN,cAAc;YACd,UAAU,EAAE,mBAAmB;YAC/B,aAAa,EAAE,QAAQ,EAAE;SACzB,CAAC;IACH,CAAC;CACD","sourcesContent":["/**\n * Goal auto-continuation loop.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Drives the bounded \"keep the\n * active goal moving\" loop: each pass reads the goal runtime snapshot, and — only while the snapshot\n * says `continue` — submits one continuation prompt back through the session's own prompt path. It\n * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is\n * gated only by real terminal conditions and limits the owner explicitly supplied: an optional\n * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token\n * budget on the goal. Each submitted pass still reports turn/wall-clock telemetry; provider usage\n * and spend are attributed at the response boundary. The host compares each pass's authoritative\n * progress revision and records unchanged passes as stalls, so a model cannot bypass the stall\n * limit by omitting a voluntary `no_progress` call.\n */\n\nimport { AgentBusyError } from \"@caupulican/pi-agent-core/agent\";\nimport type {\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tGoalContinuationLoopStopReason,\n\tGoalContinuationOnceOptions,\n\tGoalContinuationOnceResult,\n\tPromptOptions,\n} from \"./agent-session-contracts.ts\";\nimport {\n\tbuildGoalContinuationPrompt,\n\tGOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n} from \"./goals/goal-continuation-prompt.ts\";\nimport { GoalBudgetExhaustedError } from \"./goals/goal-execution-errors.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport { type GoalState, isGoalExecutionActive } from \"./goals/goal-state.ts\";\n\n/**\n * Resolve an owner-supplied durable goal budget. Wall-clock and spend counters are deliberately\n * absent here: they are telemetry unless the public goal contract grows matching explicit limits.\n * Execution limits are policy inputs, not hidden runtime defaults.\n */\nfunction getExplicitGoalBudgetExhaustion(state: GoalState | undefined): string | undefined {\n\tif (!state || !isGoalExecutionActive(state.status)) return undefined;\n\tif (state.tokenBudget !== undefined && (state.tokensUsed ?? 0) >= state.tokenBudget) {\n\t\treturn `token budget exhausted (${state.tokensUsed ?? 0}/${state.tokenBudget})`;\n\t}\n\treturn undefined;\n}\n\n/**\n * Maps a non-\"continue\" continuation action onto the loop's own stopReason vocabulary.\n * `\"waiting\"` (a worker is dispatched against an open requirement) gets its OWN benign stopReason so\n * a wait is never misreported as `continuation_not_allowed` (which reads as a terminal refusal) —\n * callers/telemetry can tell \"paused, will resume on its own\" apart from \"stopped, needs a human or a\n * new decision.\" Every other non-continue action (ask-user/finalize/stop) keeps the existing\n * `continuation_not_allowed` stopReason unchanged.\n */\nfunction nonContinueStopReason(snapshot: GoalRuntimeSnapshot): GoalContinuationLoopStopReason {\n\treturn snapshot.continuation.action === \"waiting\" ? \"worker_in_flight\" : \"continuation_not_allowed\";\n}\n\nexport interface GoalLoopControllerDeps {\n\t/** Read the current goal runtime snapshot (continuation decision + goal state) fresh each pass. */\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\t/** Submit a continuation prompt through the session's own prompt path. */\n\tprompt(text: string, options?: PromptOptions): Promise<\"completed\" | \"interrupted\">;\n\t/**\n\t * Persist one submitted pass's turn and active-wall-clock contribution. Provider usage is charged\n\t * at each assistant response before another request can be admitted. Called once per\n\t * pass actually SUBMITTED (never for a no-op `continueGoalOnce` call).\n\t */\n\trecordGoalContinuationPass(pass: {\n\t\tturns: number;\n\t\twallClockMs: number;\n\t\tgoalId: string;\n\t\tprogressRevision: number;\n\t\tstallTurns: number;\n\t}): void;\n\t/** Persist an exhausted/non-retryable continuation failure as a stopped goal state. */\n\trecordGoalContinuationFailure(error: unknown): void;\n\t/** Persist a reason-specific budget terminal state before returning control. */\n\tmarkGoalBudgetLimited(reason: string): void;\n}\n\nexport class GoalLoopController {\n\tprivate readonly deps: GoalLoopControllerDeps;\n\n\tconstructor(deps: GoalLoopControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync continueGoalOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult> {\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (snapshot.continuation.action !== \"continue\") {\n\t\t\treturn { submitted: false, snapshot };\n\t\t}\n\n\t\tconst prompt = buildGoalContinuationPrompt();\n\t\tconst turnOutcome = await this.deps.prompt(prompt.text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tprocessSlashCommands: false,\n\t\t\tautoContinueGoal: false,\n\t\t\tinternalContextType: GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n\t\t\tgoalExecutionId: snapshot.goalState?.goalId,\n\t\t});\n\n\t\treturn { submitted: true, snapshot, prompt, turnOutcome };\n\t}\n\n\tasync continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (!Number.isSafeInteger(options.maxTurns) || options.maxTurns < 0) {\n\t\t\tthrow new Error(\"Goal continuation maxTurns must be a non-negative safe integer; 0 means unbounded.\");\n\t\t}\n\t\tlet turnsSubmitted = 0;\n\t\tconst hasExplicitTurnLimit = options.maxTurns > 0;\n\t\tconst now = options.now ?? Date.now;\n\t\tconst maxWallClockMs =\n\t\t\ttypeof options.maxWallClockMinutes === \"number\" && options.maxWallClockMinutes > 0\n\t\t\t\t? options.maxWallClockMinutes * 60_000\n\t\t\t\t: undefined;\n\t\tconst startedAt = now();\n\t\tconst hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;\n\t\tconst snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (hasReachedWallClockBudget()) {\n\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t}\n\n\t\twhile (!hasExplicitTurnLimit || turnsSubmitted < options.maxTurns) {\n\t\t\tconst beforeSnapshot = snapshot();\n\t\t\tif (beforeSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\t// Owner-supplied durable token budget — read fresh every pass so an invocation stops as\n\t\t\t// soon as its own latest persisted usage crosses the explicit ceiling.\n\t\t\tconst beforeBudgetExhaustion = getExplicitGoalBudgetExhaustion(beforeSnapshot.goalState);\n\t\t\tif (beforeBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(beforeBudgetExhaustion);\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tconst passStartedAt = now();\n\t\t\tconst beforeGoal = beforeSnapshot.goalState;\n\t\t\tif (!beforeGoal) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"continuation_not_allowed\", finalSnapshot: beforeSnapshot };\n\t\t\t}\n\t\t\tconst passAccounting = {\n\t\t\t\tturns: 1,\n\t\t\t\tgoalId: beforeGoal.goalId,\n\t\t\t\tprogressRevision: beforeGoal.progressRevision ?? 0,\n\t\t\t\tstallTurns: beforeGoal.stallTurns,\n\t\t\t};\n\t\t\tlet result: GoalContinuationOnceResult;\n\t\t\ttry {\n\t\t\t\tresult = await this.continueGoalOnce(options);\n\t\t\t} catch (error) {\n\t\t\t\t// Prompt admission did not happen. A concurrent foreground owner is transient session\n\t\t\t\t// coordination, not a consumed goal turn and not evidence that the goal is blocked.\n\t\t\t\tif (error instanceof AgentBusyError) throw error;\n\t\t\t\tif (error instanceof GoalBudgetExhaustedError) {\n\t\t\t\t\t// The goal already stopped itself durably (markBudgetLimited ran synchronously before\n\t\t\t\t\t// this signal was thrown) — surface the existing clean stop instead of charging a turn.\n\t\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t\t}\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ ...passAccounting, wallClockMs: now() - passStartedAt });\n\t\t\t\tthis.deps.recordGoalContinuationFailure(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (result.submitted) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ ...passAccounting, wallClockMs: now() - passStartedAt });\n\t\t\t}\n\n\t\t\tlet afterSnapshot = snapshot();\n\t\t\tif (afterSnapshot.goalState?.status === \"budget_limited\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tconst afterBudgetExhaustion = getExplicitGoalBudgetExhaustion(afterSnapshot.goalState);\n\t\t\tif (afterBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(afterBudgetExhaustion);\n\t\t\t\tafterSnapshot = snapshot();\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (afterSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (result.turnOutcome === \"interrupted\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"turn_interrupted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tturnsSubmitted,\n\t\t\tstopReason: \"max_turns_reached\",\n\t\t\tfinalSnapshot: snapshot(),\n\t\t};\n\t}\n}\n"]}
1
+ {"version":3,"file":"goal-loop-controller.js","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Goal auto-continuation loop.\n *\n * Extracted verbatim from agent-session.ts (god-file decomposition). Drives the bounded \"keep the\n * active goal moving\" loop: each pass reads the goal runtime snapshot, and — only while the snapshot\n * says `continue` — submits one continuation prompt back through the session's own prompt path. It\n * owns no state; the goal state lives in the session log and is read fresh every pass. Termination is\n * gated only by real terminal conditions and limits the owner explicitly supplied: an optional\n * per-invocation turn cap, an optional per-invocation wall-clock cap, and an optional durable token\n * budget on the goal. Each submitted pass still reports turn/wall-clock telemetry; provider usage\n * and spend are attributed at the response boundary. The host compares each pass's authoritative\n * progress revision and records unchanged passes as stalls, so the continuation prompt can force\n * a different recovery approach even when a model omits a voluntary `no_progress` call.\n */\n\nimport { AgentBusyError } from \"@caupulican/pi-agent-core/agent\";\nimport type {\n\tGoalContinuationLoopOptions,\n\tGoalContinuationLoopResult,\n\tGoalContinuationLoopStopReason,\n\tGoalContinuationOnceOptions,\n\tGoalContinuationOnceResult,\n\tPromptOptions,\n} from \"./agent-session-contracts.ts\";\nimport {\n\tbuildGoalContinuationPrompt,\n\tGOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n} from \"./goals/goal-continuation-prompt.ts\";\nimport { GoalBudgetExhaustedError } from \"./goals/goal-execution-errors.ts\";\nimport type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport { type GoalState, isGoalExecutionActive } from \"./goals/goal-state.ts\";\n\n/**\n * Resolve an owner-supplied durable goal budget. Wall-clock and spend counters are deliberately\n * absent here: they are telemetry unless the public goal contract grows matching explicit limits.\n * Execution limits are policy inputs, not hidden runtime defaults.\n */\nfunction getExplicitGoalBudgetExhaustion(state: GoalState | undefined): string | undefined {\n\tif (!state || !isGoalExecutionActive(state.status)) return undefined;\n\tif (state.tokenBudget !== undefined && (state.tokensUsed ?? 0) >= state.tokenBudget) {\n\t\treturn `token budget exhausted (${state.tokensUsed ?? 0}/${state.tokenBudget})`;\n\t}\n\treturn undefined;\n}\n\n/**\n * Maps a non-\"continue\" continuation action onto the loop's own stopReason vocabulary.\n * `\"waiting\"` (a worker is dispatched against an open requirement) gets its OWN benign stopReason so\n * a wait is never misreported as `continuation_not_allowed` (which reads as a terminal refusal) —\n * callers/telemetry can tell \"paused, will resume on its own\" apart from \"stopped, needs a human or a\n * new decision.\" Every other non-continue action (ask-user/finalize/stop) keeps the existing\n * `continuation_not_allowed` stopReason unchanged.\n */\nfunction nonContinueStopReason(snapshot: GoalRuntimeSnapshot): GoalContinuationLoopStopReason {\n\treturn snapshot.continuation.action === \"waiting\" ? \"worker_in_flight\" : \"continuation_not_allowed\";\n}\n\nexport interface GoalLoopControllerDeps {\n\t/** Read the current goal runtime snapshot (continuation decision + goal state) fresh each pass. */\n\tgetGoalRuntimeSnapshot(settings: GoalRuntimeSnapshotSettings): GoalRuntimeSnapshot;\n\t/** Submit a continuation prompt through the session's own prompt path. */\n\tprompt(text: string, options?: PromptOptions): Promise<\"completed\" | \"interrupted\">;\n\t/**\n\t * Persist one submitted pass's turn and active-wall-clock contribution. Provider usage is charged\n\t * at each assistant response before another request can be admitted. Called once per\n\t * pass actually SUBMITTED (never for a no-op `continueGoalOnce` call).\n\t */\n\trecordGoalContinuationPass(pass: {\n\t\tturns: number;\n\t\twallClockMs: number;\n\t\tgoalId: string;\n\t\tprogressRevision: number;\n\t\tstallTurns: number;\n\t}): void;\n\t/** Persist an exhausted/non-retryable continuation failure as a stopped goal state. */\n\trecordGoalContinuationFailure(error: unknown): void;\n\t/** Persist a reason-specific budget terminal state before returning control. */\n\tmarkGoalBudgetLimited(reason: string): void;\n}\n\nexport class GoalLoopController {\n\tprivate readonly deps: GoalLoopControllerDeps;\n\n\tconstructor(deps: GoalLoopControllerDeps) {\n\t\tthis.deps = deps;\n\t}\n\n\tasync continueGoalOnce(options: GoalContinuationOnceOptions): Promise<GoalContinuationOnceResult> {\n\t\tconst snapshot = this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (snapshot.continuation.action !== \"continue\") {\n\t\t\treturn { submitted: false, snapshot };\n\t\t}\n\n\t\tconst prompt = buildGoalContinuationPrompt();\n\t\tconst turnOutcome = await this.deps.prompt(prompt.text, {\n\t\t\texpandPromptTemplates: false,\n\t\t\tprocessSlashCommands: false,\n\t\t\tautoContinueGoal: false,\n\t\t\tinternalContextType: GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE,\n\t\t\tgoalExecutionId: snapshot.goalState?.goalId,\n\t\t});\n\n\t\treturn { submitted: true, snapshot, prompt, turnOutcome };\n\t}\n\n\tasync continueGoalLoop(options: GoalContinuationLoopOptions): Promise<GoalContinuationLoopResult> {\n\t\tif (!Number.isSafeInteger(options.maxTurns) || options.maxTurns < 0) {\n\t\t\tthrow new Error(\"Goal continuation maxTurns must be a non-negative safe integer; 0 means unbounded.\");\n\t\t}\n\t\tlet turnsSubmitted = 0;\n\t\tconst hasExplicitTurnLimit = options.maxTurns > 0;\n\t\tconst now = options.now ?? Date.now;\n\t\tconst maxWallClockMs =\n\t\t\ttypeof options.maxWallClockMinutes === \"number\" && options.maxWallClockMinutes > 0\n\t\t\t\t? options.maxWallClockMinutes * 60_000\n\t\t\t\t: undefined;\n\t\tconst startedAt = now();\n\t\tconst hasReachedWallClockBudget = () => maxWallClockMs !== undefined && now() - startedAt >= maxWallClockMs;\n\t\tconst snapshot = () => this.deps.getGoalRuntimeSnapshot({ maxStallTurns: options.maxStallTurns });\n\n\t\tif (hasReachedWallClockBudget()) {\n\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\n\t\t}\n\n\t\twhile (!hasExplicitTurnLimit || turnsSubmitted < options.maxTurns) {\n\t\t\tconst beforeSnapshot = snapshot();\n\t\t\tif (beforeSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(beforeSnapshot), finalSnapshot: beforeSnapshot };\n\t\t\t}\n\n\t\t\t// Owner-supplied durable token budget — read fresh every pass so an invocation stops as\n\t\t\t// soon as its own latest persisted usage crosses the explicit ceiling.\n\t\t\tconst beforeBudgetExhaustion = getExplicitGoalBudgetExhaustion(beforeSnapshot.goalState);\n\t\t\tif (beforeBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(beforeBudgetExhaustion);\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t}\n\n\t\t\tconst passStartedAt = now();\n\t\t\tconst beforeGoal = beforeSnapshot.goalState;\n\t\t\tif (!beforeGoal) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"continuation_not_allowed\", finalSnapshot: beforeSnapshot };\n\t\t\t}\n\t\t\tconst passAccounting = {\n\t\t\t\tturns: 1,\n\t\t\t\tgoalId: beforeGoal.goalId,\n\t\t\t\tprogressRevision: beforeGoal.progressRevision ?? 0,\n\t\t\t\tstallTurns: beforeGoal.stallTurns,\n\t\t\t};\n\t\t\tlet result: GoalContinuationOnceResult;\n\t\t\ttry {\n\t\t\t\tresult = await this.continueGoalOnce(options);\n\t\t\t} catch (error) {\n\t\t\t\t// Prompt admission did not happen. A concurrent foreground owner is transient session\n\t\t\t\t// coordination, not a consumed goal turn and not evidence that the goal is blocked.\n\t\t\t\tif (error instanceof AgentBusyError) throw error;\n\t\t\t\tif (error instanceof GoalBudgetExhaustedError) {\n\t\t\t\t\t// The goal already stopped itself durably (markBudgetLimited ran synchronously before\n\t\t\t\t\t// this signal was thrown) — surface the existing clean stop instead of charging a turn.\n\t\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t\t}\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ ...passAccounting, wallClockMs: now() - passStartedAt });\n\t\t\t\tthis.deps.recordGoalContinuationFailure(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\tif (result.submitted) {\n\t\t\t\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ ...passAccounting, wallClockMs: now() - passStartedAt });\n\t\t\t}\n\n\t\t\tlet afterSnapshot = snapshot();\n\t\t\tif (afterSnapshot.goalState?.status === \"budget_limited\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tconst afterBudgetExhaustion = getExplicitGoalBudgetExhaustion(afterSnapshot.goalState);\n\t\t\tif (afterBudgetExhaustion) {\n\t\t\t\tthis.deps.markGoalBudgetLimited(afterBudgetExhaustion);\n\t\t\t\tafterSnapshot = snapshot();\n\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (afterSnapshot.continuation.action !== \"continue\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: nonContinueStopReason(afterSnapshot), finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (result.turnOutcome === \"interrupted\") {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"turn_interrupted\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: afterSnapshot };\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tturnsSubmitted,\n\t\t\tstopReason: \"max_turns_reached\",\n\t\t\tfinalSnapshot: snapshot(),\n\t\t};\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"compact-goal-context.d.ts","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAIpE,OAAO,EAAE,KAAK,SAAS,EAAyB,MAAM,iBAAiB,CAAC;AAExE,eAAO,MAAM,+BAA+B,wBAAwB,CAAC;AAsBrE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,GAAG,MAAM,CAkB5F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,EAAE,CAkB/G"}
1
+ {"version":3,"file":"compact-goal-context.d.ts","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAIpE,OAAO,EAAE,KAAK,SAAS,EAAyB,MAAM,iBAAiB,CAAC;AAExE,eAAO,MAAM,+BAA+B,wBAAwB,CAAC;AAsBrE,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,SAAS,EAAE,gBAAgB,EAAE,OAAO,GAAG,MAAM,CAuB5F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,EAAE,CAkB/G"}
@@ -23,21 +23,25 @@ function isGoalContextMessage(message) {
23
23
  }
24
24
  export function formatCompactGoalContext(state, continuationTurn) {
25
25
  const record = projectGoalRecord(state);
26
- const instruction = continuationTurn
27
- ? "Continue now: pursue full objective."
28
- : "current user message steers this turn.";
26
+ const instruction = continuationTurn ? "Continue objective." : "User steers.";
27
+ const recoveryInstruction = continuationTurn && state.stallTurns > 0
28
+ ? `RECOVERY REQUIRED: ${state.stallTurns} turns without authoritative progress. Inspect evidence; change approach/tool/route. Do not repeat unchanged work or ask owner without a proven approval boundary.`
29
+ : undefined;
29
30
  const compactRecord = record.tokenBudget === undefined
30
31
  ? { untrustedObjective: record.objective }
31
32
  : { untrustedObjective: record.objective, tokenBudget: String(record.tokenBudget) };
32
33
  const encodedRecord = JSON.stringify(compactRecord).replaceAll("<", "\\u003c").replaceAll(">", "\\u003e");
33
34
  return [
34
- "ACTIVE GOAL — HOST-OWNED CONTINUATION",
35
+ "ACTIVE GOAL — HOST-OWNED",
35
36
  encodedRecord,
36
37
  instruction,
37
- "get_goal; task_steps for decomposition.",
38
- 'Progress: update_goal status "active".',
39
- 'update_goal with status "complete" after requirement-by-requirement audit; "blocked" only after same blocking condition lasts 3 consecutive goal turns; else continue.',
40
- ].join("\n");
38
+ recoveryInstruction,
39
+ "get_goal; task_steps",
40
+ "Recover/reassign timeouts; verify/reopen blocks.",
41
+ "update_goal: complete=audited requirements; blocked=proven owner/approval boundary or impossible capability after 3 no-progress turns and distinct recoveries requiring owner/external change; else continue.",
42
+ ]
43
+ .filter((line) => line !== undefined)
44
+ .join("\n");
41
45
  }
42
46
  /**
43
47
  * Replace every historical goal continuation payload with one current compact projection. The
@@ -1 +1 @@
1
- {"version":3,"file":"compact-goal-context.js","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCustomMessage } from \"@caupulican/pi-agent-core/messages\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core/types\";\nimport type { TextContent } from \"@caupulican/pi-ai\";\nimport { GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE } from \"./goal-continuation-prompt.ts\";\nimport { projectGoalRecord } from \"./goal-record.ts\";\nimport { type GoalState, isGoalExecutionActive } from \"./goal-state.ts\";\n\nexport const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = \"active_goal_context\";\nconst LEGACY_GOAL_CONTINUATION_PREFIX = \"Goal continuation context\\n=========================\";\n\nfunction messageText(message: AgentMessage): string {\n\tif (message.role !== \"user\") return \"\";\n\tif (typeof message.content === \"string\") return message.content;\n\treturn message.content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction isGoalContextMessage(message: AgentMessage): boolean {\n\tif (message.role === \"custom\") {\n\t\treturn (\n\t\t\tmessage.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE ||\n\t\t\tmessage.customType === ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE\n\t\t);\n\t}\n\treturn messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX);\n}\n\nexport function formatCompactGoalContext(state: GoalState, continuationTurn: boolean): string {\n\tconst record = projectGoalRecord(state);\n\tconst instruction = continuationTurn\n\t\t? \"Continue now: pursue full objective.\"\n\t\t: \"current user message steers this turn.\";\n\tconst compactRecord =\n\t\trecord.tokenBudget === undefined\n\t\t\t? { untrustedObjective: record.objective }\n\t\t\t: { untrustedObjective: record.objective, tokenBudget: String(record.tokenBudget) };\n\tconst encodedRecord = JSON.stringify(compactRecord).replaceAll(\"<\", \"\\\\u003c\").replaceAll(\">\", \"\\\\u003e\");\n\treturn [\n\t\t\"ACTIVE GOAL — HOST-OWNED CONTINUATION\",\n\t\tencodedRecord,\n\t\tinstruction,\n\t\t\"get_goal; task_steps for decomposition.\",\n\t\t'Progress: update_goal status \"active\".',\n\t\t'update_goal with status \"complete\" after requirement-by-requirement audit; \"blocked\" only after same blocking condition lasts 3 consecutive goal turns; else continue.',\n\t].join(\"\\n\");\n}\n\n/**\n * Replace every historical goal continuation payload with one current compact projection. The\n * projection exists only in the provider request returned from context assembly; it is never\n * appended to the transcript or session log.\n */\nexport function injectCompactGoalContext(messages: AgentMessage[], state: GoalState | undefined): AgentMessage[] {\n\tconst continuationTurn = messages.some(\n\t\t(message) =>\n\t\t\t(message.role === \"custom\" && message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE) ||\n\t\t\tmessageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX),\n\t);\n\tconst filtered = messages.filter((message) => !isGoalContextMessage(message));\n\tif (!state || !isGoalExecutionActive(state.status)) return filtered;\n\treturn [\n\t\t...filtered,\n\t\tcreateCustomMessage(\n\t\t\tACTIVE_GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t\tformatCompactGoalContext(state, continuationTurn),\n\t\t\tfalse,\n\t\t\t{ goalId: state.goalId, revision: state.revision ?? 0 },\n\t\t\tnew Date().toISOString(),\n\t\t),\n\t];\n}\n"]}
1
+ {"version":3,"file":"compact-goal-context.js","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"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","sourcesContent":["import { createCustomMessage } from \"@caupulican/pi-agent-core/messages\";\nimport type { AgentMessage } from \"@caupulican/pi-agent-core/types\";\nimport type { TextContent } from \"@caupulican/pi-ai\";\nimport { GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE } from \"./goal-continuation-prompt.ts\";\nimport { projectGoalRecord } from \"./goal-record.ts\";\nimport { type GoalState, isGoalExecutionActive } from \"./goal-state.ts\";\n\nexport const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = \"active_goal_context\";\nconst LEGACY_GOAL_CONTINUATION_PREFIX = \"Goal continuation context\\n=========================\";\n\nfunction messageText(message: AgentMessage): string {\n\tif (message.role !== \"user\") return \"\";\n\tif (typeof message.content === \"string\") return message.content;\n\treturn message.content\n\t\t.filter((part): part is TextContent => part.type === \"text\")\n\t\t.map((part) => part.text)\n\t\t.join(\"\\n\");\n}\n\nfunction isGoalContextMessage(message: AgentMessage): boolean {\n\tif (message.role === \"custom\") {\n\t\treturn (\n\t\t\tmessage.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE ||\n\t\t\tmessage.customType === ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE\n\t\t);\n\t}\n\treturn messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX);\n}\n\nexport function formatCompactGoalContext(state: GoalState, continuationTurn: boolean): string {\n\tconst record = projectGoalRecord(state);\n\tconst instruction = continuationTurn ? \"Continue objective.\" : \"User steers.\";\n\tconst recoveryInstruction =\n\t\tcontinuationTurn && state.stallTurns > 0\n\t\t\t? `RECOVERY REQUIRED: ${state.stallTurns} turns without authoritative progress. Inspect evidence; change approach/tool/route. Do not repeat unchanged work or ask owner without a proven approval boundary.`\n\t\t\t: undefined;\n\tconst compactRecord =\n\t\trecord.tokenBudget === undefined\n\t\t\t? { untrustedObjective: record.objective }\n\t\t\t: { untrustedObjective: record.objective, tokenBudget: String(record.tokenBudget) };\n\tconst encodedRecord = JSON.stringify(compactRecord).replaceAll(\"<\", \"\\\\u003c\").replaceAll(\">\", \"\\\\u003e\");\n\treturn [\n\t\t\"ACTIVE GOAL — HOST-OWNED\",\n\t\tencodedRecord,\n\t\tinstruction,\n\t\trecoveryInstruction,\n\t\t\"get_goal; task_steps\",\n\t\t\"Recover/reassign timeouts; verify/reopen blocks.\",\n\t\t\"update_goal: complete=audited requirements; blocked=proven owner/approval boundary or impossible capability after 3 no-progress turns and distinct recoveries requiring owner/external change; else continue.\",\n\t]\n\t\t.filter((line): line is string => line !== undefined)\n\t\t.join(\"\\n\");\n}\n\n/**\n * Replace every historical goal continuation payload with one current compact projection. The\n * projection exists only in the provider request returned from context assembly; it is never\n * appended to the transcript or session log.\n */\nexport function injectCompactGoalContext(messages: AgentMessage[], state: GoalState | undefined): AgentMessage[] {\n\tconst continuationTurn = messages.some(\n\t\t(message) =>\n\t\t\t(message.role === \"custom\" && message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE) ||\n\t\t\tmessageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX),\n\t);\n\tconst filtered = messages.filter((message) => !isGoalContextMessage(message));\n\tif (!state || !isGoalExecutionActive(state.status)) return filtered;\n\treturn [\n\t\t...filtered,\n\t\tcreateCustomMessage(\n\t\t\tACTIVE_GOAL_CONTEXT_CUSTOM_TYPE,\n\t\t\tformatCompactGoalContext(state, continuationTurn),\n\t\t\tfalse,\n\t\t\t{ goalId: state.goalId, revision: state.revision ?? 0 },\n\t\t\tnew Date().toISOString(),\n\t\t),\n\t];\n}\n"]}