@namzu/sdk 51.1.0 → 52.1.0
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 +119 -0
- package/dist/agents/QueryAgent.d.ts.map +1 -1
- package/dist/agents/QueryAgent.js +2 -0
- package/dist/agents/QueryAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/agents/examples/SupervisorAgent.d.ts +42 -0
- package/dist/agents/examples/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/examples/SupervisorAgent.js +80 -4
- package/dist/agents/examples/SupervisorAgent.js.map +1 -1
- package/dist/agents/index.d.ts +1 -1
- package/dist/agents/index.d.ts.map +1 -1
- package/dist/agents/index.js.map +1 -1
- package/dist/authorization/protected-paths.d.ts +36 -0
- package/dist/authorization/protected-paths.d.ts.map +1 -0
- package/dist/authorization/protected-paths.js +107 -0
- package/dist/authorization/protected-paths.js.map +1 -0
- package/dist/authorization/readonly-commands.d.ts +39 -0
- package/dist/authorization/readonly-commands.d.ts.map +1 -0
- package/dist/authorization/readonly-commands.js +797 -0
- package/dist/authorization/readonly-commands.js.map +1 -0
- package/dist/authorization/readonly-flags.d.ts +19 -0
- package/dist/authorization/readonly-flags.d.ts.map +1 -0
- package/dist/authorization/readonly-flags.js +178 -0
- package/dist/authorization/readonly-flags.js.map +1 -0
- package/dist/authorization/removal.d.ts +52 -0
- package/dist/authorization/removal.d.ts.map +1 -0
- package/dist/authorization/removal.js +283 -0
- package/dist/authorization/removal.js.map +1 -0
- package/dist/authorization/shell-paths.d.ts +66 -0
- package/dist/authorization/shell-paths.d.ts.map +1 -0
- package/dist/authorization/shell-paths.js +697 -0
- package/dist/authorization/shell-paths.js.map +1 -0
- package/dist/bridge/acp/update.d.ts.map +1 -1
- package/dist/bridge/acp/update.js +1 -0
- package/dist/bridge/acp/update.js.map +1 -1
- package/dist/compaction/context-window.d.ts +24 -0
- package/dist/compaction/context-window.d.ts.map +1 -1
- package/dist/compaction/context-window.js +34 -0
- package/dist/compaction/context-window.js.map +1 -1
- package/dist/compaction/manual.d.ts.map +1 -1
- package/dist/compaction/manual.js +10 -2
- package/dist/compaction/manual.js.map +1 -1
- package/dist/compaction/plan.d.ts +4 -0
- package/dist/compaction/plan.d.ts.map +1 -1
- package/dist/compaction/plan.js +6 -2
- package/dist/compaction/plan.js.map +1 -1
- package/dist/compaction/verifier.d.ts +11 -1
- package/dist/compaction/verifier.d.ts.map +1 -1
- package/dist/compaction/verifier.js +75 -23
- package/dist/compaction/verifier.js.map +1 -1
- package/dist/config/runtime.d.ts +55 -7
- package/dist/config/runtime.d.ts.map +1 -1
- package/dist/config/runtime.js +23 -2
- package/dist/config/runtime.js.map +1 -1
- package/dist/connector/web/guarded-fetch.d.ts.map +1 -1
- package/dist/connector/web/guarded-fetch.js +24 -0
- package/dist/connector/web/guarded-fetch.js.map +1 -1
- package/dist/connector/web/index.d.ts +1 -1
- package/dist/connector/web/index.d.ts.map +1 -1
- package/dist/connector/web/page.d.ts +59 -0
- package/dist/connector/web/page.d.ts.map +1 -0
- package/dist/connector/web/page.js +112 -0
- package/dist/connector/web/page.js.map +1 -0
- package/dist/connector/web/types.d.ts +47 -0
- package/dist/connector/web/types.d.ts.map +1 -1
- package/dist/connector/web/types.js.map +1 -1
- package/dist/constants/continuation.d.ts +8 -0
- package/dist/constants/continuation.d.ts.map +1 -1
- package/dist/constants/continuation.js +8 -0
- package/dist/constants/continuation.js.map +1 -1
- package/dist/constants/plugin/index.d.ts +1 -1
- package/dist/constants/plugin/index.d.ts.map +1 -1
- package/dist/constants/plugin/index.js +1 -1
- package/dist/constants/plugin/index.js.map +1 -1
- package/dist/contracts/a2a.d.ts +2 -2
- package/dist/manager/agent/lifecycle.d.ts +7 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +11 -2
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/session/turn-recorder.d.ts.map +1 -1
- package/dist/manager/session/turn-recorder.js +4 -2
- package/dist/manager/session/turn-recorder.js.map +1 -1
- package/dist/plugin/index.d.ts +1 -1
- package/dist/plugin/index.d.ts.map +1 -1
- package/dist/plugin/index.js +1 -1
- package/dist/plugin/index.js.map +1 -1
- package/dist/plugin/lifecycle.d.ts +6 -0
- package/dist/plugin/lifecycle.d.ts.map +1 -1
- package/dist/plugin/lifecycle.js +98 -114
- package/dist/plugin/lifecycle.js.map +1 -1
- package/dist/plugin/shell-hook.d.ts +90 -22
- package/dist/plugin/shell-hook.d.ts.map +1 -1
- package/dist/plugin/shell-hook.js +434 -41
- package/dist/plugin/shell-hook.js.map +1 -1
- package/dist/provider/capabilities.d.ts +9 -0
- package/dist/provider/capabilities.d.ts.map +1 -1
- package/dist/provider/capabilities.js +15 -0
- package/dist/provider/capabilities.js.map +1 -1
- package/dist/provider/errors.d.ts.map +1 -1
- package/dist/provider/errors.js +13 -0
- package/dist/provider/errors.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +10 -0
- package/dist/provider/fallback.js.map +1 -1
- package/dist/provider/idle-timeout.d.ts.map +1 -1
- package/dist/provider/idle-timeout.js +5 -0
- package/dist/provider/idle-timeout.js.map +1 -1
- package/dist/provider/image-input-refusal.d.ts +9 -0
- package/dist/provider/image-input-refusal.d.ts.map +1 -0
- package/dist/provider/image-input-refusal.js +54 -0
- package/dist/provider/image-input-refusal.js.map +1 -0
- package/dist/provider/index.d.ts +2 -1
- package/dist/provider/index.d.ts.map +1 -1
- package/dist/provider/index.js +2 -1
- package/dist/provider/index.js.map +1 -1
- package/dist/provider/retry.d.ts +7 -2
- package/dist/provider/retry.d.ts.map +1 -1
- package/dist/provider/retry.js +38 -4
- package/dist/provider/retry.js.map +1 -1
- package/dist/public-runtime.d.ts +5 -2
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +5 -2
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +2 -2
- package/dist/public-types.d.ts.map +1 -1
- package/dist/runtime/jobs/registry.d.ts +21 -0
- package/dist/runtime/jobs/registry.d.ts.map +1 -1
- package/dist/runtime/jobs/registry.js +15 -2
- package/dist/runtime/jobs/registry.js.map +1 -1
- package/dist/runtime/query/deferred-sandbox.d.ts +54 -0
- package/dist/runtime/query/deferred-sandbox.d.ts.map +1 -0
- package/dist/runtime/query/deferred-sandbox.js +75 -0
- package/dist/runtime/query/deferred-sandbox.js.map +1 -0
- package/dist/runtime/query/executor/tool-call-admission.d.ts +10 -0
- package/dist/runtime/query/executor/tool-call-admission.d.ts.map +1 -1
- package/dist/runtime/query/executor/tool-call-admission.js +74 -13
- package/dist/runtime/query/executor/tool-call-admission.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +51 -2
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +214 -9
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/finalize-turn.d.ts +6 -0
- package/dist/runtime/query/finalize-turn.d.ts.map +1 -1
- package/dist/runtime/query/finalize-turn.js +1 -1
- package/dist/runtime/query/finalize-turn.js.map +1 -1
- package/dist/runtime/query/index.d.ts +29 -0
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +108 -28
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +57 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +380 -28
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts +61 -0
- package/dist/runtime/query/iteration/phases/compaction-breaker.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/compaction-breaker.js +94 -0
- package/dist/runtime/query/iteration/phases/compaction-breaker.js.map +1 -0
- package/dist/runtime/query/iteration/phases/compaction.d.ts +42 -1
- package/dist/runtime/query/iteration/phases/compaction.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/compaction.js +203 -23
- package/dist/runtime/query/iteration/phases/compaction.js.map +1 -1
- package/dist/runtime/query/iteration/phases/context.d.ts +10 -0
- package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/context.js.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/tool-review.js +165 -2
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts +21 -1
- package/dist/runtime/query/iteration/provider-rejected-image.d.ts.map +1 -1
- package/dist/runtime/query/iteration/provider-rejected-image.js +53 -7
- package/dist/runtime/query/iteration/provider-rejected-image.js.map +1 -1
- package/dist/runtime/query/iteration/request-repair.d.ts +108 -0
- package/dist/runtime/query/iteration/request-repair.d.ts.map +1 -0
- package/dist/runtime/query/iteration/request-repair.js +593 -0
- package/dist/runtime/query/iteration/request-repair.js.map +1 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts +6 -0
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +2 -2
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/path-escalation.d.ts +36 -0
- package/dist/runtime/query/path-escalation.d.ts.map +1 -0
- package/dist/runtime/query/path-escalation.js +184 -0
- package/dist/runtime/query/path-escalation.js.map +1 -0
- package/dist/runtime/query/plugin-hooks.d.ts.map +1 -1
- package/dist/runtime/query/plugin-hooks.js +8 -0
- package/dist/runtime/query/plugin-hooks.js.map +1 -1
- package/dist/runtime/query/reminders.d.ts +35 -0
- package/dist/runtime/query/reminders.d.ts.map +1 -0
- package/dist/runtime/query/reminders.js +7 -0
- package/dist/runtime/query/reminders.js.map +1 -0
- package/dist/runtime/query/request-rich-content.d.ts +5 -1
- package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
- package/dist/runtime/query/request-rich-content.js +67 -25
- package/dist/runtime/query/request-rich-content.js.map +1 -1
- package/dist/runtime/query/resume-pending.d.ts.map +1 -1
- package/dist/runtime/query/resume-pending.js +26 -0
- package/dist/runtime/query/resume-pending.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +26 -0
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +79 -5
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/runtime/query/tool-output-budget.d.ts +46 -0
- package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
- package/dist/runtime/query/tool-output-budget.js +85 -1
- package/dist/runtime/query/tool-output-budget.js.map +1 -1
- package/dist/runtime/query/tooling.d.ts +1 -0
- package/dist/runtime/query/tooling.d.ts.map +1 -1
- package/dist/runtime/query/tooling.js +5 -0
- package/dist/runtime/query/tooling.js.map +1 -1
- package/dist/session/paths.d.ts +5 -1
- package/dist/session/paths.d.ts.map +1 -1
- package/dist/session/paths.js +8 -0
- package/dist/session/paths.js.map +1 -1
- package/dist/store/memory/disk.d.ts.map +1 -1
- package/dist/store/memory/disk.js +2 -2
- package/dist/store/memory/disk.js.map +1 -1
- package/dist/store/memory/markdown.d.ts.map +1 -1
- package/dist/store/memory/markdown.js +2 -2
- package/dist/store/memory/markdown.js.map +1 -1
- package/dist/store/memory/naming.d.ts +9 -0
- package/dist/store/memory/naming.d.ts.map +1 -1
- package/dist/store/memory/naming.js +12 -0
- package/dist/store/memory/naming.js.map +1 -1
- package/dist/tools/builtins/bash.d.ts +30 -1
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +170 -26
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/computer-use.d.ts +1 -1
- package/dist/tools/builtins/computer-use.d.ts.map +1 -1
- package/dist/tools/builtins/computer-use.js +12 -5
- package/dist/tools/builtins/computer-use.js.map +1 -1
- package/dist/tools/builtins/content-fingerprint.d.ts +2 -0
- package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -1
- package/dist/tools/builtins/content-fingerprint.js +4 -0
- package/dist/tools/builtins/content-fingerprint.js.map +1 -1
- package/dist/tools/builtins/edit.d.ts.map +1 -1
- package/dist/tools/builtins/edit.js +60 -18
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/grep.d.ts +8 -1
- package/dist/tools/builtins/grep.d.ts.map +1 -1
- package/dist/tools/builtins/grep.js +152 -33
- package/dist/tools/builtins/grep.js.map +1 -1
- package/dist/tools/builtins/read-file.d.ts +1 -0
- package/dist/tools/builtins/read-file.d.ts.map +1 -1
- package/dist/tools/builtins/read-file.js +44 -5
- package/dist/tools/builtins/read-file.js.map +1 -1
- package/dist/tools/builtins/read-render.d.ts +52 -0
- package/dist/tools/builtins/read-render.d.ts.map +1 -1
- package/dist/tools/builtins/read-render.js +143 -0
- package/dist/tools/builtins/read-render.js.map +1 -1
- package/dist/tools/builtins/web.d.ts +13 -2
- package/dist/tools/builtins/web.d.ts.map +1 -1
- package/dist/tools/builtins/web.js +225 -32
- package/dist/tools/builtins/web.js.map +1 -1
- package/dist/tools/coordinator/ask-user-question.d.ts +2 -0
- package/dist/tools/coordinator/ask-user-question.d.ts.map +1 -1
- package/dist/tools/coordinator/ask-user-question.js +256 -92
- package/dist/tools/coordinator/ask-user-question.js.map +1 -1
- package/dist/tools/coordinator/question-options.d.ts +1 -0
- package/dist/tools/coordinator/question-options.d.ts.map +1 -1
- package/dist/tools/coordinator/question-options.js +6 -1
- package/dist/tools/coordinator/question-options.js.map +1 -1
- package/dist/tools/defineTool.d.ts +4 -1
- package/dist/tools/defineTool.d.ts.map +1 -1
- package/dist/tools/defineTool.js +6 -1
- package/dist/tools/defineTool.js.map +1 -1
- package/dist/tools/paths.d.ts +6 -0
- package/dist/tools/paths.d.ts.map +1 -1
- package/dist/tools/paths.js +1 -1
- package/dist/tools/paths.js.map +1 -1
- package/dist/types/agent/query.d.ts +3 -0
- package/dist/types/agent/query.d.ts.map +1 -1
- package/dist/types/errors/catalog.js +1 -1
- package/dist/types/errors/catalog.js.map +1 -1
- package/dist/types/hitl/index.d.ts +104 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/message/index.d.ts +1 -1
- package/dist/types/message/index.d.ts.map +1 -1
- package/dist/types/message/index.js +2 -0
- package/dist/types/message/index.js.map +1 -1
- package/dist/types/plugin/index.d.ts +93 -19
- package/dist/types/plugin/index.d.ts.map +1 -1
- package/dist/types/plugin/index.js +3 -0
- package/dist/types/plugin/index.js.map +1 -1
- package/dist/types/provider/errors.d.ts +19 -0
- package/dist/types/provider/errors.d.ts.map +1 -1
- package/dist/types/provider/errors.js +54 -5
- package/dist/types/provider/errors.js.map +1 -1
- package/dist/types/provider/interface.d.ts +12 -0
- package/dist/types/provider/interface.d.ts.map +1 -1
- package/dist/types/provider/stream.d.ts +1 -1
- package/dist/types/session/config.d.ts +14 -0
- package/dist/types/session/config.d.ts.map +1 -1
- package/dist/types/session/events.d.ts +27 -4
- package/dist/types/session/events.d.ts.map +1 -1
- package/dist/types/session/events.js.map +1 -1
- package/dist/types/session/records.d.ts +9 -9
- package/dist/types/session/records.d.ts.map +1 -1
- package/dist/types/session/records.js +1 -0
- package/dist/types/session/records.js.map +1 -1
- package/dist/types/session/stop-reason.d.ts +5 -0
- package/dist/types/session/stop-reason.d.ts.map +1 -1
- package/dist/types/tool/index.d.ts +52 -0
- package/dist/types/tool/index.d.ts.map +1 -1
- package/dist/types/tool/index.js.map +1 -1
- package/package.json +4 -2
- package/src/agents/QueryAgent.ts +5 -1
- package/src/agents/SupervisorAgent.ts +1 -1
- package/src/agents/examples/SupervisorAgent.ts +217 -106
- package/src/agents/index.ts +1 -1
- package/src/authorization/protected-paths.ts +110 -0
- package/src/authorization/readonly-commands.ts +771 -0
- package/src/authorization/readonly-flags.ts +196 -0
- package/src/authorization/removal.ts +326 -0
- package/src/authorization/shell-paths.ts +927 -0
- package/src/bridge/acp/update.ts +1 -0
- package/src/compaction/context-window.ts +41 -0
- package/src/compaction/manual.ts +10 -2
- package/src/compaction/plan.ts +11 -2
- package/src/compaction/verifier.ts +84 -22
- package/src/config/runtime.ts +23 -2
- package/src/connector/web/guarded-fetch.ts +26 -0
- package/src/connector/web/index.ts +3 -0
- package/src/connector/web/page.ts +130 -0
- package/src/connector/web/types.ts +47 -0
- package/src/constants/continuation.ts +10 -0
- package/src/constants/plugin/index.ts +1 -1
- package/src/manager/agent/lifecycle.ts +12 -4
- package/src/manager/session/turn-recorder.ts +10 -2
- package/src/plugin/index.ts +1 -0
- package/src/plugin/lifecycle.ts +107 -119
- package/src/plugin/shell-hook.ts +477 -43
- package/src/provider/capabilities.ts +17 -0
- package/src/provider/errors.ts +13 -0
- package/src/provider/fallback.ts +10 -0
- package/src/provider/idle-timeout.ts +5 -0
- package/src/provider/image-input-refusal.ts +54 -0
- package/src/provider/index.ts +2 -0
- package/src/provider/retry.ts +42 -4
- package/src/public-runtime.ts +11 -0
- package/src/public-types.ts +4 -0
- package/src/runtime/jobs/registry.ts +39 -2
- package/src/runtime/query/deferred-sandbox.ts +110 -0
- package/src/runtime/query/executor/tool-call-admission.ts +79 -13
- package/src/runtime/query/executor.ts +267 -11
- package/src/runtime/query/finalize-turn.ts +7 -1
- package/src/runtime/query/index.ts +169 -52
- package/src/runtime/query/iteration/index.ts +439 -35
- package/src/runtime/query/iteration/phases/compaction-breaker.ts +108 -0
- package/src/runtime/query/iteration/phases/compaction.ts +241 -38
- package/src/runtime/query/iteration/phases/context.ts +11 -0
- package/src/runtime/query/iteration/phases/tool-review.ts +177 -2
- package/src/runtime/query/iteration/provider-rejected-image.ts +71 -5
- package/src/runtime/query/iteration/request-repair.ts +743 -0
- package/src/runtime/query/iteration/stream-turn.ts +11 -1
- package/src/runtime/query/path-escalation.ts +204 -0
- package/src/runtime/query/plugin-hooks.ts +8 -0
- package/src/runtime/query/reminders.ts +45 -0
- package/src/runtime/query/request-rich-content.ts +77 -27
- package/src/runtime/query/resume-pending.ts +27 -0
- package/src/runtime/query/review-policy.ts +106 -5
- package/src/runtime/query/tool-output-budget.ts +115 -1
- package/src/runtime/query/tooling.ts +6 -0
- package/src/session/paths.ts +11 -1
- package/src/store/memory/disk.ts +2 -1
- package/src/store/memory/markdown.ts +2 -1
- package/src/store/memory/naming.ts +13 -0
- package/src/tools/builtins/bash.ts +203 -34
- package/src/tools/builtins/computer-use.ts +13 -4
- package/src/tools/builtins/content-fingerprint.ts +5 -0
- package/src/tools/builtins/edit.ts +69 -19
- package/src/tools/builtins/grep.ts +159 -38
- package/src/tools/builtins/read-file.ts +48 -5
- package/src/tools/builtins/read-render.ts +193 -0
- package/src/tools/builtins/web.ts +258 -33
- package/src/tools/coordinator/ask-user-question.ts +309 -103
- package/src/tools/coordinator/question-options.ts +8 -1
- package/src/tools/defineTool.ts +11 -2
- package/src/tools/paths.ts +1 -1
- package/src/types/agent/query.ts +3 -0
- package/src/types/errors/catalog.ts +1 -1
- package/src/types/hitl/index.ts +104 -0
- package/src/types/message/index.ts +2 -0
- package/src/types/plugin/index.ts +101 -18
- package/src/types/provider/errors.ts +66 -5
- package/src/types/provider/interface.ts +13 -0
- package/src/types/provider/stream.ts +1 -1
- package/src/types/session/config.ts +14 -0
- package/src/types/session/events.ts +32 -4
- package/src/types/session/records.ts +1 -0
- package/src/types/session/stop-reason.ts +5 -0
- package/src/types/tool/index.ts +53 -2
|
@@ -4,7 +4,10 @@ import {
|
|
|
4
4
|
extractFromUserMessage,
|
|
5
5
|
} from '../../../compaction/extractor.js'
|
|
6
6
|
import { estimateMessageTokens } from '../../../compaction/token-estimate.js'
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
AUTO_CONTINUATION_USER_MESSAGE,
|
|
9
|
+
REASONING_CUT_USER_MESSAGE,
|
|
10
|
+
} from '../../../constants/continuation.js'
|
|
8
11
|
import { CHARS_PER_TOKEN } from '../../../constants/limits.js'
|
|
9
12
|
import {
|
|
10
13
|
DEFAULT_STRUCTURED_OUTPUT_RETRIES,
|
|
@@ -12,7 +15,7 @@ import {
|
|
|
12
15
|
} from '../../../constants/tools/index.js'
|
|
13
16
|
import { withStreamedMessageIdentity } from '../../../manager/session/streamed-message-identity.js'
|
|
14
17
|
import { renderSkillsSection } from '../../../persona/assembler.js'
|
|
15
|
-
import { resolveProviderCapabilities } from '../../../provider/capabilities.js'
|
|
18
|
+
import { modelReadsImages, resolveProviderCapabilities } from '../../../provider/capabilities.js'
|
|
16
19
|
import { collectChatCompletion } from '../../../provider/collect-chat-completion.js'
|
|
17
20
|
import { renderToolSchema } from '../../../registry/tool/schema.js'
|
|
18
21
|
import { formatCompletionNotification } from '../../../scheduler/completion-inbox.js'
|
|
@@ -27,7 +30,7 @@ import { STRUCTURED_OUTPUT_TOOL_NAME } from '../../../tools/builtins/structuredO
|
|
|
27
30
|
import type { ToolManager } from '../../../toolsets/manager.js'
|
|
28
31
|
import type { CostInfo, TokenUsage } from '../../../types/common/index.js'
|
|
29
32
|
import { NamzuError } from '../../../types/errors/index.js'
|
|
30
|
-
import type { MessageId } from '../../../types/ids/index.js'
|
|
33
|
+
import type { MessageId, SessionId, TurnId } from '../../../types/ids/index.js'
|
|
31
34
|
import {
|
|
32
35
|
type Message,
|
|
33
36
|
type UserMessage,
|
|
@@ -35,7 +38,7 @@ import {
|
|
|
35
38
|
createRuntimeContextMessage,
|
|
36
39
|
createSystemMessage,
|
|
37
40
|
} from '../../../types/message/index.js'
|
|
38
|
-
import { classifyProviderError } from '../../../types/provider/errors.js'
|
|
41
|
+
import { classifyProviderError, readOutputOverflow } from '../../../types/provider/errors.js'
|
|
39
42
|
import type { ChatCompletionResponse } from '../../../types/provider/index.js'
|
|
40
43
|
import type { AnswerReview, AnswerReviewContext } from '../../../types/session/answer-review.js'
|
|
41
44
|
import type {
|
|
@@ -51,6 +54,7 @@ import { stableDigest } from '../../../utils/hash.js'
|
|
|
51
54
|
import { generateMessageId } from '../../../utils/id.js'
|
|
52
55
|
import { parseStructuredResultJson } from '../../../utils/structured-result-json.js'
|
|
53
56
|
import { createCallbackInference } from '../callback-inference.js'
|
|
57
|
+
import { SandboxAcquisitionStopped } from '../deferred-sandbox.js'
|
|
54
58
|
import { deliverDurableInbound } from '../durable-inbound.js'
|
|
55
59
|
import type { ToolCallOutcome } from '../executor.js'
|
|
56
60
|
import { projectObservationContext } from '../observation-context.js'
|
|
@@ -75,18 +79,29 @@ import {
|
|
|
75
79
|
} from './outstanding-work.js'
|
|
76
80
|
import { runAdvisoryPhase } from './phases/advisory.js'
|
|
77
81
|
import { runIterationCheckpoint } from './phases/checkpoint.js'
|
|
82
|
+
import { compactionBreaker } from './phases/compaction-breaker.js'
|
|
78
83
|
import {
|
|
84
|
+
AUTOMATIC_COMPACTION_FAILED,
|
|
85
|
+
OVERFLOW_RELIEF_LIMIT,
|
|
79
86
|
activeContextWindow,
|
|
87
|
+
clearCompactionErrorNote,
|
|
88
|
+
compactionErrorNote,
|
|
80
89
|
measureContext,
|
|
81
90
|
relieveOverflow,
|
|
82
91
|
runCompactionCheck,
|
|
92
|
+
stopOnRefill,
|
|
83
93
|
} from './phases/compaction.js'
|
|
84
94
|
import { runHandoffPause } from './phases/handoff.js'
|
|
85
95
|
import type { IterationContext } from './phases/index.js'
|
|
86
96
|
import { runPlanGate } from './phases/plan.js'
|
|
87
97
|
import { runToolReview } from './phases/tool-review.js'
|
|
88
98
|
import { refreshWorkingMemory, splitWorkingMemoryForRequest } from './phases/working-memory.js'
|
|
89
|
-
import {
|
|
99
|
+
import {
|
|
100
|
+
type TextOnlyModelRecovery,
|
|
101
|
+
type TextOnlyModelRefusal,
|
|
102
|
+
streamWithProviderRejectedImageRecovery,
|
|
103
|
+
} from './provider-rejected-image.js'
|
|
104
|
+
import { type MediaRemoval, RequestRepair } from './request-repair.js'
|
|
90
105
|
import {
|
|
91
106
|
type StepShaping,
|
|
92
107
|
appendWorkContext,
|
|
@@ -125,6 +140,11 @@ export type { ToolReviewOutcome } from './phases/index.js'
|
|
|
125
140
|
*/
|
|
126
141
|
const DEFAULT_ANSWER_REVIEW_LIMIT = 3
|
|
127
142
|
|
|
143
|
+
/** Left unused when an output cap is shrunk to fit the window (reference: 1000). */
|
|
144
|
+
const OUTPUT_CAP_MARGIN_TOKENS = 1000
|
|
145
|
+
/** A shrunk output cap below this is not worth a call (reference floor: 3000). */
|
|
146
|
+
const MIN_OUTPUT_CAP_TOKENS = 3000
|
|
147
|
+
|
|
128
148
|
// Ending a turn changes the available actions, not the strength of its evidence.
|
|
129
149
|
// Use the same standard for warning closure and empty-completion recovery.
|
|
130
150
|
const CLOSING_RESPONSE_GUIDANCE =
|
|
@@ -132,6 +152,11 @@ const CLOSING_RESPONSE_GUIDANCE =
|
|
|
132
152
|
|
|
133
153
|
export { awaitedJobGraceMs, settleGraceMs } from './outstanding-work.js'
|
|
134
154
|
|
|
155
|
+
/** One provider's model, as {@link IterationOrchestrator} remembers it. */
|
|
156
|
+
function textOnlyKey(providerId: string, model: string): string {
|
|
157
|
+
return `${providerId}\u0000${model}`
|
|
158
|
+
}
|
|
159
|
+
|
|
135
160
|
export class IterationOrchestrator {
|
|
136
161
|
private ctx: IterationContext
|
|
137
162
|
private advisoryTurn:
|
|
@@ -179,6 +204,73 @@ export class IterationOrchestrator {
|
|
|
179
204
|
}
|
|
180
205
|
/** Rich tool blocks already reported; durable history is scanned every turn. */
|
|
181
206
|
private readonly warnedRichToolResults = new Set<string>()
|
|
207
|
+
/** What this run has learned about requests its provider rejects as invalid, and how to repair them. */
|
|
208
|
+
private readonly requestRepair = new RequestRepair({
|
|
209
|
+
debug: (message) => this.ctx.log.debug(message),
|
|
210
|
+
onMediaRemoved: (removal) => this.noteMediaRemoved(removal),
|
|
211
|
+
servedBy: () => this.ctx.servingMember?.(),
|
|
212
|
+
})
|
|
213
|
+
/**
|
|
214
|
+
* Provider and model pairs that refused a request for holding an image; they
|
|
215
|
+
* get none for the rest of the run. Keyed by both: one model id can be served
|
|
216
|
+
* by two members of a fallback chain, and only the one that refused is known.
|
|
217
|
+
*/
|
|
218
|
+
private readonly textOnlyModels = new Set<string>()
|
|
219
|
+
|
|
220
|
+
/**
|
|
221
|
+
* The member a request for `model` goes to first. A fallback chain keeps
|
|
222
|
+
* serving from the member it last moved to, so that member, not the head,
|
|
223
|
+
* is the one whose reading of images counts.
|
|
224
|
+
*/
|
|
225
|
+
private servingModel(model: string): { readonly providerId: string; readonly model: string } {
|
|
226
|
+
const serving = this.ctx.servingMember?.()
|
|
227
|
+
return {
|
|
228
|
+
providerId: serving?.providerId ?? this.ctx.provider.id,
|
|
229
|
+
model: serving?.model ?? model,
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Whether a request for `model` may carry images: the driver's catalogue and this run's own evidence agree. */
|
|
234
|
+
private modelReadsImages(model: string): boolean {
|
|
235
|
+
const serving = this.servingModel(model)
|
|
236
|
+
return (
|
|
237
|
+
!this.textOnlyModels.has(textOnlyKey(serving.providerId, serving.model)) &&
|
|
238
|
+
modelReadsImages(this.ctx.provider, model)
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** What a request for `model` does when its model turns out to read text only. */
|
|
243
|
+
private textOnlyRecovery(model: string): TextOnlyModelRecovery {
|
|
244
|
+
return {
|
|
245
|
+
servedBy: () => this.servingModel(model),
|
|
246
|
+
onAccepted: (refused) => this.noteTextOnlyModel(refused),
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* A provider refused a request for holding an image its model cannot read, and
|
|
252
|
+
* the retry without images was accepted. Stop sending images to it, and say so
|
|
253
|
+
* once, so the host can remember the model beyond this run.
|
|
254
|
+
*/
|
|
255
|
+
private async noteTextOnlyModel(refused: TextOnlyModelRefusal): Promise<void> {
|
|
256
|
+
const key = textOnlyKey(refused.providerId, refused.model ?? '')
|
|
257
|
+
if (this.textOnlyModels.has(key)) return
|
|
258
|
+
this.textOnlyModels.add(key)
|
|
259
|
+
const { providerId, model } = refused
|
|
260
|
+
this.ctx.log.warn('Capability mismatch: the model cannot read images', {
|
|
261
|
+
[GENAI.SYSTEM]: providerId,
|
|
262
|
+
[GENAI.REQUEST_MODEL]: model ?? '',
|
|
263
|
+
})
|
|
264
|
+
await this.ctx.emitEvent?.({
|
|
265
|
+
type: 'capability_warning',
|
|
266
|
+
turnId: this.ctx.recorder.turnId,
|
|
267
|
+
capability: 'vision',
|
|
268
|
+
contentSource: 'history',
|
|
269
|
+
providerId,
|
|
270
|
+
...(model !== undefined ? { model } : {}),
|
|
271
|
+
message: `Model '${model ?? 'unknown'}' on provider '${providerId}' refused a request that held an image, so images are left out of its requests. They stay in the conversation and are sent again to a model that reads them.`,
|
|
272
|
+
})
|
|
273
|
+
}
|
|
182
274
|
/**
|
|
183
275
|
* The previous iteration held a `stopWhen` decision open for a worker.
|
|
184
276
|
*
|
|
@@ -194,6 +286,74 @@ export class IterationOrchestrator {
|
|
|
194
286
|
* sets it.
|
|
195
287
|
*/
|
|
196
288
|
private stopDeferredForOutstandingWork = false
|
|
289
|
+
/** Nudges sent since the model last finished a call without hitting its output cap. */
|
|
290
|
+
private outputContinuations = 0
|
|
291
|
+
/**
|
|
292
|
+
* `turn_end` (and, for a child, `subagent_stop`) fired when the model
|
|
293
|
+
* finished and no hook asked for more. `finalizeTurn` then does not fire
|
|
294
|
+
* them a second time.
|
|
295
|
+
*/
|
|
296
|
+
private turnEndFired = false
|
|
297
|
+
/** A hook already kept this turn going once: it is asked again with `stop_hook_active`. */
|
|
298
|
+
private stopHookActive = false
|
|
299
|
+
get turnEndHooksFired(): boolean {
|
|
300
|
+
return this.turnEndFired
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Fire `turn_end` (and `subagent_stop` for a child) at the point the model
|
|
305
|
+
* has finished, and read the answer.
|
|
306
|
+
*
|
|
307
|
+
* A hook that answers `skip` is refusing to let the turn end: its reasons
|
|
308
|
+
* are returned, joined, as feedback for the model. A hook that asks for the
|
|
309
|
+
* turn to halt wins over any such feedback (`takeHalt`). With nothing asked,
|
|
310
|
+
* the events have fired for this turn and the finalizer does not repeat them.
|
|
311
|
+
*/
|
|
312
|
+
private async *askStopHooks(): AsyncGenerator<SessionEvent, string | undefined> {
|
|
313
|
+
const manager = this.ctx.pluginManager
|
|
314
|
+
if (!manager) return undefined
|
|
315
|
+
const recorder = this.ctx.recorder
|
|
316
|
+
const feedback: string[] = []
|
|
317
|
+
const ask = async (
|
|
318
|
+
event: 'turn_end' | 'subagent_stop',
|
|
319
|
+
extra: { parentSessionId?: SessionId; parentTurnId?: TurnId },
|
|
320
|
+
): Promise<void> => {
|
|
321
|
+
const results = await manager.executeHooks(
|
|
322
|
+
event,
|
|
323
|
+
{
|
|
324
|
+
sessionId: recorder.sessionId,
|
|
325
|
+
turnId: recorder.turnId,
|
|
326
|
+
...extra,
|
|
327
|
+
...(this.stopHookActive ? { stopHookActive: true } : {}),
|
|
328
|
+
signal: this.ctx.abortController.signal,
|
|
329
|
+
},
|
|
330
|
+
this.ctx.emitEvent,
|
|
331
|
+
)
|
|
332
|
+
applyLifecycleHookResults(event, results)
|
|
333
|
+
for (const result of results) {
|
|
334
|
+
if (result.action === 'skip') feedback.push(result.reason)
|
|
335
|
+
if ((result.action === 'continue' || result.action === 'skip') && result.halt) {
|
|
336
|
+
this.ctx.toolExecutor.requestHalt?.(result.halt.reason)
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
await ask('turn_end', {})
|
|
341
|
+
yield* this.ctx.drainPending()
|
|
342
|
+
if (this.ctx.parentSessionId !== undefined) {
|
|
343
|
+
await ask('subagent_stop', {
|
|
344
|
+
parentSessionId: this.ctx.parentSessionId,
|
|
345
|
+
...(this.ctx.parentTurnId !== undefined ? { parentTurnId: this.ctx.parentTurnId } : {}),
|
|
346
|
+
})
|
|
347
|
+
yield* this.ctx.drainPending()
|
|
348
|
+
}
|
|
349
|
+
if (feedback.length === 0) {
|
|
350
|
+
this.turnEndFired = true
|
|
351
|
+
return undefined
|
|
352
|
+
}
|
|
353
|
+
this.stopHookActive = true
|
|
354
|
+
return feedback.join('\n')
|
|
355
|
+
}
|
|
356
|
+
|
|
197
357
|
/** One current input, independent of the compactable history array. */
|
|
198
358
|
private latestUserMessage: UserMessage | undefined
|
|
199
359
|
private initialDurableDelivered = false
|
|
@@ -365,16 +525,22 @@ export class IterationOrchestrator {
|
|
|
365
525
|
// checkpoint names the message the turn is answering.
|
|
366
526
|
await this.ctx.checkpointMgr.markLoopStart?.(recorder)
|
|
367
527
|
|
|
368
|
-
//
|
|
528
|
+
// Context-overflow relief is a two-rung ladder per *stuck point*, not per
|
|
529
|
+
// turn, as in the reference terminal (at most two reactive compactions per
|
|
530
|
+
// overflow): the first relief, then one deeper pass if the retry still
|
|
531
|
+
// overflows.
|
|
369
532
|
//
|
|
370
|
-
// The
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
//
|
|
377
|
-
let
|
|
533
|
+
// The limit exists so that an overflow that survives both rungs — an
|
|
534
|
+
// irreducible prompt — stops instead of looping. It was never meant to
|
|
535
|
+
// disarm the mechanism for the rest of the turn, which is what a
|
|
536
|
+
// turn-scoped flag did: one relief at iteration 3 left iteration 40 to die
|
|
537
|
+
// on an overflow with obvious moves left. The count is cleared by a turn
|
|
538
|
+
// that actually succeeded, which is the evidence that the turn is no
|
|
539
|
+
// longer stuck.
|
|
540
|
+
let overflowReliefs = 0
|
|
541
|
+
// The output cap a provider told us fits beside this prompt. One request's
|
|
542
|
+
// worth: it is cleared by a call that went through.
|
|
543
|
+
let outputCapOverride: number | undefined
|
|
378
544
|
|
|
379
545
|
// A `finally` rather than a line at each exit, for the reason written
|
|
380
546
|
// beside `iterSpan.end()` below: this loop leaves by eight `break`s,
|
|
@@ -573,12 +739,15 @@ export class IterationOrchestrator {
|
|
|
573
739
|
yield* this.ctx.drainPending()
|
|
574
740
|
}
|
|
575
741
|
|
|
742
|
+
if (!forceFinalize) await this.deliverReminders(iterationNum)
|
|
743
|
+
|
|
576
744
|
// Re-pin the working-memory block from ground truth at the primacy
|
|
577
745
|
// edge BEFORE compaction runs (so the refreshed slot is what
|
|
578
746
|
// compaction preserves). No-op when no provider is configured.
|
|
579
747
|
await refreshWorkingMemory(this.ctx)
|
|
580
748
|
await runCompactionCheck(this.ctx)
|
|
581
749
|
yield* this.ctx.drainPending()
|
|
750
|
+
if (this.stopForCompactionBreaker()) break
|
|
582
751
|
|
|
583
752
|
// Cache discipline: keep the tools param byte-stable even on the
|
|
584
753
|
// forced-final iteration and forbid tool use via tool_choice
|
|
@@ -630,6 +799,7 @@ export class IterationOrchestrator {
|
|
|
630
799
|
if (stepModel !== contextModelBeforePreparation) await runCompactionCheck(this.ctx)
|
|
631
800
|
// Publish context edits before entering a possibly slow provider.
|
|
632
801
|
yield* this.ctx.drainPending()
|
|
802
|
+
if (this.stopForCompactionBreaker()) break
|
|
633
803
|
|
|
634
804
|
const stepAllowedTools = step.allowedTools ?? this.ctx.allowedTools
|
|
635
805
|
const deferredMcpContext = deferredMcpHints?.forNames(stepAllowedTools) ?? ''
|
|
@@ -730,6 +900,7 @@ export class IterationOrchestrator {
|
|
|
730
900
|
this.projectObservations(requestHistory),
|
|
731
901
|
this.ctx.turnConfig.maxRequestRichContentBytes ??
|
|
732
902
|
DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES,
|
|
903
|
+
{ imagesReadable: this.modelReadsImages(stepModel) },
|
|
733
904
|
)
|
|
734
905
|
appendWorkContext(shaping, messages, iterationNum, step)
|
|
735
906
|
if (closingDirective) messages.push(closingDirective)
|
|
@@ -808,7 +979,8 @@ export class IterationOrchestrator {
|
|
|
808
979
|
messages: Object.freeze(messages.map((m) => Object.freeze({ ...m }))),
|
|
809
980
|
toolNames: Object.freeze(llmTools.map((t) => t.function.name)),
|
|
810
981
|
temperature: step.temperature ?? turnConfig.temperature,
|
|
811
|
-
maxTokens:
|
|
982
|
+
maxTokens:
|
|
983
|
+
outputCapOverride ?? step.maxResponseTokens ?? turnConfig.maxResponseTokens,
|
|
812
984
|
}),
|
|
813
985
|
},
|
|
814
986
|
this.ctx.emitEvent,
|
|
@@ -881,7 +1053,8 @@ export class IterationOrchestrator {
|
|
|
881
1053
|
? step.toolChoice
|
|
882
1054
|
: undefined,
|
|
883
1055
|
temperature: step.temperature ?? turnConfig.temperature,
|
|
884
|
-
maxTokens:
|
|
1056
|
+
maxTokens:
|
|
1057
|
+
outputCapOverride ?? step.maxResponseTokens ?? turnConfig.maxResponseTokens,
|
|
885
1058
|
cacheControl: { type: 'auto' },
|
|
886
1059
|
...(turnConfig.thinking ? { thinking: turnConfig.thinking } : {}),
|
|
887
1060
|
...(turnConfig.effort ? { effort: turnConfig.effort } : {}),
|
|
@@ -903,6 +1076,8 @@ export class IterationOrchestrator {
|
|
|
903
1076
|
stepMessageId,
|
|
904
1077
|
{
|
|
905
1078
|
onAccepted: (identity) => this.acceptProviderRejectedImage(identity),
|
|
1079
|
+
textOnly: this.textOnlyRecovery(stepModel),
|
|
1080
|
+
repair: this.requestRepair,
|
|
906
1081
|
},
|
|
907
1082
|
Boolean(
|
|
908
1083
|
this.ctx.reviewAnswer || this.ctx.structuredOutput?.review || this.ctx.advisoryCtx,
|
|
@@ -956,7 +1131,10 @@ export class IterationOrchestrator {
|
|
|
956
1131
|
|
|
957
1132
|
// The turn went through, so the turn is not sitting on an
|
|
958
1133
|
// irreducible prompt any more. Re-arm relief for the next one.
|
|
959
|
-
|
|
1134
|
+
overflowReliefs = 0
|
|
1135
|
+
clearCompactionErrorNote(this.ctx)
|
|
1136
|
+
outputCapOverride = undefined
|
|
1137
|
+
if (response.finishReason !== 'length') this.outputContinuations = 0
|
|
960
1138
|
|
|
961
1139
|
if (this.ctx.pluginManager) {
|
|
962
1140
|
const hookResults = await this.ctx.pluginManager.executeHooks(
|
|
@@ -1283,19 +1461,55 @@ export class IterationOrchestrator {
|
|
|
1283
1461
|
// it has no room left to continue into, and the
|
|
1284
1462
|
// continuation would only send a longer prompt into
|
|
1285
1463
|
// the same full window. The reply stands as it is.
|
|
1464
|
+
const cutDuringReasoning =
|
|
1465
|
+
!hasContent &&
|
|
1466
|
+
(response.message.toolCalls?.length ?? 0) === 0 &&
|
|
1467
|
+
(response.message.reasoning?.length ?? 0) > 0
|
|
1286
1468
|
if (
|
|
1287
1469
|
!forceFinalize &&
|
|
1288
1470
|
response.finishReason === 'length' &&
|
|
1289
1471
|
response.finishDetail !== 'context_window' &&
|
|
1290
|
-
hasContent
|
|
1472
|
+
(hasContent || cutDuringReasoning)
|
|
1291
1473
|
) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1474
|
+
// A host that opted in gets a cap on the nudges: a model that
|
|
1475
|
+
// overruns its output limit every time would otherwise spend the
|
|
1476
|
+
// whole turn on it. Past the cap the turn stops, and says why.
|
|
1477
|
+
const cap = this.ctx.maxOutputContinuations
|
|
1478
|
+
if (cap !== undefined && this.outputContinuations >= cap) {
|
|
1479
|
+
this.ctx.log.warn('LLM kept hitting max_tokens — stopping the turn', {
|
|
1480
|
+
[NAMZU.TURN_ID]: recorder.turnId,
|
|
1481
|
+
[NAMZU.ITERATION]: iterationNum,
|
|
1482
|
+
'namzu.runtime.output_continuations': this.outputContinuations,
|
|
1483
|
+
})
|
|
1484
|
+
recorder.setLastError(
|
|
1485
|
+
`The reply was cut off at the output limit ${cap + 1} times in a row. Ask for a smaller piece of the work, or raise the output limit.`,
|
|
1486
|
+
)
|
|
1487
|
+
recorder.setStopReason('output_limit')
|
|
1488
|
+
await this.ctx.emitEvent({
|
|
1489
|
+
type: 'iteration_completed',
|
|
1490
|
+
turnId: recorder.turnId,
|
|
1491
|
+
iteration: iterationNum,
|
|
1492
|
+
hasToolCalls: false,
|
|
1493
|
+
})
|
|
1494
|
+
yield* this.ctx.drainPending()
|
|
1495
|
+
break
|
|
1496
|
+
}
|
|
1497
|
+
this.outputContinuations++
|
|
1498
|
+
this.ctx.log.info(
|
|
1499
|
+
cutDuringReasoning
|
|
1500
|
+
? 'LLM hit max_tokens while reasoning — nudging to answer briefly'
|
|
1501
|
+
: 'LLM hit max_tokens mid-text — auto-continuing',
|
|
1502
|
+
{
|
|
1503
|
+
[NAMZU.TURN_ID]: recorder.turnId,
|
|
1504
|
+
[NAMZU.ITERATION]: iterationNum,
|
|
1505
|
+
[GENAI.USAGE_OUTPUT_TOKENS]: response.usage.completionTokens,
|
|
1506
|
+
},
|
|
1507
|
+
)
|
|
1297
1508
|
recorder.pushMessage(
|
|
1298
|
-
createRuntimeContextMessage(
|
|
1509
|
+
createRuntimeContextMessage(
|
|
1510
|
+
cutDuringReasoning ? REASONING_CUT_USER_MESSAGE : AUTO_CONTINUATION_USER_MESSAGE,
|
|
1511
|
+
'auto-continuation',
|
|
1512
|
+
),
|
|
1299
1513
|
)
|
|
1300
1514
|
await this.ctx.emitEvent({
|
|
1301
1515
|
type: 'iteration_completed',
|
|
@@ -1451,6 +1665,27 @@ export class IterationOrchestrator {
|
|
|
1451
1665
|
// also settle as `end_turn`, and there the deferred predicate
|
|
1452
1666
|
// is not why the turn ended: those decided the answer
|
|
1453
1667
|
// themselves.
|
|
1668
|
+
// The model is done and has no tool calls. A `turn_end` (or
|
|
1669
|
+
// `subagent_stop`) hook may refuse to let it be: its reason goes
|
|
1670
|
+
// back to the model and the turn goes on.
|
|
1671
|
+
if (!forceFinalize && closingStopReason === undefined) {
|
|
1672
|
+
const feedback = yield* this.askStopHooks()
|
|
1673
|
+
const stoppedByHook = this.ctx.toolExecutor.takeHalt?.()
|
|
1674
|
+
if (stoppedByHook !== undefined) {
|
|
1675
|
+
recorder.setLastError(`Stopped by a hook: ${stoppedByHook}`)
|
|
1676
|
+
recorder.setStopReason('stop_condition')
|
|
1677
|
+
break
|
|
1678
|
+
}
|
|
1679
|
+
if (feedback !== undefined) {
|
|
1680
|
+
recorder.pushMessage(
|
|
1681
|
+
createRuntimeContextMessage(
|
|
1682
|
+
`A hook asked for more before this turn ends:\n${feedback}`,
|
|
1683
|
+
'hook-feedback',
|
|
1684
|
+
),
|
|
1685
|
+
)
|
|
1686
|
+
continue
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1454
1689
|
recorder.setStopReason(
|
|
1455
1690
|
closingStopReason ??
|
|
1456
1691
|
(stopWasDeferredForOutstandingWork ? 'stop_condition' : 'end_turn'),
|
|
@@ -1495,6 +1730,28 @@ export class IterationOrchestrator {
|
|
|
1495
1730
|
return
|
|
1496
1731
|
}
|
|
1497
1732
|
|
|
1733
|
+
// A hook asked for the turn to stop once this step's calls were
|
|
1734
|
+
// answered. Every `tool_use` has its `tool_result` by now, so the
|
|
1735
|
+
// transcript is whole; what is left is to end the turn and say why.
|
|
1736
|
+
const hookHalt = this.ctx.toolExecutor.takeHalt?.()
|
|
1737
|
+
if (hookHalt !== undefined) {
|
|
1738
|
+
this.ctx.log.info('A hook stopped the turn', {
|
|
1739
|
+
[NAMZU.TURN_ID]: recorder.turnId,
|
|
1740
|
+
[NAMZU.ITERATION]: iterationNum,
|
|
1741
|
+
'namzu.hook.reason': hookHalt,
|
|
1742
|
+
})
|
|
1743
|
+
recorder.setLastError(`Stopped by a hook: ${hookHalt}`)
|
|
1744
|
+
recorder.setStopReason('stop_condition')
|
|
1745
|
+
await this.ctx.emitEvent({
|
|
1746
|
+
type: 'iteration_completed',
|
|
1747
|
+
turnId: recorder.turnId,
|
|
1748
|
+
iteration: iterationNum,
|
|
1749
|
+
hasToolCalls: true,
|
|
1750
|
+
})
|
|
1751
|
+
yield* this.ctx.drainPending()
|
|
1752
|
+
break
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1498
1755
|
if (reviewOutcome.decision === 'rejected') {
|
|
1499
1756
|
continue
|
|
1500
1757
|
}
|
|
@@ -1728,6 +1985,12 @@ export class IterationOrchestrator {
|
|
|
1728
1985
|
yield* this.ctx.drainPending()
|
|
1729
1986
|
} catch (err) {
|
|
1730
1987
|
const cancelled = this.ctx.abortController.signal.aborted
|
|
1988
|
+
// A deferred sandbox that was cancelled or ran out of time. The
|
|
1989
|
+
// turn settles it as `cancelled` / `timeout` in `query()`, which is
|
|
1990
|
+
// not a failure of this iteration: it is recorded the way a turn
|
|
1991
|
+
// stopped by its own abort or timeout is (a cancelled step, no
|
|
1992
|
+
// error span), so the ledger and the stop reason agree.
|
|
1993
|
+
const sandboxStopped = err instanceof SandboxAcquisitionStopped
|
|
1731
1994
|
|
|
1732
1995
|
// This iteration gets a step too, and it is the one the
|
|
1733
1996
|
// argument three hundred lines above was actually about.
|
|
@@ -1788,12 +2051,13 @@ export class IterationOrchestrator {
|
|
|
1788
2051
|
startedAt: stepStartedAt,
|
|
1789
2052
|
usageBefore,
|
|
1790
2053
|
costBefore,
|
|
1791
|
-
unfinished:
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
2054
|
+
unfinished:
|
|
2055
|
+
cancelled || sandboxStopped
|
|
2056
|
+
? { finishReason: 'cancelled' }
|
|
2057
|
+
: {
|
|
2058
|
+
finishReason: 'error',
|
|
2059
|
+
failure: describeStepFailure(err, this.ctx.provider.id),
|
|
2060
|
+
},
|
|
1797
2061
|
})
|
|
1798
2062
|
}
|
|
1799
2063
|
|
|
@@ -1822,23 +2086,89 @@ export class IterationOrchestrator {
|
|
|
1822
2086
|
// actually shed something. A second overflow after a successful
|
|
1823
2087
|
// compaction means the prompt is irreducible, and looping on it
|
|
1824
2088
|
// would burn the budget to arrive at the same error.
|
|
2089
|
+
// The prompt fit and only the requested output did not: ask for what
|
|
2090
|
+
// room is left (less a margin) and send it again, once. A reply that
|
|
2091
|
+
// would be too small to be useful, or a cap that is not smaller than
|
|
2092
|
+
// the one already tried, is not retried: the same failure would follow.
|
|
2093
|
+
const outputOverflow =
|
|
2094
|
+
err instanceof AnswerReviewFailure ? undefined : readOutputOverflow(err)
|
|
2095
|
+
if (outputOverflow) {
|
|
2096
|
+
const room = Math.max(
|
|
2097
|
+
0,
|
|
2098
|
+
outputOverflow.contextLimit - outputOverflow.inputTokens - OUTPUT_CAP_MARGIN_TOKENS,
|
|
2099
|
+
)
|
|
2100
|
+
if (
|
|
2101
|
+
room >= MIN_OUTPUT_CAP_TOKENS &&
|
|
2102
|
+
(outputCapOverride === undefined || room < outputCapOverride)
|
|
2103
|
+
) {
|
|
2104
|
+
outputCapOverride = room
|
|
2105
|
+
this.ctx.log.info('Output cap does not fit beside the prompt — retrying with less', {
|
|
2106
|
+
[NAMZU.TURN_ID]: recorder.turnId,
|
|
2107
|
+
[NAMZU.ITERATION]: iterationNum,
|
|
2108
|
+
'namzu.runtime.input_tokens': outputOverflow.inputTokens,
|
|
2109
|
+
'namzu.runtime.context_limit': outputOverflow.contextLimit,
|
|
2110
|
+
'namzu.runtime.adjusted_max_tokens': room,
|
|
2111
|
+
})
|
|
2112
|
+
if (iterationActivity) {
|
|
2113
|
+
this.ctx.activityStore.complete(iterationActivity.id)
|
|
2114
|
+
}
|
|
2115
|
+
continue
|
|
2116
|
+
}
|
|
2117
|
+
}
|
|
2118
|
+
|
|
1825
2119
|
if (
|
|
1826
|
-
!overflowRelieved &&
|
|
1827
2120
|
!(err instanceof AnswerReviewFailure) &&
|
|
1828
2121
|
classifyProviderError(err, this.ctx.provider.id).code === 'context_length_exceeded'
|
|
1829
2122
|
) {
|
|
1830
|
-
|
|
1831
|
-
|
|
2123
|
+
// The rapid-refill check comes first, before the first reactive relief
|
|
2124
|
+
// of an overflow, as in the reference terminal. A relief that follows
|
|
2125
|
+
// the previous compaction within the refill window counts toward the
|
|
2126
|
+
// limit, so a tool that re-fills the window every time it is called
|
|
2127
|
+
// stops the turn instead of being cleared and called again without end.
|
|
2128
|
+
// The deeper rung of the same overflow is not counted again.
|
|
2129
|
+
if (overflowReliefs === 0 && (await stopOnRefill(this.ctx))) {
|
|
2130
|
+
if (iterationActivity) {
|
|
2131
|
+
this.ctx.activityStore.fail(iterationActivity.id, toErrorMessage(err))
|
|
2132
|
+
}
|
|
2133
|
+
if (this.stopForCompactionBreaker()) break
|
|
2134
|
+
}
|
|
2135
|
+
// A rung that sheds too little to change the verdict is not worth a
|
|
2136
|
+
// provider call; climb to the next one at once.
|
|
2137
|
+
let shed = false
|
|
2138
|
+
while (!shed && overflowReliefs < OVERFLOW_RELIEF_LIMIT) {
|
|
2139
|
+
overflowReliefs++
|
|
2140
|
+
shed = await relieveOverflow(this.ctx, { deeper: overflowReliefs > 1 })
|
|
2141
|
+
}
|
|
1832
2142
|
if (shed) {
|
|
2143
|
+
// Clearing results is a compaction too: only summaries and reducers
|
|
2144
|
+
// recorded themselves, so a clear-only relief was invisible to the
|
|
2145
|
+
// breaker.
|
|
2146
|
+
compactionBreaker(this.ctx)?.recordCompaction(iterationNum)
|
|
1833
2147
|
this.ctx.log.info('Retrying the turn after relieving a context overflow', {
|
|
1834
2148
|
[NAMZU.TURN_ID]: recorder.turnId,
|
|
1835
2149
|
[NAMZU.ITERATION]: iterationNum,
|
|
2150
|
+
'namzu.runtime.relief_rung': overflowReliefs,
|
|
1836
2151
|
})
|
|
1837
2152
|
if (iterationActivity) {
|
|
1838
2153
|
this.ctx.activityStore.complete(iterationActivity.id)
|
|
1839
2154
|
}
|
|
1840
2155
|
continue
|
|
1841
2156
|
}
|
|
2157
|
+
// Out of rungs. The conversation is kept; say why compaction could not
|
|
2158
|
+
// make room when it errored, as the reference does.
|
|
2159
|
+
const cause = compactionErrorNote(this.ctx)
|
|
2160
|
+
if (cause !== undefined && err instanceof Error) {
|
|
2161
|
+
try {
|
|
2162
|
+
err.message = `${err.message}${AUTOMATIC_COMPACTION_FAILED}${cause}`
|
|
2163
|
+
} catch {
|
|
2164
|
+
// A frozen error keeps its own message; the cause stays in the log.
|
|
2165
|
+
}
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
|
|
2169
|
+
if (sandboxStopped) {
|
|
2170
|
+
if (iterationActivity) this.ctx.activityStore.complete(iterationActivity.id)
|
|
2171
|
+
throw err
|
|
1842
2172
|
}
|
|
1843
2173
|
|
|
1844
2174
|
if (iterationActivity) {
|
|
@@ -1925,6 +2255,39 @@ export class IterationOrchestrator {
|
|
|
1925
2255
|
}
|
|
1926
2256
|
}
|
|
1927
2257
|
|
|
2258
|
+
/**
|
|
2259
|
+
* Ask the host's reminder source (`QueryParams.reminders`) what the model
|
|
2260
|
+
* should be told before this request, and append each text as a hidden
|
|
2261
|
+
* user-role message. The start of a request is a provider-valid boundary:
|
|
2262
|
+
* the history ends in the operator's message or in a finished tool batch.
|
|
2263
|
+
* A source that throws has nothing to say; it never fails the turn.
|
|
2264
|
+
*/
|
|
2265
|
+
private async deliverReminders(iteration: number): Promise<void> {
|
|
2266
|
+
const source = this.ctx.reminders
|
|
2267
|
+
if (!source) return
|
|
2268
|
+
const { recorder } = this.ctx
|
|
2269
|
+
let texts: readonly string[] | undefined
|
|
2270
|
+
try {
|
|
2271
|
+
texts = await source({
|
|
2272
|
+
sessionId: recorder.sessionId,
|
|
2273
|
+
turnId: recorder.turnId,
|
|
2274
|
+
iteration,
|
|
2275
|
+
messages: recorder.messages,
|
|
2276
|
+
})
|
|
2277
|
+
} catch (error) {
|
|
2278
|
+
this.ctx.log.warn('A reminder source threw; the request goes without its reminders', {
|
|
2279
|
+
[NAMZU.TURN_ID]: recorder.turnId,
|
|
2280
|
+
[NAMZU.ITERATION]: iteration,
|
|
2281
|
+
'exception.message': error instanceof Error ? error.message : String(error),
|
|
2282
|
+
})
|
|
2283
|
+
return
|
|
2284
|
+
}
|
|
2285
|
+
for (const text of texts ?? []) {
|
|
2286
|
+
if (text.trim().length === 0) continue
|
|
2287
|
+
recorder.pushMessage(createRuntimeContextMessage(text, 'reminder'))
|
|
2288
|
+
}
|
|
2289
|
+
}
|
|
2290
|
+
|
|
1928
2291
|
private async deliverInbound(): Promise<number> {
|
|
1929
2292
|
const queued = this.ctx.inboundMessages?.() ?? []
|
|
1930
2293
|
for (const message of queued) {
|
|
@@ -2078,6 +2441,15 @@ export class IterationOrchestrator {
|
|
|
2078
2441
|
return true
|
|
2079
2442
|
}
|
|
2080
2443
|
|
|
2444
|
+
/** The compaction circuit breaker asked for the turn to stop (opt-in; see `compactionConfig.circuitBreaker`). */
|
|
2445
|
+
private stopForCompactionBreaker(): boolean {
|
|
2446
|
+
const reason = compactionBreaker(this.ctx)?.stop
|
|
2447
|
+
if (reason === undefined) return false
|
|
2448
|
+
this.ctx.recorder.setLastError(reason)
|
|
2449
|
+
this.ctx.recorder.setStopReason('error')
|
|
2450
|
+
return true
|
|
2451
|
+
}
|
|
2452
|
+
|
|
2081
2453
|
private async recordToolStructuredFailure(
|
|
2082
2454
|
results: readonly ToolCallOutcome[],
|
|
2083
2455
|
iteration: number,
|
|
@@ -2404,6 +2776,32 @@ export class IterationOrchestrator {
|
|
|
2404
2776
|
.some((t) => t.state !== 'completed' && t.state !== 'failed' && t.state !== 'canceled')
|
|
2405
2777
|
}
|
|
2406
2778
|
|
|
2779
|
+
/** Media the provider could not process was left out of a request that then went through. */
|
|
2780
|
+
private async noteMediaRemoved(removal: MediaRemoval): Promise<void> {
|
|
2781
|
+
this.ctx.log.warn('Media the provider rejected was left out of the request', {
|
|
2782
|
+
[GENAI.SYSTEM]: this.ctx.provider.id,
|
|
2783
|
+
'namzu.request.media_removed': removal.count,
|
|
2784
|
+
})
|
|
2785
|
+
const noun = removal.count === 1 ? 'a file' : `${removal.count} files`
|
|
2786
|
+
const it = removal.count === 1 ? 'it' : 'they'
|
|
2787
|
+
await this.ctx.emitEvent?.({
|
|
2788
|
+
type: 'capability_warning',
|
|
2789
|
+
turnId: this.ctx.recorder.turnId,
|
|
2790
|
+
capability: removal.kind === 'document' ? 'documents' : 'vision',
|
|
2791
|
+
// The person's own latest attachment is named as such; a count limit is
|
|
2792
|
+
// not a fault in any file.
|
|
2793
|
+
contentSource: removal.current
|
|
2794
|
+
? 'media-removed-current'
|
|
2795
|
+
: removal.limit
|
|
2796
|
+
? 'media-limit'
|
|
2797
|
+
: 'media-removed',
|
|
2798
|
+
providerId: this.ctx.provider.id,
|
|
2799
|
+
message: removal.limit
|
|
2800
|
+
? `The conversation holds more files than the provider accepts at once, so ${noun} (the oldest) ${removal.count === 1 ? 'was' : 'were'} left out of the request. The conversation still holds ${it}.`
|
|
2801
|
+
: `The provider could not process ${noun}${removal.current ? ' attached to your latest message' : ' in this conversation'}, so ${it} ${removal.count === 1 ? 'was' : 'were'} left out of the request. The conversation still holds ${it}.`,
|
|
2802
|
+
})
|
|
2803
|
+
}
|
|
2804
|
+
|
|
2407
2805
|
private async acceptProviderRejectedImage(identity: RequestImageIdentity): Promise<void> {
|
|
2408
2806
|
const repaired = markProviderRejectedImage(this.ctx.recorder.messages, identity)
|
|
2409
2807
|
if (repaired.count === 0) {
|
|
@@ -2461,6 +2859,7 @@ export class IterationOrchestrator {
|
|
|
2461
2859
|
const finalMessages = projectRequestRichContent(
|
|
2462
2860
|
this.projectObservations(finalHistory),
|
|
2463
2861
|
this.ctx.turnConfig.maxRequestRichContentBytes ?? DEFAULT_MAX_REQUEST_RICH_CONTENT_BYTES,
|
|
2862
|
+
{ imagesReadable: this.modelReadsImages(model) },
|
|
2464
2863
|
)
|
|
2465
2864
|
appendWorkContext(this.stepShaping(), finalMessages, this.steps.length + 1, { model })
|
|
2466
2865
|
// The closing directive is the last thing the model reads: after
|
|
@@ -2507,8 +2906,13 @@ export class IterationOrchestrator {
|
|
|
2507
2906
|
signal: this.ctx.abortController.signal,
|
|
2508
2907
|
} satisfies import('../../../types/provider/index.js').ChatCompletionParams
|
|
2509
2908
|
const response = await collectChatCompletion(
|
|
2510
|
-
streamWithProviderRejectedImageRecovery(
|
|
2511
|
-
this.
|
|
2909
|
+
streamWithProviderRejectedImageRecovery(
|
|
2910
|
+
this.ctx.provider,
|
|
2911
|
+
finalParams,
|
|
2912
|
+
(identity) => this.acceptProviderRejectedImage(identity),
|
|
2913
|
+
undefined,
|
|
2914
|
+
this.textOnlyRecovery(model),
|
|
2915
|
+
this.requestRepair,
|
|
2512
2916
|
),
|
|
2513
2917
|
)
|
|
2514
2918
|
|