agent-nuvira 3.1.3 → 3.2.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.
Files changed (146) hide show
  1. package/dist/agents/agents/reasoner.d.ts +8 -0
  2. package/dist/agents/agents/reasoner.d.ts.map +1 -1
  3. package/dist/agents/agents/reasoner.js +53 -2
  4. package/dist/agents/agents/reasoner.js.map +1 -1
  5. package/dist/agents/agents/writer.d.ts +24 -0
  6. package/dist/agents/agents/writer.d.ts.map +1 -1
  7. package/dist/agents/agents/writer.js +194 -0
  8. package/dist/agents/agents/writer.js.map +1 -1
  9. package/dist/agents/composite-plan.d.ts +143 -0
  10. package/dist/agents/composite-plan.d.ts.map +1 -0
  11. package/dist/agents/composite-plan.js +399 -0
  12. package/dist/agents/composite-plan.js.map +1 -0
  13. package/dist/agents/long-form-plan.d.ts +156 -0
  14. package/dist/agents/long-form-plan.d.ts.map +1 -0
  15. package/dist/agents/long-form-plan.js +274 -0
  16. package/dist/agents/long-form-plan.js.map +1 -0
  17. package/dist/agents/orchestrator.d.ts +107 -0
  18. package/dist/agents/orchestrator.d.ts.map +1 -1
  19. package/dist/agents/orchestrator.js +501 -35
  20. package/dist/agents/orchestrator.js.map +1 -1
  21. package/dist/agents/prompt-assembly.d.ts +8 -0
  22. package/dist/agents/prompt-assembly.d.ts.map +1 -1
  23. package/dist/agents/prompt-assembly.js +17 -0
  24. package/dist/agents/prompt-assembly.js.map +1 -1
  25. package/dist/cli/chat.d.ts +27 -0
  26. package/dist/cli/chat.d.ts.map +1 -1
  27. package/dist/cli/chat.js +116 -6
  28. package/dist/cli/chat.js.map +1 -1
  29. package/dist/cli/execute.d.ts +12 -0
  30. package/dist/cli/execute.d.ts.map +1 -1
  31. package/dist/cli/execute.js +105 -2
  32. package/dist/cli/execute.js.map +1 -1
  33. package/dist/cli/models.d.ts.map +1 -1
  34. package/dist/cli/models.js +10 -0
  35. package/dist/cli/models.js.map +1 -1
  36. package/dist/cli/trace.d.ts.map +1 -1
  37. package/dist/cli/trace.js +27 -0
  38. package/dist/cli/trace.js.map +1 -1
  39. package/dist/gateway/registry.d.ts +31 -0
  40. package/dist/gateway/registry.d.ts.map +1 -1
  41. package/dist/gateway/registry.js +143 -13
  42. package/dist/gateway/registry.js.map +1 -1
  43. package/dist/inference/model-entitlement.d.ts +46 -0
  44. package/dist/inference/model-entitlement.d.ts.map +1 -0
  45. package/dist/inference/model-entitlement.js +98 -0
  46. package/dist/inference/model-entitlement.js.map +1 -0
  47. package/dist/learning/autonomy-policy.d.ts +334 -0
  48. package/dist/learning/autonomy-policy.d.ts.map +1 -0
  49. package/dist/learning/autonomy-policy.js +500 -0
  50. package/dist/learning/autonomy-policy.js.map +1 -0
  51. package/dist/learning/credential-fingerprint.d.ts +58 -0
  52. package/dist/learning/credential-fingerprint.d.ts.map +1 -0
  53. package/dist/learning/credential-fingerprint.js +126 -0
  54. package/dist/learning/credential-fingerprint.js.map +1 -0
  55. package/dist/learning/deliverable-class.d.ts +130 -0
  56. package/dist/learning/deliverable-class.d.ts.map +1 -0
  57. package/dist/learning/deliverable-class.js +432 -0
  58. package/dist/learning/deliverable-class.js.map +1 -0
  59. package/dist/learning/long-form.d.ts +252 -0
  60. package/dist/learning/long-form.d.ts.map +1 -0
  61. package/dist/learning/long-form.js +510 -0
  62. package/dist/learning/long-form.js.map +1 -0
  63. package/dist/learning/model-first-router.d.ts +17 -0
  64. package/dist/learning/model-first-router.d.ts.map +1 -1
  65. package/dist/learning/model-first-router.js +27 -0
  66. package/dist/learning/model-first-router.js.map +1 -1
  67. package/dist/learning/model-registry.d.ts +66 -4
  68. package/dist/learning/model-registry.d.ts.map +1 -1
  69. package/dist/learning/model-registry.js +67 -6
  70. package/dist/learning/model-registry.js.map +1 -1
  71. package/dist/learning/model-warmup.d.ts +97 -2
  72. package/dist/learning/model-warmup.d.ts.map +1 -1
  73. package/dist/learning/model-warmup.js +165 -60
  74. package/dist/learning/model-warmup.js.map +1 -1
  75. package/dist/learning/prompt-layers.d.ts +61 -0
  76. package/dist/learning/prompt-layers.d.ts.map +1 -0
  77. package/dist/learning/prompt-layers.js +140 -0
  78. package/dist/learning/prompt-layers.js.map +1 -0
  79. package/dist/learning/provider-limits.d.ts +66 -0
  80. package/dist/learning/provider-limits.d.ts.map +1 -0
  81. package/dist/learning/provider-limits.js +184 -0
  82. package/dist/learning/provider-limits.js.map +1 -0
  83. package/dist/learning/reasoning-trace.d.ts +36 -1
  84. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  85. package/dist/learning/reasoning-trace.js +36 -2
  86. package/dist/learning/reasoning-trace.js.map +1 -1
  87. package/dist/learning/resilient-call.d.ts +36 -1
  88. package/dist/learning/resilient-call.d.ts.map +1 -1
  89. package/dist/learning/resilient-call.js +80 -5
  90. package/dist/learning/resilient-call.js.map +1 -1
  91. package/dist/learning/unattended-job.d.ts +293 -0
  92. package/dist/learning/unattended-job.d.ts.map +1 -0
  93. package/dist/learning/unattended-job.js +544 -0
  94. package/dist/learning/unattended-job.js.map +1 -0
  95. package/dist/learning/unattended-progress.d.ts +95 -0
  96. package/dist/learning/unattended-progress.d.ts.map +1 -0
  97. package/dist/learning/unattended-progress.js +147 -0
  98. package/dist/learning/unattended-progress.js.map +1 -0
  99. package/dist/learning/working-state.d.ts +109 -0
  100. package/dist/learning/working-state.d.ts.map +1 -0
  101. package/dist/learning/working-state.js +244 -0
  102. package/dist/learning/working-state.js.map +1 -0
  103. package/dist/nlu/conversation-gate.d.ts +24 -0
  104. package/dist/nlu/conversation-gate.d.ts.map +1 -1
  105. package/dist/nlu/conversation-gate.js +47 -3
  106. package/dist/nlu/conversation-gate.js.map +1 -1
  107. package/dist/tools/coding-tools.d.ts.map +1 -1
  108. package/dist/tools/coding-tools.js +95 -19
  109. package/dist/tools/coding-tools.js.map +1 -1
  110. package/dist/tools/edit-verification.d.ts +125 -0
  111. package/dist/tools/edit-verification.d.ts.map +1 -0
  112. package/dist/tools/edit-verification.js +237 -0
  113. package/dist/tools/edit-verification.js.map +1 -0
  114. package/dist/tools/git-tool.d.ts.map +1 -1
  115. package/dist/tools/git-tool.js +37 -4
  116. package/dist/tools/git-tool.js.map +1 -1
  117. package/dist/tools/registry.d.ts +30 -2
  118. package/dist/tools/registry.d.ts.map +1 -1
  119. package/dist/tools/registry.js +40 -11
  120. package/dist/tools/registry.js.map +1 -1
  121. package/dist/tools/run-cli.d.ts.map +1 -1
  122. package/dist/tools/run-cli.js +40 -13
  123. package/dist/tools/run-cli.js.map +1 -1
  124. package/dist/tools/run-terminal.d.ts +6 -1
  125. package/dist/tools/run-terminal.d.ts.map +1 -1
  126. package/dist/tools/run-terminal.js +158 -18
  127. package/dist/tools/run-terminal.js.map +1 -1
  128. package/dist/tools/tool-loop.d.ts +35 -0
  129. package/dist/tools/tool-loop.d.ts.map +1 -1
  130. package/dist/tools/tool-loop.js +141 -1
  131. package/dist/tools/tool-loop.js.map +1 -1
  132. package/dist/web-dashboard/chat-console.d.ts +6 -0
  133. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  134. package/dist/web-dashboard/chat-console.js.map +1 -1
  135. package/dist/web-dashboard/chat-retry.d.ts.map +1 -1
  136. package/dist/web-dashboard/chat-retry.js +10 -2
  137. package/dist/web-dashboard/chat-retry.js.map +1 -1
  138. package/dist/web-dashboard/server.d.ts.map +1 -1
  139. package/dist/web-dashboard/server.js +80 -8
  140. package/dist/web-dashboard/server.js.map +1 -1
  141. package/dist/web-dashboard/src/types.d.ts +81 -4
  142. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  143. package/package.json +1 -1
  144. package/src/web-dashboard/public/assets/{index-Co7Hk2FT.js → index-kCUkORm7.js} +2 -2
  145. package/src/web-dashboard/public/assets/{index-Co7Hk2FT.js.map → index-kCUkORm7.js.map} +1 -1
  146. package/src/web-dashboard/public/index.html +1 -1
