agent-nuvira 3.1.3 → 3.3.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/dist/agents/agents/reasoner.d.ts +8 -0
- package/dist/agents/agents/reasoner.d.ts.map +1 -1
- package/dist/agents/agents/reasoner.js +53 -2
- package/dist/agents/agents/reasoner.js.map +1 -1
- package/dist/agents/agents/writer.d.ts +24 -0
- package/dist/agents/agents/writer.d.ts.map +1 -1
- package/dist/agents/agents/writer.js +200 -0
- package/dist/agents/agents/writer.js.map +1 -1
- package/dist/agents/composite-plan.d.ts +143 -0
- package/dist/agents/composite-plan.d.ts.map +1 -0
- package/dist/agents/composite-plan.js +399 -0
- package/dist/agents/composite-plan.js.map +1 -0
- package/dist/agents/long-form-plan.d.ts +156 -0
- package/dist/agents/long-form-plan.d.ts.map +1 -0
- package/dist/agents/long-form-plan.js +274 -0
- package/dist/agents/long-form-plan.js.map +1 -0
- package/dist/agents/orchestrator.d.ts +107 -0
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +501 -35
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/agents/prompt-assembly.d.ts +8 -0
- package/dist/agents/prompt-assembly.d.ts.map +1 -1
- package/dist/agents/prompt-assembly.js +17 -0
- package/dist/agents/prompt-assembly.js.map +1 -1
- package/dist/cli/chat.d.ts +33 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +161 -7
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/execute.d.ts +12 -0
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +150 -2
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/loop-executor.d.ts +17 -0
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +160 -1
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/models.d.ts.map +1 -1
- package/dist/cli/models.js +10 -0
- package/dist/cli/models.js.map +1 -1
- package/dist/cli/trace.d.ts +19 -0
- package/dist/cli/trace.d.ts.map +1 -1
- package/dist/cli/trace.js +109 -2
- package/dist/cli/trace.js.map +1 -1
- package/dist/gateway/registry.d.ts +31 -0
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +162 -13
- package/dist/gateway/registry.js.map +1 -1
- package/dist/inference/model-entitlement.d.ts +46 -0
- package/dist/inference/model-entitlement.d.ts.map +1 -0
- package/dist/inference/model-entitlement.js +98 -0
- package/dist/inference/model-entitlement.js.map +1 -0
- package/dist/inference/tool-call-utils.d.ts +10 -0
- package/dist/inference/tool-call-utils.d.ts.map +1 -1
- package/dist/inference/tool-call-utils.js +90 -0
- package/dist/inference/tool-call-utils.js.map +1 -1
- package/dist/learning/autonomy-policy.d.ts +370 -0
- package/dist/learning/autonomy-policy.d.ts.map +1 -0
- package/dist/learning/autonomy-policy.js +544 -0
- package/dist/learning/autonomy-policy.js.map +1 -0
- package/dist/learning/cost-tracker.d.ts +14 -0
- package/dist/learning/cost-tracker.d.ts.map +1 -1
- package/dist/learning/cost-tracker.js +22 -0
- package/dist/learning/cost-tracker.js.map +1 -1
- package/dist/learning/credential-fingerprint.d.ts +58 -0
- package/dist/learning/credential-fingerprint.d.ts.map +1 -0
- package/dist/learning/credential-fingerprint.js +126 -0
- package/dist/learning/credential-fingerprint.js.map +1 -0
- package/dist/learning/deliverable-class.d.ts +178 -0
- package/dist/learning/deliverable-class.d.ts.map +1 -0
- package/dist/learning/deliverable-class.js +504 -0
- package/dist/learning/deliverable-class.js.map +1 -0
- package/dist/learning/engine-router.d.ts +12 -1
- package/dist/learning/engine-router.d.ts.map +1 -1
- package/dist/learning/engine-router.js +28 -0
- package/dist/learning/engine-router.js.map +1 -1
- package/dist/learning/long-form.d.ts +252 -0
- package/dist/learning/long-form.d.ts.map +1 -0
- package/dist/learning/long-form.js +521 -0
- package/dist/learning/long-form.js.map +1 -0
- package/dist/learning/model-first-router.d.ts +17 -0
- package/dist/learning/model-first-router.d.ts.map +1 -1
- package/dist/learning/model-first-router.js +27 -0
- package/dist/learning/model-first-router.js.map +1 -1
- package/dist/learning/model-registry.d.ts +66 -4
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +67 -6
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/model-warmup.d.ts +97 -2
- package/dist/learning/model-warmup.d.ts.map +1 -1
- package/dist/learning/model-warmup.js +165 -60
- package/dist/learning/model-warmup.js.map +1 -1
- package/dist/learning/prompt-layers.d.ts +61 -0
- package/dist/learning/prompt-layers.d.ts.map +1 -0
- package/dist/learning/prompt-layers.js +140 -0
- package/dist/learning/prompt-layers.js.map +1 -0
- package/dist/learning/provider-limits.d.ts +66 -0
- package/dist/learning/provider-limits.d.ts.map +1 -0
- package/dist/learning/provider-limits.js +184 -0
- package/dist/learning/provider-limits.js.map +1 -0
- package/dist/learning/reasoning-trace.d.ts +125 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js +85 -2
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/resilient-call.d.ts +36 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +80 -5
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/unattended-job.d.ts +350 -0
- package/dist/learning/unattended-job.d.ts.map +1 -0
- package/dist/learning/unattended-job.js +636 -0
- package/dist/learning/unattended-job.js.map +1 -0
- package/dist/learning/unattended-progress.d.ts +95 -0
- package/dist/learning/unattended-progress.d.ts.map +1 -0
- package/dist/learning/unattended-progress.js +147 -0
- package/dist/learning/unattended-progress.js.map +1 -0
- package/dist/learning/working-state.d.ts +109 -0
- package/dist/learning/working-state.d.ts.map +1 -0
- package/dist/learning/working-state.js +244 -0
- package/dist/learning/working-state.js.map +1 -0
- package/dist/nlu/conversation-gate.d.ts +33 -0
- package/dist/nlu/conversation-gate.d.ts.map +1 -1
- package/dist/nlu/conversation-gate.js +68 -3
- package/dist/nlu/conversation-gate.js.map +1 -1
- package/dist/tools/coding-tools.d.ts.map +1 -1
- package/dist/tools/coding-tools.js +95 -19
- package/dist/tools/coding-tools.js.map +1 -1
- package/dist/tools/edit-verification.d.ts +142 -0
- package/dist/tools/edit-verification.d.ts.map +1 -0
- package/dist/tools/edit-verification.js +262 -0
- package/dist/tools/edit-verification.js.map +1 -0
- package/dist/tools/git-tool.d.ts.map +1 -1
- package/dist/tools/git-tool.js +37 -4
- package/dist/tools/git-tool.js.map +1 -1
- package/dist/tools/registry.d.ts +30 -2
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +40 -11
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/run-cli.d.ts.map +1 -1
- package/dist/tools/run-cli.js +40 -13
- package/dist/tools/run-cli.js.map +1 -1
- package/dist/tools/run-terminal.d.ts +6 -1
- package/dist/tools/run-terminal.d.ts.map +1 -1
- package/dist/tools/run-terminal.js +158 -18
- package/dist/tools/run-terminal.js.map +1 -1
- package/dist/tools/tool-loop.d.ts +109 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +362 -2
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/web-dashboard/chat-console.d.ts +8 -0
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +9 -0
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/chat-retry.d.ts.map +1 -1
- package/dist/web-dashboard/chat-retry.js +10 -2
- package/dist/web-dashboard/chat-retry.js.map +1 -1
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +80 -8
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +81 -4
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/web-dashboard/public/assets/{index-Co7Hk2FT.js → index-kCUkORm7.js} +2 -2
- package/src/web-dashboard/public/assets/{index-Co7Hk2FT.js.map → index-kCUkORm7.js.map} +1 -1
- package/src/web-dashboard/public/index.html +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/tools/run-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"run-cli.d.ts","sourceRoot":"","sources":["../../src/tools/run-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAoBjD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAKvD;AAED,uEAAuE;AACvE,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAqBtD;AAED;;GAEG;AACH,wBAAsB,UAAU,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA0HjF"}
|
package/dist/tools/run-cli.js
CHANGED
|
@@ -31,6 +31,7 @@ import { existsSync } from 'node:fs';
|
|
|
31
31
|
import { dirname, join } from 'node:path';
|
|
32
32
|
import { fileURLToPath } from 'node:url';
|
|
33
33
|
import { resolveAsk } from '../commands/intent-router.js';
|
|
34
|
+
import { decideCliIntentConfirmation } from '../learning/autonomy-policy.js';
|
|
34
35
|
import { maskSenderId } from '../utils/mask.js';
|
|
35
36
|
/** Cap on how much CLI output is fed back to the model. */
|
|
36
37
|
const MAX_OUTPUT_CHARS = 6000;
|
|
@@ -98,12 +99,12 @@ export async function runCliTool(args, ctx) {
|
|
|
98
99
|
confirm = parsed.confirm ?? false;
|
|
99
100
|
}
|
|
100
101
|
catch (err) {
|
|
101
|
-
return `run_cli: missing/invalid arguments — expected { ask, confirm? }. ${err instanceof Error ? err.message.split('\n')[0] : ''}`.trim();
|
|
102
|
+
return `Error: run_cli: missing/invalid arguments — expected { ask, confirm? }. ${err instanceof Error ? err.message.split('\n')[0] : ''}`.trim();
|
|
102
103
|
}
|
|
103
104
|
const matches = resolveAsk(ask);
|
|
104
105
|
const top = matches[0];
|
|
105
106
|
if (!top) {
|
|
106
|
-
return (`run_cli: could not map "${ask}" to a known intent. Tell the user no matching ` +
|
|
107
|
+
return (`Error: run_cli: could not map "${ask}" to a known intent. Tell the user no matching ` +
|
|
107
108
|
`capability was found and suggest checking 'nuvira doctor' or docs/COMMANDS.md.`);
|
|
108
109
|
}
|
|
109
110
|
// Ambiguous → ask the user which they mean (never guess).
|
|
@@ -111,29 +112,51 @@ export async function runCliTool(args, ctx) {
|
|
|
111
112
|
const choices = top.options
|
|
112
113
|
.map((o) => `- "${o.when}" → \`${o.command}\``)
|
|
113
114
|
.join('\n');
|
|
114
|
-
return (`run_cli: the ask "${ask}" is AMBIGUOUS — it maps to more than one command. ` +
|
|
115
|
+
return (`Error: run_cli: the ask "${ask}" is AMBIGUOUS — it maps to more than one command. ` +
|
|
115
116
|
`Call ask_user with 2 choices (one per option below), then re-call run_cli with the ` +
|
|
116
117
|
`resolved command phrased unambiguously:\n${choices}`);
|
|
117
118
|
}
|
|
118
119
|
const command = top.command;
|
|
119
120
|
if (!command) {
|
|
120
|
-
return `run_cli: intent "${top.intent}" has no executable command — tell the user to run the equivalent step manually.`;
|
|
121
|
+
return `Error: run_cli: intent "${top.intent}" has no executable command — tell the user to run the equivalent step manually.`;
|
|
121
122
|
}
|
|
122
|
-
//
|
|
123
|
+
// ── G16: the gate's missing input is whether the USER asked for this ───────
|
|
124
|
+
// The manifest flag says the ACTION is stateful; it does not say the user has
|
|
125
|
+
// to approve what they just asked for. "Stop the dashboard" resolved to this
|
|
126
|
+
// exact command is the authorization — asking again is the manual cadence.
|
|
127
|
+
// Resolved with the SAME router the tool already used, so the tool's ask and
|
|
128
|
+
// the user's ask are compared like for like, and only on an identical command.
|
|
129
|
+
// Intents that cannot be undone (history.clear, memory.prune, publish, …) are
|
|
130
|
+
// still always gated, however the request is phrased.
|
|
131
|
+
let decidedAutonomously = false;
|
|
132
|
+
let autonomyReason = '';
|
|
123
133
|
if (top.confirmation && !confirm) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
134
|
+
const namedByRequest = resolveAsk(ctx.authorizationRequest ?? '').some((m) => m.command === command);
|
|
135
|
+
const verdict = decideCliIntentConfirmation({ intent: top.intent, namedByRequest });
|
|
136
|
+
if (verdict.action !== 'proceed') {
|
|
137
|
+
return (`Error: run_cli: "${top.intent}" changes running services/state and needs explicit confirmation ` +
|
|
138
|
+
`(${verdict.reason}). ` +
|
|
139
|
+
`Call ask_user with choices yes/no confirming this exact command, then re-call ` +
|
|
140
|
+
`run_cli with the SAME ask plus confirm: true only if the user agreed:\n` +
|
|
141
|
+
`\`${command}\``);
|
|
142
|
+
}
|
|
143
|
+
decidedAutonomously = true;
|
|
144
|
+
autonomyReason = verdict.reason;
|
|
145
|
+
ctx.emit?.('autonomy:write-applied', {
|
|
146
|
+
tool: 'run_cli',
|
|
147
|
+
intent: top.intent,
|
|
148
|
+
command,
|
|
149
|
+
reason: verdict.reason,
|
|
150
|
+
}, 'tool-loop');
|
|
128
151
|
}
|
|
129
152
|
// Execute the manifest-resolved command as a child process (the real CLI).
|
|
130
153
|
const entry = cliEntry();
|
|
131
154
|
if (!existsSync(entry)) {
|
|
132
|
-
return `run_cli: CLI entry not found at ${entry} — build the project first (npm run build).`;
|
|
155
|
+
return `Error: run_cli: CLI entry not found at ${entry} — build the project first (npm run build).`;
|
|
133
156
|
}
|
|
134
157
|
const argv = stripCliPrefix(splitCommand(command));
|
|
135
158
|
if (argv.length === 0)
|
|
136
|
-
return `run_cli: empty command resolved for intent "${top.intent}".`;
|
|
159
|
+
return `Error: run_cli: empty command resolved for intent "${top.intent}".`;
|
|
137
160
|
return new Promise((resolve) => {
|
|
138
161
|
const child = spawn(process.execPath, [entry, ...argv], {
|
|
139
162
|
cwd: process.cwd(),
|
|
@@ -170,8 +193,12 @@ export async function runCliTool(args, ctx) {
|
|
|
170
193
|
const body = (out || err).trim().slice(0, MAX_OUTPUT_CHARS);
|
|
171
194
|
const masked = maskSenderId(body);
|
|
172
195
|
const status = code === 0 ? '✅ succeeded' : `❌ failed (exit ${code ?? '?'})`;
|
|
173
|
-
|
|
174
|
-
(masked ? `Output:\n${masked}` : '(no output)')
|
|
196
|
+
const body2 = `run_cli: \`${command}\` ${status}.\n` +
|
|
197
|
+
(masked ? `Output:\n${masked}` : '(no output)');
|
|
198
|
+
resolve(decidedAutonomously
|
|
199
|
+
? `${body2}\n💡 Ran without asking: ${autonomyReason}. State the action plainly in your answer — ` +
|
|
200
|
+
'do not ask for permission to do work the user already asked for.'
|
|
201
|
+
: body2);
|
|
175
202
|
});
|
|
176
203
|
});
|
|
177
204
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-cli.js","sourceRoot":"","sources":["../../src/tools/run-cli.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,OAAO,EAAc,IAAI,EAAE,MAAM,WAAW,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC1D,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEhD,2DAA2D;AAC3D,MAAM,gBAAgB,GAAG,IAAI,CAAC;AAC9B,+CAA+C;AAC/C,MAAM,eAAe,GAAG,MAAM,CAAC;AAE/B,SAAS,WAAW;IAClB,yDAAyD;IACzD,iDAAiD;IACjD,OAAO,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACnE,CAAC;AAED,SAAS,QAAQ;IACf,OAAO,IAAI,CAAC,WAAW,EAAE,EAAE,MAAM,EAAE,UAAU,CAAC,CAAC;AACjD,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc,CAAC,IAAc;IAC3C,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,cAAc,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;QAC7E,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,uEAAuE;AACvE,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,KAAK,GAAkB,IAAI,CAAC;IAChC,KAAK,MAAM,EAAE,IAAI,MAAM,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9C,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,EAAE,KAAK,KAAK;gBAAE,KAAK,GAAG,IAAI,CAAC;;gBAC1B,GAAG,IAAI,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACpC,KAAK,GAAG,EAAE,CAAC;QACb,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,IAAI,GAAG,EAAE,CAAC;gBACR,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACf,GAAG,GAAG,EAAE,CAAC;YACX,CAAC;QACH,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IACD,IAAI,GAAG;QAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACxB,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAa,EAAE,GAAgB;IAC9D,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;IACvD,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACxC,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC;QACjB,OAAO,GAAG,MAAM,CAAC,OAAO,IAAI,KAAK,CAAC;IACpC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,
|
|
1
|
+
{"version":3,"file":"run-cli.js","sourceRoot":"","sources":["../../src/tools/run-cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -31,8 +31,13 @@
|
|
|
31
31
|
* (maskSenderId — phone numbers never echo back in full).
|
|
32
32
|
*/
|
|
33
33
|
import type { ToolContext } from './registry.js';
|
|
34
|
+
/**
|
|
35
|
+
* Is this a recoverable workspace command the agent may run on its own when the
|
|
36
|
+
* request authorized the work?
|
|
37
|
+
*/
|
|
38
|
+
export declare function isRecoverableWorkspaceCommand(command: string): boolean;
|
|
34
39
|
type CommandClass = 'deny' | 'verify' | 'confirm';
|
|
35
|
-
/** Classify a command — deny regexes on the FULL string,
|
|
40
|
+
/** Classify a command — deny regexes on the FULL string, worst-class on segments. */
|
|
36
41
|
export declare function classifyCommand(command: string): CommandClass;
|
|
37
42
|
/** ─── The tool ───────────────────────────────────────────────────────────── */
|
|
38
43
|
export interface RunTerminalArgs {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-terminal.d.ts","sourceRoot":"","sources":["../../src/tools/run-terminal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"run-terminal.d.ts","sourceRoot":"","sources":["../../src/tools/run-terminal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAIH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAuGjD;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAUtE;AAED,KAAK,YAAY,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,CAAC;AA8ClD,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAe7D;AAED,iFAAiF;AAEjF,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAwE9F"}
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
import { spawn } from 'node:child_process';
|
|
34
34
|
import { existsSync } from 'node:fs';
|
|
35
35
|
import { maskSenderId } from '../utils/mask.js';
|
|
36
|
+
import { decideStateChange } from '../learning/autonomy-policy.js';
|
|
36
37
|
/** Cap on how much terminal output is fed back to the model. */
|
|
37
38
|
const MAX_OUTPUT_CHARS = 6000;
|
|
38
39
|
/** Default timeout for a terminal command (tests/builds are slow). */
|
|
@@ -81,7 +82,70 @@ const VERIFY_PREFIXES = [
|
|
|
81
82
|
'git status', 'git diff', 'git log', 'git show', 'git branch', 'git rev-parse',
|
|
82
83
|
// Basic read-only shell.
|
|
83
84
|
'ls', 'cat', 'head', 'tail', 'grep', 'rg', 'find', 'pwd', 'echo', 'wc', 'printf', 'which',
|
|
85
|
+
// Read-only path helpers. Listed because a verify command routinely embeds
|
|
86
|
+
// them in a substitution (`npx vitest run tests/$(basename x).test.ts`) and the
|
|
87
|
+
// segment splitter cannot tell a helper from a real command.
|
|
88
|
+
'basename', 'dirname', 'realpath',
|
|
84
89
|
];
|
|
90
|
+
/**
|
|
91
|
+
* Recoverable WORKSPACE commands — the state-changing operations a requested
|
|
92
|
+
* build/development task legitimately needs, and that cannot strand the user
|
|
93
|
+
* (a dependency uninstalls, a directory removes, a staged file unstages).
|
|
94
|
+
*
|
|
95
|
+
* They run without confirmation when the request authorized the work. That is
|
|
96
|
+
* the case a build task hits on every single run: `npm install` was a mandatory
|
|
97
|
+
* human round trip before this, which is the manual cadence in its purest form.
|
|
98
|
+
*
|
|
99
|
+
* Deliberately NOT here, so they keep the confirm gate:
|
|
100
|
+
* - anything global (`npm install -g`), which mutates the machine, not the repo;
|
|
101
|
+
* - anything fetched and executed (`curl … | bash`);
|
|
102
|
+
* - publishing, deploying, pushing (denied outright anyway);
|
|
103
|
+
* - arbitrary code (`node -e`, `python -c`) and unknown commands — the
|
|
104
|
+
* deny-first default is unchanged, so this list is the ONLY new autonomy.
|
|
105
|
+
*/
|
|
106
|
+
const RECOVERABLE_PREFIXES = [
|
|
107
|
+
// Dependency lifecycle — the requested build's own setup.
|
|
108
|
+
'npm install', 'npm i', 'npm ci', 'npm add', 'npm init',
|
|
109
|
+
'pnpm install', 'pnpm i', 'pnpm add',
|
|
110
|
+
'yarn install', 'yarn add',
|
|
111
|
+
'bun install', 'bun add',
|
|
112
|
+
'pip install', 'pip3 install', 'python -m pip install', 'uv pip install', 'uv add',
|
|
113
|
+
'poetry add', 'poetry install',
|
|
114
|
+
'cargo add', 'cargo build', 'go get', 'go mod tidy', 'composer require',
|
|
115
|
+
// Workspace-local filesystem mutations.
|
|
116
|
+
'mkdir', 'touch', 'cp', 'mv', 'ln -s',
|
|
117
|
+
// Workspace-local git staging.
|
|
118
|
+
'git add', 'git stage', 'git stash',
|
|
119
|
+
];
|
|
120
|
+
/**
|
|
121
|
+
* Shell composition (`a && b`, `a | b`, `a > f`, `$(…)`) makes the effect
|
|
122
|
+
* impossible to attribute to a single prefix, so a recoverable prefix never
|
|
123
|
+
* gets autonomy inside a composed command: `npm install x && rm -rf src` is not
|
|
124
|
+
* an install.
|
|
125
|
+
*/
|
|
126
|
+
const COMPOSED_COMMAND_RE = /[;&|<>`]|\$\(/;
|
|
127
|
+
/** A global install mutates the machine, not the repo — never recoverable. */
|
|
128
|
+
const GLOBAL_INSTALL_RE = /(?:^|\s)(?:-g|--global)(?:\s|$)/;
|
|
129
|
+
/**
|
|
130
|
+
* Is this a recoverable workspace command the agent may run on its own when the
|
|
131
|
+
* request authorized the work?
|
|
132
|
+
*/
|
|
133
|
+
export function isRecoverableWorkspaceCommand(command) {
|
|
134
|
+
const lower = normalize(command).toLowerCase();
|
|
135
|
+
if (!lower)
|
|
136
|
+
return false;
|
|
137
|
+
if (COMPOSED_COMMAND_RE.test(lower))
|
|
138
|
+
return false;
|
|
139
|
+
if (GLOBAL_INSTALL_RE.test(lower))
|
|
140
|
+
return false;
|
|
141
|
+
const toks = leadingTokens(lower, 3);
|
|
142
|
+
return RECOVERABLE_PREFIXES.some((prefix) => {
|
|
143
|
+
const pt = prefix.split(' ');
|
|
144
|
+
return pt.length <= toks.length && toks.slice(0, pt.length).join(' ') === prefix;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/** Severity order — a chain is only as safe as its WORST segment. */
|
|
148
|
+
const CLASS_SEVERITY = { deny: 3, confirm: 2, verify: 1 };
|
|
85
149
|
/** Normalize a command for classification (trim + collapse whitespace). */
|
|
86
150
|
function normalize(command) {
|
|
87
151
|
return String(command ?? '').trim().replace(/\s+/g, ' ');
|
|
@@ -89,49 +153,119 @@ function normalize(command) {
|
|
|
89
153
|
function leadingTokens(lower, n) {
|
|
90
154
|
return lower.split(' ').slice(0, n);
|
|
91
155
|
}
|
|
92
|
-
/**
|
|
156
|
+
/**
|
|
157
|
+
* Split a command into the pieces a shell would run separately.
|
|
158
|
+
*
|
|
159
|
+
* AUDIT FIX (G17): the classifier used to score the WHOLE string against the
|
|
160
|
+
* verify allowlist, so a verify prefix granted the entire line its safety —
|
|
161
|
+
* `npm run build && rm -rf src/` was classified `verify` and ran with no
|
|
162
|
+
* confirmation at all. Now each segment is classified and the chain takes the
|
|
163
|
+
* WORST class. `npx tsc --noEmit && npx vitest run` (both verify) still runs
|
|
164
|
+
* freely, which is the chained form the loop actually uses.
|
|
165
|
+
*
|
|
166
|
+
* Substitutions are split on too, so a body is classified as the command it is;
|
|
167
|
+
* an unrecognised body falls through to `confirm` (the safe direction).
|
|
168
|
+
*/
|
|
169
|
+
function splitSegments(lower) {
|
|
170
|
+
return lower
|
|
171
|
+
.split(/&&|\|\||;|\n|\||\$\(|`/)
|
|
172
|
+
.map((s) => s.replace(/\)+/g, ' ').trim())
|
|
173
|
+
.filter(Boolean);
|
|
174
|
+
}
|
|
175
|
+
/** Classify ONE segment by its leading tokens. */
|
|
176
|
+
function classifySegment(segment) {
|
|
177
|
+
const toks = leadingTokens(segment, 3);
|
|
178
|
+
for (const prefix of VERIFY_PREFIXES) {
|
|
179
|
+
const pt = prefix.split(' ');
|
|
180
|
+
if (pt.length <= toks.length && toks.slice(0, pt.length).join(' ') === prefix) {
|
|
181
|
+
return 'verify';
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return 'confirm';
|
|
185
|
+
}
|
|
186
|
+
/** Classify a command — deny regexes on the FULL string, worst-class on segments. */
|
|
93
187
|
export function classifyCommand(command) {
|
|
94
188
|
const c = normalize(command);
|
|
95
189
|
const lower = c.toLowerCase();
|
|
96
190
|
if (!lower)
|
|
97
191
|
return 'deny';
|
|
192
|
+
// Deny-first on the WHOLE string — a denied command cannot hide behind a
|
|
193
|
+
// substitution or a pipe (this is what keeps `echo $(rm -rf /)` denied).
|
|
98
194
|
for (const d of DENY_PATTERNS) {
|
|
99
195
|
if (d.test(lower))
|
|
100
196
|
return 'deny';
|
|
101
197
|
}
|
|
102
|
-
|
|
103
|
-
for (const
|
|
104
|
-
const
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
}
|
|
198
|
+
let worst = 'verify';
|
|
199
|
+
for (const segment of splitSegments(lower)) {
|
|
200
|
+
const cls = classifySegment(segment);
|
|
201
|
+
if (CLASS_SEVERITY[cls] > CLASS_SEVERITY[worst])
|
|
202
|
+
worst = cls;
|
|
108
203
|
}
|
|
109
|
-
return
|
|
204
|
+
return worst;
|
|
110
205
|
}
|
|
111
206
|
export async function runTerminalTool(args, ctx) {
|
|
112
207
|
const command = normalize(args.command);
|
|
208
|
+
// NOTE: every refusal below is prefixed `Error: ` on purpose. The tool-result
|
|
209
|
+
// convention treats that prefix as "this did not run", and the loop's honest
|
|
210
|
+
// accounting (successfulToolCalls → mutation/verification classification)
|
|
211
|
+
// depends on it. Without the prefix, a no-op `run_terminal` (empty command,
|
|
212
|
+
// denied, awaiting confirmation) counted as a SUCCESSFUL verification — a live
|
|
213
|
+
// run produced exactly that: the model emitted `run_terminal` with no command
|
|
214
|
+
// after the verification nudge and the turn read as verified.
|
|
113
215
|
if (!command)
|
|
114
|
-
return 'run_terminal: empty command.';
|
|
216
|
+
return 'Error: run_terminal: empty command — supply the `command` to run.';
|
|
115
217
|
// Route `buff`/`agent-nuvira` control to the manifest resolver — run_cli —
|
|
116
218
|
// so CLI control has exactly one execution path (no double execution).
|
|
117
219
|
const first = command.split(' ')[0].toLowerCase();
|
|
118
220
|
if (first === 'buff' || first === 'agent-nuvira' || first === 'nuvira') {
|
|
119
|
-
return (`run_terminal: "${command}" looks like an agent-nuvira CLI command. Use the ` +
|
|
221
|
+
return (`Error: run_terminal: "${command}" looks like an agent-nuvira CLI command. Use the ` +
|
|
120
222
|
`run_cli tool instead (it resolves the plain-English ask against the command ` +
|
|
121
223
|
`manifest and applies its own confirmation rules).`);
|
|
122
224
|
}
|
|
123
225
|
const cls = classifyCommand(command);
|
|
124
226
|
if (cls === 'deny') {
|
|
125
|
-
return (`run_terminal: command DENIED — "${command}" is outside what the agent may run. ` +
|
|
227
|
+
return (`Error: run_terminal: command DENIED — "${command}" is outside what the agent may run. ` +
|
|
126
228
|
`Tell the user, and suggest the safe alternative (or that they run it themselves).`);
|
|
127
229
|
}
|
|
230
|
+
// ── G16: the gate consults the request before it consults the model ───────
|
|
231
|
+
// A recoverable workspace command (dependency install, mkdir/cp/mv, git add)
|
|
232
|
+
// on a run that authorized the work is the build's own setup, not a surprise
|
|
233
|
+
// — `npm install` used to be a mandatory human round trip on every build
|
|
234
|
+
// task. Everything else stays exactly where it was: classified `external`, so
|
|
235
|
+
// it asks no matter what the request said.
|
|
236
|
+
let decidedAutonomously = false;
|
|
237
|
+
let autonomyReason = '';
|
|
128
238
|
if (cls === 'confirm' && !args.confirm) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
239
|
+
const recoverable = isRecoverableWorkspaceCommand(command);
|
|
240
|
+
const verdict = decideStateChange({
|
|
241
|
+
tool: 'run_terminal',
|
|
242
|
+
action: `running "${command}"`,
|
|
243
|
+
changeClass: recoverable ? 'local-state' : 'external',
|
|
244
|
+
recoverable,
|
|
245
|
+
authorizedByRequest: ctx.writesAuthorized?.authorized === true,
|
|
246
|
+
});
|
|
247
|
+
if (verdict.action !== 'proceed') {
|
|
248
|
+
return (`Error: run_terminal: "${command}" changes state and needs explicit confirmation ` +
|
|
249
|
+
`(${verdict.reason}). Call ask_user (yes/no, one-line reason), then re-call run_terminal ` +
|
|
250
|
+
`with the SAME command plus confirm:true only if the user agreed.`);
|
|
251
|
+
}
|
|
252
|
+
decidedAutonomously = true;
|
|
253
|
+
autonomyReason = verdict.reason;
|
|
254
|
+
ctx.emit?.('autonomy:write-applied', {
|
|
255
|
+
tool: 'run_terminal',
|
|
256
|
+
command,
|
|
257
|
+
reason: verdict.reason,
|
|
258
|
+
authorization: ctx.writesAuthorized?.reason,
|
|
259
|
+
}, 'tool-loop');
|
|
132
260
|
}
|
|
133
261
|
const timeoutMs = Math.min(MAX_TIMEOUT_MS, Math.max(1000, Math.floor(args.timeout_ms ?? DEFAULT_TIMEOUT_MS)));
|
|
134
|
-
|
|
262
|
+
const output = await execCommand(command, ctx.cwd, timeoutMs);
|
|
263
|
+
if (!decidedAutonomously)
|
|
264
|
+
return output;
|
|
265
|
+
// Reported, never silent — a judgment call the user cannot see is
|
|
266
|
+
// indistinguishable from a bug.
|
|
267
|
+
return (`${output}\n💡 Ran without asking: ${autonomyReason}. State what you ran in your answer — ` +
|
|
268
|
+
'do not ask for permission to do work the user already asked for.');
|
|
135
269
|
}
|
|
136
270
|
/** Spawn the command (shell-interpreted — pipes, &&, substitutions work). */
|
|
137
271
|
function execCommand(command, cwd, timeoutMs) {
|
|
@@ -173,19 +307,25 @@ function execCommand(command, cwd, timeoutMs) {
|
|
|
173
307
|
});
|
|
174
308
|
child.on('error', (e) => {
|
|
175
309
|
clearTimeout(timer);
|
|
176
|
-
resolve(`run_terminal: failed to spawn — ${e.message}`);
|
|
310
|
+
resolve(`Error: run_terminal: failed to spawn — ${e.message}`);
|
|
177
311
|
});
|
|
178
312
|
child.on('exit', (code) => {
|
|
179
313
|
clearTimeout(timer);
|
|
180
314
|
const body = (out || err).trim().slice(0, MAX_OUTPUT_CHARS);
|
|
181
315
|
const masked = maskSenderId(body);
|
|
182
316
|
const timedOut = code === null;
|
|
317
|
+
const ok = !timedOut && code === 0;
|
|
183
318
|
const status = timedOut
|
|
184
319
|
? `⏱ timed out after ${timeoutMs}ms`
|
|
185
|
-
:
|
|
320
|
+
: ok
|
|
186
321
|
? '✅ succeeded'
|
|
187
322
|
: `❌ failed (exit ${code ?? '?'})`;
|
|
188
|
-
|
|
323
|
+
// Enterprise G1: a command that FAILED is not a verification. The loop's
|
|
324
|
+
// honest accounting reads the `Error:` prefix, and the verification gate
|
|
325
|
+
// counts a successful run_terminal as proof — so a non-zero exit (or a
|
|
326
|
+
// timeout) MUST carry the prefix, or a failing test/build would mark the
|
|
327
|
+
// turn "verified". The real output is preserved for diagnosis.
|
|
328
|
+
resolve(`${ok ? '' : 'Error: '}run_terminal: \`${maskSenderId(command)}\` ${status}.\n` +
|
|
189
329
|
(masked ? `Output:\n${masked}` : '(no output)'));
|
|
190
330
|
});
|
|
191
331
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-terminal.js","sourceRoot":"","sources":["../../src/tools/run-terminal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAC3C,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"run-terminal.js","sourceRoot":"","sources":["../../src/tools/run-terminal.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,18 @@
|
|
|
17
17
|
*/
|
|
18
18
|
import { type ToolContext, type ToolJsonSchema } from './registry.js';
|
|
19
19
|
import { type FollowupSuggestion } from './followup-utils.js';
|
|
20
|
+
import { type ToolCallEvidence } from './edit-verification.js';
|
|
21
|
+
import type { TraceEvent, TraceGateName } from '../learning/reasoning-trace.js';
|
|
22
|
+
/**
|
|
23
|
+
* G18 — one NON-LLM fact about a loop turn, as the loop observed it.
|
|
24
|
+
*
|
|
25
|
+
* Type-only on purpose: the loop DESCRIBES what happened and the surface
|
|
26
|
+
* decides where to record it (this module must not reach into the trace store,
|
|
27
|
+
* which is what kept the loop invisible in the first place — see the G18 entry
|
|
28
|
+
* in ENTERPRISE_GRADE_TRACKER.md). `seq`/`timestamp` belong to the store, so
|
|
29
|
+
* they are assigned there, exactly like a trace step.
|
|
30
|
+
*/
|
|
31
|
+
export type LoopTraceEvent = Omit<TraceEvent, 'seq' | 'timestamp'>;
|
|
20
32
|
import type { ToolMessage } from '../inference/interface.js';
|
|
21
33
|
export { type ToolMessage };
|
|
22
34
|
/**
|
|
@@ -98,6 +110,49 @@ export interface ToolLoopOptions {
|
|
|
98
110
|
threadBudgetChars?: number;
|
|
99
111
|
/** Bound on steps per turn (default: 8) — never an infinite loop. */
|
|
100
112
|
maxSteps?: number;
|
|
113
|
+
/**
|
|
114
|
+
* G1 — VERIFICATION GATE (default ON). When a turn mutated the workspace
|
|
115
|
+
* (`edit_file`/`write_file` succeeded) and ran nothing that could observe
|
|
116
|
+
* the result (`run_terminal`/`test`/`browser`/`run_cli`), the loop spends
|
|
117
|
+
* ONE bounded nudge asking the model to verify before it can end the turn.
|
|
118
|
+
* The residual signal is `ToolLoopResult.unverifiedEdit` (which is annotated
|
|
119
|
+
* whether or not the nudge runs). Set false to restore the pre-gate behavior
|
|
120
|
+
* (kept for tests that assert step counts on pure-edit scripts).
|
|
121
|
+
*/
|
|
122
|
+
requireVerification?: boolean;
|
|
123
|
+
/**
|
|
124
|
+
* G13b — DELIVERABLE GATE (default ON). When the request asks for an AUTHORED
|
|
125
|
+
* deliverable to be produced ("write a 12 page story at /path/Mahagatha.md")
|
|
126
|
+
* and the turn ends having written NOTHING to disk, the loop spends ONE
|
|
127
|
+
* bounded nudge naming the destination the request gave, then reports the
|
|
128
|
+
* residual honestly (`ToolLoopResult.undeliveredArtifact`).
|
|
129
|
+
*
|
|
130
|
+
* Why a nudge and not a refusal: the loop reaches this in the cases the engine
|
|
131
|
+
* router cannot cover — a chat surface, or an explicit `engineMode='loop'`
|
|
132
|
+
* override — and in those cases the right outcome is still the ARTIFACT, not a
|
|
133
|
+
* lecture. The router sends the default path to the pipeline engine (which
|
|
134
|
+
* plans units and assembles the document); this gate is what makes "the
|
|
135
|
+
* artifact lands" true on every entry point rather than only the default one.
|
|
136
|
+
* Set false to restore the pre-gate behaviour.
|
|
137
|
+
*/
|
|
138
|
+
requireDeliverable?: boolean;
|
|
139
|
+
/**
|
|
140
|
+
* G18 — OBSERVABILITY SINK for the loop's non-LLM facts: every tool call that
|
|
141
|
+
* ran (name, args, ok/error, duration), every gate DECISION (a nudge spent,
|
|
142
|
+
* or a bound reached), and every REFUSAL (a call declined pending
|
|
143
|
+
* confirmation, an unknown/disabled tool, a repeated dispatch).
|
|
144
|
+
*
|
|
145
|
+
* Why the loop must report its own refusals: they are the one class that
|
|
146
|
+
* reads as nothing at all in a trace — the store showed 0 confirmation
|
|
147
|
+
* refusals not because there were none but because it could not see them, and
|
|
148
|
+
* the audit of the confirmation gates had to be done by reading code and
|
|
149
|
+
* driving the real tools instead. A closed turn is a claim; this is the
|
|
150
|
+
* evidence behind it.
|
|
151
|
+
*
|
|
152
|
+
* Best-effort by contract: the sink is called inside a try/catch, so a broken
|
|
153
|
+
* recorder can never break the turn it observes.
|
|
154
|
+
*/
|
|
155
|
+
onTraceEvent?: (event: LoopTraceEvent) => void;
|
|
101
156
|
/**
|
|
102
157
|
* Bounded auto-continuation budget (default: 2). A turn that dies MID-WAY —
|
|
103
158
|
* the provider walk exhausted every candidate at step N, or the step bound
|
|
@@ -198,6 +253,38 @@ export interface ToolLoopResult {
|
|
|
198
253
|
* as "in progress".
|
|
199
254
|
*/
|
|
200
255
|
unfulfilledPromise?: boolean;
|
|
256
|
+
/**
|
|
257
|
+
* G1 — VERIFICATION GATE — a workspace mutation (`edit_file`/`write_file`)
|
|
258
|
+
* SUCCEEDED this turn and NOTHING that could observe the result
|
|
259
|
+
* (`run_terminal`/`test`/`browser`/`run_cli`) ran. The edit is real, but "it
|
|
260
|
+
* works" is unproven: the caller must not present the turn as a verified
|
|
261
|
+
* change (the dashboard shows a warning; the trace records it). Set by the
|
|
262
|
+
* loop; never guessed by callers. Unlike `unverifiedActionClaim` (which is
|
|
263
|
+
* about an outbound DELIVERY), this is about a CODE change.
|
|
264
|
+
*/
|
|
265
|
+
unverifiedEdit?: boolean;
|
|
266
|
+
/**
|
|
267
|
+
* HONESTY FLAG (G13b) — the request asked for an AUTHORED deliverable to be
|
|
268
|
+
* PRODUCED and this turn wrote NOTHING to disk, so the answer is prose about
|
|
269
|
+
* the work rather than the work.
|
|
270
|
+
*
|
|
271
|
+
* Distinct from `unfulfilledPromise` (the model announced an action and did
|
|
272
|
+
* nothing) and from `unverifiedEdit` (it wrote and nothing checked): here the
|
|
273
|
+
* model DID the composition and simply never produced the artifact. Annotated
|
|
274
|
+
* on every exit path and independent of the nudge being enabled, because a
|
|
275
|
+
* caller must never read "the story is done" from a turn that wrote no file.
|
|
276
|
+
*/
|
|
277
|
+
undeliveredArtifact?: boolean;
|
|
278
|
+
/**
|
|
279
|
+
* G2 — HONESTY FLAG — the answer ASSERTS a completed code change ("I have
|
|
280
|
+
* successfully fixed…", "now fully operational") while the turn mutated the
|
|
281
|
+
* workspace and verified nothing. The delivery-claim guard deliberately
|
|
282
|
+
* ignores code edits, so a false "I fixed it" after a botched `edit_file`
|
|
283
|
+
* passed unreported eight turns in a row in the calculator session. When
|
|
284
|
+
* true, the claim is unverified — the caller appends a correction and the
|
|
285
|
+
* trace flags it.
|
|
286
|
+
*/
|
|
287
|
+
unverifiedEditClaim?: boolean;
|
|
201
288
|
}
|
|
202
289
|
/** An orphan reasoning block or bare <think> is a think-only response. */
|
|
203
290
|
export declare function isThinkOnlyResponse(content: string): boolean;
|
|
@@ -266,6 +353,10 @@ export interface ToolLoopProgress {
|
|
|
266
353
|
successfulToolCalls: string[];
|
|
267
354
|
/** True when a delivery tool reported an actual `✅` send. */
|
|
268
355
|
deliveryConfirmed: boolean;
|
|
356
|
+
/** Session 4 — paths mutated successfully this turn (for verification relevance). */
|
|
357
|
+
mutatedPaths: string[];
|
|
358
|
+
/** Session 4 — successful verification calls (args + result) to judge relevance. */
|
|
359
|
+
verificationEvidence: ToolCallEvidence[];
|
|
269
360
|
}
|
|
270
361
|
/**
|
|
271
362
|
* True when the answer asserts a delivery that no delivery tool performed.
|
|
@@ -301,6 +392,24 @@ export declare function detectUnfulfilledIntentPromise(content: string): boolean
|
|
|
301
392
|
* distinguish "generated a reply" from "actually performed the action".
|
|
302
393
|
*/
|
|
303
394
|
export declare function runToolLoop(opts: ToolLoopOptions): Promise<ToolLoopResult>;
|
|
395
|
+
/**
|
|
396
|
+
* Classify a DECLINED call's result text (G18).
|
|
397
|
+
*
|
|
398
|
+
* The single class this exists for is the confirmation refusal: a tool that
|
|
399
|
+
* says "call ask_user first, then retry with confirm:true" has not failed — it
|
|
400
|
+
* has handed the decision to the user, and that is exactly the event the trace
|
|
401
|
+
* store could not see at all (the G18 audit read "0 refusals" and could not
|
|
402
|
+
* tell it from "no refusals"). The remaining cases are the loop's own guards,
|
|
403
|
+
* named so the record distinguishes *why* work did not happen: a guard is not a
|
|
404
|
+
* provider error — the turn can continue either way, and only the record knows.
|
|
405
|
+
*
|
|
406
|
+
* Returns null when the result is an ordinary tool/runtime error, so the caller
|
|
407
|
+
* keeps its own wording rather than inventing a cause.
|
|
408
|
+
*/
|
|
409
|
+
export declare function classifyToolRefusal(result: string): {
|
|
410
|
+
gate?: TraceGateName;
|
|
411
|
+
summary: string;
|
|
412
|
+
} | null;
|
|
304
413
|
/** Default thread budget in characters (~50K tokens at 4 chars/token). */
|
|
305
414
|
export declare const DEFAULT_THREAD_BUDGET_CHARS = 200000;
|
|
306
415
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-loop.d.ts","sourceRoot":"","sources":["../../src/tools/tool-loop.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAA4B,KAAK,WAAW,EAAE,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-loop.d.ts","sourceRoot":"","sources":["../../src/tools/tool-loop.ts"],"names":[],"mappings":"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"}
|