@caupulican/pi-adaptative 0.90.7 → 0.90.11
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.
- package/CHANGELOG.md +49 -0
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +5 -4
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +6 -3
- package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +1 -0
- package/dist/core/agent-session-contracts.d.ts +2 -0
- package/dist/core/agent-session-contracts.d.ts.map +1 -1
- package/dist/core/agent-session-contracts.js.map +1 -1
- package/dist/core/agent-session.d.ts +8 -7
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +80 -196
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/autonomy/bounded-completion.d.ts +7 -1
- package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
- package/dist/core/autonomy/bounded-completion.js +8 -2
- package/dist/core/autonomy/bounded-completion.js.map +1 -1
- package/dist/core/autonomy/contracts.d.ts +1 -1
- package/dist/core/autonomy/contracts.d.ts.map +1 -1
- package/dist/core/autonomy/contracts.js.map +1 -1
- package/dist/core/background-lane-controller.d.ts +14 -0
- package/dist/core/background-lane-controller.d.ts.map +1 -1
- package/dist/core/background-lane-controller.js +32 -0
- package/dist/core/background-lane-controller.js.map +1 -1
- package/dist/core/billing-failover-controller.js +1 -1
- package/dist/core/billing-failover-controller.js.map +1 -1
- package/dist/core/context/current-work-memory.d.ts +1 -1
- package/dist/core/context/current-work-memory.d.ts.map +1 -1
- package/dist/core/context/current-work-memory.js +2 -1
- package/dist/core/context/current-work-memory.js.map +1 -1
- package/dist/core/context/long-term-memory-trigger.d.ts +1 -1
- package/dist/core/context/long-term-memory-trigger.d.ts.map +1 -1
- package/dist/core/context/long-term-memory-trigger.js +2 -1
- package/dist/core/context/long-term-memory-trigger.js.map +1 -1
- package/dist/core/delegation/managed-lane-controller.js +2 -2
- package/dist/core/delegation/managed-lane-controller.js.map +1 -1
- package/dist/core/delegation/worker-agent-control-coordinator.d.ts +13 -0
- package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-agent-control-coordinator.js +71 -8
- package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-attempt-executor.d.ts.map +1 -1
- package/dist/core/delegation/worker-attempt-executor.js +13 -8
- package/dist/core/delegation/worker-attempt-executor.js.map +1 -1
- package/dist/core/delegation/worker-claim.d.ts.map +1 -1
- package/dist/core/delegation/worker-claim.js +14 -1
- package/dist/core/delegation/worker-claim.js.map +1 -1
- package/dist/core/delegation/worker-delegation-controller.d.ts +3 -2
- package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -1
- package/dist/core/delegation/worker-delegation-controller.js +95 -42
- package/dist/core/delegation/worker-delegation-controller.js.map +1 -1
- package/dist/core/delegation/worker-fleet-limits.d.ts.map +1 -1
- package/dist/core/delegation/worker-fleet-limits.js +5 -1
- package/dist/core/delegation/worker-fleet-limits.js.map +1 -1
- package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -1
- package/dist/core/delegation/worker-lane-projection.js +7 -4
- package/dist/core/delegation/worker-lane-projection.js.map +1 -1
- package/dist/core/delegation/worker-lifecycle.d.ts +8 -0
- package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -1
- package/dist/core/delegation/worker-lifecycle.js.map +1 -1
- package/dist/core/delegation/worker-notification-coordinator.d.ts +21 -0
- package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-notification-coordinator.js +65 -2
- package/dist/core/delegation/worker-notification-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-runner.d.ts +7 -0
- package/dist/core/delegation/worker-runner.d.ts.map +1 -1
- package/dist/core/delegation/worker-runner.js +24 -7
- package/dist/core/delegation/worker-runner.js.map +1 -1
- package/dist/core/delegation/worker-system-prompt.d.ts +54 -0
- package/dist/core/delegation/worker-system-prompt.d.ts.map +1 -0
- package/dist/core/delegation/worker-system-prompt.js +85 -0
- package/dist/core/delegation/worker-system-prompt.js.map +1 -0
- package/dist/core/delegation/worker-tree-budget-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-tree-budget-coordinator.js +4 -0
- package/dist/core/delegation/worker-tree-budget-coordinator.js.map +1 -1
- package/dist/core/delegation/worker-write-reservation-coordinator.d.ts +4 -0
- package/dist/core/delegation/worker-write-reservation-coordinator.d.ts.map +1 -1
- package/dist/core/delegation/worker-write-reservation-coordinator.js +28 -1
- package/dist/core/delegation/worker-write-reservation-coordinator.js.map +1 -1
- package/dist/core/durable-custom-message-turn-controller.d.ts.map +1 -1
- package/dist/core/durable-custom-message-turn-controller.js +14 -3
- package/dist/core/durable-custom-message-turn-controller.js.map +1 -1
- package/dist/core/extension-binding-controller.d.ts +107 -0
- package/dist/core/extension-binding-controller.d.ts.map +1 -0
- package/dist/core/extension-binding-controller.js +224 -0
- package/dist/core/extension-binding-controller.js.map +1 -0
- package/dist/core/extensions/types.d.ts +2 -0
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/foreground-terminal-handoff-controller.d.ts +9 -0
- package/dist/core/foreground-terminal-handoff-controller.d.ts.map +1 -1
- package/dist/core/foreground-terminal-handoff-controller.js +35 -9
- package/dist/core/foreground-terminal-handoff-controller.js.map +1 -1
- package/dist/core/goal-loop-controller.d.ts.map +1 -1
- package/dist/core/goal-loop-controller.js +10 -1
- package/dist/core/goal-loop-controller.js.map +1 -1
- package/dist/core/goals/compact-goal-context.d.ts +1 -1
- package/dist/core/goals/compact-goal-context.d.ts.map +1 -1
- package/dist/core/goals/compact-goal-context.js +2 -1
- package/dist/core/goals/compact-goal-context.js.map +1 -1
- package/dist/core/goals/goal-execution-errors.d.ts +18 -0
- package/dist/core/goals/goal-execution-errors.d.ts.map +1 -0
- package/dist/core/goals/goal-execution-errors.js +21 -0
- package/dist/core/goals/goal-execution-errors.js.map +1 -0
- package/dist/core/goals/goal-lifecycle.d.ts.map +1 -1
- package/dist/core/goals/goal-lifecycle.js +3 -3
- package/dist/core/goals/goal-lifecycle.js.map +1 -1
- package/dist/core/goals/goal-session-controller.d.ts +11 -0
- package/dist/core/goals/goal-session-controller.d.ts.map +1 -1
- package/dist/core/goals/goal-session-controller.js +74 -14
- package/dist/core/goals/goal-session-controller.js.map +1 -1
- package/dist/core/goals/goal-state.js +1 -1
- package/dist/core/goals/goal-state.js.map +1 -1
- package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
- package/dist/core/goals/goal-tool-core.js +2 -2
- package/dist/core/goals/goal-tool-core.js.map +1 -1
- package/dist/core/goals/natural-language-goal.d.ts +18 -0
- package/dist/core/goals/natural-language-goal.d.ts.map +1 -1
- package/dist/core/goals/natural-language-goal.js +99 -16
- package/dist/core/goals/natural-language-goal.js.map +1 -1
- package/dist/core/model-registry.d.ts +5 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +10 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +3 -1
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/orchestration/capability-gateway.d.ts +1 -1
- package/dist/core/orchestration/capability-gateway.d.ts.map +1 -1
- package/dist/core/orchestration/capability-gateway.js +4 -4
- package/dist/core/orchestration/capability-gateway.js.map +1 -1
- package/dist/core/orchestration/event-store.d.ts +8 -0
- package/dist/core/orchestration/event-store.d.ts.map +1 -1
- package/dist/core/orchestration/event-store.js +9 -7
- package/dist/core/orchestration/event-store.js.map +1 -1
- package/dist/core/orchestration/task-runtime-reducer.js +1 -1
- package/dist/core/orchestration/task-runtime-reducer.js.map +1 -1
- package/dist/core/orchestration/worker-model-pins.d.ts +7 -0
- package/dist/core/orchestration/worker-model-pins.d.ts.map +1 -1
- package/dist/core/orchestration/worker-model-pins.js +17 -1
- package/dist/core/orchestration/worker-model-pins.js.map +1 -1
- package/dist/core/provider-request-runtime-controller.d.ts +9 -0
- package/dist/core/provider-request-runtime-controller.d.ts.map +1 -1
- package/dist/core/provider-request-runtime-controller.js +17 -3
- package/dist/core/provider-request-runtime-controller.js.map +1 -1
- package/dist/core/provider-tool-text.d.ts +15 -1
- package/dist/core/provider-tool-text.d.ts.map +1 -1
- package/dist/core/provider-tool-text.js +42 -10
- package/dist/core/provider-tool-text.js.map +1 -1
- package/dist/core/research/research-lane-controller.d.ts +1 -1
- package/dist/core/research/research-lane-controller.d.ts.map +1 -1
- package/dist/core/research/research-lane-controller.js +2 -1
- package/dist/core/research/research-lane-controller.js.map +1 -1
- package/dist/core/resource-loader.d.ts +3 -0
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +8 -0
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/runtime-builder.d.ts +8 -0
- package/dist/core/runtime-builder.d.ts.map +1 -1
- package/dist/core/runtime-builder.js +6 -0
- package/dist/core/runtime-builder.js.map +1 -1
- package/dist/core/session-supervision-runtime.d.ts.map +1 -1
- package/dist/core/session-supervision-runtime.js +2 -1
- package/dist/core/session-supervision-runtime.js.map +1 -1
- package/dist/core/settings-manager.d.ts +2 -2
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +7 -2
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/delegate.d.ts +13 -0
- package/dist/core/tools/delegate.d.ts.map +1 -1
- package/dist/core/tools/delegate.js +20 -18
- package/dist/core/tools/delegate.js.map +1 -1
- package/dist/core/util/atomic-file.d.ts +7 -0
- package/dist/core/util/atomic-file.d.ts.map +1 -1
- package/dist/core/util/atomic-file.js +8 -6
- package/dist/core/util/atomic-file.js.map +1 -1
- package/dist/core/util/faultable-fs.d.ts +30 -0
- package/dist/core/util/faultable-fs.d.ts.map +1 -0
- package/dist/core/util/faultable-fs.js +30 -0
- package/dist/core/util/faultable-fs.js.map +1 -0
- package/dist/modes/interactive/auth-dialogs-controller.d.ts.map +1 -1
- package/dist/modes/interactive/auth-dialogs-controller.js +1 -0
- package/dist/modes/interactive/auth-dialogs-controller.js.map +1 -1
- package/dist/modes/interactive/components/activity-lane.d.ts.map +1 -1
- package/dist/modes/interactive/components/activity-lane.js +4 -3
- package/dist/modes/interactive/components/activity-lane.js.map +1 -1
- package/dist/modes/interactive/components/footer.js +1 -1
- package/dist/modes/interactive/components/footer.js.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.d.ts +2 -0
- package/dist/modes/interactive/components/oauth-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/oauth-selector.js +3 -2
- package/dist/modes/interactive/components/oauth-selector.js.map +1 -1
- package/dist/modes/interactive/report-commands.js +1 -1
- package/dist/modes/interactive/report-commands.js.map +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts +1 -1
- package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
- package/dist/modes/interactive/session-flow-commands.js +3 -2
- package/dist/modes/interactive/session-flow-commands.js.map +1 -1
- package/docs/providers.md +3 -0
- package/docs/settings.md +4 -2
- package/docs/tool-repair.md +1 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +9 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-loop-controller.js","sourceRoot":"","sources":["../../src/core/goal-loop-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AASjE,OAAO,EACN,2BAA2B,EAC3B,qCAAqC,GACrC,MAAM,qCAAqC,CAAC;AAI7C;;;;GAIG;AACH,SAAS,+BAA+B,CAAC,KAA4B;IACpE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAC;IAC1D,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;AAmBD,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,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE;YACnC,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,CAAC;IAC9C,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,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,cAAc,EAAE,CAAC;gBACjB,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC;gBACvF,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,KAAK,EAAE,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,aAAa,EAAE,CAAC,CAAC;YACxF,CAAC;YAED,IAAI,yBAAyB,EAAE,EAAE,CAAC;gBACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,2BAA2B,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,CAAC;YAC/F,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;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. Progress is inferred from real work and\n * terminal goal updates; telemetry never becomes an implicit execution limit.\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 type { GoalRuntimeSnapshot, GoalRuntimeSnapshotSettings } from \"./goals/goal-runtime-snapshot.ts\";\nimport type { GoalState } 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 || state.status !== \"active\") 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<void>;\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: { turns: number; wallClockMs: number }): 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\tawait 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 };\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\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\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, 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({ turns: 1, wallClockMs: now() - passStartedAt });\n\t\t\t}\n\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\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}\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. Progress is inferred from real work and\n * terminal goal updates; telemetry never becomes an implicit execution limit.\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<void>;\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: { turns: number; wallClockMs: number }): 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\tawait 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 };\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\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\tturnsSubmitted++;\n\t\t\t\tthis.deps.recordGoalContinuationPass({ turns: 1, wallClockMs: now() - passStartedAt });\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 reclassifying an\n\t\t\t\t\t// intentional, already-recorded stop as a generic continuation failure and rejecting\n\t\t\t\t\t// the whole loop promise.\n\t\t\t\t\treturn { turnsSubmitted, stopReason: \"goal_budget_exhausted\", finalSnapshot: snapshot() };\n\t\t\t\t}\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({ turns: 1, wallClockMs: now() - passStartedAt });\n\t\t\t}\n\n\t\t\tif (hasReachedWallClockBudget()) {\n\t\t\t\treturn { turnsSubmitted, stopReason: \"wall_clock_budget_reached\", finalSnapshot: snapshot() };\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}\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,5 +1,5 @@
|
|
|
1
1
|
import type { AgentMessage } from "@caupulican/pi-agent-core/types";
|
|
2
|
-
import type
|
|
2
|
+
import { type GoalState } from "./goal-state.ts";
|
|
3
3
|
export declare const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = "active_goal_context";
|
|
4
4
|
export declare function formatCompactGoalContext(state: GoalState, continuationTurn: boolean): string;
|
|
5
5
|
/**
|
|
@@ -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,KAAK,
|
|
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,CAqB5F;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,GAAG,SAAS,GAAG,YAAY,EAAE,CAkB/G"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createCustomMessage } from "@caupulican/pi-agent-core/messages";
|
|
2
2
|
import { GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE } from "./goal-continuation-prompt.js";
|
|
3
3
|
import { projectGoalRecord } from "./goal-record.js";
|
|
4
|
+
import { isGoalExecutionActive } from "./goal-state.js";
|
|
4
5
|
export const ACTIVE_GOAL_CONTEXT_CUSTOM_TYPE = "active_goal_context";
|
|
5
6
|
const LEGACY_GOAL_CONTINUATION_PREFIX = "Goal continuation context\n=========================";
|
|
6
7
|
function messageText(message) {
|
|
@@ -51,7 +52,7 @@ export function injectCompactGoalContext(messages, state) {
|
|
|
51
52
|
const continuationTurn = messages.some((message) => (message.role === "custom" && message.customType === GOAL_CONTINUATION_TRIGGER_CUSTOM_TYPE) ||
|
|
52
53
|
messageText(message).startsWith(LEGACY_GOAL_CONTINUATION_PREFIX));
|
|
53
54
|
const filtered = messages.filter((message) => !isGoalContextMessage(message));
|
|
54
|
-
if (!state || state.status
|
|
55
|
+
if (!state || !isGoalExecutionActive(state.status))
|
|
55
56
|
return filtered;
|
|
56
57
|
return [
|
|
57
58
|
...filtered,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compact-goal-context.js","sourceRoot":"","sources":["../../../src/core/goals/compact-goal-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAGzE,OAAO,EAAE,qCAAqC,EAAE,MAAM,+BAA+B,CAAC;AACtF,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
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 budgetText = record.tokenBudget === undefined ? \"unbounded\" : String(record.tokenBudget);\n\tconst remainingText = record.tokensRemaining === undefined ? \"unbounded\" : String(record.tokensRemaining);\n\tconst instruction = continuationTurn\n\t\t? \"Continue now: inspect authoritative state, make concrete progress toward full objective.\"\n\t\t: \"Goal persists; current user message steers this turn, never replaces objective.\";\n\tconst encodedRecord = JSON.stringify({\n\t\tobjective: record.objective,\n\t\ttokensUsed: record.tokensUsed,\n\t\ttokenBudget: budgetText,\n\t\ttokensRemaining: remainingText,\n\t})\n\t\t.replaceAll(\"<\", \"\\\\u003c\")\n\t\t.replaceAll(\">\", \"\\\\u003e\");\n\treturn [\n\t\t\"ACTIVE GOAL\",\n\t\tencodedRecord,\n\t\tinstruction,\n\t\t\"Use task_steps for decomposition, delegate for workers, tool/artifact results as evidence. Keep active unless completion is proven or same genuine blocker persists 3 goal turns.\",\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"]}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed execution-admission signals, kept in their own module so both the goal session controller
|
|
3
|
+
* (which throws them) and the goal continuation loop (which must recognize them) can import without
|
|
4
|
+
* creating a cycle between `goal-session-controller.ts` and `../goal-loop-controller.ts`.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Thrown by `GoalSessionController#admitProviderRequest` when a goal's token budget is exhausted —
|
|
8
|
+
* either already recorded (`status: "budget_limited"`) or just crossed by this very admission. The
|
|
9
|
+
* durable stop (`markBudgetLimited`) is always applied synchronously BEFORE this is thrown, so by the
|
|
10
|
+
* time a caller observes it the goal state already reflects the clean stop. Callers that own a
|
|
11
|
+
* bounded "keep going until told to stop" contract (the goal continuation loop) must recognize this
|
|
12
|
+
* distinctly from a genuine unexpected failure and report their own clean stop reason instead of
|
|
13
|
+
* reclassifying an intentional, already-recorded stop as a continuation failure.
|
|
14
|
+
*/
|
|
15
|
+
export declare class GoalBudgetExhaustedError extends Error {
|
|
16
|
+
constructor(message: string);
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=goal-execution-errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-execution-errors.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-execution-errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,SAAQ,KAAK;IAClD,YAAY,OAAO,EAAE,MAAM,EAG1B;CACD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed execution-admission signals, kept in their own module so both the goal session controller
|
|
3
|
+
* (which throws them) and the goal continuation loop (which must recognize them) can import without
|
|
4
|
+
* creating a cycle between `goal-session-controller.ts` and `../goal-loop-controller.ts`.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Thrown by `GoalSessionController#admitProviderRequest` when a goal's token budget is exhausted —
|
|
8
|
+
* either already recorded (`status: "budget_limited"`) or just crossed by this very admission. The
|
|
9
|
+
* durable stop (`markBudgetLimited`) is always applied synchronously BEFORE this is thrown, so by the
|
|
10
|
+
* time a caller observes it the goal state already reflects the clean stop. Callers that own a
|
|
11
|
+
* bounded "keep going until told to stop" contract (the goal continuation loop) must recognize this
|
|
12
|
+
* distinctly from a genuine unexpected failure and report their own clean stop reason instead of
|
|
13
|
+
* reclassifying an intentional, already-recorded stop as a continuation failure.
|
|
14
|
+
*/
|
|
15
|
+
export class GoalBudgetExhaustedError extends Error {
|
|
16
|
+
constructor(message) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = "GoalBudgetExhaustedError";
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=goal-execution-errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"goal-execution-errors.js","sourceRoot":"","sources":["../../../src/core/goals/goal-execution-errors.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;;;;GAQG;AACH,MAAM,OAAO,wBAAyB,SAAQ,KAAK;IAClD,YAAY,OAAe;QAC1B,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,0BAA0B,CAAC;IACxC,CAAC;CACD","sourcesContent":["/**\n * Typed execution-admission signals, kept in their own module so both the goal session controller\n * (which throws them) and the goal continuation loop (which must recognize them) can import without\n * creating a cycle between `goal-session-controller.ts` and `../goal-loop-controller.ts`.\n */\n\n/**\n * Thrown by `GoalSessionController#admitProviderRequest` when a goal's token budget is exhausted —\n * either already recorded (`status: \"budget_limited\"`) or just crossed by this very admission. The\n * durable stop (`markBudgetLimited`) is always applied synchronously BEFORE this is thrown, so by the\n * time a caller observes it the goal state already reflects the clean stop. Callers that own a\n * bounded \"keep going until told to stop\" contract (the goal continuation loop) must recognize this\n * distinctly from a genuine unexpected failure and report their own clean stop reason instead of\n * reclassifying an intentional, already-recorded stop as a continuation failure.\n */\nexport class GoalBudgetExhaustedError extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = \"GoalBudgetExhaustedError\";\n\t}\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,SAAS,
|
|
1
|
+
{"version":3,"file":"goal-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"AAAA,OAAO,EAEN,KAAK,SAAS,EAKd,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAmB,KAAK,iBAAiB,EAAE,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAErG,MAAM,WAAW,iBAAiB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CACjB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,SAAS,GAAG,iBAAiB,CAExE;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACtC,oBAAoB,IAAI,SAAS,GAAG,SAAS,CAAC;IAC9C,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC;IAC9E,sBAAsB,CAAC,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/D;AAgBD,wBAAgB,SAAS,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAMvF;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CASxF;AAED,wBAAgB,QAAQ,CACvB,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChD,GAAG,EAAE,MAAM,GACT,gBAAgB,CAiBlB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAMxF;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAC1B,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChE,GAAG,EAAE,MAAM,GACT,gBAAgB,CAElB;AAED,wBAAgB,kBAAkB,CACjC,OAAO,EAAE,SAAS,GAAG,SAAS,EAC9B,IAAI,EAAE;IAAE,MAAM,EAAE,SAAS,GAAG,eAAe,GAAG,gBAAgB,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EAChF,GAAG,EAAE,MAAM,GACT,gBAAgB,CAQlB;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGjH;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGlH;AAED,wBAAgB,iBAAiB,CAChC,IAAI,EAAE,sBAAsB,EAC5B,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,CAAC,EAAE,MAAM,CAAA;CAAE,EAChD,GAAG,SAA2B,GAC5B,gBAAgB,CAGlB;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,sBAAsB,EAAE,GAAG,SAA2B,GAAG,gBAAgB,CAGlH;AAED,MAAM,MAAM,wBAAwB,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,GAAG,iBAAiB,CAAC;AAE1F,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,sBAAsB,EAC5B,GAAG,SAA2B,GAC5B,wBAAwB,CAM1B"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyGoalEvent, isGoalResumableStatus, isGoalUnfinishedStatus, MAX_GOAL_OBJECTIVE_LENGTH, } from "./goal-state.js";
|
|
1
|
+
import { applyGoalEvent, isGoalExecutionActive, isGoalResumableStatus, isGoalUnfinishedStatus, MAX_GOAL_OBJECTIVE_LENGTH, } from "./goal-state.js";
|
|
2
2
|
import { applyGoalAction } from "./goal-tool-core.js";
|
|
3
3
|
export function getGoalStateRevision(state) {
|
|
4
4
|
return { goalId: state.goalId, revision: state.revision ?? 0 };
|
|
@@ -15,7 +15,7 @@ function persistResult(host, current, result) {
|
|
|
15
15
|
export function pauseGoal(current, now) {
|
|
16
16
|
if (!current)
|
|
17
17
|
return missingGoal("pause");
|
|
18
|
-
if (current.status
|
|
18
|
+
if (!isGoalExecutionActive(current.status)) {
|
|
19
19
|
return { ok: false, error: `Goal '${current.goalId}' is ${current.status}; only active goals can be paused.` };
|
|
20
20
|
}
|
|
21
21
|
return { ok: true, state: applyGoalEvent(current, { type: "pause_goal", now }) };
|
|
@@ -66,7 +66,7 @@ export function replaceGoal(args, now) {
|
|
|
66
66
|
export function stopGoalFromSystem(current, args, now) {
|
|
67
67
|
if (!current)
|
|
68
68
|
return missingGoal("stop");
|
|
69
|
-
if (current.status
|
|
69
|
+
if (!isGoalExecutionActive(current.status)) {
|
|
70
70
|
return { ok: false, error: `Goal '${current.goalId}' is ${current.status}; no system stop is needed.` };
|
|
71
71
|
}
|
|
72
72
|
const reason = args.reason.trim();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-lifecycle.js","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tapplyGoalEvent,\n\ttype GoalState,\n\tisGoalResumableStatus,\n\tisGoalUnfinishedStatus,\n\tMAX_GOAL_OBJECTIVE_LENGTH,\n} from \"./goal-state.ts\";\nimport { applyGoalAction, type GoalActionFailure, type GoalActionResult } from \"./goal-tool-core.ts\";\n\nexport interface GoalStateRevision {\n\tgoalId: string;\n\trevision: number;\n}\n\nexport function getGoalStateRevision(state: GoalState): GoalStateRevision {\n\treturn { goalId: state.goalId, revision: state.revision ?? 0 };\n}\n\n/** Minimal durable seam shared by CLI, tools, and in-process session restoration. */\nexport interface PersistedGoalStateHost {\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tsaveGoalStateSnapshot(state: GoalState, expected?: GoalStateRevision): string;\n\tclearGoalStateSnapshot?(state: GoalState, now: string): string;\n}\n\nfunction missingGoal(action: string): GoalActionFailure {\n\treturn { ok: false, error: `No goal exists to ${action}.` };\n}\n\nfunction persistResult(\n\thost: PersistedGoalStateHost,\n\tcurrent: GoalState | undefined,\n\tresult: GoalActionResult,\n): GoalActionResult {\n\tif (!result.ok) return result;\n\thost.saveGoalStateSnapshot(result.state, current ? getGoalStateRevision(current) : undefined);\n\treturn result;\n}\n\nexport function pauseGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"pause\");\n\tif (current.status !== \"active\") {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; only active goals can be paused.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"pause_goal\", now }) };\n}\n\nexport function resumeGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"resume\");\n\tif (!isGoalResumableStatus(current.status)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `Goal '${current.goalId}' is ${current.status}; only paused, blocked, or usage-limited goals can be resumed.`,\n\t\t};\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"resume_goal\", now }) };\n}\n\nexport function editGoal(\n\tcurrent: GoalState | undefined,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"edit\");\n\tif (current.status === \"cancelled\") {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is cancelled; start a new goal instead.` };\n\t}\n\tconst userGoal = args.userGoal.trim();\n\tif (!userGoal) return { ok: false, error: \"Goal objective must not be empty.\" };\n\tif (userGoal.length > MAX_GOAL_OBJECTIVE_LENGTH) {\n\t\treturn { ok: false, error: `Goal objective must be at most ${MAX_GOAL_OBJECTIVE_LENGTH} characters.` };\n\t}\n\tif (args.tokenBudget !== undefined && (!Number.isSafeInteger(args.tokenBudget) || args.tokenBudget <= 0)) {\n\t\treturn { ok: false, error: \"Goal token budget must be a positive integer when provided.\" };\n\t}\n\treturn {\n\t\tok: true,\n\t\tstate: applyGoalEvent(current, { type: \"edit_goal\", userGoal, tokenBudget: args.tokenBudget, now }),\n\t};\n}\n\nexport function cancelGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"cancel\");\n\tif (!isGoalUnfinishedStatus(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is already ${current.status}.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"cancel_goal\", now }) };\n}\n\n/** Explicit owner replacement. The old and new states cross one persistence boundary. */\nexport function replaceGoal(\n\targs: { goalId: string; userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\treturn applyGoalAction(undefined, { action: \"start\", ...args }, now);\n}\n\nexport function stopGoalFromSystem(\n\tcurrent: GoalState | undefined,\n\targs: { status: \"blocked\" | \"usage_limited\" | \"budget_limited\"; reason: string },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"stop\");\n\tif (current.status !== \"active\") {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; no system stop is needed.` };\n\t}\n\tconst reason = args.reason.trim();\n\tif (!reason) return { ok: false, error: \"System goal stop requires a reason.\" };\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"system_stop_goal\", ...args, reason, now }) };\n}\n\nexport function pausePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, pauseGoal(current, now));\n}\n\nexport function resumePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, resumeGoal(current, now));\n}\n\nexport function editPersistedGoal(\n\thost: PersistedGoalStateHost,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow = new Date().toISOString(),\n): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, editGoal(current, args, now));\n}\n\nexport function cancelPersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, cancelGoal(current, now));\n}\n\nexport type ClearPersistedGoalResult = { ok: true; cleared: boolean } | GoalActionFailure;\n\nexport function clearPersistedGoal(\n\thost: PersistedGoalStateHost,\n\tnow = new Date().toISOString(),\n): ClearPersistedGoalResult {\n\tconst current = host.getGoalStateSnapshot();\n\tif (!current) return { ok: true, cleared: false };\n\tif (!host.clearGoalStateSnapshot) return { ok: false, error: \"This session does not support clearing goals.\" };\n\thost.clearGoalStateSnapshot(current, now);\n\treturn { ok: true, cleared: true };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"goal-lifecycle.js","sourceRoot":"","sources":["../../../src/core/goals/goal-lifecycle.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\tapplyGoalEvent,\n\ttype GoalState,\n\tisGoalExecutionActive,\n\tisGoalResumableStatus,\n\tisGoalUnfinishedStatus,\n\tMAX_GOAL_OBJECTIVE_LENGTH,\n} from \"./goal-state.ts\";\nimport { applyGoalAction, type GoalActionFailure, type GoalActionResult } from \"./goal-tool-core.ts\";\n\nexport interface GoalStateRevision {\n\tgoalId: string;\n\trevision: number;\n}\n\nexport function getGoalStateRevision(state: GoalState): GoalStateRevision {\n\treturn { goalId: state.goalId, revision: state.revision ?? 0 };\n}\n\n/** Minimal durable seam shared by CLI, tools, and in-process session restoration. */\nexport interface PersistedGoalStateHost {\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tsaveGoalStateSnapshot(state: GoalState, expected?: GoalStateRevision): string;\n\tclearGoalStateSnapshot?(state: GoalState, now: string): string;\n}\n\nfunction missingGoal(action: string): GoalActionFailure {\n\treturn { ok: false, error: `No goal exists to ${action}.` };\n}\n\nfunction persistResult(\n\thost: PersistedGoalStateHost,\n\tcurrent: GoalState | undefined,\n\tresult: GoalActionResult,\n): GoalActionResult {\n\tif (!result.ok) return result;\n\thost.saveGoalStateSnapshot(result.state, current ? getGoalStateRevision(current) : undefined);\n\treturn result;\n}\n\nexport function pauseGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"pause\");\n\tif (!isGoalExecutionActive(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; only active goals can be paused.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"pause_goal\", now }) };\n}\n\nexport function resumeGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"resume\");\n\tif (!isGoalResumableStatus(current.status)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `Goal '${current.goalId}' is ${current.status}; only paused, blocked, or usage-limited goals can be resumed.`,\n\t\t};\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"resume_goal\", now }) };\n}\n\nexport function editGoal(\n\tcurrent: GoalState | undefined,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"edit\");\n\tif (current.status === \"cancelled\") {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is cancelled; start a new goal instead.` };\n\t}\n\tconst userGoal = args.userGoal.trim();\n\tif (!userGoal) return { ok: false, error: \"Goal objective must not be empty.\" };\n\tif (userGoal.length > MAX_GOAL_OBJECTIVE_LENGTH) {\n\t\treturn { ok: false, error: `Goal objective must be at most ${MAX_GOAL_OBJECTIVE_LENGTH} characters.` };\n\t}\n\tif (args.tokenBudget !== undefined && (!Number.isSafeInteger(args.tokenBudget) || args.tokenBudget <= 0)) {\n\t\treturn { ok: false, error: \"Goal token budget must be a positive integer when provided.\" };\n\t}\n\treturn {\n\t\tok: true,\n\t\tstate: applyGoalEvent(current, { type: \"edit_goal\", userGoal, tokenBudget: args.tokenBudget, now }),\n\t};\n}\n\nexport function cancelGoal(current: GoalState | undefined, now: string): GoalActionResult {\n\tif (!current) return missingGoal(\"cancel\");\n\tif (!isGoalUnfinishedStatus(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is already ${current.status}.` };\n\t}\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"cancel_goal\", now }) };\n}\n\n/** Explicit owner replacement. The old and new states cross one persistence boundary. */\nexport function replaceGoal(\n\targs: { goalId: string; userGoal: string; tokenBudget?: number },\n\tnow: string,\n): GoalActionResult {\n\treturn applyGoalAction(undefined, { action: \"start\", ...args }, now);\n}\n\nexport function stopGoalFromSystem(\n\tcurrent: GoalState | undefined,\n\targs: { status: \"blocked\" | \"usage_limited\" | \"budget_limited\"; reason: string },\n\tnow: string,\n): GoalActionResult {\n\tif (!current) return missingGoal(\"stop\");\n\tif (!isGoalExecutionActive(current.status)) {\n\t\treturn { ok: false, error: `Goal '${current.goalId}' is ${current.status}; no system stop is needed.` };\n\t}\n\tconst reason = args.reason.trim();\n\tif (!reason) return { ok: false, error: \"System goal stop requires a reason.\" };\n\treturn { ok: true, state: applyGoalEvent(current, { type: \"system_stop_goal\", ...args, reason, now }) };\n}\n\nexport function pausePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, pauseGoal(current, now));\n}\n\nexport function resumePersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, resumeGoal(current, now));\n}\n\nexport function editPersistedGoal(\n\thost: PersistedGoalStateHost,\n\targs: { userGoal: string; tokenBudget?: number },\n\tnow = new Date().toISOString(),\n): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, editGoal(current, args, now));\n}\n\nexport function cancelPersistedGoal(host: PersistedGoalStateHost, now = new Date().toISOString()): GoalActionResult {\n\tconst current = host.getGoalStateSnapshot();\n\treturn persistResult(host, current, cancelGoal(current, now));\n}\n\nexport type ClearPersistedGoalResult = { ok: true; cleared: boolean } | GoalActionFailure;\n\nexport function clearPersistedGoal(\n\thost: PersistedGoalStateHost,\n\tnow = new Date().toISOString(),\n): ClearPersistedGoalResult {\n\tconst current = host.getGoalStateSnapshot();\n\tif (!current) return { ok: true, cleared: false };\n\tif (!host.clearGoalStateSnapshot) return { ok: false, error: \"This session does not support clearing goals.\" };\n\thost.clearGoalStateSnapshot(current, now);\n\treturn { ok: true, cleared: true };\n}\n"]}
|
|
@@ -70,6 +70,17 @@ export declare class GoalSessionController {
|
|
|
70
70
|
authorizeStartFromTool(input: {
|
|
71
71
|
tokenBudget?: number;
|
|
72
72
|
}): string | undefined;
|
|
73
|
+
/**
|
|
74
|
+
* True once the currently held execution lease's goal has crossed into `budget_limited` — set
|
|
75
|
+
* synchronously by `chargeExecutionUsage` as soon as a just-charged response crosses the ceiling.
|
|
76
|
+
* Wired to the agent's `shouldStopAfterTurn` hook so a mid-turn budget stop ends the loop
|
|
77
|
+
* gracefully BEFORE the next provider request is even planned, instead of only being caught by
|
|
78
|
+
* `admitProviderRequest`'s throw — which still exists as the backstop for a fresh turn or an
|
|
79
|
+
* external admission starting against an already budget_limited goal, but would otherwise also
|
|
80
|
+
* fire for a request this same lease was already mid-flight for, surfacing a synthetic error
|
|
81
|
+
* message where a clean turn end belongs.
|
|
82
|
+
*/
|
|
83
|
+
hasExecutionLeaseCrossedBudgetLimit(): boolean;
|
|
73
84
|
/** Reserve only remaining output capacity; actual provider usage is charged on response. */
|
|
74
85
|
admitProviderRequest(): number | undefined;
|
|
75
86
|
private resolveExecutionState;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"goal-session-controller.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-session-controller.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mCAAmC,CAAC;AACxE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,OAAO,KAAK,EACX,2BAA2B,EAC3B,0BAA0B,EAC1B,2BAA2B,EAC3B,0BAA0B,EAC1B,aAAa,EACb,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAC;AAG9D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,kCAAkC,CAAC;
|
|
1
|
+
{"version":3,"file":"goal-session-controller.d.ts","sourceRoot":"","sources":["../../../src/core/goals/goal-session-controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,12 +2,25 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
import { classifyFailure } from "@caupulican/pi-agent-core/reliability";
|
|
3
3
|
import { GoalLoopController } from "../goal-loop-controller.js";
|
|
4
4
|
import { budgetedTokens } from "../orchestration/capability-gateway.js";
|
|
5
|
+
import { GoalBudgetExhaustedError } from "./goal-execution-errors.js";
|
|
5
6
|
import { getGoalStateRevision, stopGoalFromSystem } from "./goal-lifecycle.js";
|
|
6
7
|
import { buildGoalRuntimeSnapshot, } from "./goal-runtime-snapshot.js";
|
|
7
|
-
import { applyGoalEvent, isGoalUnfinishedStatus } from "./goal-state.js";
|
|
8
|
+
import { applyGoalEvent, isGoalExecutionActive, isGoalUnfinishedStatus } from "./goal-state.js";
|
|
8
9
|
import { applyGoalAction } from "./goal-tool-core.js";
|
|
9
10
|
import { parseExplicitChatGoal } from "./natural-language-goal.js";
|
|
10
11
|
import { appendGoalClearedSnapshot, appendGoalStateSnapshot, getLatestGoalStateSnapshot, } from "./session-goal-state.js";
|
|
12
|
+
/**
|
|
13
|
+
* Smallest remaining goal budget worth handing to the provider as one more request's OUTPUT cap.
|
|
14
|
+
* `admitProviderRequest` returns the goal's remaining TOTAL budget (input+output, cache-weighted) as
|
|
15
|
+
* that cap — correct only because it also narrows further downstream against the model's real output
|
|
16
|
+
* limit. When remaining drops below this floor (e.g. 200k budget, 199.4k used → 600 remaining), handing
|
|
17
|
+
* 600 to the provider as maxTokens produces a request that pays the FULL input cost of the turn only to
|
|
18
|
+
* get cut off mid-generation (`stopReason: "length"`) — a doomed, wasted turn. Below the floor, stop
|
|
19
|
+
* the goal cleanly BEFORE sending instead of gambling on a truncated one. Above it, the remaining-total
|
|
20
|
+
* value is a generous (imprecise but safe) protective ceiling — a modest final-turn overrun is
|
|
21
|
+
* acceptable; a truncated turn is not.
|
|
22
|
+
*/
|
|
23
|
+
const MIN_VIABLE_GOAL_TURN_OUTPUT_TOKENS = 1_000;
|
|
11
24
|
const goalExecutionLeaseMarker = Symbol("goalExecutionLease");
|
|
12
25
|
/**
|
|
13
26
|
* Owns durable goal state, exact continuation accounting, and the raw continuation loop. The
|
|
@@ -103,7 +116,7 @@ export class GoalSessionController {
|
|
|
103
116
|
if (this.executionLease)
|
|
104
117
|
throw new Error("Goal execution attribution is already active");
|
|
105
118
|
const state = this.getState();
|
|
106
|
-
if (goalId && (!state || state.goalId !== goalId || state.status
|
|
119
|
+
if (goalId && (!state || state.goalId !== goalId || !isGoalExecutionActive(state.status)))
|
|
107
120
|
return undefined;
|
|
108
121
|
const lease = {
|
|
109
122
|
...(goalId ? { goalId } : {}),
|
|
@@ -115,6 +128,7 @@ export class GoalSessionController {
|
|
|
115
128
|
: {}),
|
|
116
129
|
pendingTokens: 0,
|
|
117
130
|
pendingSpendUsd: 0,
|
|
131
|
+
admittedWhileActive: false,
|
|
118
132
|
};
|
|
119
133
|
this.executionLease = lease;
|
|
120
134
|
return lease;
|
|
@@ -162,7 +176,7 @@ export class GoalSessionController {
|
|
|
162
176
|
this.saveState(updated, getGoalStateRevision(state));
|
|
163
177
|
lease.pendingTokens = 0;
|
|
164
178
|
lease.pendingSpendUsd = 0;
|
|
165
|
-
if (updated.status
|
|
179
|
+
if (isGoalExecutionActive(updated.status) &&
|
|
166
180
|
updated.tokenBudget !== undefined &&
|
|
167
181
|
(updated.tokensUsed ?? 0) >= updated.tokenBudget) {
|
|
168
182
|
this.markBudgetLimited(`token budget exhausted (${updated.tokensUsed ?? 0}/${updated.tokenBudget}) during goal execution`);
|
|
@@ -173,7 +187,7 @@ export class GoalSessionController {
|
|
|
173
187
|
if (!lease)
|
|
174
188
|
return false;
|
|
175
189
|
const state = this.resolveExecutionState(lease);
|
|
176
|
-
if (!state || state.status
|
|
190
|
+
if (!state || !isGoalExecutionActive(state.status))
|
|
177
191
|
return false;
|
|
178
192
|
const stopped = stopGoalFromSystem(state, { status: "blocked", reason: errorMessage.slice(0, 500) }, new Date().toISOString());
|
|
179
193
|
if (!stopped.ok)
|
|
@@ -196,6 +210,22 @@ export class GoalSessionController {
|
|
|
196
210
|
}
|
|
197
211
|
return undefined;
|
|
198
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* True once the currently held execution lease's goal has crossed into `budget_limited` — set
|
|
215
|
+
* synchronously by `chargeExecutionUsage` as soon as a just-charged response crosses the ceiling.
|
|
216
|
+
* Wired to the agent's `shouldStopAfterTurn` hook so a mid-turn budget stop ends the loop
|
|
217
|
+
* gracefully BEFORE the next provider request is even planned, instead of only being caught by
|
|
218
|
+
* `admitProviderRequest`'s throw — which still exists as the backstop for a fresh turn or an
|
|
219
|
+
* external admission starting against an already budget_limited goal, but would otherwise also
|
|
220
|
+
* fire for a request this same lease was already mid-flight for, surfacing a synthetic error
|
|
221
|
+
* message where a clean turn end belongs.
|
|
222
|
+
*/
|
|
223
|
+
hasExecutionLeaseCrossedBudgetLimit() {
|
|
224
|
+
const lease = this.executionLease;
|
|
225
|
+
if (!lease)
|
|
226
|
+
return false;
|
|
227
|
+
return this.resolveExecutionState(lease)?.status === "budget_limited";
|
|
228
|
+
}
|
|
199
229
|
/** Reserve only remaining output capacity; actual provider usage is charged on response. */
|
|
200
230
|
admitProviderRequest() {
|
|
201
231
|
const lease = this.executionLease;
|
|
@@ -203,21 +233,39 @@ export class GoalSessionController {
|
|
|
203
233
|
return undefined;
|
|
204
234
|
this.flushPendingExecutionUsage(lease);
|
|
205
235
|
const state = this.resolveExecutionState(lease);
|
|
206
|
-
const tokenBudget = state?.tokenBudget ?? lease.provisionalTokenBudget;
|
|
207
|
-
if (tokenBudget === undefined)
|
|
208
|
-
return undefined;
|
|
209
236
|
if (state?.status === "budget_limited") {
|
|
210
|
-
throw new
|
|
237
|
+
throw new GoalBudgetExhaustedError(`goal_token_budget_exhausted: ${state.blockedReason ?? lease.goalId}`);
|
|
211
238
|
}
|
|
212
|
-
if (state && state.status
|
|
239
|
+
if (state && !isGoalExecutionActive(state.status)) {
|
|
240
|
+
if (!lease.admittedWhileActive) {
|
|
241
|
+
// A fresh turn/continuation is being started against a goal that is already done —
|
|
242
|
+
// keep this denied so a dead goal cannot restart itself.
|
|
243
|
+
throw new Error(`goal_execution_not_active: ${state.goalId} is ${state.status}`);
|
|
244
|
+
}
|
|
245
|
+
// This lease already admitted at least one request while the goal was active, so the
|
|
246
|
+
// goal ended mid-turn (e.g. the model itself just called `goal complete`/`block`). Let
|
|
247
|
+
// the already-in-flight turn drain to its closing response instead of throwing an error
|
|
248
|
+
// at the user right after a successful stop.
|
|
249
|
+
return undefined;
|
|
250
|
+
}
|
|
251
|
+
if (!state && lease.goalId !== undefined) {
|
|
252
|
+
throw new Error(`goal_execution_not_active: ${lease.goalId} no longer exists`);
|
|
253
|
+
}
|
|
254
|
+
lease.admittedWhileActive = true;
|
|
255
|
+
const tokenBudget = state?.tokenBudget ?? lease.provisionalTokenBudget;
|
|
256
|
+
if (tokenBudget === undefined)
|
|
213
257
|
return undefined;
|
|
214
258
|
const tokensUsed = state?.tokensUsed ?? lease.pendingTokens;
|
|
215
259
|
const remaining = Math.max(0, tokenBudget - tokensUsed);
|
|
216
|
-
if (remaining
|
|
260
|
+
if (remaining < MIN_VIABLE_GOAL_TURN_OUTPUT_TOKENS) {
|
|
261
|
+
// Below the floor, remaining is too small to hand to the provider as an output cap without
|
|
262
|
+
// dooming the turn to a mid-generation truncation that still burns the full input cost.
|
|
263
|
+
// Stop cleanly now instead of sending a request that cannot possibly complete.
|
|
217
264
|
if (state) {
|
|
218
|
-
this.markBudgetLimited(`token budget exhausted (${tokensUsed}/${tokenBudget}
|
|
265
|
+
this.markBudgetLimited(`token budget nearly exhausted (${tokensUsed}/${tokenBudget}, ${remaining} remaining is below the ` +
|
|
266
|
+
`${MIN_VIABLE_GOAL_TURN_OUTPUT_TOKENS}-token minimum viable turn) before provider request`);
|
|
219
267
|
}
|
|
220
|
-
throw new
|
|
268
|
+
throw new GoalBudgetExhaustedError(`goal_token_budget_exhausted: ${remaining} tokens remain, below the ${MIN_VIABLE_GOAL_TURN_OUTPUT_TOKENS}-token minimum viable turn`);
|
|
221
269
|
}
|
|
222
270
|
return remaining;
|
|
223
271
|
}
|
|
@@ -238,8 +286,20 @@ export class GoalSessionController {
|
|
|
238
286
|
if (lease.pendingTokens === 0 && lease.pendingSpendUsd === 0)
|
|
239
287
|
return;
|
|
240
288
|
const state = this.resolveExecutionState(lease);
|
|
241
|
-
if (!state)
|
|
289
|
+
if (!state) {
|
|
290
|
+
// A speculative adopt-new-goal lease (lease.goalId still undefined) that never actually
|
|
291
|
+
// adopted a goal this turn has nowhere to attribute usage — that is normal, not a loss.
|
|
292
|
+
// A lease that WAS bound to a real goal but can no longer resolve it is a genuine loss of
|
|
293
|
+
// buffered spend; fail loudly instead of silently discarding it (matches the cursor-based
|
|
294
|
+
// accounting this replaced, which stopped the goal on `goal_usage_cursor_lost`).
|
|
295
|
+
if (lease.goalId !== undefined) {
|
|
296
|
+
this.deps.emitWarning(`Goal usage cursor is no longer resolvable for '${lease.goalId}'; ${lease.pendingTokens} pending tokens and $${lease.pendingSpendUsd.toFixed(6)} pending spend could not be attributed and were dropped.`);
|
|
297
|
+
this.recordContinuationFailure(new Error("goal_usage_cursor_lost"));
|
|
298
|
+
}
|
|
299
|
+
lease.pendingTokens = 0;
|
|
300
|
+
lease.pendingSpendUsd = 0;
|
|
242
301
|
return;
|
|
302
|
+
}
|
|
243
303
|
this.chargeExecutionUsage(lease, state, lease.pendingTokens, lease.pendingSpendUsd);
|
|
244
304
|
}
|
|
245
305
|
markToolUnavailable() {
|
|
@@ -270,7 +330,7 @@ export class GoalSessionController {
|
|
|
270
330
|
}
|
|
271
331
|
recordContinuationFailure(error) {
|
|
272
332
|
const state = this.getState();
|
|
273
|
-
if (!state || state.status
|
|
333
|
+
if (!state || !isGoalExecutionActive(state.status))
|
|
274
334
|
return;
|
|
275
335
|
const message = error instanceof Error ? error.message : String(error);
|
|
276
336
|
const classified = classifyFailure({ message, provider: this.deps.getModelProvider() });
|