@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
|
@@ -12,7 +12,13 @@
|
|
|
12
12
|
|
|
13
13
|
import { z } from 'zod'
|
|
14
14
|
import type { PendingAnswers, QuestionParkRecorder } from '../../runtime/query/question-park.js'
|
|
15
|
-
import type {
|
|
15
|
+
import type {
|
|
16
|
+
HITLResumeDecision,
|
|
17
|
+
ResumeHandler,
|
|
18
|
+
UserQuestionData,
|
|
19
|
+
UserQuestionItem,
|
|
20
|
+
UserQuestionOption,
|
|
21
|
+
} from '../../types/hitl/index.js'
|
|
16
22
|
import type { SessionId, TurnId } from '../../types/ids/index.js'
|
|
17
23
|
import type { ToolDefinition } from '../../types/tool/index.js'
|
|
18
24
|
import { generateCheckpointId } from '../../utils/id.js'
|
|
@@ -31,7 +37,7 @@ export const ASK_USER_QUESTION_TOOL_NAME = 'ask_user_question' as const
|
|
|
31
37
|
* `additionalProperties: false` turns that into a refusal at generation time
|
|
32
38
|
* rather than a rejection after the fact.
|
|
33
39
|
*/
|
|
34
|
-
const
|
|
40
|
+
const askUserQuestionItemModelSchema: Record<string, unknown> = {
|
|
35
41
|
type: 'object',
|
|
36
42
|
properties: {
|
|
37
43
|
question: {
|
|
@@ -40,7 +46,8 @@ const askUserQuestionModelInputSchema: Record<string, unknown> = {
|
|
|
40
46
|
},
|
|
41
47
|
header: {
|
|
42
48
|
type: 'string',
|
|
43
|
-
description:
|
|
49
|
+
description:
|
|
50
|
+
'Optional very short topic label, no more than 24 characters; unique within the call.',
|
|
44
51
|
},
|
|
45
52
|
options: {
|
|
46
53
|
type: 'array',
|
|
@@ -62,6 +69,11 @@ const askUserQuestionModelInputSchema: Record<string, unknown> = {
|
|
|
62
69
|
description:
|
|
63
70
|
'True on the option you recommend; put that option first. The host shows the recommendation, so never write it into the label.',
|
|
64
71
|
},
|
|
72
|
+
preview: {
|
|
73
|
+
type: 'string',
|
|
74
|
+
description:
|
|
75
|
+
'Optional plain text or markdown shown beside the options while this one is focused: a snippet, a mock-up, a side-by-side. Leave it out unless it helps the choice.',
|
|
76
|
+
},
|
|
65
77
|
},
|
|
66
78
|
required: ['label'],
|
|
67
79
|
additionalProperties: false,
|
|
@@ -80,6 +92,135 @@ const askUserQuestionModelInputSchema: Record<string, unknown> = {
|
|
|
80
92
|
additionalProperties: false,
|
|
81
93
|
}
|
|
82
94
|
|
|
95
|
+
/**
|
|
96
|
+
* The single closed shape a capable provider constrains this call to: a
|
|
97
|
+
* `questions` array of one to four questions. The older single-question
|
|
98
|
+
* input (`question` and `options` at the top level) is still accepted at
|
|
99
|
+
* run time as a one-element batch, but is not offered to the model.
|
|
100
|
+
*/
|
|
101
|
+
const askUserQuestionModelInputSchema: Record<string, unknown> = {
|
|
102
|
+
type: 'object',
|
|
103
|
+
properties: {
|
|
104
|
+
questions: {
|
|
105
|
+
type: 'array',
|
|
106
|
+
description:
|
|
107
|
+
'A JSON array of 1-4 questions. Batch only related decisions that all block your next step; ask a single decision as one entry.',
|
|
108
|
+
items: askUserQuestionItemModelSchema,
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
required: ['questions'],
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** The most questions one call may carry. */
|
|
116
|
+
export const MAX_QUESTIONS_PER_CALL = 4
|
|
117
|
+
|
|
118
|
+
const optionSchema = z
|
|
119
|
+
.object({
|
|
120
|
+
label: z
|
|
121
|
+
.string()
|
|
122
|
+
.min(1)
|
|
123
|
+
.max(80)
|
|
124
|
+
.describe(
|
|
125
|
+
'Concise option label (1-5 words), plain text: no "(Recommended)" or other parenthesised note at the end.',
|
|
126
|
+
),
|
|
127
|
+
description: z
|
|
128
|
+
.string()
|
|
129
|
+
.max(300)
|
|
130
|
+
.optional()
|
|
131
|
+
.describe('One line on what practically changes if this option is chosen.'),
|
|
132
|
+
recommended: z
|
|
133
|
+
.boolean()
|
|
134
|
+
.optional()
|
|
135
|
+
.describe(
|
|
136
|
+
'True on the option you recommend; put it first. Never write the recommendation into the label.',
|
|
137
|
+
),
|
|
138
|
+
preview: z
|
|
139
|
+
.string()
|
|
140
|
+
.max(4000)
|
|
141
|
+
.optional()
|
|
142
|
+
.describe(
|
|
143
|
+
'Optional plain text or markdown shown beside the options while this one is focused.',
|
|
144
|
+
),
|
|
145
|
+
})
|
|
146
|
+
.strict()
|
|
147
|
+
|
|
148
|
+
const questionSchema = z
|
|
149
|
+
.object({
|
|
150
|
+
question: z
|
|
151
|
+
.string()
|
|
152
|
+
.min(1)
|
|
153
|
+
.describe('Full question text — clear, specific, ends with a question mark.'),
|
|
154
|
+
header: z
|
|
155
|
+
.string()
|
|
156
|
+
.max(24)
|
|
157
|
+
.optional()
|
|
158
|
+
.describe('Very short topic label for the question (e.g. "Audience", "Auth method").'),
|
|
159
|
+
options: z
|
|
160
|
+
.array(optionSchema)
|
|
161
|
+
.min(2)
|
|
162
|
+
.max(4)
|
|
163
|
+
.describe('2-4 genuinely distinct, context-derived options.'),
|
|
164
|
+
multiSelect: z
|
|
165
|
+
.boolean()
|
|
166
|
+
.optional()
|
|
167
|
+
.default(false)
|
|
168
|
+
.describe('True only when several options can apply at once.'),
|
|
169
|
+
allowFreeText: z
|
|
170
|
+
.boolean()
|
|
171
|
+
.optional()
|
|
172
|
+
.default(true)
|
|
173
|
+
.describe('Whether the user may answer in their own words.'),
|
|
174
|
+
})
|
|
175
|
+
.strict()
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* The old single-question input is a one-element batch. Anything that has
|
|
179
|
+
* `questions` is left alone, so a call mixing both shapes fails the strict
|
|
180
|
+
* object below instead of silently dropping one.
|
|
181
|
+
*/
|
|
182
|
+
function batchFromLegacy(input: unknown): unknown {
|
|
183
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) return input
|
|
184
|
+
const record = input as Record<string, unknown>
|
|
185
|
+
if ('questions' in record || !('question' in record)) return input
|
|
186
|
+
return { questions: [record] }
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const inputSchema = z
|
|
190
|
+
.preprocess(
|
|
191
|
+
batchFromLegacy,
|
|
192
|
+
z
|
|
193
|
+
.object({
|
|
194
|
+
questions: z
|
|
195
|
+
.array(questionSchema)
|
|
196
|
+
.min(1)
|
|
197
|
+
.max(MAX_QUESTIONS_PER_CALL)
|
|
198
|
+
.describe('1-4 related questions, asked together; one answer comes back per question.'),
|
|
199
|
+
})
|
|
200
|
+
.strict(),
|
|
201
|
+
)
|
|
202
|
+
.superRefine((value, ctx) => {
|
|
203
|
+
const questions = value.questions.map((q) => q.question.trim().toLowerCase())
|
|
204
|
+
if (new Set(questions).size !== questions.length) {
|
|
205
|
+
ctx.addIssue({
|
|
206
|
+
code: 'custom',
|
|
207
|
+
path: ['questions'],
|
|
208
|
+
message: 'Question texts must be unique within one call.',
|
|
209
|
+
})
|
|
210
|
+
}
|
|
211
|
+
const headers = value.questions.flatMap((q) =>
|
|
212
|
+
q.header !== undefined ? [q.header.trim().toLowerCase()] : [],
|
|
213
|
+
)
|
|
214
|
+
if (new Set(headers).size !== headers.length) {
|
|
215
|
+
ctx.addIssue({
|
|
216
|
+
code: 'custom',
|
|
217
|
+
path: ['questions'],
|
|
218
|
+
message:
|
|
219
|
+
'Headers must be unique within one call: a host uses them as tab labels and answer keys.',
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
})
|
|
223
|
+
|
|
83
224
|
export interface AskUserQuestionToolOptions {
|
|
84
225
|
/** Where the question goes; the turn parks on it until an answer comes back. */
|
|
85
226
|
resumeHandler: ResumeHandler
|
|
@@ -96,68 +237,141 @@ export interface AskUserQuestionToolOptions {
|
|
|
96
237
|
pendingAnswers?: PendingAnswers
|
|
97
238
|
}
|
|
98
239
|
|
|
240
|
+
const NO_ANSWER_TEXT =
|
|
241
|
+
'The user did not answer this question. Do not assume a choice or consent; proceed on your best judgment or continue without this information.'
|
|
242
|
+
|
|
243
|
+
const NO_ANSWER_BATCH_TEXT =
|
|
244
|
+
'The user did not answer these questions. Do not assume a choice or consent; proceed on your best judgment or continue without this information.'
|
|
245
|
+
|
|
246
|
+
/** One question's answer as the tool reads it, after the host's entry is checked. */
|
|
247
|
+
interface ReadAnswer {
|
|
248
|
+
readonly item: UserQuestionItem
|
|
249
|
+
readonly selected: readonly {
|
|
250
|
+
id: string
|
|
251
|
+
label: string
|
|
252
|
+
recommended?: true
|
|
253
|
+
}[]
|
|
254
|
+
readonly freeText: string
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const isAnswered = (answer: ReadAnswer): boolean =>
|
|
258
|
+
answer.selected.length > 0 || answer.freeText !== ''
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Which answer belongs to which question. `answers` is the batch form; a
|
|
262
|
+
* decision without it answers the FIRST question only — the shape a host
|
|
263
|
+
* that predates batches sends, and what a single-question call has always
|
|
264
|
+
* received. An entry that names no question of this call, or names one
|
|
265
|
+
* twice, is dropped: it was meant for something else.
|
|
266
|
+
*/
|
|
267
|
+
function readAnswers(
|
|
268
|
+
items: readonly UserQuestionItem[],
|
|
269
|
+
decision: Extract<HITLResumeDecision, { action: 'answer_question' }>,
|
|
270
|
+
): ReadAnswer[] {
|
|
271
|
+
const entries =
|
|
272
|
+
decision.answers ??
|
|
273
|
+
(items[0]
|
|
274
|
+
? [
|
|
275
|
+
{
|
|
276
|
+
questionId: items[0].id,
|
|
277
|
+
selectedOptionIds: decision.selectedOptionIds,
|
|
278
|
+
freeText: decision.freeText,
|
|
279
|
+
},
|
|
280
|
+
]
|
|
281
|
+
: [])
|
|
282
|
+
const byId = new Map<string, (typeof entries)[number]>()
|
|
283
|
+
for (const entry of entries) {
|
|
284
|
+
if (!byId.has(entry.questionId)) byId.set(entry.questionId, entry)
|
|
285
|
+
}
|
|
286
|
+
return items.map((item) => {
|
|
287
|
+
const entry = byId.get(item.id)
|
|
288
|
+
// The label the user saw, never a marker: `questionOptions` took it
|
|
289
|
+
// out. Whether it was the recommended option is a field of its own.
|
|
290
|
+
const chosen = (entry?.selectedOptionIds ?? [])
|
|
291
|
+
.map((id) => item.options.find((opt) => opt.id === id))
|
|
292
|
+
.filter((opt): opt is UserQuestionOption => opt !== undefined)
|
|
293
|
+
const selected = (item.multiSelect ? chosen : chosen.slice(0, 1)).map((opt) => ({
|
|
294
|
+
id: opt.id,
|
|
295
|
+
label: opt.label,
|
|
296
|
+
...(opt.recommended === true ? { recommended: true as const } : {}),
|
|
297
|
+
}))
|
|
298
|
+
return { item, selected, freeText: entry?.freeText?.trim() ?? '' }
|
|
299
|
+
})
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
function describeSingle(answer: ReadAnswer): {
|
|
303
|
+
output: string
|
|
304
|
+
data: Record<string, unknown>
|
|
305
|
+
} {
|
|
306
|
+
const { item, selected, freeText } = answer
|
|
307
|
+
let output: string
|
|
308
|
+
if (selected.length > 0) {
|
|
309
|
+
const joined = selected.map((s) => `"${s.label}"`).join(', ')
|
|
310
|
+
output = `User answered "${item.question}": ${joined}`
|
|
311
|
+
if (freeText) output += `\nAdditional note from the user: "${freeText}"`
|
|
312
|
+
} else {
|
|
313
|
+
output = `User answered "${item.question}" in their own words: "${freeText}"`
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
output,
|
|
317
|
+
data: {
|
|
318
|
+
question: item.question,
|
|
319
|
+
selected,
|
|
320
|
+
...(freeText ? { freeText } : {}),
|
|
321
|
+
answered: true,
|
|
322
|
+
},
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
const labelOf = (item: UserQuestionItem): string => item.header ?? item.question
|
|
327
|
+
|
|
328
|
+
function describeBatch(answers: readonly ReadAnswer[]): {
|
|
329
|
+
output: string
|
|
330
|
+
data: Record<string, unknown>
|
|
331
|
+
} {
|
|
332
|
+
const lines = answers.map((answer) => {
|
|
333
|
+
const { item, selected, freeText } = answer
|
|
334
|
+
if (selected.length > 0) {
|
|
335
|
+
const joined = selected.map((s) => `"${s.label}"`).join(', ')
|
|
336
|
+
return `${labelOf(item)}: ${joined}${freeText ? ` (note: "${freeText}")` : ''}`
|
|
337
|
+
}
|
|
338
|
+
if (freeText) return `${labelOf(item)} (own words): "${freeText}"`
|
|
339
|
+
return `${labelOf(item)}: not answered, assume nothing`
|
|
340
|
+
})
|
|
341
|
+
const answered = answers.filter(isAnswered).length
|
|
342
|
+
return {
|
|
343
|
+
output: `The user answered ${answered} of ${answers.length} questions:\n${lines.join('\n')}`,
|
|
344
|
+
data: {
|
|
345
|
+
questions: answers.map(({ item }) => ({
|
|
346
|
+
questionId: item.id,
|
|
347
|
+
...(item.header !== undefined ? { header: item.header } : {}),
|
|
348
|
+
question: item.question,
|
|
349
|
+
})),
|
|
350
|
+
answers: answers.map((answer) => ({
|
|
351
|
+
questionId: answer.item.id,
|
|
352
|
+
...(answer.item.header !== undefined ? { header: answer.item.header } : {}),
|
|
353
|
+
question: answer.item.question,
|
|
354
|
+
selected: answer.selected,
|
|
355
|
+
...(answer.freeText ? { freeText: answer.freeText } : {}),
|
|
356
|
+
answered: isAnswered(answer),
|
|
357
|
+
})),
|
|
358
|
+
answered: true,
|
|
359
|
+
},
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
99
363
|
export function buildAskUserQuestionTool(config: AskUserQuestionToolOptions): ToolDefinition {
|
|
100
364
|
const parkHandler = config.resumeHandler
|
|
101
365
|
const { questionParks, pendingAnswers } = config
|
|
102
366
|
return defineTool({
|
|
103
367
|
name: ASK_USER_QUESTION_TOOL_NAME,
|
|
104
368
|
description:
|
|
105
|
-
'Ask the user
|
|
106
|
-
inputSchema
|
|
107
|
-
.object({
|
|
108
|
-
question: z
|
|
109
|
-
.string()
|
|
110
|
-
.min(1)
|
|
111
|
-
.describe('Full question text — clear, specific, ends with a question mark.'),
|
|
112
|
-
header: z
|
|
113
|
-
.string()
|
|
114
|
-
.max(24)
|
|
115
|
-
.optional()
|
|
116
|
-
.describe('Very short topic label for the question (e.g. "Audience", "Auth method").'),
|
|
117
|
-
options: z
|
|
118
|
-
.array(
|
|
119
|
-
z
|
|
120
|
-
.object({
|
|
121
|
-
label: z
|
|
122
|
-
.string()
|
|
123
|
-
.min(1)
|
|
124
|
-
.max(80)
|
|
125
|
-
.describe(
|
|
126
|
-
'Concise option label (1-5 words), plain text: no "(Recommended)" or other parenthesised note at the end.',
|
|
127
|
-
),
|
|
128
|
-
description: z
|
|
129
|
-
.string()
|
|
130
|
-
.max(300)
|
|
131
|
-
.optional()
|
|
132
|
-
.describe('One line on what practically changes if this option is chosen.'),
|
|
133
|
-
recommended: z
|
|
134
|
-
.boolean()
|
|
135
|
-
.optional()
|
|
136
|
-
.describe(
|
|
137
|
-
'True on the option you recommend; put it first. Never write the recommendation into the label.',
|
|
138
|
-
),
|
|
139
|
-
})
|
|
140
|
-
.strict(),
|
|
141
|
-
)
|
|
142
|
-
.min(2)
|
|
143
|
-
.max(4)
|
|
144
|
-
.describe('2-4 genuinely distinct, context-derived options.'),
|
|
145
|
-
multiSelect: z
|
|
146
|
-
.boolean()
|
|
147
|
-
.optional()
|
|
148
|
-
.default(false)
|
|
149
|
-
.describe('True only when several options can apply at once.'),
|
|
150
|
-
allowFreeText: z
|
|
151
|
-
.boolean()
|
|
152
|
-
.optional()
|
|
153
|
-
.default(true)
|
|
154
|
-
.describe('Whether the user may answer in their own words.'),
|
|
155
|
-
})
|
|
156
|
-
.strict(),
|
|
369
|
+
'Ask the user when you are blocked on a decision that is genuinely theirs to make — one you cannot resolve from their request, your tools, the files you can read, or sensible defaults. The question must be the genuinely undecidable thing in THIS task. Never ask for information a tool can discover (do not ask what you can read, list, or search), never re-ask what the conversation already answers, and never ask meta-questions like "Shall I proceed?" — plan ratification goes through approve_plan. Provide 2-4 genuinely distinct options derived from the actual context — concrete paths, never generic placeholders (for example, asked to prepare a presentation, ask "Who is the audience?" with options like Board / Engineering team / Customer); keep labels short (1-5 words) and give each option a one-line description of what practically changes if it is chosen. If you recommend an option, put it FIRST and set recommended: true on it; the host marks it for the user, so never write "(Recommended)" or any translation of it into a label, and never end a label with a parenthesised note (put qualifiers in the description). Set multiSelect: true only when several options can apply at once. An option may carry a preview (plain text or markdown) that the host shows beside the list while it is focused; use it only when seeing the thing helps the choice. A free-text "Something else" escape hatch is always shown automatically — do not add your own "Other" option. Put the questions in the questions array. Use ONE entry for a single decision. Put several entries in the same call only when they are related decisions that ALL block your next step and the user can answer them together (for example which account, for what purpose, which environment before a credentialed step), at most 4, each with a short unique header; the user answers them all in one card and you get one answer per question. Never batch questions that depend on one another\'s answers — ask the first, then decide. Most work needs at most 2-3 questions in all, so prefer proceeding on stated defaults over interrogating the user. Never invent answers or synthetic content on the user\'s behalf unless they explicitly asked for a random/test scenario. The answers arrive as this tool\'s result; a question the result says was not answered must not be assumed, and if the result says the user did not answer at all, do not ask again — proceed on your best judgment without assuming consent.',
|
|
370
|
+
inputSchema,
|
|
157
371
|
modelInputSchema: structuredClone(askUserQuestionModelInputSchema),
|
|
158
372
|
enforceModelInput: true,
|
|
159
373
|
validationErrorHint:
|
|
160
|
-
'Required shape: {"question":"...?","options":[{"label":"First","description":"What changes","recommended":true},{"label":"Second","description":"What changes"}]}. "options" must be a JSON array of 2-4 objects, never a string.',
|
|
374
|
+
'Required shape: {"questions":[{"question":"...?","header":"Short","options":[{"label":"First","description":"What changes","recommended":true},{"label":"Second","description":"What changes"}]}]}. "questions" must be a JSON array of 1-4 objects. "options" must be a JSON array of 2-4 objects, never a string. Question texts and headers must be unique within one call.',
|
|
161
375
|
category: 'custom',
|
|
162
376
|
permissions: [],
|
|
163
377
|
readOnly: true,
|
|
@@ -168,7 +382,11 @@ export function buildAskUserQuestionTool(config: AskUserQuestionToolOptions): To
|
|
|
168
382
|
// registries by turn — concurrent parks on one turn clobber each
|
|
169
383
|
// other and the first promise never resolves (the turn hangs to TTL).
|
|
170
384
|
concurrencySafe: false,
|
|
171
|
-
async execute(
|
|
385
|
+
async execute(input, context) {
|
|
386
|
+
// A host that calls the tool without going through the registry
|
|
387
|
+
// hands over the older single-question shape or unfilled defaults;
|
|
388
|
+
// parsing again is a no-op for input the registry already parsed.
|
|
389
|
+
const { questions } = inputSchema.parse(input)
|
|
172
390
|
const toolUseId = context.toolUseId
|
|
173
391
|
if (!toolUseId) {
|
|
174
392
|
// Without the executing tool_use_id the question has no
|
|
@@ -186,15 +404,28 @@ export function buildAskUserQuestionTool(config: AskUserQuestionToolOptions): To
|
|
|
186
404
|
// Labels without a recommendation marker, in any language, and the
|
|
187
405
|
// recommendation as a field: what the host shows and what the
|
|
188
406
|
// answer below quotes back to the model.
|
|
189
|
-
const
|
|
407
|
+
const items: UserQuestionItem[] = questions.map((q, index) => ({
|
|
408
|
+
id: `${toolUseId}#${index}`,
|
|
409
|
+
question: q.question,
|
|
410
|
+
...(q.header !== undefined ? { header: q.header } : {}),
|
|
411
|
+
options: questionOptions(q.options),
|
|
412
|
+
multiSelect: q.multiSelect,
|
|
413
|
+
allowFreeText: q.allowFreeText,
|
|
414
|
+
}))
|
|
415
|
+
const batch = items.length > 1
|
|
416
|
+
const [first] = items
|
|
417
|
+
if (!first) return { success: false, output: '', error: 'No question was asked.' }
|
|
190
418
|
|
|
191
|
-
|
|
419
|
+
// The top level mirrors the first question, so a host that does
|
|
420
|
+
// not know `questions` still shows and answers a real question.
|
|
421
|
+
const questionData: UserQuestionData = {
|
|
192
422
|
questionId: toolUseId,
|
|
193
|
-
question,
|
|
194
|
-
...(header !== undefined ? { header } : {}),
|
|
195
|
-
options:
|
|
196
|
-
multiSelect,
|
|
197
|
-
allowFreeText,
|
|
423
|
+
question: first.question,
|
|
424
|
+
...(first.header !== undefined ? { header: first.header } : {}),
|
|
425
|
+
options: first.options,
|
|
426
|
+
multiSelect: first.multiSelect,
|
|
427
|
+
allowFreeText: first.allowFreeText,
|
|
428
|
+
...(batch ? { questions: items } : {}),
|
|
198
429
|
}
|
|
199
430
|
|
|
200
431
|
// An answer carried in from a resumed turn. Checked before the
|
|
@@ -237,17 +468,23 @@ export function buildAskUserQuestionTool(config: AskUserQuestionToolOptions): To
|
|
|
237
468
|
// carry a different question's id.
|
|
238
469
|
const noAnswer = {
|
|
239
470
|
success: true,
|
|
240
|
-
output:
|
|
241
|
-
|
|
242
|
-
|
|
471
|
+
output: batch ? NO_ANSWER_BATCH_TEXT : NO_ANSWER_TEXT,
|
|
472
|
+
data: batch
|
|
473
|
+
? {
|
|
474
|
+
question: first.question,
|
|
475
|
+
questions: items.map((i) => i.question),
|
|
476
|
+
answered: false,
|
|
477
|
+
}
|
|
478
|
+
: { question: first.question, answered: false },
|
|
243
479
|
}
|
|
244
480
|
|
|
245
481
|
if (decision.action === 'abort') {
|
|
482
|
+
// One decline ends the whole batch: there is no partial refusal.
|
|
246
483
|
return {
|
|
247
484
|
success: false,
|
|
248
485
|
output:
|
|
249
486
|
'The user declined to answer and asked to stop. Acknowledge briefly and end your turn.',
|
|
250
|
-
data: { question, answered: false, declined: true },
|
|
487
|
+
data: { question: first.question, answered: false, declined: true },
|
|
251
488
|
}
|
|
252
489
|
}
|
|
253
490
|
|
|
@@ -259,42 +496,11 @@ export function buildAskUserQuestionTool(config: AskUserQuestionToolOptions): To
|
|
|
259
496
|
return noAnswer
|
|
260
497
|
}
|
|
261
498
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
const selected = decision.selectedOptionIds
|
|
265
|
-
.map((id) => shownOptions.find((opt) => opt.id === id))
|
|
266
|
-
.filter((opt): opt is UserQuestionOption => opt !== undefined)
|
|
267
|
-
.map((opt) => ({
|
|
268
|
-
id: opt.id,
|
|
269
|
-
label: opt.label,
|
|
270
|
-
...(opt.recommended === true ? { recommended: true } : {}),
|
|
271
|
-
}))
|
|
272
|
-
|
|
273
|
-
const freeText = decision.freeText?.trim() ?? ''
|
|
274
|
-
|
|
275
|
-
if (selected.length === 0 && !freeText) return noAnswer
|
|
276
|
-
|
|
277
|
-
let output: string
|
|
278
|
-
if (selected.length > 0) {
|
|
279
|
-
const joined = selected.map((s) => `"${s.label}"`).join(', ')
|
|
280
|
-
output = `User answered "${question}": ${joined}`
|
|
281
|
-
if (freeText) {
|
|
282
|
-
output += `\nAdditional note from the user: "${freeText}"`
|
|
283
|
-
}
|
|
284
|
-
} else {
|
|
285
|
-
output = `User answered "${question}" in their own words: "${freeText}"`
|
|
286
|
-
}
|
|
499
|
+
const answers = readAnswers(items, decision)
|
|
500
|
+
if (!answers.some(isAnswered)) return noAnswer
|
|
287
501
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
output,
|
|
291
|
-
data: {
|
|
292
|
-
question,
|
|
293
|
-
selected,
|
|
294
|
-
...(freeText ? { freeText } : {}),
|
|
295
|
-
answered: true,
|
|
296
|
-
},
|
|
297
|
-
}
|
|
502
|
+
const described = batch ? describeBatch(answers) : describeSingle(answers[0] as ReadAnswer)
|
|
503
|
+
return { success: true, output: described.output, data: described.data }
|
|
298
504
|
},
|
|
299
505
|
})
|
|
300
506
|
}
|
|
@@ -55,6 +55,7 @@ export interface AuthoredQuestionOption {
|
|
|
55
55
|
readonly label: string
|
|
56
56
|
readonly description?: string
|
|
57
57
|
readonly recommended?: boolean
|
|
58
|
+
readonly preview?: string
|
|
58
59
|
}
|
|
59
60
|
|
|
60
61
|
/** A label's last parenthesised group, ASCII "(…)" or full-width "(…)". */
|
|
@@ -75,7 +76,10 @@ interface TrailingGroup {
|
|
|
75
76
|
function trailingGroup(label: string): TrailingGroup | null {
|
|
76
77
|
const match = TRAILING_GROUP.exec(label)
|
|
77
78
|
if (!match) return null
|
|
78
|
-
return {
|
|
79
|
+
return {
|
|
80
|
+
base: (match[1] ?? '').trim(),
|
|
81
|
+
text: (match[2] ?? match[3] ?? '').trim(),
|
|
82
|
+
}
|
|
79
83
|
}
|
|
80
84
|
|
|
81
85
|
/**
|
|
@@ -126,6 +130,7 @@ function isMarker(grouped: readonly { option: Working; group: TrailingGroup }[])
|
|
|
126
130
|
|
|
127
131
|
interface Working {
|
|
128
132
|
label: string
|
|
133
|
+
readonly preview?: string
|
|
129
134
|
readonly recommended: boolean
|
|
130
135
|
/**
|
|
131
136
|
* The label ended in "(Recommended)", which came off. That was the marker,
|
|
@@ -154,6 +159,7 @@ export function questionOptions(options: readonly AuthoredQuestionOption[]): Use
|
|
|
154
159
|
recommended: option.recommended ?? english,
|
|
155
160
|
hadEnglishMarker: removed,
|
|
156
161
|
description: option.description,
|
|
162
|
+
...(option.preview !== undefined ? { preview: option.preview } : {}),
|
|
157
163
|
}
|
|
158
164
|
})
|
|
159
165
|
|
|
@@ -190,6 +196,7 @@ export function questionOptions(options: readonly AuthoredQuestionOption[]): Use
|
|
|
190
196
|
id: `opt_${index + 1}`,
|
|
191
197
|
label: option.label,
|
|
192
198
|
...(option.description !== undefined ? { description: option.description } : {}),
|
|
199
|
+
...(option.preview !== undefined ? { preview: option.preview } : {}),
|
|
193
200
|
...(option.recommended ? { recommended: true } : {}),
|
|
194
201
|
}))
|
|
195
202
|
}
|
package/src/tools/defineTool.ts
CHANGED
|
@@ -27,7 +27,8 @@ export interface DefineToolOptions<S extends z.ZodType> {
|
|
|
27
27
|
/** Whether this exact call only observes state; conservative for unknown inputs. */
|
|
28
28
|
readOnly: boolean | ((input: z.infer<S>) => boolean)
|
|
29
29
|
destructive: boolean | ((input: z.infer<S>) => boolean)
|
|
30
|
-
|
|
30
|
+
/** Whether this exact call may run beside others; a function decides per call. */
|
|
31
|
+
concurrencySafe: boolean | ((input: z.infer<S>) => boolean)
|
|
31
32
|
/** Whether this exact call sends the screen to the provider; see {@link ToolDefinition.capturesScreen}. */
|
|
32
33
|
capturesScreen?: boolean | ((input: z.infer<S>) => boolean)
|
|
33
34
|
/** Whether this exact call always needs a person's approval; see {@link ToolDefinition.requiresApproval}. */
|
|
@@ -36,6 +37,8 @@ export interface DefineToolOptions<S extends z.ZodType> {
|
|
|
36
37
|
metadata?: Readonly<Record<string, unknown>>
|
|
37
38
|
/** Batch ordering boundary; see {@link ToolDefinition.executionBarrier}. */
|
|
38
39
|
executionBarrier?: boolean
|
|
40
|
+
/** The tool bounds its own output; see {@link ToolDefinition.selfLimitingOutput}. */
|
|
41
|
+
selfLimitingOutput?: boolean
|
|
39
42
|
tier?: string
|
|
40
43
|
/**
|
|
41
44
|
* How this tool's call and result should be shown; see
|
|
@@ -152,6 +155,9 @@ export function defineTool<S extends z.ZodType>(
|
|
|
152
155
|
...(options.executionBarrier !== undefined
|
|
153
156
|
? { executionBarrier: options.executionBarrier }
|
|
154
157
|
: {}),
|
|
158
|
+
...(options.selfLimitingOutput !== undefined
|
|
159
|
+
? { selfLimitingOutput: options.selfLimitingOutput }
|
|
160
|
+
: {}),
|
|
155
161
|
category: options.category,
|
|
156
162
|
permissions: options.permissions,
|
|
157
163
|
isReadOnly:
|
|
@@ -160,7 +166,10 @@ export function defineTool<S extends z.ZodType>(
|
|
|
160
166
|
typeof options.destructive === 'function'
|
|
161
167
|
? options.destructive
|
|
162
168
|
: constantDestructive(options.destructive as boolean),
|
|
163
|
-
isConcurrencySafe:
|
|
169
|
+
isConcurrencySafe:
|
|
170
|
+
typeof options.concurrencySafe === 'function'
|
|
171
|
+
? options.concurrencySafe
|
|
172
|
+
: () => options.concurrencySafe as boolean,
|
|
164
173
|
...(options.capturesScreen !== undefined
|
|
165
174
|
? {
|
|
166
175
|
capturesScreen:
|
package/src/tools/paths.ts
CHANGED
|
@@ -229,7 +229,7 @@ export async function resolveWithinReal(
|
|
|
229
229
|
* existing ancestor with its links resolved, and the rest appended as
|
|
230
230
|
* written. A path of which nothing exists is returned as it stands.
|
|
231
231
|
*/
|
|
232
|
-
async function canonicalize(absolute: string): Promise<string> {
|
|
232
|
+
export async function canonicalize(absolute: string): Promise<string> {
|
|
233
233
|
// Walk up to the deepest existing ancestor. Terminates at the filesystem
|
|
234
234
|
// root, where `dirname` becomes a fixed point.
|
|
235
235
|
let existing = absolute
|
package/src/types/agent/query.ts
CHANGED
|
@@ -94,7 +94,10 @@ export interface QueryAgentConfig extends BaseAgentConfig {
|
|
|
94
94
|
toolTimeoutMs?: number
|
|
95
95
|
toolRetryBackoff?: QueryParams['toolRetryBackoff']
|
|
96
96
|
maxToolConcurrency?: number
|
|
97
|
+
/** See {@link QueryParams.maxOutputContinuations}. */
|
|
98
|
+
maxOutputContinuations?: QueryParams['maxOutputContinuations']
|
|
97
99
|
maxToolOutputChars?: number
|
|
100
|
+
maxToolOutputCharsPerMessage?: number
|
|
98
101
|
retainedToolPreviewChars?: QueryParams['retainedToolPreviewChars']
|
|
99
102
|
/**
|
|
100
103
|
* Cap on the RICH channel of a single tool result, in base64 characters.
|
|
@@ -165,7 +165,7 @@ export const DEFAULT_ERROR_RULES: readonly ErrorCatalogRule[] = [
|
|
|
165
165
|
id: 'provider.context_overflow',
|
|
166
166
|
when: (facts) => facts.code === 'context_length_exceeded',
|
|
167
167
|
message: 'The prompt is larger than the model can accept.',
|
|
168
|
-
hint: 'Compaction ran and could not make enough room.
|
|
168
|
+
hint: 'Compaction ran and could not make enough room. Set a lower `compactionConfig.triggerThreshold`, reduce `keepRecentMessages`, or cap large tool outputs so history stops growing faster than it can be shed.',
|
|
169
169
|
},
|
|
170
170
|
{
|
|
171
171
|
id: 'provider.unavailable',
|