@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
|
@@ -42,7 +42,11 @@ import { generateMessageId, generateToolCallId } from '../../../utils/id.js'
|
|
|
42
42
|
import type { Logger } from '../../../utils/logger.js'
|
|
43
43
|
import type { EmitEvent } from '../events.js'
|
|
44
44
|
import type { RequestImageIdentity } from '../request-rich-content.js'
|
|
45
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
type TextOnlyModelRecovery,
|
|
47
|
+
streamWithProviderRejectedImageRecovery,
|
|
48
|
+
} from './provider-rejected-image.js'
|
|
49
|
+
import type { RequestRepair } from './request-repair.js'
|
|
46
50
|
import {
|
|
47
51
|
type ParsedToolArguments,
|
|
48
52
|
capPartialArguments,
|
|
@@ -237,6 +241,10 @@ export async function* streamProviderTurn(
|
|
|
237
241
|
announceAs?: import('../../../types/ids/index.js').MessageId,
|
|
238
242
|
imageRecovery?: {
|
|
239
243
|
readonly onAccepted: (identity: RequestImageIdentity) => Promise<void>
|
|
244
|
+
/** A model refused the request for holding an image it cannot read; the retry sent none. */
|
|
245
|
+
readonly textOnly?: TextOnlyModelRecovery
|
|
246
|
+
/** Repairs and resends a request the provider rejects as invalid. */
|
|
247
|
+
readonly repair?: RequestRepair
|
|
240
248
|
},
|
|
241
249
|
captureRequest = false,
|
|
242
250
|
/** The session the turn belongs to, named on the chat span as `gen_ai.conversation.id`. */
|
|
@@ -363,6 +371,8 @@ export async function* streamProviderTurn(
|
|
|
363
371
|
streamParams,
|
|
364
372
|
imageRecovery.onAccepted,
|
|
365
373
|
observeRequest,
|
|
374
|
+
imageRecovery.textOnly,
|
|
375
|
+
imageRecovery.repair,
|
|
366
376
|
)
|
|
367
377
|
: provider.chatStream(streamParams)
|
|
368
378
|
) as AsyncIterable<StreamChunk>
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a call writes or removes that no mode may approve in advance.
|
|
3
|
+
*
|
|
4
|
+
* Three questions the kernel answers about a prepared call before it runs, all
|
|
5
|
+
* of them about the call's own arguments and none about the model's intent:
|
|
6
|
+
*
|
|
7
|
+
* - does it write a protected path (a git hook, a shell rc file, editor or
|
|
8
|
+
* tool configuration, the project's `.namzu` directory)?
|
|
9
|
+
* - does its shell line remove something catastrophic?
|
|
10
|
+
* - does its shell line reach a path outside the turn's roots, through a
|
|
11
|
+
* command whose operands are paths or through a redirection?
|
|
12
|
+
*
|
|
13
|
+
* The first two are floors: they hold in every mode, the way a sandbox escape
|
|
14
|
+
* does. The third is the existing outside-root boundary, extended from the
|
|
15
|
+
* file tools' one declared argument to the paths a shell line names.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { homedir } from 'node:os'
|
|
19
|
+
import { isAbsolute, relative, resolve } from 'node:path'
|
|
20
|
+
|
|
21
|
+
import { isProtectedPath } from '../../authorization/protected-paths.js'
|
|
22
|
+
import { dangerousRemoval } from '../../authorization/removal.js'
|
|
23
|
+
import type { ShellDialect } from '../../authorization/shell-lexer.js'
|
|
24
|
+
import { readShellLine, shellPathAccess } from '../../authorization/shell-paths.js'
|
|
25
|
+
import { canonicalize, pathOutsideRoots } from '../../tools/paths.js'
|
|
26
|
+
|
|
27
|
+
/** What the escalation records carry. */
|
|
28
|
+
export interface PathEscalations {
|
|
29
|
+
readonly outsidePaths: readonly string[]
|
|
30
|
+
readonly protectedPaths: readonly string[]
|
|
31
|
+
readonly dangerousRemoval?: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export interface PathEscalationContext {
|
|
35
|
+
/** The working directory first, then the added directories. */
|
|
36
|
+
readonly roots: readonly string[]
|
|
37
|
+
/** Whether to report paths outside the roots (`outsideRootAccess: 'review'`, no sandbox). */
|
|
38
|
+
readonly reviewOutside: boolean
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The part of `absolute` that protected names are looked for in.
|
|
43
|
+
*
|
|
44
|
+
* Inside a root (the working directory or an added directory) that is the part
|
|
45
|
+
* below the root, not the whole path: the root is where the turn was put, and
|
|
46
|
+
* a root that itself sits under a protected name is not a reason to ask about
|
|
47
|
+
* every file in it. The case that matters is the managed worktree a sub-agent
|
|
48
|
+
* runs in, `~/.namzu/projects/<slug>/worktrees/<name>`, which lies under
|
|
49
|
+
* `.namzu` by construction; the reference terminal makes the same exception
|
|
50
|
+
* for its own worktrees directory. A path in no root is looked at whole.
|
|
51
|
+
*/
|
|
52
|
+
function protectedScope(absolute: string, roots: readonly string[]): string {
|
|
53
|
+
let best: string | undefined
|
|
54
|
+
for (const root of roots) {
|
|
55
|
+
const base = resolve(root)
|
|
56
|
+
const below = relative(base, absolute)
|
|
57
|
+
if (below === '' || below.startsWith('..') || isAbsolute(below)) continue
|
|
58
|
+
if (best === undefined || below.length < best.length) best = below
|
|
59
|
+
}
|
|
60
|
+
return best ?? absolute
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** A write is protected when its spelling, or the place a link leads to, is. */
|
|
64
|
+
async function isProtectedWrite(
|
|
65
|
+
spelled: string,
|
|
66
|
+
absolute: string,
|
|
67
|
+
roots: readonly string[],
|
|
68
|
+
): Promise<boolean> {
|
|
69
|
+
if (isProtectedPath(isAbsolute(spelled) ? protectedScope(absolute, roots) : spelled)) return true
|
|
70
|
+
if (isProtectedPath(protectedScope(absolute, roots))) return true
|
|
71
|
+
const real = await canonicalize(absolute)
|
|
72
|
+
const realRoots = await Promise.all(roots.map((root) => canonicalize(resolve(root))))
|
|
73
|
+
return isProtectedPath(protectedScope(real, [...roots, ...realRoots]))
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/** `{a,b}` with plain comma lists, one level at a time, bounded. */
|
|
77
|
+
export function expandBraces(value: string, limit = 16): string[] {
|
|
78
|
+
const open = value.indexOf('{')
|
|
79
|
+
if (open < 0) return [value]
|
|
80
|
+
let depth = 0
|
|
81
|
+
let close = -1
|
|
82
|
+
const commas: number[] = []
|
|
83
|
+
for (let i = open; i < value.length; i += 1) {
|
|
84
|
+
const c = value[i]
|
|
85
|
+
if (c === '{') depth += 1
|
|
86
|
+
else if (c === '}') {
|
|
87
|
+
depth -= 1
|
|
88
|
+
if (depth === 0) {
|
|
89
|
+
close = i
|
|
90
|
+
break
|
|
91
|
+
}
|
|
92
|
+
} else if (c === ',' && depth === 1) commas.push(i)
|
|
93
|
+
}
|
|
94
|
+
if (close < 0 || commas.length === 0) return [value]
|
|
95
|
+
const head = value.slice(0, open)
|
|
96
|
+
const tail = value.slice(close + 1)
|
|
97
|
+
const parts: string[] = []
|
|
98
|
+
let start = open + 1
|
|
99
|
+
for (const comma of [...commas, close]) {
|
|
100
|
+
parts.push(value.slice(start, comma))
|
|
101
|
+
start = comma + 1
|
|
102
|
+
}
|
|
103
|
+
const out: string[] = []
|
|
104
|
+
for (const part of parts) {
|
|
105
|
+
for (const rest of expandBraces(head + part + tail, limit)) {
|
|
106
|
+
out.push(rest)
|
|
107
|
+
if (out.length >= limit) return out
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
return out
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/** The path a use names with `~` and `$HOME` read as the home directory, or why it cannot be. */
|
|
114
|
+
function settle(
|
|
115
|
+
value: string,
|
|
116
|
+
home: string,
|
|
117
|
+
): { readonly path: string } | { readonly unresolved: true } {
|
|
118
|
+
if (value === '~') return { path: home }
|
|
119
|
+
if (value.startsWith('~/')) return { path: resolve(home, value.slice(2)) }
|
|
120
|
+
if (value.startsWith('~')) return { unresolved: true }
|
|
121
|
+
const variable = /^\$(?:\{HOME\}|HOME)(?=\/|$)/.exec(value)
|
|
122
|
+
if (variable !== null) return { path: resolve(home, `.${value.slice(variable[0].length)}`) }
|
|
123
|
+
if (/[$`]/.test(value)) return { unresolved: true }
|
|
124
|
+
return { path: value }
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/** The part of a glob path before the first segment that holds a glob character. */
|
|
128
|
+
function beforeGlob(path: string): string {
|
|
129
|
+
const at = path.search(/[*?[]/)
|
|
130
|
+
if (at < 0) return path
|
|
131
|
+
const cut = path.lastIndexOf('/', at)
|
|
132
|
+
return cut <= 0 ? '/' : path.slice(0, cut)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** A write the file tool's own declared path argument names. */
|
|
136
|
+
export async function declaredWriteEscalation(
|
|
137
|
+
roots: readonly string[],
|
|
138
|
+
value: string,
|
|
139
|
+
): Promise<string | undefined> {
|
|
140
|
+
const [first] = roots
|
|
141
|
+
if (first === undefined || value === '') return undefined
|
|
142
|
+
const absolute = resolve(resolve(first), value)
|
|
143
|
+
return (await isProtectedWrite(value, absolute, roots)) ? absolute : undefined
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** What a shell line reaches. */
|
|
147
|
+
export async function shellEscalations(
|
|
148
|
+
line: string,
|
|
149
|
+
dialect: ShellDialect,
|
|
150
|
+
context: PathEscalationContext,
|
|
151
|
+
): Promise<PathEscalations> {
|
|
152
|
+
const reading = readShellLine(line, dialect)
|
|
153
|
+
const access = shellPathAccess(reading)
|
|
154
|
+
const [cwd, ...added] = context.roots
|
|
155
|
+
const outside = new Set<string>()
|
|
156
|
+
const protectedPaths = new Set<string>()
|
|
157
|
+
const home = homedir()
|
|
158
|
+
if (cwd !== undefined) {
|
|
159
|
+
for (const use of access.uses) {
|
|
160
|
+
for (const spelled of expandBraces(use.path)) {
|
|
161
|
+
const settled = settle(spelled, home)
|
|
162
|
+
const unresolved = use.unresolved || 'unresolved' in settled
|
|
163
|
+
const base = 'path' in settled ? settled.path : spelled
|
|
164
|
+
const absolute = isAbsolute(base) ? resolve(base) : resolve(cwd, base)
|
|
165
|
+
if (use.access === 'write' && (await isProtectedWrite(spelled, absolute, context.roots))) {
|
|
166
|
+
protectedPaths.add(absolute)
|
|
167
|
+
}
|
|
168
|
+
if (!context.reviewOutside) continue
|
|
169
|
+
if (unresolved) {
|
|
170
|
+
// A write whose target is decided at runtime cannot be checked; a
|
|
171
|
+
// read of one is left, as the reference leaves it.
|
|
172
|
+
if (use.access === 'write') outside.add(spelled)
|
|
173
|
+
continue
|
|
174
|
+
}
|
|
175
|
+
if (
|
|
176
|
+
access.changesDirectory &&
|
|
177
|
+
use.access === 'write' &&
|
|
178
|
+
!isAbsolute(base) &&
|
|
179
|
+
!spelled.startsWith('~')
|
|
180
|
+
) {
|
|
181
|
+
// A `cd` earlier in the line moves a relative target somewhere the
|
|
182
|
+
// roots cannot be compared with.
|
|
183
|
+
outside.add(spelled)
|
|
184
|
+
continue
|
|
185
|
+
}
|
|
186
|
+
const reached = await pathOutsideRoots(context.roots, beforeGlob(absolute))
|
|
187
|
+
if (reached !== undefined) outside.add(reached)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const removal =
|
|
192
|
+
cwd === undefined
|
|
193
|
+
? undefined
|
|
194
|
+
: dangerousRemoval(reading, access.changesDirectory, {
|
|
195
|
+
cwd,
|
|
196
|
+
additionalDirectories: added,
|
|
197
|
+
home,
|
|
198
|
+
})
|
|
199
|
+
return {
|
|
200
|
+
outsidePaths: [...outside],
|
|
201
|
+
protectedPaths: [...protectedPaths],
|
|
202
|
+
...(removal !== undefined ? { dangerousRemoval: removal } : {}),
|
|
203
|
+
}
|
|
204
|
+
}
|
|
@@ -27,6 +27,14 @@ export function applyLifecycleHookResults(
|
|
|
27
27
|
if (result.text.trim().length > 0) annotations.push(result.text.trim())
|
|
28
28
|
continue
|
|
29
29
|
case 'skip':
|
|
30
|
+
// `turn_end`, `subagent_stop` and `pre_compact` answer with `skip`
|
|
31
|
+
// to keep the turn going or to cancel a pass. The sites that can act
|
|
32
|
+
// on that read the results themselves; a site that cannot (the
|
|
33
|
+
// final `turn_end` of a turn that already ended) has nothing to
|
|
34
|
+
// refuse and carries on.
|
|
35
|
+
if (event === 'turn_end' || event === 'subagent_stop' || event === 'pre_compact') {
|
|
36
|
+
continue
|
|
37
|
+
}
|
|
30
38
|
// The one lifecycle event with a verdict: a hook may refuse the
|
|
31
39
|
// prompt before the model sees it, and the turn ends there.
|
|
32
40
|
if (event === 'user_prompt_submit') {
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { SessionId, TurnId } from '../../types/ids/index.js'
|
|
2
|
+
import type { Message } from '../../types/message/index.js'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* What a reminder source is told when the kernel asks it for hidden reminders.
|
|
6
|
+
*/
|
|
7
|
+
export interface ReminderContext {
|
|
8
|
+
readonly sessionId: SessionId
|
|
9
|
+
readonly turnId: TurnId
|
|
10
|
+
/** The model request about to be made; 1 for the first of the turn. */
|
|
11
|
+
readonly iteration: number
|
|
12
|
+
/**
|
|
13
|
+
* The conversation as it stands, reminders included. Read-only: a source
|
|
14
|
+
* derives its cadence from this (how many assistant turns since it last
|
|
15
|
+
* spoke), so a resumed or compacted conversation needs no counter of its own.
|
|
16
|
+
*/
|
|
17
|
+
readonly messages: readonly Message[]
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* A host's hidden reminders for the next model request.
|
|
22
|
+
*
|
|
23
|
+
* The kernel calls it once at the start of every model request of a turn
|
|
24
|
+
* (never the closing one) and appends each returned text to the conversation
|
|
25
|
+
* as a user-role message with provenance `{ type: 'runtime-context', kind:
|
|
26
|
+
* 'reminder' }`. The message is part of the durable history, so it is not
|
|
27
|
+
* operator input, never counts as the latest user request, and is not shown as
|
|
28
|
+
* something the operator typed. The channel is opt-in
|
|
29
|
+
* (`QueryParams.reminders`): a turn without a source behaves as before.
|
|
30
|
+
*
|
|
31
|
+
* A source that throws is treated as having nothing to say; a reminder is
|
|
32
|
+
* context, and a fault in one must not end a turn.
|
|
33
|
+
*/
|
|
34
|
+
export type ReminderSource = (
|
|
35
|
+
context: ReminderContext,
|
|
36
|
+
) => readonly string[] | undefined | Promise<readonly string[] | undefined>
|
|
37
|
+
|
|
38
|
+
/** Whether a message is a reminder the kernel appended for a {@link ReminderSource}. */
|
|
39
|
+
export function isReminderMessage(message: Message): boolean {
|
|
40
|
+
return (
|
|
41
|
+
message.role === 'user' &&
|
|
42
|
+
message.source?.type === 'runtime-context' &&
|
|
43
|
+
message.source.kind === 'reminder'
|
|
44
|
+
)
|
|
45
|
+
}
|
|
@@ -34,7 +34,8 @@ interface RichOccurrence {
|
|
|
34
34
|
readonly source: 'user' | 'tool'
|
|
35
35
|
readonly kind: RichKind
|
|
36
36
|
readonly bytes: number
|
|
37
|
-
readonly
|
|
37
|
+
readonly mediaType?: string
|
|
38
|
+
readonly reason: 'budget' | 'provider-rejected' | 'invalid-image' | 'model-text-only'
|
|
38
39
|
}
|
|
39
40
|
|
|
40
41
|
export interface RequestImageIdentity {
|
|
@@ -65,6 +66,24 @@ const invalidUserImageMarker = (): string =>
|
|
|
65
66
|
const invalidToolImageMarker = (): string =>
|
|
66
67
|
`[image omitted from this model request because the producing tool returned encoded bytes that are not a complete supported raster matching the declared media type. ${toolRecovery} Correct the image source before presenting it again.]`
|
|
67
68
|
|
|
69
|
+
/** `12 KB`-style size of an encoded payload, so the model can tell a thumbnail from a full screenshot. */
|
|
70
|
+
function describeEncodedSize(base64Length: number): string {
|
|
71
|
+
const bytes = Math.floor((base64Length * 3) / 4)
|
|
72
|
+
if (bytes < 1024) return `${bytes} B`
|
|
73
|
+
if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`
|
|
74
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* What stands in for an image the current model cannot read. It says so, and
|
|
79
|
+
* what the image was, because the model otherwise sees a tool that reported
|
|
80
|
+
* success next to nothing and tends to retry it or claim to have seen the screen.
|
|
81
|
+
*/
|
|
82
|
+
const textOnlyImageMarker = (mediaType: string | undefined, base64Length: number): string =>
|
|
83
|
+
`[image omitted: the current model cannot read images${
|
|
84
|
+
mediaType ? ` (${mediaType}, ${describeEncodedSize(base64Length)})` : ''
|
|
85
|
+
}]`
|
|
86
|
+
|
|
68
87
|
function assertInlineAttachment(
|
|
69
88
|
attachment: MessageAttachment,
|
|
70
89
|
): asserts attachment is Exclude<MessageAttachment, { readonly type: 'stored' }> {
|
|
@@ -75,7 +94,10 @@ function assertInlineAttachment(
|
|
|
75
94
|
}
|
|
76
95
|
}
|
|
77
96
|
|
|
78
|
-
function collectRichOccurrences(
|
|
97
|
+
function collectRichOccurrences(
|
|
98
|
+
messages: readonly Message[],
|
|
99
|
+
imagesReadable: boolean,
|
|
100
|
+
): RichOccurrence[] {
|
|
79
101
|
const occurrences: RichOccurrence[] = []
|
|
80
102
|
|
|
81
103
|
for (const [messageIndex, message] of messages.entries()) {
|
|
@@ -88,13 +110,17 @@ function collectRichOccurrences(messages: readonly Message[]): RichOccurrence[]
|
|
|
88
110
|
source: 'user',
|
|
89
111
|
kind: attachment.type === 'document' ? 'document' : 'image',
|
|
90
112
|
bytes: attachment.data.length,
|
|
113
|
+
mediaType: attachment.mediaType,
|
|
91
114
|
reason:
|
|
92
|
-
attachment.type !== 'document' &&
|
|
93
|
-
? '
|
|
115
|
+
attachment.type !== 'document' && !imagesReadable
|
|
116
|
+
? 'model-text-only'
|
|
94
117
|
: attachment.type !== 'document' &&
|
|
95
|
-
attachment.modelOmission?.reason === '
|
|
96
|
-
? '
|
|
97
|
-
: '
|
|
118
|
+
attachment.modelOmission?.reason === 'invalid-image'
|
|
119
|
+
? 'invalid-image'
|
|
120
|
+
: attachment.type !== 'document' &&
|
|
121
|
+
attachment.modelOmission?.reason === 'provider-rejected'
|
|
122
|
+
? 'provider-rejected'
|
|
123
|
+
: 'budget',
|
|
98
124
|
})
|
|
99
125
|
}
|
|
100
126
|
continue
|
|
@@ -109,12 +135,15 @@ function collectRichOccurrences(messages: readonly Message[]): RichOccurrence[]
|
|
|
109
135
|
source: 'tool',
|
|
110
136
|
kind: block.type,
|
|
111
137
|
bytes: block.data.length,
|
|
138
|
+
mediaType: block.mediaType,
|
|
112
139
|
reason:
|
|
113
|
-
block.type === 'image' &&
|
|
114
|
-
? '
|
|
115
|
-
: block.type === 'image' && block.modelOmission?.reason === '
|
|
116
|
-
? '
|
|
117
|
-
: '
|
|
140
|
+
block.type === 'image' && !imagesReadable
|
|
141
|
+
? 'model-text-only'
|
|
142
|
+
: block.type === 'image' && block.modelOmission?.reason === 'invalid-image'
|
|
143
|
+
? 'invalid-image'
|
|
144
|
+
: block.type === 'image' && block.modelOmission?.reason === 'provider-rejected'
|
|
145
|
+
? 'provider-rejected'
|
|
146
|
+
: 'budget',
|
|
118
147
|
})
|
|
119
148
|
}
|
|
120
149
|
}
|
|
@@ -130,11 +159,13 @@ function appendTextMarkers(content: string, markers: readonly string[]): string
|
|
|
130
159
|
|
|
131
160
|
function appendMarkers(content: string, occurrences: readonly RichOccurrence[]): string {
|
|
132
161
|
const markers = occurrences.map((occurrence) =>
|
|
133
|
-
occurrence.reason === '
|
|
134
|
-
?
|
|
135
|
-
: occurrence.reason === '
|
|
136
|
-
?
|
|
137
|
-
:
|
|
162
|
+
occurrence.reason === 'model-text-only'
|
|
163
|
+
? textOnlyImageMarker(occurrence.mediaType, occurrence.bytes)
|
|
164
|
+
: occurrence.reason === 'provider-rejected'
|
|
165
|
+
? rejectedUserImageMarker()
|
|
166
|
+
: occurrence.reason === 'invalid-image'
|
|
167
|
+
? invalidUserImageMarker()
|
|
168
|
+
: userMarker(occurrence.kind),
|
|
138
169
|
)
|
|
139
170
|
return appendTextMarkers(content, markers)
|
|
140
171
|
}
|
|
@@ -148,8 +179,12 @@ function appendMarkers(content: string, occurrences: readonly RichOccurrence[]):
|
|
|
148
179
|
* original array when nothing is omitted makes the no-op and exact-boundary
|
|
149
180
|
* cases observable and keeps the common path allocation-free.
|
|
150
181
|
*/
|
|
151
|
-
export function projectRequestRichContent(
|
|
152
|
-
|
|
182
|
+
export function projectRequestRichContent(
|
|
183
|
+
messages: Message[],
|
|
184
|
+
maxBytes: number,
|
|
185
|
+
options: { readonly imagesReadable?: boolean } = {},
|
|
186
|
+
): Message[] {
|
|
187
|
+
const occurrences = collectRichOccurrences(messages, options.imagesReadable ?? true)
|
|
153
188
|
if (occurrences.length === 0) return messages
|
|
154
189
|
|
|
155
190
|
const omitted = new Map<number, Map<number, RichOccurrence>>()
|
|
@@ -163,9 +198,7 @@ export function projectRequestRichContent(messages: Message[], maxBytes: number)
|
|
|
163
198
|
}
|
|
164
199
|
|
|
165
200
|
for (const occurrence of occurrences) {
|
|
166
|
-
if (occurrence.reason
|
|
167
|
-
omit(occurrence)
|
|
168
|
-
}
|
|
201
|
+
if (occurrence.reason !== 'budget') omit(occurrence)
|
|
169
202
|
}
|
|
170
203
|
|
|
171
204
|
let total = occurrences.reduce(
|
|
@@ -206,11 +239,13 @@ export function projectRequestRichContent(messages: Message[], maxBytes: number)
|
|
|
206
239
|
? {
|
|
207
240
|
type: 'text',
|
|
208
241
|
text:
|
|
209
|
-
occurrence.reason === '
|
|
210
|
-
?
|
|
211
|
-
: occurrence.reason === '
|
|
212
|
-
?
|
|
213
|
-
:
|
|
242
|
+
occurrence.reason === 'model-text-only'
|
|
243
|
+
? textOnlyImageMarker(occurrence.mediaType, occurrence.bytes)
|
|
244
|
+
: occurrence.reason === 'provider-rejected'
|
|
245
|
+
? rejectedToolImageMarker()
|
|
246
|
+
: occurrence.reason === 'invalid-image'
|
|
247
|
+
? invalidToolImageMarker()
|
|
248
|
+
: toolMarker(occurrence.kind),
|
|
214
249
|
}
|
|
215
250
|
: block
|
|
216
251
|
})
|
|
@@ -221,6 +256,21 @@ export function projectRequestRichContent(messages: Message[], maxBytes: number)
|
|
|
221
256
|
})
|
|
222
257
|
}
|
|
223
258
|
|
|
259
|
+
/** Whether the provider-bound request carries an image anywhere, in a user attachment or a tool result. */
|
|
260
|
+
export function requestHasImages(messages: readonly Message[]): boolean {
|
|
261
|
+
for (const message of messages) {
|
|
262
|
+
if (message.role === 'user') {
|
|
263
|
+
for (const attachment of message.attachments ?? []) {
|
|
264
|
+
if (attachment.type !== 'stored' && attachment.type !== 'document') return true
|
|
265
|
+
}
|
|
266
|
+
continue
|
|
267
|
+
}
|
|
268
|
+
if (message.role !== 'tool' || !Array.isArray(message.content)) continue
|
|
269
|
+
if (message.content.some((block) => block.type === 'image')) return true
|
|
270
|
+
}
|
|
271
|
+
return false
|
|
272
|
+
}
|
|
273
|
+
|
|
224
274
|
function sameImage(
|
|
225
275
|
image: { readonly data: string; readonly mediaType: string },
|
|
226
276
|
identity: RequestImageIdentity,
|
|
@@ -517,6 +517,24 @@ export async function applyPendingResume(
|
|
|
517
517
|
reason: "the turn's review approved this call, answered across a restart",
|
|
518
518
|
})
|
|
519
519
|
}
|
|
520
|
+
for (const path of call.escalation?.protectedPaths ?? []) {
|
|
521
|
+
await recorder.recordAudit({
|
|
522
|
+
what: { action: 'protected_path_write', tool: call.name, resource: path },
|
|
523
|
+
outcome: 'approved',
|
|
524
|
+
reason: "the turn's review approved this call, answered across a restart",
|
|
525
|
+
})
|
|
526
|
+
}
|
|
527
|
+
if (call.escalation?.dangerousRemoval !== undefined) {
|
|
528
|
+
await recorder.recordAudit({
|
|
529
|
+
what: {
|
|
530
|
+
action: 'dangerous_removal',
|
|
531
|
+
tool: call.name,
|
|
532
|
+
resource: call.escalation.dangerousRemoval,
|
|
533
|
+
},
|
|
534
|
+
outcome: 'approved',
|
|
535
|
+
reason: "the turn's review approved this call, answered across a restart",
|
|
536
|
+
})
|
|
537
|
+
}
|
|
520
538
|
}
|
|
521
539
|
|
|
522
540
|
// The parked assistant message is already in the log: it goes back into
|
|
@@ -562,6 +580,15 @@ export function escalationRefusal(
|
|
|
562
580
|
for (const path of escalation.outsidePaths ?? []) {
|
|
563
581
|
if (!shown?.outsidePaths?.includes(path)) return refusal
|
|
564
582
|
}
|
|
583
|
+
for (const path of escalation.protectedPaths ?? []) {
|
|
584
|
+
if (!shown?.protectedPaths?.includes(path)) return refusal
|
|
585
|
+
}
|
|
586
|
+
if (
|
|
587
|
+
escalation.dangerousRemoval !== undefined &&
|
|
588
|
+
shown?.dangerousRemoval !== escalation.dangerousRemoval
|
|
589
|
+
) {
|
|
590
|
+
return refusal
|
|
591
|
+
}
|
|
565
592
|
if (escalation.sandboxEscape && (!shown?.sandboxEscape || !confirmed?.includes(id))) {
|
|
566
593
|
return 'Refused after resume: running this command outside the sandbox needs a person to confirm it for this call, and the durable approval did not.'
|
|
567
594
|
}
|