@namzu/sdk 61.4.0 → 62.0.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 +55 -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/bridge/acp/permission.d.ts +8 -0
- package/dist/bridge/acp/permission.d.ts.map +1 -1
- package/dist/bridge/acp/permission.js.map +1 -1
- package/dist/bridge/acp/server.d.ts.map +1 -1
- package/dist/bridge/acp/server.js +8 -1
- package/dist/bridge/acp/server.js.map +1 -1
- package/dist/constants/tools/index.d.ts +2 -0
- package/dist/constants/tools/index.d.ts.map +1 -1
- package/dist/constants/tools/index.js +23 -0
- package/dist/constants/tools/index.js.map +1 -1
- package/dist/eval/harness-protection.js +1 -1
- package/dist/eval/harness-protection.js.map +1 -1
- package/dist/learning/cycle.d.ts +5 -3
- package/dist/learning/cycle.d.ts.map +1 -1
- package/dist/learning/cycle.js +11 -13
- package/dist/learning/cycle.js.map +1 -1
- package/dist/learning/guidance.d.ts +74 -0
- package/dist/learning/guidance.d.ts.map +1 -0
- package/dist/learning/guidance.js +259 -0
- package/dist/learning/guidance.js.map +1 -0
- package/dist/learning/skill.d.ts +2 -2
- package/dist/learning/skill.d.ts.map +1 -1
- package/dist/learning/skill.js +6 -6
- package/dist/learning/skill.js.map +1 -1
- package/dist/learning/store.d.ts.map +1 -1
- package/dist/learning/store.js +6 -6
- package/dist/learning/store.js.map +1 -1
- package/dist/pals/communication/ingress-schema.d.ts +8 -8
- package/dist/pals/communication/schema.d.ts +2 -2
- package/dist/peers/client.d.ts +2 -3
- package/dist/peers/client.d.ts.map +1 -1
- package/dist/peers/client.js +2 -3
- package/dist/peers/client.js.map +1 -1
- package/dist/peers/endpoint.d.ts +1 -2
- package/dist/peers/endpoint.d.ts.map +1 -1
- package/dist/peers/endpoint.js +1 -2
- package/dist/peers/endpoint.js.map +1 -1
- package/dist/peers/protocol.d.ts.map +1 -1
- package/dist/peers/protocol.js +1 -0
- package/dist/peers/protocol.js.map +1 -1
- package/dist/prompt/coding-agent-doctrine.d.ts +4 -4
- package/dist/prompt/coding-agent-doctrine.d.ts.map +1 -1
- package/dist/prompt/coding-agent-doctrine.js +5 -3
- package/dist/prompt/coding-agent-doctrine.js.map +1 -1
- package/dist/prompt/index.d.ts +0 -4
- package/dist/prompt/index.d.ts.map +1 -1
- package/dist/prompt/index.js +0 -2
- package/dist/prompt/index.js.map +1 -1
- package/dist/provider/fallback.d.ts.map +1 -1
- package/dist/provider/fallback.js +3 -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/model-window-suffix.d.ts.map +1 -1
- package/dist/provider/model-window-suffix.js +1 -0
- package/dist/provider/model-window-suffix.js.map +1 -1
- package/dist/provider/retry.d.ts.map +1 -1
- package/dist/provider/retry.js +5 -0
- package/dist/provider/retry.js.map +1 -1
- package/dist/provider/step-stopped.d.ts +19 -0
- package/dist/provider/step-stopped.d.ts.map +1 -0
- package/dist/provider/step-stopped.js +25 -0
- package/dist/provider/step-stopped.js.map +1 -0
- package/dist/provider/token-budget.d.ts.map +1 -1
- package/dist/provider/token-budget.js +6 -1
- package/dist/provider/token-budget.js.map +1 -1
- package/dist/public-runtime.d.ts +3 -14
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +3 -14
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-tools.d.ts +0 -2
- package/dist/public-tools.d.ts.map +1 -1
- package/dist/public-tools.js +0 -2
- package/dist/public-tools.js.map +1 -1
- package/dist/public-types.d.ts +3 -21
- package/dist/public-types.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.d.ts +17 -0
- package/dist/runtime/query/iteration/index.d.ts.map +1 -1
- package/dist/runtime/query/iteration/index.js +168 -5
- package/dist/runtime/query/iteration/index.js.map +1 -1
- package/dist/runtime/query/iteration/phases/per-call-review.d.ts.map +1 -1
- package/dist/runtime/query/iteration/phases/per-call-review.js +4 -5
- package/dist/runtime/query/iteration/phases/per-call-review.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 +6 -3
- package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts +9 -1
- package/dist/runtime/query/iteration/stream-turn.d.ts.map +1 -1
- package/dist/runtime/query/iteration/stream-turn.js +48 -2
- package/dist/runtime/query/iteration/stream-turn.js.map +1 -1
- package/dist/runtime/query/resume-pending.d.ts.map +1 -1
- package/dist/runtime/query/resume-pending.js +7 -4
- package/dist/runtime/query/resume-pending.js.map +1 -1
- package/dist/runtime/query/review-policy.d.ts +40 -8
- package/dist/runtime/query/review-policy.d.ts.map +1 -1
- package/dist/runtime/query/review-policy.js +139 -24
- package/dist/runtime/query/review-policy.js.map +1 -1
- package/dist/runtime/query/turn/completion-audit.d.ts +32 -0
- package/dist/runtime/query/turn/completion-audit.d.ts.map +1 -0
- package/dist/runtime/query/turn/completion-audit.js +56 -0
- package/dist/runtime/query/turn/completion-audit.js.map +1 -0
- package/dist/runtime/query/turn/stall-monitor.d.ts +78 -0
- package/dist/runtime/query/turn/stall-monitor.d.ts.map +1 -0
- package/dist/runtime/query/turn/stall-monitor.js +101 -0
- package/dist/runtime/query/turn/stall-monitor.js.map +1 -0
- package/dist/session/paths.d.ts +1 -2
- package/dist/session/paths.d.ts.map +1 -1
- package/dist/session/paths.js +1 -4
- package/dist/session/paths.js.map +1 -1
- package/dist/tools/builtins/bash.d.ts +2 -1
- package/dist/tools/builtins/bash.d.ts.map +1 -1
- package/dist/tools/builtins/bash.js +5 -2
- package/dist/tools/builtins/bash.js.map +1 -1
- package/dist/tools/builtins/content-fingerprint.d.ts +13 -0
- package/dist/tools/builtins/content-fingerprint.d.ts.map +1 -1
- package/dist/tools/builtins/content-fingerprint.js +25 -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 +7 -2
- package/dist/tools/builtins/edit.js.map +1 -1
- package/dist/tools/builtins/shell-read-credit.d.ts +15 -0
- package/dist/tools/builtins/shell-read-credit.d.ts.map +1 -0
- package/dist/tools/builtins/shell-read-credit.js +161 -0
- package/dist/tools/builtins/shell-read-credit.js.map +1 -0
- package/dist/tools/paths.d.ts +15 -2
- package/dist/tools/paths.d.ts.map +1 -1
- package/dist/tools/paths.js +17 -2
- package/dist/tools/paths.js.map +1 -1
- package/dist/turn/evidence-recall.d.ts +1 -1
- package/dist/turn/evidence-recall.d.ts.map +1 -1
- package/dist/turn/evidence-recall.js +5 -14
- package/dist/turn/evidence-recall.js.map +1 -1
- package/dist/types/acp/index.d.ts +6 -0
- package/dist/types/acp/index.d.ts.map +1 -1
- package/dist/types/agent/base.d.ts +4 -0
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/hitl/index.d.ts +8 -0
- package/dist/types/hitl/index.d.ts.map +1 -1
- package/dist/types/hitl/index.js.map +1 -1
- package/dist/types/ids/index.d.ts +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 +1 -0
- package/dist/types/message/index.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/session/config.d.ts +25 -0
- package/dist/types/session/config.d.ts.map +1 -1
- package/dist/types/session/records.d.ts.map +1 -1
- package/dist/types/session/records.js +2 -0
- package/dist/types/session/records.js.map +1 -1
- package/dist/types/session/turn.d.ts +1 -1
- package/dist/types/session/turn.d.ts.map +1 -1
- package/dist/types/session/turn.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/QueryAgent.ts +2 -0
- package/src/bridge/acp/permission.ts +8 -0
- package/src/bridge/acp/server.ts +7 -1
- package/src/constants/tools/index.ts +27 -0
- package/src/eval/harness-protection.ts +1 -1
- package/src/learning/cycle.ts +15 -16
- package/src/learning/guidance.ts +339 -0
- package/src/learning/skill.ts +7 -7
- package/src/learning/store.ts +5 -6
- package/src/peers/client.ts +2 -3
- package/src/peers/endpoint.ts +1 -2
- package/src/peers/protocol.ts +1 -0
- package/src/prompt/coding-agent-doctrine.ts +5 -3
- package/src/prompt/index.ts +0 -4
- package/src/provider/fallback.ts +7 -0
- package/src/provider/idle-timeout.ts +8 -0
- package/src/provider/model-window-suffix.ts +1 -0
- package/src/provider/retry.ts +8 -0
- package/src/provider/step-stopped.ts +27 -0
- package/src/provider/token-budget.ts +6 -1
- package/src/public-runtime.ts +6 -28
- package/src/public-tools.ts +0 -3
- package/src/public-types.ts +5 -137
- package/src/runtime/query/iteration/index.ts +207 -5
- package/src/runtime/query/iteration/phases/per-call-review.ts +7 -5
- package/src/runtime/query/iteration/phases/tool-review.ts +5 -3
- package/src/runtime/query/iteration/stream-turn.ts +51 -1
- package/src/runtime/query/resume-pending.ts +11 -4
- package/src/runtime/query/review-policy.ts +157 -24
- package/src/runtime/query/turn/completion-audit.ts +71 -0
- package/src/runtime/query/turn/stall-monitor.ts +158 -0
- package/src/session/paths.ts +2 -6
- package/src/tools/builtins/bash.ts +6 -2
- package/src/tools/builtins/content-fingerprint.ts +25 -0
- package/src/tools/builtins/edit.ts +11 -2
- package/src/tools/builtins/shell-read-credit.ts +159 -0
- package/src/tools/paths.ts +18 -2
- package/src/turn/evidence-recall.ts +7 -15
- package/src/types/acp/index.ts +6 -0
- package/src/types/agent/base.ts +4 -0
- package/src/types/hitl/index.ts +8 -0
- package/src/types/ids/index.ts +1 -1
- package/src/types/message/index.ts +1 -0
- package/src/types/provider/interface.ts +13 -0
- package/src/types/session/config.ts +27 -0
- package/src/types/session/records.ts +2 -0
- package/src/types/session/turn.ts +2 -1
- package/dist/learning/deprecated.d.ts +0 -86
- package/dist/learning/deprecated.d.ts.map +0 -1
- package/dist/learning/deprecated.js +0 -22
- package/dist/learning/deprecated.js.map +0 -1
- package/dist/manager/resident/activity.d.ts +0 -74
- package/dist/manager/resident/activity.d.ts.map +0 -1
- package/dist/manager/resident/activity.js +0 -125
- package/dist/manager/resident/activity.js.map +0 -1
- package/dist/manager/resident/agenda.d.ts +0 -167
- package/dist/manager/resident/agenda.d.ts.map +0 -1
- package/dist/manager/resident/agenda.js +0 -588
- package/dist/manager/resident/agenda.js.map +0 -1
- package/dist/manager/resident/consumption.d.ts +0 -98
- package/dist/manager/resident/consumption.d.ts.map +0 -1
- package/dist/manager/resident/consumption.js +0 -237
- package/dist/manager/resident/consumption.js.map +0 -1
- package/dist/manager/resident/delivery-window.d.ts +0 -28
- package/dist/manager/resident/delivery-window.d.ts.map +0 -1
- package/dist/manager/resident/delivery-window.js +0 -80
- package/dist/manager/resident/delivery-window.js.map +0 -1
- package/dist/manager/resident/evidence-recall.d.ts +0 -30
- package/dist/manager/resident/evidence-recall.d.ts.map +0 -1
- package/dist/manager/resident/evidence-recall.js +0 -297
- package/dist/manager/resident/evidence-recall.js.map +0 -1
- package/dist/manager/resident/history-disk.d.ts +0 -10
- package/dist/manager/resident/history-disk.d.ts.map +0 -1
- package/dist/manager/resident/history-disk.js +0 -50
- package/dist/manager/resident/history-disk.js.map +0 -1
- package/dist/manager/resident/history.d.ts +0 -115
- package/dist/manager/resident/history.d.ts.map +0 -1
- package/dist/manager/resident/history.js +0 -203
- package/dist/manager/resident/history.js.map +0 -1
- package/dist/manager/resident/host.d.ts +0 -112
- package/dist/manager/resident/host.d.ts.map +0 -1
- package/dist/manager/resident/host.js +0 -254
- package/dist/manager/resident/host.js.map +0 -1
- package/dist/manager/resident/initiative.d.ts +0 -86
- package/dist/manager/resident/initiative.d.ts.map +0 -1
- package/dist/manager/resident/initiative.js +0 -131
- package/dist/manager/resident/initiative.js.map +0 -1
- package/dist/manager/resident/loop.d.ts +0 -49
- package/dist/manager/resident/loop.d.ts.map +0 -1
- package/dist/manager/resident/loop.js +0 -75
- package/dist/manager/resident/loop.js.map +0 -1
- package/dist/manager/resident/outbox.d.ts +0 -124
- package/dist/manager/resident/outbox.d.ts.map +0 -1
- package/dist/manager/resident/outbox.js +0 -216
- package/dist/manager/resident/outbox.js.map +0 -1
- package/dist/manager/resident/proposal.d.ts +0 -65
- package/dist/manager/resident/proposal.d.ts.map +0 -1
- package/dist/manager/resident/proposal.js +0 -77
- package/dist/manager/resident/proposal.js.map +0 -1
- package/dist/manager/resident/store.d.ts +0 -108
- package/dist/manager/resident/store.d.ts.map +0 -1
- package/dist/manager/resident/store.js +0 -205
- package/dist/manager/resident/store.js.map +0 -1
- package/dist/manager/resident/tool-evidence.d.ts +0 -112
- package/dist/manager/resident/tool-evidence.d.ts.map +0 -1
- package/dist/manager/resident/tool-evidence.js +0 -289
- package/dist/manager/resident/tool-evidence.js.map +0 -1
- package/dist/prompt/resident-learning.d.ts +0 -29
- package/dist/prompt/resident-learning.d.ts.map +0 -1
- package/dist/prompt/resident-learning.js +0 -126
- package/dist/prompt/resident-learning.js.map +0 -1
- package/dist/prompt/resident-step.d.ts +0 -42
- package/dist/prompt/resident-step.d.ts.map +0 -1
- package/dist/prompt/resident-step.js +0 -137
- package/dist/prompt/resident-step.js.map +0 -1
- package/dist/tools/resident-history.d.ts +0 -12
- package/dist/tools/resident-history.d.ts.map +0 -1
- package/dist/tools/resident-history.js +0 -82
- package/dist/tools/resident-history.js.map +0 -1
- package/dist/tools/resident-tool-evidence.d.ts +0 -9
- package/dist/tools/resident-tool-evidence.d.ts.map +0 -1
- package/dist/tools/resident-tool-evidence.js +0 -61
- package/dist/tools/resident-tool-evidence.js.map +0 -1
- package/src/learning/deprecated.ts +0 -124
- package/src/manager/resident/activity.ts +0 -211
- package/src/manager/resident/agenda.ts +0 -937
- package/src/manager/resident/consumption.ts +0 -335
- package/src/manager/resident/delivery-window.ts +0 -99
- package/src/manager/resident/evidence-recall.ts +0 -369
- package/src/manager/resident/history-disk.ts +0 -63
- package/src/manager/resident/history.ts +0 -348
- package/src/manager/resident/host.ts +0 -390
- package/src/manager/resident/initiative.ts +0 -231
- package/src/manager/resident/loop.ts +0 -119
- package/src/manager/resident/outbox.ts +0 -341
- package/src/manager/resident/proposal.ts +0 -119
- package/src/manager/resident/store.ts +0 -279
- package/src/manager/resident/tool-evidence.ts +0 -455
- package/src/prompt/resident-learning.ts +0 -152
- package/src/prompt/resident-step.ts +0 -182
- package/src/tools/resident-history.ts +0 -88
- package/src/tools/resident-tool-evidence.ts +0 -72
|
@@ -145,7 +145,7 @@ export declare function batchNeedsReview(toolCalls: readonly ToolCallSummary[],
|
|
|
145
145
|
* answers for the batch as a unit, and approving its other calls while the
|
|
146
146
|
* one that needed a person is dropped would run a plan with a hole in it.
|
|
147
147
|
*/
|
|
148
|
-
export declare const SANDBOX_ESCAPE_UNATTENDED_REFUSAL = "Refused:
|
|
148
|
+
export declare const SANDBOX_ESCAPE_UNATTENDED_REFUSAL = "Refused: this call asks to run outside the sandbox, which needs a person to confirm it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Run the command inside the sandbox instead.";
|
|
149
149
|
/**
|
|
150
150
|
* What the model is told when a batch reaches a path outside the turn's roots
|
|
151
151
|
* and nobody can be asked.
|
|
@@ -155,7 +155,7 @@ export declare const SANDBOX_ESCAPE_UNATTENDED_REFUSAL = "Refused: a call in thi
|
|
|
155
155
|
* nobody to ask widens the roots up front instead (`additionalDirectories`,
|
|
156
156
|
* the CLI's `--add-dir`), where an operator wrote the directory down.
|
|
157
157
|
*/
|
|
158
|
-
export declare const OUTSIDE_ROOTS_UNATTENDED_REFUSAL = "Refused:
|
|
158
|
+
export declare const OUTSIDE_ROOTS_UNATTENDED_REFUSAL = "Refused: this call reaches a path outside the working directory and the directories added to this session, which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Use a path inside the working directory, or tell the user which directory you need so they can start the session with it added (the CLI's --add-dir).";
|
|
159
159
|
/**
|
|
160
160
|
* What the model is told when a batch carries a call the tool itself
|
|
161
161
|
* declared always needs a person's approval and nobody can be asked.
|
|
@@ -164,7 +164,7 @@ export declare const OUTSIDE_ROOTS_UNATTENDED_REFUSAL = "Refused: a call in this
|
|
|
164
164
|
* declaration is the tool author's, not the operator's, so no rule, mode or
|
|
165
165
|
* remembered grant can stand in for the person it names.
|
|
166
166
|
*/
|
|
167
|
-
export declare const REQUIRES_APPROVAL_UNATTENDED_REFUSAL = "Refused:
|
|
167
|
+
export declare const REQUIRES_APPROVAL_UNATTENDED_REFUSAL = "Refused: this call is one the tool itself declared always needs a person's approval, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. This cannot be granted by a rule, an automation mode, a remembered approval or a skill; run it in a session where a person can be asked.";
|
|
168
168
|
/**
|
|
169
169
|
* What the model is told when a batch runs a command whose own program name
|
|
170
170
|
* is decided at runtime and nobody can be asked.
|
|
@@ -174,7 +174,7 @@ export declare const REQUIRES_APPROVAL_UNATTENDED_REFUSAL = "Refused: a call in
|
|
|
174
174
|
* before it runs — unlike a sandbox escape, there is no equivalent
|
|
175
175
|
* "unattended allow" for this.
|
|
176
176
|
*/
|
|
177
|
-
export declare const UNKNOWN_PROGRAM_UNATTENDED_REFUSAL = "Refused:
|
|
177
|
+
export declare const UNKNOWN_PROGRAM_UNATTENDED_REFUSAL = "Refused: this call runs a command whose own program name is decided at runtime (a substitution or a variable stands for it), which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Write the program name literally; compute what needs computing in the arguments instead.";
|
|
178
178
|
/**
|
|
179
179
|
* What the model is told when a batch writes a protected path (a git hook, a
|
|
180
180
|
* shell rc file, editor or tool configuration, the project's `.namzu`
|
|
@@ -184,23 +184,23 @@ export declare const UNKNOWN_PROGRAM_UNATTENDED_REFUSAL = "Refused: a call in th
|
|
|
184
184
|
* the turn, with the operator's rights, so an answer given before the call
|
|
185
185
|
* existed (a mode, a rule, "approve all") is not an answer about it.
|
|
186
186
|
*/
|
|
187
|
-
export declare const PROTECTED_PATH_UNATTENDED_REFUSAL = "Refused:
|
|
187
|
+
export declare const PROTECTED_PATH_UNATTENDED_REFUSAL = "Refused: this call writes a protected path (a git hook or config, a shell startup file, editor or tool configuration, or the project's .namzu directory), which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Leave those files alone, or tell the user what change you need so they can make it.";
|
|
188
188
|
/**
|
|
189
189
|
* What the model is told when a batch removes something catastrophic (the
|
|
190
190
|
* root, the home directory, the working directory or a parent of it, a glob
|
|
191
191
|
* across directories, a target a variable may empty) and nobody can be asked.
|
|
192
192
|
*/
|
|
193
|
-
export declare const DANGEROUS_REMOVAL_UNATTENDED_REFUSAL = "Refused:
|
|
193
|
+
export declare const DANGEROUS_REMOVAL_UNATTENDED_REFUSAL = "Refused: this call removes something this check treats as catastrophic (the file system root, a top-level or home directory, the working directory or a parent of it, a glob across directories, or a target a variable or substitution may leave empty), which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Name the exact directory to remove with a literal path.";
|
|
194
194
|
/**
|
|
195
195
|
* What the model is told when a batch carries a call a rule or a hook asked a
|
|
196
196
|
* person to approve and nobody can be asked.
|
|
197
197
|
*/
|
|
198
|
-
export declare const ASK_RULE_UNATTENDED_REFUSAL = "Refused:
|
|
198
|
+
export declare const ASK_RULE_UNATTENDED_REFUSAL = "Refused: this call is one a rule or a hook says a person must approve, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Run it in a session where a person can be asked, or have the operator change the rule.";
|
|
199
199
|
/**
|
|
200
200
|
* What the model is told when the checks that decide whether a call reaches
|
|
201
201
|
* past its boundary did not finish and nobody can be asked.
|
|
202
202
|
*/
|
|
203
|
-
export declare const UNFINISHED_CHECK_UNATTENDED_REFUSAL = "Refused: the safety checks on
|
|
203
|
+
export declare const UNFINISHED_CHECK_UNATTENDED_REFUSAL = "Refused: the safety checks on this call did not finish, so it cannot be shown to be safe, and a person has to approve it and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Try a simpler form of the call.";
|
|
204
204
|
/** What the model is told when the conversation is too long for the classifier to read. */
|
|
205
205
|
export declare const CLASSIFIER_TRANSCRIPT_TOO_LONG_FEEDBACK = "Blocked by auto mode: the conversation has become too long for the safety check to read, so this action was not run. The conversation is being shortened; try the action again.";
|
|
206
206
|
/**
|
|
@@ -227,6 +227,10 @@ export declare const SCREEN_CONSENT_DECLINED_FEEDBACK = "The user declined to sh
|
|
|
227
227
|
export interface ScreenConsentRecord {
|
|
228
228
|
readonly sessions: Set<string>;
|
|
229
229
|
}
|
|
230
|
+
/** The outside-the-roots refusal, naming the directory and the way to allow it. */
|
|
231
|
+
export declare function outsideRootsRefusal(toolCalls: readonly ToolCallSummary[]): string;
|
|
232
|
+
/** The catastrophic-removal refusal with the one-line reason the check found. */
|
|
233
|
+
export declare function dangerousRemovalRefusal(toolCalls: readonly ToolCallSummary[]): string;
|
|
230
234
|
/**
|
|
231
235
|
* Whether a mode needs a batch a rule already allowed to come to the policy.
|
|
232
236
|
*
|
|
@@ -235,6 +239,34 @@ export interface ScreenConsentRecord {
|
|
|
235
239
|
* answers its `reviewAllowedCalls` with this for the mode it is in.
|
|
236
240
|
*/
|
|
237
241
|
export declare function modeReviewsAllowedCalls(mode: ReviewMode): boolean;
|
|
242
|
+
/** The slice of a reviewed call {@link mustAskPerson} reads; a `ToolCallSummary` fits it. */
|
|
243
|
+
export interface MustAskCall {
|
|
244
|
+
readonly escalation?: unknown;
|
|
245
|
+
readonly requiresApproval?: boolean;
|
|
246
|
+
readonly authorization?: {
|
|
247
|
+
readonly explicitReview?: boolean;
|
|
248
|
+
readonly askRule?: boolean;
|
|
249
|
+
};
|
|
250
|
+
readonly hookPermission?: {
|
|
251
|
+
readonly decision?: string;
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Whether a standing "yes" (a remembered `approve-all`, or a host's own
|
|
256
|
+
* "allow for this conversation") must not cover this call: it exists to put a
|
|
257
|
+
* question to a person.
|
|
258
|
+
*
|
|
259
|
+
* It crosses the turn's boundary in any way (a sandbox escape, a path outside
|
|
260
|
+
* the roots, a protected path, a catastrophic removal, a program nobody can
|
|
261
|
+
* name, a check that did not finish), its tool needs a yes on every call, or a
|
|
262
|
+
* rule or a hook asked for a person. `escalation` is tested as a whole rather
|
|
263
|
+
* than field by field, so a kind of escalation added later is asked about
|
|
264
|
+
* before anyone remembers to list it. A call that reaches the first look at
|
|
265
|
+
* the screen is asked about too; that is a property of the request
|
|
266
|
+
* (`ToolReviewRequest.screenConsent`), so a host adds it where it builds the
|
|
267
|
+
* ask.
|
|
268
|
+
*/
|
|
269
|
+
export declare function mustAskPerson(call: MustAskCall): boolean;
|
|
238
270
|
/** The batch a person is asked about. */
|
|
239
271
|
export interface ToolReviewRequest {
|
|
240
272
|
/** Originating session, preserved by createReviewHandler for host attribution. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-policy.d.ts","sourceRoot":"","sources":["../../../src/runtime/query/review-policy.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;
|
|
1
|
+
{"version":3,"file":"review-policy.d.ts","sourceRoot":"","sources":["../../../src/runtime/query/review-policy.ts"],"names":[],"mappings":"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"}
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
* What a host supplies is the one thing the kernel cannot: how to ask a
|
|
21
21
|
* person (`prompt`).
|
|
22
22
|
*/
|
|
23
|
+
import { homedir } from 'node:os';
|
|
24
|
+
import { dirname, parse } from 'node:path';
|
|
23
25
|
import { unknownProgramInLine } from '../../authorization/program.js';
|
|
24
26
|
import { readShellLine, shellPathAccess, } from '../../authorization/shell-paths.js';
|
|
25
27
|
import { effectiveBashWorkingDirectory } from '../../tools/builtins/bash-cwd.js';
|
|
@@ -135,7 +137,7 @@ function onlyReadsOutsideRoots(toolCalls, exempt) {
|
|
|
135
137
|
* answers for the batch as a unit, and approving its other calls while the
|
|
136
138
|
* one that needed a person is dropped would run a plan with a hole in it.
|
|
137
139
|
*/
|
|
138
|
-
export const SANDBOX_ESCAPE_UNATTENDED_REFUSAL = 'Refused:
|
|
140
|
+
export const SANDBOX_ESCAPE_UNATTENDED_REFUSAL = 'Refused: this call asks to run outside the sandbox, which needs a person to confirm it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Run the command inside the sandbox instead.';
|
|
139
141
|
/**
|
|
140
142
|
* What the model is told when a batch reaches a path outside the turn's roots
|
|
141
143
|
* and nobody can be asked.
|
|
@@ -145,7 +147,7 @@ export const SANDBOX_ESCAPE_UNATTENDED_REFUSAL = 'Refused: a call in this batch
|
|
|
145
147
|
* nobody to ask widens the roots up front instead (`additionalDirectories`,
|
|
146
148
|
* the CLI's `--add-dir`), where an operator wrote the directory down.
|
|
147
149
|
*/
|
|
148
|
-
export const OUTSIDE_ROOTS_UNATTENDED_REFUSAL = "Refused:
|
|
150
|
+
export const OUTSIDE_ROOTS_UNATTENDED_REFUSAL = "Refused: this call reaches a path outside the working directory and the directories added to this session, which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Use a path inside the working directory, or tell the user which directory you need so they can start the session with it added (the CLI's --add-dir).";
|
|
149
151
|
/**
|
|
150
152
|
* What the model is told when a batch carries a call the tool itself
|
|
151
153
|
* declared always needs a person's approval and nobody can be asked.
|
|
@@ -154,7 +156,7 @@ export const OUTSIDE_ROOTS_UNATTENDED_REFUSAL = "Refused: a call in this batch r
|
|
|
154
156
|
* declaration is the tool author's, not the operator's, so no rule, mode or
|
|
155
157
|
* remembered grant can stand in for the person it names.
|
|
156
158
|
*/
|
|
157
|
-
export const REQUIRES_APPROVAL_UNATTENDED_REFUSAL = "Refused:
|
|
159
|
+
export const REQUIRES_APPROVAL_UNATTENDED_REFUSAL = "Refused: this call is one the tool itself declared always needs a person's approval, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. This cannot be granted by a rule, an automation mode, a remembered approval or a skill; run it in a session where a person can be asked.";
|
|
158
160
|
/**
|
|
159
161
|
* What the model is told when a batch runs a command whose own program name
|
|
160
162
|
* is decided at runtime and nobody can be asked.
|
|
@@ -164,7 +166,7 @@ export const REQUIRES_APPROVAL_UNATTENDED_REFUSAL = "Refused: a call in this bat
|
|
|
164
166
|
* before it runs — unlike a sandbox escape, there is no equivalent
|
|
165
167
|
* "unattended allow" for this.
|
|
166
168
|
*/
|
|
167
|
-
export const UNKNOWN_PROGRAM_UNATTENDED_REFUSAL = 'Refused:
|
|
169
|
+
export const UNKNOWN_PROGRAM_UNATTENDED_REFUSAL = 'Refused: this call runs a command whose own program name is decided at runtime (a substitution or a variable stands for it), which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Write the program name literally; compute what needs computing in the arguments instead.';
|
|
168
170
|
/**
|
|
169
171
|
* What the model is told when a batch writes a protected path (a git hook, a
|
|
170
172
|
* shell rc file, editor or tool configuration, the project's `.namzu`
|
|
@@ -174,23 +176,23 @@ export const UNKNOWN_PROGRAM_UNATTENDED_REFUSAL = 'Refused: a call in this batch
|
|
|
174
176
|
* the turn, with the operator's rights, so an answer given before the call
|
|
175
177
|
* existed (a mode, a rule, "approve all") is not an answer about it.
|
|
176
178
|
*/
|
|
177
|
-
export const PROTECTED_PATH_UNATTENDED_REFUSAL = "Refused:
|
|
179
|
+
export const PROTECTED_PATH_UNATTENDED_REFUSAL = "Refused: this call writes a protected path (a git hook or config, a shell startup file, editor or tool configuration, or the project's .namzu directory), which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Leave those files alone, or tell the user what change you need so they can make it.";
|
|
178
180
|
/**
|
|
179
181
|
* What the model is told when a batch removes something catastrophic (the
|
|
180
182
|
* root, the home directory, the working directory or a parent of it, a glob
|
|
181
183
|
* across directories, a target a variable may empty) and nobody can be asked.
|
|
182
184
|
*/
|
|
183
|
-
export const DANGEROUS_REMOVAL_UNATTENDED_REFUSAL = 'Refused:
|
|
185
|
+
export const DANGEROUS_REMOVAL_UNATTENDED_REFUSAL = 'Refused: this call removes something this check treats as catastrophic (the file system root, a top-level or home directory, the working directory or a parent of it, a glob across directories, or a target a variable or substitution may leave empty), which needs a person to approve it each time, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Name the exact directory to remove with a literal path.';
|
|
184
186
|
/**
|
|
185
187
|
* What the model is told when a batch carries a call a rule or a hook asked a
|
|
186
188
|
* person to approve and nobody can be asked.
|
|
187
189
|
*/
|
|
188
|
-
export const ASK_RULE_UNATTENDED_REFUSAL = 'Refused:
|
|
190
|
+
export const ASK_RULE_UNATTENDED_REFUSAL = 'Refused: this call is one a rule or a hook says a person must approve, and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Run it in a session where a person can be asked, or have the operator change the rule.';
|
|
189
191
|
/**
|
|
190
192
|
* What the model is told when the checks that decide whether a call reaches
|
|
191
193
|
* past its boundary did not finish and nobody can be asked.
|
|
192
194
|
*/
|
|
193
|
-
export const UNFINISHED_CHECK_UNATTENDED_REFUSAL = 'Refused: the safety checks on
|
|
195
|
+
export const UNFINISHED_CHECK_UNATTENDED_REFUSAL = 'Refused: the safety checks on this call did not finish, so it cannot be shown to be safe, and a person has to approve it and nobody can be asked in this session. This call did not run; the other calls in the batch are not affected. Try a simpler form of the call.';
|
|
194
196
|
/** What the model is told when the conversation is too long for the classifier to read. */
|
|
195
197
|
export const CLASSIFIER_TRANSCRIPT_TOO_LONG_FEEDBACK = 'Blocked by auto mode: the conversation has become too long for the safety check to read, so this action was not run. The conversation is being shortened; try the action again.';
|
|
196
198
|
/**
|
|
@@ -391,6 +393,35 @@ export const ACCEPT_EDITS_SHELL_COMMANDS = new Set([
|
|
|
391
393
|
export const SCREEN_CONSENT_UNATTENDED_REFUSAL = "Refused: this call would send what is on the user's screen to the model provider, which a person agrees to once per session, and nobody can be asked in this session. Nothing in this batch ran. Tell the user computer use needs their consent in an interactive session.";
|
|
392
394
|
/** What the model is told when the operator declines to share the screen. */
|
|
393
395
|
export const SCREEN_CONSENT_DECLINED_FEEDBACK = 'The user declined to share their screen in this session. Nothing in this batch ran. Do not take screenshots or read windows again; ask the user how they want to proceed.';
|
|
396
|
+
/** The directory to name for a path the guard stopped: the path itself unless it looks like a file. */
|
|
397
|
+
function directoryToAllow(path) {
|
|
398
|
+
const last = path.split(/[\\/]/).pop() ?? '';
|
|
399
|
+
return last.includes('.') ? dirname(path) : path;
|
|
400
|
+
}
|
|
401
|
+
/** The outside-the-roots refusal, naming the directory and the way to allow it. */
|
|
402
|
+
export function outsideRootsRefusal(toolCalls) {
|
|
403
|
+
const paths = [...new Set(toolCalls.flatMap((tc) => tc.escalation?.outsidePaths ?? []))];
|
|
404
|
+
if (paths.length === 0)
|
|
405
|
+
return OUTSIDE_ROOTS_UNATTENDED_REFUSAL;
|
|
406
|
+
const blocked = `${OUTSIDE_ROOTS_UNATTENDED_REFUSAL} Blocked: ${paths.slice(0, 3).join(', ')}.`;
|
|
407
|
+
const directories = [...new Set(paths.map(directoryToAllow))];
|
|
408
|
+
// A directory that is the file system root or the home directory is too wide to
|
|
409
|
+
// suggest adding; a path directly under the root is more often a mistyped name.
|
|
410
|
+
const wide = new Set([parse(directories[0] ?? '/').root, homedir()]);
|
|
411
|
+
const addable = directories.filter((d) => !wide.has(d)).slice(0, 3);
|
|
412
|
+
if (addable.length === 0) {
|
|
413
|
+
return `${blocked} It sits directly under a directory too wide to add; if the name is a typo, use a path inside the working directory or the system temp directory.`;
|
|
414
|
+
}
|
|
415
|
+
return `${blocked} To allow it, the user starts the session with ${addable.map((d) => `--add-dir ${d}`).join(' ')}.`;
|
|
416
|
+
}
|
|
417
|
+
/** The catastrophic-removal refusal with the one-line reason the check found. */
|
|
418
|
+
export function dangerousRemovalRefusal(toolCalls) {
|
|
419
|
+
const why = toolCalls.find((tc) => tc.escalation?.dangerousRemoval !== undefined)?.escalation
|
|
420
|
+
?.dangerousRemoval;
|
|
421
|
+
return why === undefined
|
|
422
|
+
? DANGEROUS_REMOVAL_UNATTENDED_REFUSAL
|
|
423
|
+
: `${DANGEROUS_REMOVAL_UNATTENDED_REFUSAL} Why: ${why}.`;
|
|
424
|
+
}
|
|
394
425
|
/**
|
|
395
426
|
* Whether the call writes a protected path, removes something catastrophic, or
|
|
396
427
|
* could not be checked.
|
|
@@ -406,7 +437,7 @@ function floorRefusal(toolCalls) {
|
|
|
406
437
|
return PROTECTED_PATH_UNATTENDED_REFUSAL;
|
|
407
438
|
}
|
|
408
439
|
return toolCalls.some((tc) => tc.escalation?.dangerousRemoval !== undefined)
|
|
409
|
-
?
|
|
440
|
+
? dangerousRemovalRefusal(toolCalls)
|
|
410
441
|
: UNFINISHED_CHECK_UNATTENDED_REFUSAL;
|
|
411
442
|
}
|
|
412
443
|
/**
|
|
@@ -437,6 +468,28 @@ function isBypassImmune(tc) {
|
|
|
437
468
|
tc.escalation?.unfinishedCheck !== undefined ||
|
|
438
469
|
tc.requiresApproval === true);
|
|
439
470
|
}
|
|
471
|
+
/**
|
|
472
|
+
* Whether a standing "yes" (a remembered `approve-all`, or a host's own
|
|
473
|
+
* "allow for this conversation") must not cover this call: it exists to put a
|
|
474
|
+
* question to a person.
|
|
475
|
+
*
|
|
476
|
+
* It crosses the turn's boundary in any way (a sandbox escape, a path outside
|
|
477
|
+
* the roots, a protected path, a catastrophic removal, a program nobody can
|
|
478
|
+
* name, a check that did not finish), its tool needs a yes on every call, or a
|
|
479
|
+
* rule or a hook asked for a person. `escalation` is tested as a whole rather
|
|
480
|
+
* than field by field, so a kind of escalation added later is asked about
|
|
481
|
+
* before anyone remembers to list it. A call that reaches the first look at
|
|
482
|
+
* the screen is asked about too; that is a property of the request
|
|
483
|
+
* (`ToolReviewRequest.screenConsent`), so a host adds it where it builds the
|
|
484
|
+
* ask.
|
|
485
|
+
*/
|
|
486
|
+
export function mustAskPerson(call) {
|
|
487
|
+
return (call.escalation !== undefined ||
|
|
488
|
+
call.requiresApproval === true ||
|
|
489
|
+
call.authorization?.explicitReview === true ||
|
|
490
|
+
call.authorization?.askRule === true ||
|
|
491
|
+
call.hookPermission?.decision === 'ask');
|
|
492
|
+
}
|
|
440
493
|
/** The refusal for the first immune thing in a batch nobody can be asked about, or undefined. */
|
|
441
494
|
function immuneRefusal(toolCalls, escapeConfirmed) {
|
|
442
495
|
if (!escapeConfirmed && toolCalls.some((tc) => tc.escalation?.sandboxEscape === true)) {
|
|
@@ -446,7 +499,7 @@ function immuneRefusal(toolCalls, escapeConfirmed) {
|
|
|
446
499
|
return PROTECTED_PATH_UNATTENDED_REFUSAL;
|
|
447
500
|
}
|
|
448
501
|
if (toolCalls.some((tc) => tc.escalation?.dangerousRemoval !== undefined)) {
|
|
449
|
-
return
|
|
502
|
+
return dangerousRemovalRefusal(toolCalls);
|
|
450
503
|
}
|
|
451
504
|
if (toolCalls.some((tc) => tc.escalation?.unfinishedCheck !== undefined)) {
|
|
452
505
|
return UNFINISHED_CHECK_UNATTENDED_REFUSAL;
|
|
@@ -665,7 +718,15 @@ export function createReviewHandler(options = {}) {
|
|
|
665
718
|
}
|
|
666
719
|
return acceptEditsAllows(tc, sessionId);
|
|
667
720
|
};
|
|
668
|
-
|
|
721
|
+
// Decisions that refuse one call and say so. The wrapper below splits a batch on
|
|
722
|
+
// this mark, never on the wording of the refusal.
|
|
723
|
+
const perCallRefusals = new WeakSet();
|
|
724
|
+
const callRefusal = (feedback) => {
|
|
725
|
+
const decision = { action: 'reject_tools', feedback };
|
|
726
|
+
perCallRefusals.add(decision);
|
|
727
|
+
return decision;
|
|
728
|
+
};
|
|
729
|
+
const decide = async (request, context, classified = false) => {
|
|
669
730
|
if (request.type !== 'tool_review') {
|
|
670
731
|
return request.type === 'plan_approval' ? { action: 'approve_plan' } : { action: 'continue' };
|
|
671
732
|
}
|
|
@@ -779,7 +840,7 @@ export function createReviewHandler(options = {}) {
|
|
|
779
840
|
};
|
|
780
841
|
const live = request.toolCalls.filter((tc) => tc.authorization?.decision !== 'deny');
|
|
781
842
|
const escapes = live.filter((tc) => tc.escalation?.sandboxEscape === true).map((tc) => tc.id);
|
|
782
|
-
if (mode === 'classify') {
|
|
843
|
+
if (mode === 'classify' && !classified) {
|
|
783
844
|
const classifier = options.classifier;
|
|
784
845
|
const transcript = context?.transcript() ?? [];
|
|
785
846
|
for (const tc of live) {
|
|
@@ -834,7 +895,7 @@ export function createReviewHandler(options = {}) {
|
|
|
834
895
|
if (!prompt) {
|
|
835
896
|
const refusal = immuneRefusal(live, options.unattendedSandboxEscape === 'allow');
|
|
836
897
|
if (refusal !== undefined)
|
|
837
|
-
return
|
|
898
|
+
return callRefusal(refusal);
|
|
838
899
|
return {
|
|
839
900
|
action: 'approve_tools',
|
|
840
901
|
...(escapes.length > 0 ? { confirmedEscalations: escapes } : {}),
|
|
@@ -854,22 +915,22 @@ export function createReviewHandler(options = {}) {
|
|
|
854
915
|
if (escapes.length > 0) {
|
|
855
916
|
if (!prompt) {
|
|
856
917
|
if (options.unattendedSandboxEscape !== 'allow') {
|
|
857
|
-
return
|
|
918
|
+
return callRefusal(SANDBOX_ESCAPE_UNATTENDED_REFUSAL);
|
|
858
919
|
}
|
|
859
920
|
// This opt-in confirms only the sandbox escape. A different call in
|
|
860
921
|
// the batch, or another boundary on this same call, still needs a
|
|
861
922
|
// person; the early return must not approve that boundary too.
|
|
862
923
|
if (request.toolCalls.some(reachesAFloor)) {
|
|
863
|
-
return
|
|
924
|
+
return callRefusal(floorRefusal(request.toolCalls));
|
|
864
925
|
}
|
|
865
926
|
if (request.toolCalls.some((tc) => (tc.escalation?.outsidePaths?.length ?? 0) > 0)) {
|
|
866
|
-
return
|
|
927
|
+
return callRefusal(outsideRootsRefusal(request.toolCalls));
|
|
867
928
|
}
|
|
868
929
|
if (request.toolCalls.some((tc) => tc.requiresApproval === true)) {
|
|
869
|
-
return
|
|
930
|
+
return callRefusal(REQUIRES_APPROVAL_UNATTENDED_REFUSAL);
|
|
870
931
|
}
|
|
871
932
|
if (request.toolCalls.some((tc) => tc.escalation?.unknownProgram !== undefined)) {
|
|
872
|
-
return
|
|
933
|
+
return callRefusal(UNKNOWN_PROGRAM_UNATTENDED_REFUSAL);
|
|
873
934
|
}
|
|
874
935
|
return { action: 'approve_tools', confirmedEscalations: escapes };
|
|
875
936
|
}
|
|
@@ -894,7 +955,7 @@ export function createReviewHandler(options = {}) {
|
|
|
894
955
|
// the call existed. With nobody to ask it is refused, not approved.
|
|
895
956
|
if (request.toolCalls.some(reachesAFloor)) {
|
|
896
957
|
if (!prompt)
|
|
897
|
-
return
|
|
958
|
+
return callRefusal(floorRefusal(request.toolCalls));
|
|
898
959
|
const answer = await ask();
|
|
899
960
|
if (answer.kind === 'reject') {
|
|
900
961
|
return {
|
|
@@ -915,7 +976,7 @@ export function createReviewHandler(options = {}) {
|
|
|
915
976
|
// With nobody to ask it is refused, not approved.
|
|
916
977
|
if (request.toolCalls.some((tc) => (tc.escalation?.outsidePaths?.length ?? 0) > 0)) {
|
|
917
978
|
if (!prompt)
|
|
918
|
-
return
|
|
979
|
+
return callRefusal(outsideRootsRefusal(request.toolCalls));
|
|
919
980
|
const answer = await ask();
|
|
920
981
|
if (answer.kind === 'reject') {
|
|
921
982
|
return {
|
|
@@ -938,7 +999,7 @@ export function createReviewHandler(options = {}) {
|
|
|
938
999
|
// grant was ever an answer to IT specifically.
|
|
939
1000
|
if (request.toolCalls.some((tc) => tc.requiresApproval === true)) {
|
|
940
1001
|
if (!prompt)
|
|
941
|
-
return
|
|
1002
|
+
return callRefusal(REQUIRES_APPROVAL_UNATTENDED_REFUSAL);
|
|
942
1003
|
const answer = await ask();
|
|
943
1004
|
if (answer.kind === 'reject') {
|
|
944
1005
|
return {
|
|
@@ -961,7 +1022,7 @@ export function createReviewHandler(options = {}) {
|
|
|
961
1022
|
// name literally.
|
|
962
1023
|
if (request.toolCalls.some((tc) => tc.escalation?.unknownProgram !== undefined)) {
|
|
963
1024
|
if (!prompt)
|
|
964
|
-
return
|
|
1025
|
+
return callRefusal(UNKNOWN_PROGRAM_UNATTENDED_REFUSAL);
|
|
965
1026
|
const answer = await ask();
|
|
966
1027
|
if (answer.kind === 'reject') {
|
|
967
1028
|
return {
|
|
@@ -975,7 +1036,10 @@ export function createReviewHandler(options = {}) {
|
|
|
975
1036
|
remembered.all = true;
|
|
976
1037
|
return { action: 'approve_tools' };
|
|
977
1038
|
}
|
|
978
|
-
|
|
1039
|
+
// A remembered "approve all" answers ordinary calls. A call a rule or a
|
|
1040
|
+
// hook asked a person about exists to put its own question, which the
|
|
1041
|
+
// latch was never an answer to (`mustAskPerson`): it goes on to ask.
|
|
1042
|
+
if (mode === 'auto' || !prompt || (remembered.all && !request.toolCalls.some(mustAskPerson))) {
|
|
979
1043
|
return { action: 'approve_tools' };
|
|
980
1044
|
}
|
|
981
1045
|
// Every call a person would be asked about is one a skill loaded in
|
|
@@ -1006,7 +1070,11 @@ export function createReviewHandler(options = {}) {
|
|
|
1006
1070
|
case 'approve':
|
|
1007
1071
|
return { action: 'approve_tools' };
|
|
1008
1072
|
case 'approve-all':
|
|
1009
|
-
|
|
1073
|
+
// A rule's or a hook's question was put to this person once; an
|
|
1074
|
+
// "approve all" to it approves it and leaves the latch as it was,
|
|
1075
|
+
// as the ACP bridge does.
|
|
1076
|
+
if (!request.toolCalls.some(mustAskPerson))
|
|
1077
|
+
remembered.all = true;
|
|
1010
1078
|
return { action: 'approve_tools' };
|
|
1011
1079
|
case 'reject':
|
|
1012
1080
|
return {
|
|
@@ -1017,6 +1085,53 @@ export function createReviewHandler(options = {}) {
|
|
|
1017
1085
|
};
|
|
1018
1086
|
}
|
|
1019
1087
|
};
|
|
1088
|
+
// With nobody to ask, a refusal that belongs to one call is that call's
|
|
1089
|
+
// alone. The batch is not refused for it: each call is decided on its own,
|
|
1090
|
+
// the ones that pass run, and the one that does not gets its own reason.
|
|
1091
|
+
// Without this a single stray path in a parallel batch costs the turn every
|
|
1092
|
+
// other call in it.
|
|
1093
|
+
return async (request, context) => {
|
|
1094
|
+
const whole = await decide(request, context);
|
|
1095
|
+
if (whole.action !== 'reject_tools' ||
|
|
1096
|
+
prompt ||
|
|
1097
|
+
request.type !== 'tool_review' ||
|
|
1098
|
+
request.toolCalls.length < 2 ||
|
|
1099
|
+
!perCallRefusals.has(whole)) {
|
|
1100
|
+
return whole;
|
|
1101
|
+
}
|
|
1102
|
+
// The whole-batch pass has already put every call to the classifier (it
|
|
1103
|
+
// refuses only after all of them were allowed), so the per-call passes do
|
|
1104
|
+
// not ask it again. One at a time: no pass races another on shared state.
|
|
1105
|
+
const alone = [];
|
|
1106
|
+
for (const tc of request.toolCalls) {
|
|
1107
|
+
alone.push(await decide({ ...request, toolCalls: [tc] }, context, true));
|
|
1108
|
+
}
|
|
1109
|
+
const modifications = [];
|
|
1110
|
+
const policyRefusals = {};
|
|
1111
|
+
const confirmed = [];
|
|
1112
|
+
for (const [i, decision] of alone.entries()) {
|
|
1113
|
+
const id = request.toolCalls[i].id;
|
|
1114
|
+
if (decision.action === 'approve_tools') {
|
|
1115
|
+
modifications.push({ toolCallId: id, action: 'approve' });
|
|
1116
|
+
confirmed.push(...(decision.confirmedEscalations ?? []));
|
|
1117
|
+
}
|
|
1118
|
+
else if (decision.action === 'reject_tools' && !decision.endTurn && !decision.declined) {
|
|
1119
|
+
modifications.push({ toolCallId: id, action: 'deny' });
|
|
1120
|
+
policyRefusals[id] = decision.feedback;
|
|
1121
|
+
}
|
|
1122
|
+
else {
|
|
1123
|
+
return whole;
|
|
1124
|
+
}
|
|
1125
|
+
}
|
|
1126
|
+
if (Object.keys(policyRefusals).length === 0)
|
|
1127
|
+
return whole;
|
|
1128
|
+
return {
|
|
1129
|
+
action: 'modify_tools',
|
|
1130
|
+
modifications,
|
|
1131
|
+
policyRefusals,
|
|
1132
|
+
...(confirmed.length > 0 ? { confirmedEscalations: confirmed } : {}),
|
|
1133
|
+
};
|
|
1134
|
+
};
|
|
1020
1135
|
}
|
|
1021
1136
|
/**
|
|
1022
1137
|
* The mode as an `ApprovalPolicy`, named after itself so a durable log can
|