@@ -0,0 +1,237 @@
1
+ /**
2
+ * Edit-verification guards (enterprise-grade hardening, G1 + G2).
3
+ *
4
+ * The calculator audit found the sharpest agent-side gap: across 99 LLM calls
5
+ * the loop never once ran `run_terminal`/`test`/`browser` — it edited files
6
+ * and *asserted* they worked ("successfully fixed", "now fully operational")
7
+ * eight turns in a row while the user kept reporting the same breakage. The
8
+ * loop's existing honesty guards only cover DELIVERY claims (`gateway_send`),
9
+ * so a false claim about a CODE change passed unflagged.
10
+ *
11
+ * This module is the single source of truth for two questions:
12
+ *
13
+ * 1. Which tool calls MUTATE the workspace, and which ones can VERIFY a
14
+ * mutation? (G1 — the verification gate consumes this.)
15
+ * 2. Does the final answer CLAIM an edit that no verification backed?
16
+ * (G2 — `detectUnverifiedEditClaim`.)
17
+ *
18
+ * Both are pure + deterministic (no LLM, no I/O), so they can be unit-tested
19
+ * exhaustively and behave identically across the CLI, dashboard, and gateway.
20
+ */
21
+ /**
22
+ * Tools that CHANGE the workspace. A turn that ran one of these has produced
23
+ * a claim about reality that only a verification run can support.
24
+ *
25
+ * Deliberately an ALLOWLIST: a write-capable tool added to the registry later
26
+ * is NOT assumed to be a mutation until it is reviewed here (the same
27
+ * fail-safe direction as `PARALLEL_SAFE_TOOL_NAMES`).
28
+ */
29
+ export const MUTATION_TOOLS = new Set(['edit_file', 'write_file']);
30
+ /**
31
+ * Tools that can PROVE a mutation works — they observe the artifact rather
32
+ * than assert it. `run_terminal` (typecheck/tests/build), the `test` pipeline,
33
+ * a real `browser` run, and `run_cli` (e.g. `nuvira test`) all qualify.
34
+ *
35
+ * `delegate` is intentionally excluded: a sub-agent's prose summary is not an
36
+ * observed artifact, and treating it as verification would let the exact
37
+ * failure mode we are closing through the back door.
38
+ */
39
+ export const VERIFICATION_TOOLS = new Set([
40
+ 'run_terminal',
41
+ 'test',
42
+ 'browser',
43
+ 'run_cli',
44
+ ]);
45
+ /** Whether a tool call changes the workspace. */
46
+ export function isMutationTool(name) {
47
+ return MUTATION_TOOLS.has(name);
48
+ }
49
+ /** Whether a tool call can verify a mutation (observe the artifact). */
50
+ export function isVerificationTool(name) {
51
+ return VERIFICATION_TOOLS.has(name);
52
+ }
53
+ /**
54
+ * Classify a turn's tools into mutations + verifications. Only tools that
55
+ * actually RAN SUCCESSFULLY should be passed in (an `Error:` refusal is not a
56
+ * mutation and not a verification — see `ToolLoopProgress.successfulToolCalls`).
57
+ */
58
+ export function classifyEditActivity(toolsRun) {
59
+ const mutations = [];
60
+ const verifications = [];
61
+ for (const name of toolsRun) {
62
+ if (isMutationTool(name))
63
+ mutations.push(name);
64
+ else if (isVerificationTool(name))
65
+ verifications.push(name);
66
+ }
67
+ return {
68
+ mutations,
69
+ verifications,
70
+ // A mutated workspace with nothing observed is the unverified case.
71
+ needsVerification: mutations.length > 0 && verifications.length === 0,
72
+ };
73
+ }
74
+ /**
75
+ * Commands that exercise the WHOLE project, so any change in it is covered.
76
+ * `npm test`, a typecheck, a build, a linter — these observe the artifact even
77
+ * when they never name the changed file.
78
+ */
79
+ const GENERIC_VERIFY_RE = /\b(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:test|build|lint|typecheck|check|ci)\b|\b(?:tsc|vitest|jest|pytest|mocha|cargo\s+test|go\s+test|gradle|mvn|make|node\s+--check)\b/i;
80
+ /**
81
+ * Did this turn's verification actually EXERCISE the artifact it changed?
82
+ *
83
+ * The first cut accepted ANY successful `run_terminal` — so `echo hi` or `ls`
84
+ * marked a turn "verified" (the same class of false positive the gate exists to
85
+ * prevent). A run counts only when it:
86
+ * - is the `test` pipeline or a real `browser` run (inherently project-wide), OR
87
+ * - runs a generic project check (`npm test`, typecheck, build, linter), OR
88
+ * - names one of the files the turn changed (e.g. `grep … style.css`,
89
+ * `node --check script.js`).
90
+ *
91
+ * When the turn's changed paths are UNKNOWN, it falls back to "any successful
92
+ * verification counts" — the pre-strictening behaviour — so an unidentifiable
93
+ * mutation is never falsely flagged.
94
+ */
95
+ export function verificationExercisedArtifact(evidence, changedFiles) {
96
+ if (evidence.length === 0)
97
+ return false;
98
+ // Unknown changed paths → cannot judge relevance; don't cry wolf.
99
+ if (changedFiles.length === 0)
100
+ return true;
101
+ const names = new Set();
102
+ for (const f of changedFiles) {
103
+ if (!f)
104
+ continue;
105
+ names.add(f);
106
+ const base = f.split(/[\\/]/).pop();
107
+ if (base)
108
+ names.add(base);
109
+ }
110
+ for (const e of evidence) {
111
+ if (e.tool === 'test' || e.tool === 'browser')
112
+ return true;
113
+ let text = e.result ?? '';
114
+ if (e.args) {
115
+ try {
116
+ text += ` ${JSON.stringify(e.args)}`;
117
+ }
118
+ catch {
119
+ // Unserializable args — the result text alone is still usable.
120
+ }
121
+ }
122
+ if (GENERIC_VERIFY_RE.test(text))
123
+ return true;
124
+ for (const n of names) {
125
+ if (n && text.includes(n))
126
+ return true;
127
+ }
128
+ }
129
+ return false;
130
+ }
131
+ /**
132
+ * Full edit assessment for a turn: what mutated, what verified, and whether a
133
+ * verification still OWED. This is the single call the loop uses so the gate,
134
+ * the nudge and the honesty flag can never disagree.
135
+ */
136
+ export function assessEditActivity(toolsRun, evidence = [], changedFiles = []) {
137
+ const base = classifyEditActivity(toolsRun);
138
+ if (base.mutations.length === 0)
139
+ return { ...base, needsVerification: false };
140
+ return { ...base, needsVerification: !verificationExercisedArtifact(evidence, changedFiles) };
141
+ }
142
+ /** A sentence that is future/interrogative/negated is NOT a completed claim. */
143
+ const NON_CLAIM_CONTEXT_RE = /\b(?:not|n't|never|unable|cannot|can't|couldn't|didn't|won't|will|would|should|could|can|may|might|going to|about to|try(?:ing)? to|attempt|if you|let me|shall i|should i|do you want|i'?ll|next|then)\b/i;
144
+ /**
145
+ * Past-tense sentences that ASSERT a completed code change. Grouped, because
146
+ * the audit surfaced several distinct phrasings the model used:
147
+ * - "I have successfully secured the calculator…"
148
+ * - "The inline event handlers have been successfully removed…"
149
+ * - "I have applied the requested changes…"
150
+ * - "The converter is now fully operational…"
151
+ */
152
+ const EDIT_CLAIM_RES = [
153
+ // First-person completed change: "I have fixed / updated / refactored …"
154
+ /\bi(?:'ve| have)\s+(?:just\s+|now\s+|also\s+|already\s+|successfully\s+)*(?:fixed|updated|refactored|implemented|applied|added|created|removed|corrected|replaced|rewritten|rewrote|changed|modified|enhanced|completed|adjusted|introduced|resolved|rebuilt|migrated|secured|cleaned\s+up|wired\s+up|hooked\s+up)\b/i,
155
+ // Bare verb form: "I fixed / updated …"
156
+ /\bi\s+(?:just\s+|already\s+|successfully\s+|now\s+)*(?:fixed|updated|refactored|implemented|applied|corrected|replaced|removed|resolved|rewrote|rebuilt)\b/i,
157
+ // Adverb-led success: "successfully updated / properly fixed / fully implemented"
158
+ /\b(?:successfully|properly|fully|correctly)\s+(?:fixed|updated|refactored|implemented|applied|added|created|removed|corrected|replaced|changed|modified|moderni[sz]ed|improved|polished|styled|reworked|optimi[sz]ed|simplified|hardened|enhanced|completed|resolved|rewired|restored|cleaned|secured|wired|hooked)\b/i,
159
+ // Passive change: "the fix / changes / edits have been applied"
160
+ /\b(?:the\s+)?(?:fix|change|changes|update|updates|edit|edits|issue|bug|problem|error|refactor|patch)\s+(?:has|have|is|are)\s+(?:now\s+)?(?:been\s+)?(?:applied|made|implemented|fixed|completed|resolved|added|removed|corrected|patched)\b/i,
161
+ // State assertion: "it is now fully operational / working / fixed"
162
+ /\b(?:is|are|it'?s|this\s+is|that\s+is)\s+(?:now\s+)?(?:fully\s+|properly\s+|already\s+)?(?:operational|functional|working(?:\s+(?:correctly|now|fine|as\s+expected))?|fixed|complete|completed|done|ready|in\s+place|up\s+to\s+date)\b/i,
163
+ // "I have applied the requested changes"
164
+ /\bi(?:'ve| have)\s+(?:now\s+|just\s+)*(?:applied|made)\s+the\s+(?:changes|requested\s+changes|fix|edits|updates|modifications)\b/i,
165
+ // "the changes are applied / complete"
166
+ /\b(?:changes|edits|updates|modifications)\s+(?:are|have\s+been)\s+(?:applied|made|complete|completed|done)\b/i,
167
+ ];
168
+ /**
169
+ * True when the answer asserts a completed CODE change that no verification
170
+ * backed.
171
+ *
172
+ * The claim is judged ONLY when the turn actually mutated the workspace and
173
+ * ran nothing that could observe the result. If a verification tool ran
174
+ * successfully, the assertion is (at least) grounded in an observed artifact
175
+ * and the flag stays quiet — crying wolf on a verified edit would erode the
176
+ * flag the way an over-eager linter gets ignored.
177
+ *
178
+ * Sentence-scoped so a negation or a conditional elsewhere in the answer
179
+ * never turns a truthful statement into a flag (and vice-versa).
180
+ */
181
+ export function detectUnverifiedEditClaim(content, mutationsRun, verificationsRun) {
182
+ const text = (content || '').trim();
183
+ if (!text)
184
+ return false;
185
+ // Nothing was changed → no code-change claim can be "unverified".
186
+ if (!mutationsRun.some(isMutationTool))
187
+ return false;
188
+ // Something observed the artifact → the claim is grounded.
189
+ if (verificationsRun.some(isVerificationTool))
190
+ return false;
191
+ const sentences = text.split(/(?<=[.!?\u3002\uff01\uff1f])\s+|\n+/);
192
+ for (const sentence of sentences) {
193
+ const s = sentence.trim();
194
+ if (!s || NON_CLAIM_CONTEXT_RE.test(s))
195
+ continue;
196
+ if (EDIT_CLAIM_RES.some((re) => re.test(s)))
197
+ return true;
198
+ }
199
+ return false;
200
+ }
201
+ /**
202
+ * The nudge sent when a turn mutated the workspace and verified nothing.
203
+ * Deliberately concrete (names the tools) so a weak model can act on it
204
+ * without inventing a syntax — the same principle as `TOOL_FALLBACK_HINTS`.
205
+ */
206
+ export const VERIFICATION_NUDGE = 'You changed files this turn but nothing VERIFIED the change — an edit is not ' +
207
+ 'evidence that it works. Before finishing, run the check that actually observes ' +
208
+ 'the artifact (e.g. run_terminal for a typecheck/test/build, the test pipeline, ' +
209
+ 'or a browser run), then report what that check showed. If no such check is ' +
210
+ 'possible here, say so explicitly and do NOT claim the change works.';
211
+ /**
212
+ * The nudge sent when a turn ended asking PERMISSION for work the user's own
213
+ * request already authorized (G13 — the manual-cadence complaint).
214
+ *
215
+ * Deliberately states the authorization and the expected behaviour, and names
216
+ * the one case where asking is still right, so the model does not read this as
217
+ * "never consult" — a blanket no-asking rule would produce silent wrong turns
218
+ * instead of stalls, which is worse. The vocabulary is the autonomy policy's:
219
+ * proceed unless the decision is blocking, high-impact, irreversible and has
220
+ * no sensible default.
221
+ */
222
+ export const AUTHORIZED_WORK_NUDGE = 'The user\u2019s own request already asked for this work, so asking whether to ' +
223
+ 'proceed is a round trip that delivers nothing. Do NOT end the turn on a request ' +
224
+ 'for permission: carry the work out with the tools available, decide anything that ' +
225
+ 'is yours to decide, and state the decision in your answer so the user can redirect. ' +
226
+ 'Reserve `ask_user` for a decision that is genuinely theirs — one that cannot ' +
227
+ 'proceed without an answer, is high-impact and irreversible, and has no sensible ' +
228
+ 'default — and never ask for permission in plain text.';
229
+ /**
230
+ * The correction appended to a delivered answer whose code-change claim was
231
+ * never verified. Kept short and honest — it states what is known, not a
232
+ * verdict about whether the edit is correct.
233
+ */
234
+ export const UNVERIFIED_EDIT_NOTE = '\u26a0\ufe0f Note: files were changed this turn but no verification (test / ' +
235
+ 'typecheck / build / browser run) confirmed the result — treat the claim above ' +
236
+ 'as unverified.';
237
+ //# sourceMappingURL=edit-verification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"edit-verification.js","sourceRoot":"","sources":["../../src/tools/edit-verification.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"git-tool.d.ts","sourceRoot":"","sources":["../../src/tools/git-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,kBAAkB;IAClB,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB;AAkCD,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBzF;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAyErF"}
1
+ {"version":3,"file":"git-tool.d.ts","sourceRoot":"","sources":["../../src/tools/git-tool.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAGjD,uDAAuD;AACvD,MAAM,WAAW,WAAW;IAC1B,kBAAkB;IAClB,MAAM,EAAE,QAAQ,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;IAC7C,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,oEAAoE;IACpE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,oCAAoC;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,6DAA6D;AAC7D,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC7C,OAAO,EAAE,MAAM,CAAC;CACjB;AAkCD,8EAA8E;AAC9E,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAgBzF;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7D;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CA0GrF"}
@@ -33,6 +33,7 @@
33
33
  * Never throws: every failure returns a helpful string.
34
34
  */
35
35
  import { execFileSync } from 'node:child_process';
36
+ import { decideStateChange, requestRequestsCommit } from '../learning/autonomy-policy.js';
36
37
  /** Action names that map to denied git commands (parity with run_terminal). */
37
38
  const DENIED_ACTIONS = {
38
39
  push: 'git push is denied — pushing is a human decision, never an autonomous loop.',
@@ -136,10 +137,36 @@ export async function runGitTool(args, ctx) {
136
137
  if (!message) {
137
138
  return 'Error: git commit needs a message (git refuses empty messages — it would open an editor). Call ask_user for the commit message, then re-call with it.';
138
139
  }
140
+ // ── G16: the gate's missing input is whether the USER asked for the commit ─
141
+ // "Commit these changes" IS the approval, and asking for it again is a round
142
+ // trip in the most common dev flow. Note the asymmetry, and why it is right:
143
+ // the commit is local and recoverable (a reflog entry, not a lost file), but
144
+ // it is NOT marked `recoverable` here — only the request NAMING a commit
145
+ // unlocks it, so a commit the model decided on its own still asks.
146
+ let decidedAutonomously = false;
147
+ let autonomyReason = '';
139
148
  if (!args.confirm) {
140
- return ('git commit: this changes the repository history and needs explicit confirmation. ' +
141
- 'Call ask_user (yes/no — show the diff card first so the user sees exactly what will be committed), ' +
142
- 'then re-call git commit with the SAME message plus confirm:true only if the user agreed.');
149
+ const verdict = decideStateChange({
150
+ tool: 'git commit',
151
+ action: 'recording a commit in this repository',
152
+ changeClass: 'local-state',
153
+ namedByRequest: requestRequestsCommit(ctx.authorizationRequest ?? ''),
154
+ authorizedByRequest: ctx.writesAuthorized?.authorized === true,
155
+ });
156
+ if (verdict.action !== 'proceed') {
157
+ return ('git commit: this changes the repository history and needs explicit confirmation ' +
158
+ `(${verdict.reason}). ` +
159
+ 'Call ask_user (yes/no — show the diff card first so the user sees exactly what will be committed), ' +
160
+ 'then re-call git commit with the SAME message plus confirm:true only if the user agreed.');
161
+ }
162
+ decidedAutonomously = true;
163
+ autonomyReason = verdict.reason;
164
+ ctx.emit?.('autonomy:write-applied', {
165
+ tool: 'git commit',
166
+ message,
167
+ files: args.files ?? [],
168
+ reason: verdict.reason,
169
+ }, 'tool-loop');
143
170
  }
144
171
  if (SHELL_METACHARS.test(message)) {
145
172
  return 'Error: git commit message contains shell metacharacters — denied (argv exec would still be safe, but refuse anyway).';
@@ -159,6 +186,12 @@ export async function runGitTool(args, ctx) {
159
186
  return `git commit failed: ${committed.out}`;
160
187
  }
161
188
  const what = files.length > 0 ? files.join(', ') : 'all changes';
162
- return `✅ Committed (${what}):\n${committed.out.slice(0, 800)}`;
189
+ const result = `✅ Committed (${what}):\n${committed.out.slice(0, 800)}`;
190
+ if (!decidedAutonomously)
191
+ return result;
192
+ // Reported, never silent: the user must be able to see (and undo) a commit
193
+ // they did not explicitly request in this turn's wording.
194
+ return (`${result}\n💡 Committed without asking: ${autonomyReason}. ` +
195
+ 'State the commit in your answer so the user can amend or reset it.');
163
196
  }
164
197
  //# sourceMappingURL=git-tool.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git-tool.js","sourceRoot":"","sources":["../../src/tools/git-tool.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-tool.js","sourceRoot":"","sources":["../../src/tools/git-tool.ts"],"names":[],"mappings":"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"}
@@ -80,6 +80,34 @@ export interface ToolContext {
80
80
  * Returns the user's answer(s).
81
81
  */
82
82
  askUser?: (question: string, choices: AskUserChoice[], multiSelect: boolean) => Promise<AskUserAnswer>;
83
+ /**
84
+ * G13 — does the CURRENT request authorize file writes?
85
+ *
86
+ * Set once per turn by the tool loop from the last user message (see
87
+ * `requestAuthorizesWrites` in learning/autonomy-policy.ts). The
88
+ * confirm-before-write gate and `ask_user` read it to tell "the user already
89
+ * ordered this" apart from "this would be a surprise", so an unattended run
90
+ * does not stop to ask permission for the work it was asked to do.
91
+ *
92
+ * `undefined` (no loop, direct tool invocation, a test) keeps the original
93
+ * confirm-or-refuse behaviour exactly.
94
+ */
95
+ writesAuthorized?: import('../learning/autonomy-policy.js').WriteAuthorization;
96
+ /**
97
+ * The raw last user message the verdict above was derived from.
98
+ *
99
+ * The verdict answers "did the request ask for FILES" — but each gate needs
100
+ * the evidence ITS OWN question requires, and that evidence lives in the
101
+ * request text: whether the request names the file being edited
102
+ * (`edit_file`), asks for a commit (`git commit`), or resolves to the exact
103
+ * CLI command being run (`run_cli`). Handing the gates the text lets each one
104
+ * measure for itself instead of guessing from a boolean that was computed for
105
+ * a different question.
106
+ *
107
+ * `undefined` (no loop, a direct tool call, a test) means every gate keeps
108
+ * its original confirm-or-refuse behaviour exactly.
109
+ */
110
+ authorizationRequest?: string;
83
111
  /** Emit an event on the observability bus (for pipeline runs). */
84
112
  emit?: (event: string, data: unknown, source?: string) => void;
85
113
  /** LLM call fn for C2 verify (resolved provider already chosen). */
@@ -296,9 +324,9 @@ export declare function toolJsonSchemas(toolNames?: string[]): ToolJsonSchema[];
296
324
  * calling suggest_followups with exactly 3 followups, and clarifies ambiguous
297
325
  * requests via ask_user instead of guessing.
298
326
  */
299
- export declare const TOOL_CONTRACT = "You have tools available. Call them when appropriate.\n\n- If a request is ambiguous or incomplete, call `ask_user` with a question and 2\u20134 choices \u2014 never guess, never ask in plain text.\n- If a request needs code written, debugged, or prior work resumed, call `build`, `repair`, or `resume` with the goal.\n- If a request needs documentation, a website, analysis of a project, or running tests, call `document`, `website`, `analyze`, or `test` with the goal.\n- If a request asks to publish a release (npm/GitHub), call `publish`. It is irreversible \u2014 confirm the bump type and target with the user via `ask_user` first unless they already specified them.\n- If a request's completeness is uncertain, call `verify_requirement` first.\n- If a request asks to deliver a message or result to a DIFFERENT contact/channel than the one you are currently chatting on (WhatsApp, Telegram, Slack, email, \u2026), call `gateway_send` with the target (e.g. `whatsapp:Alex`) and the text. Do NOT call gateway_send to reply to the CURRENT conversation \u2014 your text response is automatically delivered back. If the target contact is not configured, tell the user what to set up.\n- If a request asks to manage the system/agent itself in plain English \u2014 start/stop the dashboard or gateway, check status, add/remove a verified sender, configure a platform (telegram/whatsapp), run evals, show stats \u2014 call `run_cli` with the plain-English ask. It resolves the exact `buff` command and runs it. If the tool reports AMBIGUOUS or asks for confirmation, call `ask_user` first, then retry run_cli with the user's answer.\n- If a subtask can be delegated to a specialized sub-agent (gather context, review, security scan, run tests), call `delegate` with the agent type, a focused prompt, and optional file paths.\n- To find code matching a pattern (context gathering, locating definitions/usages), call `code_search` with the pattern and optional globs.\n- To READ the project: call `read_file` to open a file (with line numbers), `list_dir` to see a directory's contents, or `glob` to find files by pattern. Always prefer reading the actual file over assuming its contents \u2014 a large file reports a line range, continue with offset/limit.\n- To CHANGE code (after reading it): call `edit_file` for a surgical exact-text replacement, or `write_file` to create/replace a file. Both are state-changing and refuse without confirm \u2014 call `ask_user` to confirm the change with a one-line summary, then retry with confirm:true.\n- To VERIFY code by actual invocation: call `run_terminal` with the real command (`npx vitest run tests/x.test.ts`, `npx tsc --noEmit`, `npm run build`, `git diff`). Read-only verify commands run directly; state-changing ones need confirm:true after the user approves via ask_user. Never guess that a test passes \u2014 run it and read the output. Use run_cli (not run_terminal) for buff/agent-nuvira control commands.\n- END EVERY RESPONSE by calling `suggest_followups` with exactly 3 followups the user is likely to want next \u2014 natural next questions, deeper dives, or related directions that build on what you just said; specific to this conversation, not generic.\n- If you have nothing to add, answer directly and still end with suggest_followups.\n- ORDERING (non-negotiable): deliver the user's answer FIRST, then suggest_followups. The followup call must come only AFTER the complete answer is written \u2014 never before it, never instead of it. A bare lead-in (\"Sure, I can help!\") is NOT an answer; write the full answer in the same step as the followup call.";
327
+ export declare const TOOL_CONTRACT = "You have tools available. Call them when appropriate.\n\n- If a request is ambiguous or incomplete, call `ask_user` with a question and 2\u20134 choices \u2014 never guess, never ask in plain text.\n- If a request needs code written, debugged, or prior work resumed, call `build`, `repair`, or `resume` with the goal.\n- If a request needs documentation, a website, analysis of a project, or running tests, call `document`, `website`, `analyze`, or `test` with the goal.\n- If a request asks to publish a release (npm/GitHub), call `publish`. It leaves this machine and is irreversible \u2014 confirm the bump type and target with the user via `ask_user` first unless they already specified them.\n- If a request's completeness is uncertain, call `verify_requirement` first.\n- If a request asks to deliver a message or result to a DIFFERENT contact/channel than the one you are currently chatting on (WhatsApp, Telegram, Slack, email, \u2026), call `gateway_send` with the target (e.g. `whatsapp:Alex`) and the text. Do NOT call gateway_send to reply to the CURRENT conversation \u2014 your text response is automatically delivered back. If the target contact is not configured, tell the user what to set up.\n- If a request asks to manage the system/agent itself in plain English \u2014 start/stop the dashboard or gateway, check status, add/remove a verified sender, configure a platform (telegram/whatsapp), run evals, show stats \u2014 call `run_cli` with the plain-English ask. It resolves the exact `buff` command and runs it. If the user's own request already resolves to that command (\"stop the dashboard\"), it just runs \u2014 do not ask for permission to do what was just asked. If it reports AMBIGUOUS, call `ask_user` with the two choices; if the intent is one YOU chose rather than the user (or is irreversible: history.clear, memory.prune, stats.cost.clear, publish), call `ask_user` first and retry with confirm:true.\n- If a subtask can be delegated to a specialized sub-agent (gather context, review, security scan, run tests), call `delegate` with the agent type, a focused prompt, and optional file paths.\n- To find code matching a pattern (context gathering, locating definitions/usages), call `code_search` with the pattern and optional globs.\n- To READ the project: call `read_file` to open a file (with line numbers), `list_dir` to see a directory's contents, or `glob` to find files by pattern. Always prefer reading the actual file over assuming its contents \u2014 a large file reports a line range, continue with offset/limit.\n- To CHANGE code (after reading it): call `edit_file` for a surgical exact-text replacement, or `write_file` to create/replace a file. CREATING a file the request asked for is applied directly \u2014 no confirmation needed, so just call it. An `edit_file` that is surgical (small relative to the file) also applies directly, as does one on a file the request names \u2014 the verify loop must not need a human between iterations. A whole-file write over existing content, or an edit that rewrites most of a file, refuses without confirm \u2014 call `ask_user` with a one-line summary, then retry with confirm:true.\n- NEVER ask for permission to do work the user already asked for \u2014 not via `ask_user` and never in plain text. Decide it yourself, state the decision in your answer, and continue. Reserve `ask_user` for a decision that is genuinely the user's: it cannot proceed without an answer, it is high-impact AND irreversible, and there is no sensible default (overwriting existing work, deleting data, spending money, publishing).\n- To VERIFY code by actual invocation: call `run_terminal` with the real command (`npx vitest run tests/x.test.ts`, `npx tsc --noEmit`, `npm run build`, `git diff`). Read-only verify commands run directly, and so do recoverable workspace commands (`npm/pnpm/yarn/bun install`, `pip install`, `mkdir`, `touch`, `cp`, `mv`, `git add`, `npm init`) when the request authorized the work \u2014 the build you were asked for is your job to set up. Everything else state-changing (network fetches, arbitrary code, global installs, anything leaving the machine) needs confirm:true after the user approves via ask_user. Never guess that a test passes \u2014 run it and read the output. Use run_cli (not run_terminal) for buff/agent-nuvira control commands, and the `git` tool (not run_terminal) to commit.\n- END EVERY RESPONSE by calling `suggest_followups` with exactly 3 followups the user is likely to want next \u2014 natural next questions, deeper dives, or related directions that build on what you just said; specific to this conversation, not generic.\n- If you have nothing to add, answer directly and still end with suggest_followups.\n- ORDERING (non-negotiable): deliver the user's answer FIRST, then suggest_followups. The followup call must come only AFTER the complete answer is written \u2014 never before it, never instead of it. A bare lead-in (\"Sure, I can help!\") is NOT an answer; write the full answer in the same step as the followup call.";
300
328
  /** The JSON-fallback tool contract — for providers WITHOUT native tool-calling. */
301
- export declare const TOOL_CONTRACT_JSON = "You have tools available. Call them when appropriate.\n\n- If a request is ambiguous or incomplete, call `ask_user` with a question and 2\u20134 choices \u2014 never guess, never ask in plain text.\n- If a request needs code written, debugged, or prior work resumed, call `build`, `repair`, or `resume` with the goal.\n- If a request needs documentation, a website, analysis of a project, or running tests, call `document`, `website`, `analyze`, or `test` with the goal.\n- If a request asks to publish a release (npm/GitHub), call `publish`. It is irreversible \u2014 confirm the bump type and target with the user via `ask_user` first unless they already specified them.\n- If a request's completeness is uncertain, call `verify_requirement` first.\n- If a request asks to deliver a message or result to a DIFFERENT contact/channel than the one you are currently chatting on (WhatsApp, Telegram, Slack, email, \u2026), call `gateway_send` with the target (e.g. `whatsapp:Alex`) and the text. Do NOT call gateway_send to reply to the CURRENT conversation \u2014 your text response is automatically delivered back. If the target contact is not configured, tell the user what to set up.\n- If a request asks to manage the system/agent itself in plain English \u2014 start/stop the dashboard or gateway, check status, add/remove a verified sender, configure a platform (telegram/whatsapp), run evals, show stats \u2014 call `run_cli` with the plain-English ask. It resolves the exact `buff` command and runs it. If the tool reports AMBIGUOUS or asks for confirmation, call `ask_user` first, then retry run_cli with the user's answer.\n- If a subtask can be delegated to a specialized sub-agent (gather context, review, security scan, run tests), call `delegate` with the agent type, a focused prompt, and optional file paths.\n- To find code matching a pattern (context gathering, locating definitions/usages), call `code_search` with the pattern and optional globs.\n- To READ the project: call `read_file` to open a file (with line numbers), `list_dir` to see a directory's contents, or `glob` to find files by pattern. Always prefer reading the actual file over assuming its contents \u2014 a large file reports a line range, continue with offset/limit.\n- To CHANGE code (after reading it): call `edit_file` for a surgical exact-text replacement, or `write_file` to create/replace a file. Both are state-changing and refuse without confirm \u2014 call `ask_user` to confirm the change with a one-line summary, then retry with confirm:true.\n- To VERIFY code by actual invocation: call `run_terminal` with the real command (`npx vitest run tests/x.test.ts`, `npx tsc --noEmit`, `npm run build`, `git diff`). Read-only verify commands run directly; state-changing ones need confirm:true after the user approves via ask_user. Never guess that a test passes \u2014 run it and read the output. Use run_cli (not run_terminal) for buff/agent-nuvira control commands.\n- END EVERY RESPONSE by calling `suggest_followups` with exactly 3 followups the user is likely to want next \u2014 natural next questions, deeper dives, or related directions that build on what you just said; specific to this conversation, not generic.\n- If you have nothing to add, answer directly and still end with suggest_followups.\n- ORDERING (non-negotiable): deliver the user's answer FIRST, then suggest_followups. The followup call must come only AFTER the complete answer is written \u2014 never before it, never instead of it. A bare lead-in (\"Sure, I can help!\") is NOT an answer; write the full answer in the same step as the followup call.\n\nTOOL CALL FORMAT (JSON fallback transport):\nWhen calling a tool, emit its JSON AFTER your response text, in this exact shape:\n{\"tool\":\"<name>\",\"arguments\":{...}}\nOne tool call per block. The final block may be a suggest_followups call.";
329
+ export declare const TOOL_CONTRACT_JSON = "You have tools available. Call them when appropriate.\n\n- If a request is ambiguous or incomplete, call `ask_user` with a question and 2\u20134 choices \u2014 never guess, never ask in plain text.\n- If a request needs code written, debugged, or prior work resumed, call `build`, `repair`, or `resume` with the goal.\n- If a request needs documentation, a website, analysis of a project, or running tests, call `document`, `website`, `analyze`, or `test` with the goal.\n- If a request asks to publish a release (npm/GitHub), call `publish`. It leaves this machine and is irreversible \u2014 confirm the bump type and target with the user via `ask_user` first unless they already specified them.\n- If a request's completeness is uncertain, call `verify_requirement` first.\n- If a request asks to deliver a message or result to a DIFFERENT contact/channel than the one you are currently chatting on (WhatsApp, Telegram, Slack, email, \u2026), call `gateway_send` with the target (e.g. `whatsapp:Alex`) and the text. Do NOT call gateway_send to reply to the CURRENT conversation \u2014 your text response is automatically delivered back. If the target contact is not configured, tell the user what to set up.\n- If a request asks to manage the system/agent itself in plain English \u2014 start/stop the dashboard or gateway, check status, add/remove a verified sender, configure a platform (telegram/whatsapp), run evals, show stats \u2014 call `run_cli` with the plain-English ask. It resolves the exact `buff` command and runs it. If the user's own request already resolves to that command (\"stop the dashboard\"), it just runs \u2014 do not ask for permission to do what was just asked. If it reports AMBIGUOUS, call `ask_user` with the two choices; if the intent is one YOU chose rather than the user (or is irreversible: history.clear, memory.prune, stats.cost.clear, publish), call `ask_user` first and retry with confirm:true.\n- If a subtask can be delegated to a specialized sub-agent (gather context, review, security scan, run tests), call `delegate` with the agent type, a focused prompt, and optional file paths.\n- To find code matching a pattern (context gathering, locating definitions/usages), call `code_search` with the pattern and optional globs.\n- To READ the project: call `read_file` to open a file (with line numbers), `list_dir` to see a directory's contents, or `glob` to find files by pattern. Always prefer reading the actual file over assuming its contents \u2014 a large file reports a line range, continue with offset/limit.\n- To CHANGE code (after reading it): call `edit_file` for a surgical exact-text replacement, or `write_file` to create/replace a file. CREATING a file the request asked for is applied directly \u2014 no confirmation needed, so just call it. An `edit_file` that is surgical (small relative to the file) also applies directly, as does one on a file the request names \u2014 the verify loop must not need a human between iterations. A whole-file write over existing content, or an edit that rewrites most of a file, refuses without confirm \u2014 call `ask_user` with a one-line summary, then retry with confirm:true.\n- NEVER ask for permission to do work the user already asked for \u2014 not via `ask_user` and never in plain text. Decide it yourself, state the decision in your answer, and continue. Reserve `ask_user` for a decision that is genuinely the user's: it cannot proceed without an answer, it is high-impact AND irreversible, and there is no sensible default (overwriting existing work, deleting data, spending money, publishing).\n- To VERIFY code by actual invocation: call `run_terminal` with the real command (`npx vitest run tests/x.test.ts`, `npx tsc --noEmit`, `npm run build`, `git diff`). Read-only verify commands run directly, and so do recoverable workspace commands (`npm/pnpm/yarn/bun install`, `pip install`, `mkdir`, `touch`, `cp`, `mv`, `git add`, `npm init`) when the request authorized the work \u2014 the build you were asked for is your job to set up. Everything else state-changing (network fetches, arbitrary code, global installs, anything leaving the machine) needs confirm:true after the user approves via ask_user. Never guess that a test passes \u2014 run it and read the output. Use run_cli (not run_terminal) for buff/agent-nuvira control commands, and the `git` tool (not run_terminal) to commit.\n- END EVERY RESPONSE by calling `suggest_followups` with exactly 3 followups the user is likely to want next \u2014 natural next questions, deeper dives, or related directions that build on what you just said; specific to this conversation, not generic.\n- If you have nothing to add, answer directly and still end with suggest_followups.\n- ORDERING (non-negotiable): deliver the user's answer FIRST, then suggest_followups. The followup call must come only AFTER the complete answer is written \u2014 never before it, never instead of it. A bare lead-in (\"Sure, I can help!\") is NOT an answer; write the full answer in the same step as the followup call.\n\nTOOL CALL FORMAT (JSON fallback transport):\nWhen calling a tool, emit its JSON AFTER your response text, in this exact shape:\n{\"tool\":\"<name>\",\"arguments\":{...}}\nOne tool call per block. The final block may be a suggest_followups call.";
302
330
  /**
303
331
  * Parse + validate a model's followups output against the shared
304
332
  * suggest_followups schema. Accepts both the tool shape `[{prompt,label?}]`
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/tools/registry.ts"],"names":[],"mappings":"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"}
@@ -26,6 +26,7 @@ import { join } from 'path';
26
26
  import { envBuff } from '../config/paths.js';
27
27
  import { z, toJSONSchema } from 'zod';
28
28
  import { ACTION_BY_INTENT } from '../nlu/actions.js';
29
+ import { detectPermissionSeeking, IRREVERSIBLE_ACTION_RE } from '../learning/autonomy-policy.js';
29
30
  // ─── Tool definitions ───────────────────────────────────────────────────────
30
31
  // ─── Shared auto-delivery helper ─────────────────────────────────────────
31
32
  // Tools that produce artifact files (generate_image, speak, video_generate)
@@ -125,14 +126,14 @@ export const runCliSchema = z.object({
125
126
  .boolean()
126
127
  .optional()
127
128
  .default(false)
128
- .describe('Set true ONLY after the user explicitly confirmed a destructive/system-level command (stop/shutdown/publish/clear/disallow). The tool refuses without it.'),
129
+ .describe('Set true ONLY after the user explicitly confirmed a destructive/system-level command you initiated. When the user’s own request resolves to the exact command (they asked to stop the dashboard), that IS the confirmation — the tool applies it. Irreversible intents (history.clear, memory.prune, stats.cost.clear, publish) always need it.'),
129
130
  });
130
131
  /** P3b — gated git args: structured status/log/diff/commit. */
131
132
  export const gitToolSchema = z.object({
132
- action: z.enum(['status', 'log', 'diff', 'commit']).describe('What to do — status/log are read-only; diff returns a structured diff (rendered as a card); commit is GATED (confirm:true after ask_user)'),
133
+ action: z.enum(['status', 'log', 'diff', 'commit']).describe('What to do — status/log are read-only; diff returns a structured diff (rendered as a card); commit is GATED unless the user’s own request asked for the commit.'),
133
134
  message: z.string().optional().describe('Commit message (action=commit, required)'),
134
135
  files: z.array(z.string()).optional().describe('Files to stage+commit — the ACCEPTED subset after the user reviewed the diff card (absent = all changes)'),
135
- confirm: z.boolean().default(false).describe('Commit gate — true ONLY after the user approved via ask_user'),
136
+ confirm: z.boolean().default(false).describe('Commit gate — required only when the MODEL initiated the commit. When the user’s own request asks for a commit ("commit these changes"), that request IS the approval: call it with confirm:false and it applies.'),
136
137
  limit: z.number().int().min(1).max(100).optional().describe('Log limit (action=log, default 20)'),
137
138
  });
138
139
  /** P3a — clone_repo args: a git URL to assess (depth-1 shallow only). */
@@ -268,18 +269,18 @@ const editFileSchema = z.object({
268
269
  .optional()
269
270
  .describe('Several replacements to this ONE file in a single call, applied in order. TRANSACTIONAL: if any replacement fails to match, NOTHING is written — so a refactor can never half-apply. Use one call instead of many edits.'),
270
271
  dry_run: z.boolean().default(false).describe('Validate and preview the change (returns the unified diff) without writing anything. Needs no confirmation.'),
271
- confirm: z.boolean().default(false).describe('Set true ONLY after the user explicitly confirmed this edit via ask_user. State-changing — refused without it.'),
272
+ confirm: z.boolean().default(false).describe('Set true ONLY after the user explicitly confirmed an edit you initiated. A surgical edit (small relative to the file) to a file the request asked for is applied directly, as is an edit to a file the request names. Refused without it when the edit would rewrite most of the file — a re-run cannot recover that, so it is the user’s call.'),
272
273
  });
273
274
  /** P0.3 — write_file tool args: create/overwrite a file (confirmed). */
274
275
  const writeFileSchema = z.object({
275
276
  path: z.string().describe('Path to write, relative to the workspace root (parent directories are created as needed). Overwrites existing content.'),
276
277
  content: z.string().describe('The FULL new file content (replaces any existing content).'),
277
- confirm: z.boolean().default(false).describe('Set true ONLY after the user explicitly confirmed this write via ask_user. State-changing — refused without it.'),
278
+ confirm: z.boolean().default(false).describe('Set true ONLY after the user explicitly confirmed this write via ask_user. CREATING a new file the request asked for needs no confirmation — it is applied directly. Refused without it only when it would REPLACE content that already exists.'),
278
279
  });
279
280
  /** P0.4 — run_terminal tool args: verify commands + gated shell execution. */
280
281
  const runTerminalSchema = z.object({
281
- command: z.string().min(1).describe('The shell command to run in the workspace — e.g. "npx vitest run tests/foo.test.ts", "npx tsc --noEmit", "npm run build", "git diff --stat". Read-only verify commands run directly; state-changing commands need confirm:true after the user approves via ask_user. Destructive/system commands are denied outright.'),
282
- confirm: z.boolean().default(false).describe('Set true ONLY after the user explicitly confirmed this command via ask_user. Required for state-changing commands (installs, mutations, network, arbitrary code).'),
282
+ command: z.string().min(1).describe('The shell command to run in the workspace — e.g. "npx vitest run tests/foo.test.ts", "npx tsc --noEmit", "npm run build", "git diff --stat". Read-only verify commands run directly. Recoverable workspace commands (dependency installs, mkdir/touch/cp/mv, git add, npm init) also run directly when the request authorized the work; every other state-changing command needs confirm:true after the user approves via ask_user. Destructive/system commands are denied outright.'),
283
+ confirm: z.boolean().default(false).describe('Set true ONLY after the user explicitly confirmed a command you initiated. Required for state-changing commands outside the recoverable workspace set (network fetches, arbitrary code, global installs, anything that leaves the machine).'),
283
284
  timeout_ms: z.number().int().min(1000).max(300000).optional().describe('Timeout in ms (default 120000).'),
284
285
  });
285
286
  /** The C2 requirementState check as a reusable tool. */
@@ -347,15 +348,16 @@ export const TOOL_CONTRACT = `You have tools available. Call them when appropria
347
348
  - If a request is ambiguous or incomplete, call \`ask_user\` with a question and 2–4 choices — never guess, never ask in plain text.
348
349
  - If a request needs code written, debugged, or prior work resumed, call \`build\`, \`repair\`, or \`resume\` with the goal.
349
350
  - If a request needs documentation, a website, analysis of a project, or running tests, call \`document\`, \`website\`, \`analyze\`, or \`test\` with the goal.
350
- - If a request asks to publish a release (npm/GitHub), call \`publish\`. It is irreversible — confirm the bump type and target with the user via \`ask_user\` first unless they already specified them.
351
+ - If a request asks to publish a release (npm/GitHub), call \`publish\`. It leaves this machine and is irreversible — confirm the bump type and target with the user via \`ask_user\` first unless they already specified them.
351
352
  - If a request's completeness is uncertain, call \`verify_requirement\` first.
352
353
  - If a request asks to deliver a message or result to a DIFFERENT contact/channel than the one you are currently chatting on (WhatsApp, Telegram, Slack, email, …), call \`gateway_send\` with the target (e.g. \`whatsapp:Alex\`) and the text. Do NOT call gateway_send to reply to the CURRENT conversation — your text response is automatically delivered back. If the target contact is not configured, tell the user what to set up.
353
- - If a request asks to manage the system/agent itself in plain English — start/stop the dashboard or gateway, check status, add/remove a verified sender, configure a platform (telegram/whatsapp), run evals, show stats — call \`run_cli\` with the plain-English ask. It resolves the exact \`buff\` command and runs it. If the tool reports AMBIGUOUS or asks for confirmation, call \`ask_user\` first, then retry run_cli with the user's answer.
354
+ - If a request asks to manage the system/agent itself in plain English — start/stop the dashboard or gateway, check status, add/remove a verified sender, configure a platform (telegram/whatsapp), run evals, show stats — call \`run_cli\` with the plain-English ask. It resolves the exact \`buff\` command and runs it. If the user's own request already resolves to that command ("stop the dashboard"), it just runs — do not ask for permission to do what was just asked. If it reports AMBIGUOUS, call \`ask_user\` with the two choices; if the intent is one YOU chose rather than the user (or is irreversible: history.clear, memory.prune, stats.cost.clear, publish), call \`ask_user\` first and retry with confirm:true.
354
355
  - If a subtask can be delegated to a specialized sub-agent (gather context, review, security scan, run tests), call \`delegate\` with the agent type, a focused prompt, and optional file paths.
355
356
  - To find code matching a pattern (context gathering, locating definitions/usages), call \`code_search\` with the pattern and optional globs.
356
357
  - To READ the project: call \`read_file\` to open a file (with line numbers), \`list_dir\` to see a directory's contents, or \`glob\` to find files by pattern. Always prefer reading the actual file over assuming its contents — a large file reports a line range, continue with offset/limit.
357
- - To CHANGE code (after reading it): call \`edit_file\` for a surgical exact-text replacement, or \`write_file\` to create/replace a file. Both are state-changing and refuse without confirm — call \`ask_user\` to confirm the change with a one-line summary, then retry with confirm:true.
358
- - To VERIFY code by actual invocation: call \`run_terminal\` with the real command (\`npx vitest run tests/x.test.ts\`, \`npx tsc --noEmit\`, \`npm run build\`, \`git diff\`). Read-only verify commands run directly; state-changing ones need confirm:true after the user approves via ask_user. Never guess that a test passes — run it and read the output. Use run_cli (not run_terminal) for buff/agent-nuvira control commands.
358
+ - To CHANGE code (after reading it): call \`edit_file\` for a surgical exact-text replacement, or \`write_file\` to create/replace a file. CREATING a file the request asked for is applied directly — no confirmation needed, so just call it. An \`edit_file\` that is surgical (small relative to the file) also applies directly, as does one on a file the request names — the verify loop must not need a human between iterations. A whole-file write over existing content, or an edit that rewrites most of a file, refuses without confirm — call \`ask_user\` with a one-line summary, then retry with confirm:true.
359
+ - NEVER ask for permission to do work the user already asked for — not via \`ask_user\` and never in plain text. Decide it yourself, state the decision in your answer, and continue. Reserve \`ask_user\` for a decision that is genuinely the user's: it cannot proceed without an answer, it is high-impact AND irreversible, and there is no sensible default (overwriting existing work, deleting data, spending money, publishing).
360
+ - To VERIFY code by actual invocation: call \`run_terminal\` with the real command (\`npx vitest run tests/x.test.ts\`, \`npx tsc --noEmit\`, \`npm run build\`, \`git diff\`). Read-only verify commands run directly, and so do recoverable workspace commands (\`npm/pnpm/yarn/bun install\`, \`pip install\`, \`mkdir\`, \`touch\`, \`cp\`, \`mv\`, \`git add\`, \`npm init\`) when the request authorized the work — the build you were asked for is your job to set up. Everything else state-changing (network fetches, arbitrary code, global installs, anything leaving the machine) needs confirm:true after the user approves via ask_user. Never guess that a test passes — run it and read the output. Use run_cli (not run_terminal) for buff/agent-nuvira control commands, and the \`git\` tool (not run_terminal) to commit.
359
361
  - END EVERY RESPONSE by calling \`suggest_followups\` with exactly 3 followups the user is likely to want next — natural next questions, deeper dives, or related directions that build on what you just said; specific to this conversation, not generic.
360
362
  - If you have nothing to add, answer directly and still end with suggest_followups.
361
363
  - ORDERING (non-negotiable): deliver the user's answer FIRST, then suggest_followups. The followup call must come only AFTER the complete answer is written — never before it, never instead of it. A bare lead-in ("Sure, I can help!") is NOT an answer; write the full answer in the same step as the followup call.`;
@@ -447,6 +449,33 @@ registerTool({
447
449
  endsAgentStep: false,
448
450
  run: async (args, ctx) => {
449
451
  const { question, choices, multi_select } = askUserSchema.parse(args);
452
+ // ── G13: do not round-trip a permission question the ask already answered ─
453
+ // Over a chat surface (WhatsApp/Telegram) an ask_user call is a MESSAGE to
454
+ // the user, so a reflexive "Do you want me to create the full project
455
+ // structure?" costs a full turn and delivers nothing. When the request
456
+ // already authorized the work (and the question is not about something
457
+ // irreversible), the autonomy policy settles it here instead: the model is
458
+ // told to proceed with its own default and to state the decision.
459
+ //
460
+ // Narrow on purpose — both conditions must hold, and any question naming an
461
+ // irreversible action (overwrite, delete, publish, deploy, send, pay…) is
462
+ // passed straight through, because that decision IS the user's.
463
+ if (ctx.writesAuthorized?.authorized === true &&
464
+ detectPermissionSeeking(question) &&
465
+ !IRREVERSIBLE_ACTION_RE.test(question)) {
466
+ const recommended = choices[0]?.label ?? '';
467
+ ctx.emit?.('autonomy:consult-suppressed', {
468
+ question,
469
+ authorization: ctx.writesAuthorized.reason,
470
+ }, 'tool-loop');
471
+ return ('Not shown to the user: their request already authorized this work, and this is a ' +
472
+ 'permission question about doing it. Decide it yourself and continue.\n' +
473
+ (recommended ? `Recommended default: "${recommended}".\n` : '') +
474
+ 'Carry the work out now and state the decision in your answer so the user can redirect. ' +
475
+ 'Only if the choice is genuinely theirs — it cannot proceed without an answer, is ' +
476
+ 'high-impact and irreversible, and has no sensible default — re-call ask_user naming ' +
477
+ 'that specific irreversible choice (e.g. whether to overwrite an existing file).');
478
+ }
450
479
  const render = ctx.askUser || (await import('./ask-user.js')).renderAskUser;
451
480
  const answer = await render(question, choices, multi_select);
452
481
  const picked = Array.isArray(answer.answer) ? answer.answer.join(', ') : answer.answer;