agent-nuvira 3.3.3 → 3.3.4

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 (349) hide show
  1. package/README.md +13 -5
  2. package/dist/agent-sdk/src/agent.d.ts +2 -0
  3. package/dist/agent-sdk/src/agent.d.ts.map +1 -1
  4. package/dist/agent-sdk/src/define.d.ts +64 -0
  5. package/dist/agent-sdk/src/define.d.ts.map +1 -0
  6. package/dist/agent-sdk/src/define.js +76 -0
  7. package/dist/agent-sdk/src/define.js.map +1 -0
  8. package/dist/agent-sdk/src/index.d.ts +9 -0
  9. package/dist/agent-sdk/src/index.d.ts.map +1 -1
  10. package/dist/agent-sdk/src/index.js +9 -0
  11. package/dist/agent-sdk/src/index.js.map +1 -1
  12. package/dist/agent-sdk/src/scaffold.d.ts +11 -0
  13. package/dist/agent-sdk/src/scaffold.d.ts.map +1 -1
  14. package/dist/agent-sdk/src/scaffold.js +16 -6
  15. package/dist/agent-sdk/src/scaffold.js.map +1 -1
  16. package/dist/agents/long-form-plan.d.ts.map +1 -1
  17. package/dist/agents/long-form-plan.js +2 -1
  18. package/dist/agents/long-form-plan.js.map +1 -1
  19. package/dist/agents/orchestrator.d.ts.map +1 -1
  20. package/dist/agents/orchestrator.js +5 -4
  21. package/dist/agents/orchestrator.js.map +1 -1
  22. package/dist/cli/agent.d.ts +2 -2
  23. package/dist/cli/agent.js +10 -10
  24. package/dist/cli/chat.d.ts +94 -0
  25. package/dist/cli/chat.d.ts.map +1 -1
  26. package/dist/cli/chat.js +354 -20
  27. package/dist/cli/chat.js.map +1 -1
  28. package/dist/cli/cli-program.d.ts.map +1 -1
  29. package/dist/cli/cli-program.js +5 -0
  30. package/dist/cli/cli-program.js.map +1 -1
  31. package/dist/cli/config.d.ts.map +1 -1
  32. package/dist/cli/config.js +9 -1
  33. package/dist/cli/config.js.map +1 -1
  34. package/dist/cli/doctor.d.ts.map +1 -1
  35. package/dist/cli/doctor.js +3 -2
  36. package/dist/cli/doctor.js.map +1 -1
  37. package/dist/cli/edit.js +2 -2
  38. package/dist/cli/eval.d.ts +17 -0
  39. package/dist/cli/eval.d.ts.map +1 -1
  40. package/dist/cli/eval.js +105 -2
  41. package/dist/cli/eval.js.map +1 -1
  42. package/dist/cli/execute.d.ts +16 -1
  43. package/dist/cli/execute.d.ts.map +1 -1
  44. package/dist/cli/execute.js +192 -22
  45. package/dist/cli/execute.js.map +1 -1
  46. package/dist/cli/loop-executor.d.ts +55 -0
  47. package/dist/cli/loop-executor.d.ts.map +1 -1
  48. package/dist/cli/loop-executor.js +212 -13
  49. package/dist/cli/loop-executor.js.map +1 -1
  50. package/dist/cli/model.d.ts.map +1 -1
  51. package/dist/cli/model.js +9 -8
  52. package/dist/cli/model.js.map +1 -1
  53. package/dist/cli/models.d.ts +1 -1
  54. package/dist/cli/models.js +4 -4
  55. package/dist/cli/parity.d.ts +85 -0
  56. package/dist/cli/parity.d.ts.map +1 -0
  57. package/dist/cli/parity.js +506 -0
  58. package/dist/cli/parity.js.map +1 -0
  59. package/dist/cli/plan.d.ts.map +1 -1
  60. package/dist/cli/plan.js +2 -1
  61. package/dist/cli/plan.js.map +1 -1
  62. package/dist/cli/retrieval.d.ts.map +1 -1
  63. package/dist/cli/retrieval.js +5 -4
  64. package/dist/cli/retrieval.js.map +1 -1
  65. package/dist/cli/sdk.js +4 -4
  66. package/dist/cli/sdk.js.map +1 -1
  67. package/dist/cli/trace.d.ts.map +1 -1
  68. package/dist/cli/trace.js +2 -1
  69. package/dist/cli/trace.js.map +1 -1
  70. package/dist/cli/workflow.js +2 -2
  71. package/dist/cli/workflow.js.map +1 -1
  72. package/dist/config/types.d.ts +44 -0
  73. package/dist/config/types.d.ts.map +1 -1
  74. package/dist/findings/verdicts.d.ts +241 -0
  75. package/dist/findings/verdicts.d.ts.map +1 -0
  76. package/dist/findings/verdicts.js +284 -0
  77. package/dist/findings/verdicts.js.map +1 -0
  78. package/dist/gateway/adapters.d.ts +65 -0
  79. package/dist/gateway/adapters.d.ts.map +1 -1
  80. package/dist/gateway/adapters.js +216 -10
  81. package/dist/gateway/adapters.js.map +1 -1
  82. package/dist/gateway/channel-directory.d.ts +31 -0
  83. package/dist/gateway/channel-directory.d.ts.map +1 -1
  84. package/dist/gateway/channel-directory.js +40 -0
  85. package/dist/gateway/channel-directory.js.map +1 -1
  86. package/dist/gateway/gateway-log.d.ts +1 -1
  87. package/dist/gateway/gateway-log.d.ts.map +1 -1
  88. package/dist/gateway/gateway-log.js.map +1 -1
  89. package/dist/gateway/hooks.d.ts +87 -19
  90. package/dist/gateway/hooks.d.ts.map +1 -1
  91. package/dist/gateway/hooks.js +62 -23
  92. package/dist/gateway/hooks.js.map +1 -1
  93. package/dist/gateway/inbound-media.d.ts +147 -0
  94. package/dist/gateway/inbound-media.d.ts.map +1 -0
  95. package/dist/gateway/inbound-media.js +317 -0
  96. package/dist/gateway/inbound-media.js.map +1 -0
  97. package/dist/gateway/inbox.d.ts +8 -1
  98. package/dist/gateway/inbox.d.ts.map +1 -1
  99. package/dist/gateway/inbox.js.map +1 -1
  100. package/dist/gateway/platform-config.d.ts +14 -0
  101. package/dist/gateway/platform-config.d.ts.map +1 -1
  102. package/dist/gateway/platform-config.js +26 -8
  103. package/dist/gateway/platform-config.js.map +1 -1
  104. package/dist/gateway/realtime.d.ts +114 -0
  105. package/dist/gateway/realtime.d.ts.map +1 -0
  106. package/dist/gateway/realtime.js +402 -0
  107. package/dist/gateway/realtime.js.map +1 -0
  108. package/dist/gateway/registry.d.ts +31 -0
  109. package/dist/gateway/registry.d.ts.map +1 -1
  110. package/dist/gateway/registry.js +224 -4
  111. package/dist/gateway/registry.js.map +1 -1
  112. package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
  113. package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
  114. package/dist/gateway/whatsapp/baileys-bridge.js +123 -4
  115. package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
  116. package/dist/gateway/whatsapp/bridge.d.ts +6 -2
  117. package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
  118. package/dist/gateway/whatsapp/bridge.js.map +1 -1
  119. package/dist/index.js +8 -0
  120. package/dist/index.js.map +1 -1
  121. package/dist/inference/factory.d.ts +14 -0
  122. package/dist/inference/factory.d.ts.map +1 -1
  123. package/dist/inference/factory.js +17 -0
  124. package/dist/inference/factory.js.map +1 -1
  125. package/dist/inference/groq-adapter.d.ts +2 -0
  126. package/dist/inference/groq-adapter.d.ts.map +1 -1
  127. package/dist/inference/groq-adapter.js +16 -6
  128. package/dist/inference/groq-adapter.js.map +1 -1
  129. package/dist/inference/tools.d.ts.map +1 -1
  130. package/dist/inference/tools.js +29 -0
  131. package/dist/inference/tools.js.map +1 -1
  132. package/dist/learning/benchmark.d.ts.map +1 -1
  133. package/dist/learning/benchmark.js +3 -2
  134. package/dist/learning/benchmark.js.map +1 -1
  135. package/dist/learning/continuation.d.ts.map +1 -1
  136. package/dist/learning/continuation.js +2 -1
  137. package/dist/learning/continuation.js.map +1 -1
  138. package/dist/learning/cost-tracker.d.ts.map +1 -1
  139. package/dist/learning/cost-tracker.js +2 -1
  140. package/dist/learning/cost-tracker.js.map +1 -1
  141. package/dist/learning/deferred-task.d.ts.map +1 -1
  142. package/dist/learning/deferred-task.js +13 -4
  143. package/dist/learning/deferred-task.js.map +1 -1
  144. package/dist/learning/eval-framework.d.ts.map +1 -1
  145. package/dist/learning/eval-framework.js +2 -1
  146. package/dist/learning/eval-framework.js.map +1 -1
  147. package/dist/learning/long-form.d.ts.map +1 -1
  148. package/dist/learning/long-form.js +2 -1
  149. package/dist/learning/long-form.js.map +1 -1
  150. package/dist/learning/model-registry.d.ts.map +1 -1
  151. package/dist/learning/model-registry.js +2 -1
  152. package/dist/learning/model-registry.js.map +1 -1
  153. package/dist/learning/reasoning-cache.d.ts.map +1 -1
  154. package/dist/learning/reasoning-cache.js +2 -1
  155. package/dist/learning/reasoning-cache.js.map +1 -1
  156. package/dist/learning/reasoning-trace.d.ts +37 -1
  157. package/dist/learning/reasoning-trace.d.ts.map +1 -1
  158. package/dist/learning/reasoning-trace.js +66 -0
  159. package/dist/learning/reasoning-trace.js.map +1 -1
  160. package/dist/learning/resilient-call.d.ts.map +1 -1
  161. package/dist/learning/resilient-call.js +2 -1
  162. package/dist/learning/resilient-call.js.map +1 -1
  163. package/dist/learning/retrieval.d.ts.map +1 -1
  164. package/dist/learning/retrieval.js +2 -1
  165. package/dist/learning/retrieval.js.map +1 -1
  166. package/dist/learning/seeded-benchmark.d.ts +160 -0
  167. package/dist/learning/seeded-benchmark.d.ts.map +1 -0
  168. package/dist/learning/seeded-benchmark.js +321 -0
  169. package/dist/learning/seeded-benchmark.js.map +1 -0
  170. package/dist/learning/seeded-bugs.d.ts +142 -0
  171. package/dist/learning/seeded-bugs.d.ts.map +1 -0
  172. package/dist/learning/seeded-bugs.js +535 -0
  173. package/dist/learning/seeded-bugs.js.map +1 -0
  174. package/dist/learning/step-checkpoint.d.ts +127 -0
  175. package/dist/learning/step-checkpoint.d.ts.map +1 -0
  176. package/dist/learning/step-checkpoint.js +244 -0
  177. package/dist/learning/step-checkpoint.js.map +1 -0
  178. package/dist/nlu/intent-confirm.d.ts +23 -1
  179. package/dist/nlu/intent-confirm.d.ts.map +1 -1
  180. package/dist/nlu/intent-confirm.js +85 -2
  181. package/dist/nlu/intent-confirm.js.map +1 -1
  182. package/dist/nlu/learnings.d.ts +7 -0
  183. package/dist/nlu/learnings.d.ts.map +1 -1
  184. package/dist/nlu/learnings.js +7 -0
  185. package/dist/nlu/learnings.js.map +1 -1
  186. package/dist/observability/debug-log.d.ts +250 -0
  187. package/dist/observability/debug-log.d.ts.map +1 -0
  188. package/dist/observability/debug-log.js +500 -0
  189. package/dist/observability/debug-log.js.map +1 -0
  190. package/dist/observability/event-bus.d.ts.map +1 -1
  191. package/dist/observability/event-bus.js +4 -1
  192. package/dist/observability/event-bus.js.map +1 -1
  193. package/dist/observability/otel.d.ts +278 -0
  194. package/dist/observability/otel.d.ts.map +1 -0
  195. package/dist/observability/otel.js +590 -0
  196. package/dist/observability/otel.js.map +1 -0
  197. package/dist/parity/drivers.d.ts +99 -0
  198. package/dist/parity/drivers.d.ts.map +1 -0
  199. package/dist/parity/drivers.js +1362 -0
  200. package/dist/parity/drivers.js.map +1 -0
  201. package/dist/parity/graph.d.ts +73 -0
  202. package/dist/parity/graph.d.ts.map +1 -0
  203. package/dist/parity/graph.js +162 -0
  204. package/dist/parity/graph.js.map +1 -0
  205. package/dist/parity/matrix.d.ts +105 -0
  206. package/dist/parity/matrix.d.ts.map +1 -0
  207. package/dist/parity/matrix.js +352 -0
  208. package/dist/parity/matrix.js.map +1 -0
  209. package/dist/parity/observation.d.ts +444 -0
  210. package/dist/parity/observation.d.ts.map +1 -0
  211. package/dist/parity/observation.js +333 -0
  212. package/dist/parity/observation.js.map +1 -0
  213. package/dist/parity/scenarios.d.ts +229 -0
  214. package/dist/parity/scenarios.d.ts.map +1 -0
  215. package/dist/parity/scenarios.js +175 -0
  216. package/dist/parity/scenarios.js.map +1 -0
  217. package/dist/parity/surfaces.d.ts +122 -0
  218. package/dist/parity/surfaces.d.ts.map +1 -0
  219. package/dist/parity/surfaces.js +190 -0
  220. package/dist/parity/surfaces.js.map +1 -0
  221. package/dist/runtime/fault-injection.d.ts +173 -0
  222. package/dist/runtime/fault-injection.d.ts.map +1 -0
  223. package/dist/runtime/fault-injection.js +281 -0
  224. package/dist/runtime/fault-injection.js.map +1 -0
  225. package/dist/tools/child-agent-entry.d.ts +23 -0
  226. package/dist/tools/child-agent-entry.d.ts.map +1 -0
  227. package/dist/tools/child-agent-entry.js +129 -0
  228. package/dist/tools/child-agent-entry.js.map +1 -0
  229. package/dist/tools/child-agent-runtime.d.ts +124 -0
  230. package/dist/tools/child-agent-runtime.d.ts.map +1 -0
  231. package/dist/tools/child-agent-runtime.js +704 -0
  232. package/dist/tools/child-agent-runtime.js.map +1 -0
  233. package/dist/tools/coding-tools.d.ts.map +1 -1
  234. package/dist/tools/coding-tools.js +82 -10
  235. package/dist/tools/coding-tools.js.map +1 -1
  236. package/dist/tools/delegation-system.d.ts +31 -0
  237. package/dist/tools/delegation-system.d.ts.map +1 -1
  238. package/dist/tools/delegation-system.js +70 -9
  239. package/dist/tools/delegation-system.js.map +1 -1
  240. package/dist/tools/extract/docx.d.ts +27 -0
  241. package/dist/tools/extract/docx.d.ts.map +1 -0
  242. package/dist/tools/extract/docx.js +48 -0
  243. package/dist/tools/extract/docx.js.map +1 -0
  244. package/dist/tools/extract/html-text.d.ts +27 -0
  245. package/dist/tools/extract/html-text.d.ts.map +1 -0
  246. package/dist/tools/extract/html-text.js +86 -0
  247. package/dist/tools/extract/html-text.js.map +1 -0
  248. package/dist/tools/extract/pdf-ocr.d.ts +58 -0
  249. package/dist/tools/extract/pdf-ocr.d.ts.map +1 -0
  250. package/dist/tools/extract/pdf-ocr.js +116 -0
  251. package/dist/tools/extract/pdf-ocr.js.map +1 -0
  252. package/dist/tools/extract/pdf.d.ts +65 -0
  253. package/dist/tools/extract/pdf.d.ts.map +1 -0
  254. package/dist/tools/extract/pdf.js +197 -0
  255. package/dist/tools/extract/pdf.js.map +1 -0
  256. package/dist/tools/extract/pptx.d.ts +32 -0
  257. package/dist/tools/extract/pptx.d.ts.map +1 -0
  258. package/dist/tools/extract/pptx.js +77 -0
  259. package/dist/tools/extract/pptx.js.map +1 -0
  260. package/dist/tools/extract/xlsx.d.ts +47 -0
  261. package/dist/tools/extract/xlsx.d.ts.map +1 -0
  262. package/dist/tools/extract/xlsx.js +111 -0
  263. package/dist/tools/extract/xlsx.js.map +1 -0
  264. package/dist/tools/finding-tool.d.ts +76 -0
  265. package/dist/tools/finding-tool.d.ts.map +1 -0
  266. package/dist/tools/finding-tool.js +125 -0
  267. package/dist/tools/finding-tool.js.map +1 -0
  268. package/dist/tools/messaging-tools.d.ts +41 -11
  269. package/dist/tools/messaging-tools.d.ts.map +1 -1
  270. package/dist/tools/messaging-tools.js +104 -55
  271. package/dist/tools/messaging-tools.js.map +1 -1
  272. package/dist/tools/neutts-synth.d.ts +27 -3
  273. package/dist/tools/neutts-synth.d.ts.map +1 -1
  274. package/dist/tools/neutts-synth.js +57 -13
  275. package/dist/tools/neutts-synth.js.map +1 -1
  276. package/dist/tools/pipeline-tool.d.ts +43 -1
  277. package/dist/tools/pipeline-tool.d.ts.map +1 -1
  278. package/dist/tools/pipeline-tool.js +13 -2
  279. package/dist/tools/pipeline-tool.js.map +1 -1
  280. package/dist/tools/read-extract.d.ts +116 -45
  281. package/dist/tools/read-extract.d.ts.map +1 -1
  282. package/dist/tools/read-extract.js +494 -158
  283. package/dist/tools/read-extract.js.map +1 -1
  284. package/dist/tools/registry.d.ts +2 -2
  285. package/dist/tools/registry.d.ts.map +1 -1
  286. package/dist/tools/registry.js +152 -23
  287. package/dist/tools/registry.js.map +1 -1
  288. package/dist/tools/subagent-refusal.d.ts +15 -0
  289. package/dist/tools/subagent-refusal.d.ts.map +1 -0
  290. package/dist/tools/subagent-refusal.js +18 -0
  291. package/dist/tools/subagent-refusal.js.map +1 -0
  292. package/dist/tools/subagent-spawner.d.ts +122 -0
  293. package/dist/tools/subagent-spawner.d.ts.map +1 -1
  294. package/dist/tools/subagent-spawner.js +249 -28
  295. package/dist/tools/subagent-spawner.js.map +1 -1
  296. package/dist/tools/tool-hooks.d.ts +177 -0
  297. package/dist/tools/tool-hooks.d.ts.map +1 -0
  298. package/dist/tools/tool-hooks.js +427 -0
  299. package/dist/tools/tool-hooks.js.map +1 -0
  300. package/dist/tools/tool-loop.d.ts +82 -0
  301. package/dist/tools/tool-loop.d.ts.map +1 -1
  302. package/dist/tools/tool-loop.js +167 -9
  303. package/dist/tools/tool-loop.js.map +1 -1
  304. package/dist/tools/tool-refusal.d.ts +68 -0
  305. package/dist/tools/tool-refusal.d.ts.map +1 -0
  306. package/dist/tools/tool-refusal.js +78 -0
  307. package/dist/tools/tool-refusal.js.map +1 -0
  308. package/dist/tools/toolsets.d.ts +8 -0
  309. package/dist/tools/toolsets.d.ts.map +1 -1
  310. package/dist/tools/toolsets.js +12 -2
  311. package/dist/tools/toolsets.js.map +1 -1
  312. package/dist/tools/vision-tools.d.ts +88 -83
  313. package/dist/tools/vision-tools.d.ts.map +1 -1
  314. package/dist/tools/vision-tools.js +134 -103
  315. package/dist/tools/vision-tools.js.map +1 -1
  316. package/dist/tools/worktree.d.ts +210 -0
  317. package/dist/tools/worktree.d.ts.map +1 -0
  318. package/dist/tools/worktree.js +374 -0
  319. package/dist/tools/worktree.js.map +1 -0
  320. package/dist/utils/format.d.ts +3 -0
  321. package/dist/utils/format.d.ts.map +1 -0
  322. package/dist/utils/format.js +32 -0
  323. package/dist/utils/format.js.map +1 -0
  324. package/dist/web-dashboard/attachment-extract.d.ts +64 -0
  325. package/dist/web-dashboard/attachment-extract.d.ts.map +1 -0
  326. package/dist/web-dashboard/attachment-extract.js +154 -0
  327. package/dist/web-dashboard/attachment-extract.js.map +1 -0
  328. package/dist/web-dashboard/chat-console.d.ts +108 -1
  329. package/dist/web-dashboard/chat-console.d.ts.map +1 -1
  330. package/dist/web-dashboard/chat-console.js +36 -0
  331. package/dist/web-dashboard/chat-console.js.map +1 -1
  332. package/dist/web-dashboard/hub-data.d.ts +37 -0
  333. package/dist/web-dashboard/hub-data.d.ts.map +1 -1
  334. package/dist/web-dashboard/hub-data.js +61 -1
  335. package/dist/web-dashboard/hub-data.js.map +1 -1
  336. package/dist/web-dashboard/server.d.ts +14 -0
  337. package/dist/web-dashboard/server.d.ts.map +1 -1
  338. package/dist/web-dashboard/server.js +247 -13
  339. package/dist/web-dashboard/server.js.map +1 -1
  340. package/dist/web-dashboard/src/types.d.ts +196 -48
  341. package/dist/web-dashboard/src/types.d.ts.map +1 -1
  342. package/package.json +18 -3
  343. package/src/web-dashboard/public/assets/{index-Cyd6tIew.css → index-XJjj2cBX.css} +1 -1
  344. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js +207 -0
  345. package/src/web-dashboard/public/assets/index-YWF9FpwQ.js.map +1 -0
  346. package/src/web-dashboard/public/index.html +2 -2
  347. package/dist/tools/child-agent-worker.js +0 -212
  348. package/src/web-dashboard/public/assets/index-CxDj7p6i.js +0 -207
  349. package/src/web-dashboard/public/assets/index-CxDj7p6i.js.map +0 -1
@@ -0,0 +1,125 @@
1
+ /**
2
+ * WS1 (#23) — `finding`: the model states a CLAIM, the gate decides the VERDICT.
3
+ *
4
+ * WHY A TOOL, AND WHY IT DOES NOT ACCEPT A VERDICT. `src/findings/verdicts.ts`
5
+ * is the vocabulary and the gate; it deliberately does not decide who may
6
+ * produce a finding (`intent-confirm` produces one for a routing decision). This
7
+ * is the producer for an ORDINARY turn on every surface, and the one design rule
8
+ * that matters is here: the model may supply the claim, the outcome and the
9
+ * evidence, and must NOT be able to supply the verdict. A tool argument called
10
+ * `verdict` would be the exact bypass the gate exists to refuse — the model
11
+ * typing "CONFIRMED" is the false-success defect with a nicer name — so the
12
+ * parameter does not exist. `confirmFinding` promotes to CONFIRMED only when at
13
+ * least one non-blank evidence reference was supplied, and refuses otherwise
14
+ * with the reason attached.
15
+ *
16
+ * WHAT THE MODEL SEES BACK is the rendered finding (`describeFinding`), including
17
+ * the honest line for a PLAUSIBLE one ("no evidence — reported as PLAUSIBLE, not
18
+ * verified"). That is the point of returning the render rather than a summary: a
19
+ * model that states a claim with no evidence is told, in the tool result it must
20
+ * act on, that the claim was recorded as unverified rather than as fact.
21
+ *
22
+ * THE STRUCTURED COPY travels to the surface on the context bus as
23
+ * `finding:recorded` (the same mechanism `plan_todo` uses for `plan:changed`),
24
+ * so every surface reports the SAME wire form — which is what
25
+ * `findings-verdicts@<surface>` is proved against.
26
+ *
27
+ * A CALL THAT RECORDED NOTHING IS A FAILURE. A blank claim or a blank outcome
28
+ * returns `Error:` (the loop's own accounting is `ok: !startsWith('Error:')`),
29
+ * because a finding with no claim is not a finding — and reporting one as a
30
+ * successful call would be this repository's recurring defect in miniature.
31
+ */
32
+ import { z } from 'zod';
33
+ import { confirmFinding, describeFinding, plausibleFinding, toWire, } from '../findings/verdicts.js';
34
+ /** The registry name — one place, so the toolset/core lists and the tests agree. */
35
+ export const FINDING_TOOL_NAME = 'finding';
36
+ /**
37
+ * The bus event carrying the structured wire finding.
38
+ *
39
+ * Named `finding:recorded` (past tense) on purpose: the event is emitted AFTER
40
+ * the gate has decided, so a listener never sees a claim whose verdict is still
41
+ * being computed — the same convention `plan:changed` follows.
42
+ */
43
+ export const FINDING_EVENT = 'finding:recorded';
44
+ /** The evidence kinds the model may cite (the closed set the gate normalises to). */
45
+ const EVIDENCE_KINDS = ['quote', 'command', 'file', 'observation'];
46
+ /** `finding` args. There is deliberately no `verdict` field — see the header. */
47
+ export const findingSchema = z.object({
48
+ claim: z
49
+ .string()
50
+ .describe('What is being asserted, in the words the reader will see — e.g. "the login endpoint rejects an expired token".'),
51
+ outcome: z
52
+ .string()
53
+ .describe('What BECAME of the claim: verified, corrected, dropped, still open. A finding with no outcome is a status report, not a finding.'),
54
+ evidence: z
55
+ .array(z.object({
56
+ kind: z.enum(EVIDENCE_KINDS).describe('The sort of check that was performed.'),
57
+ ref: z
58
+ .string()
59
+ .describe('The evidence ITSELF — a verbatim quote from the input, the exact command line, the path that was read, or a value a probe returned. A restatement of the claim is not evidence, and a blank reference is not a check.'),
60
+ detail: z.string().optional().describe('Optional context: the command output, the surrounding line, why it matters.'),
61
+ }))
62
+ .optional()
63
+ .describe('The checks actually performed. Supply this and the finding is recorded CONFIRMED; omit it (or leave a reference blank) and it is recorded PLAUSIBLE, unverified — which is an honest, useful result, not an error.'),
64
+ });
65
+ /**
66
+ * Record one finding: build it PLAUSIBLE, let the gate decide, report it.
67
+ *
68
+ * Split out from the `Tool` wrapper so the behaviour is testable without the
69
+ * registry, and so a caller that already has a context (the child process) can
70
+ * reuse it.
71
+ */
72
+ export function recordFinding(args, ctx) {
73
+ const claim = String(args?.claim ?? '').trim();
74
+ const outcome = String(args?.outcome ?? '').trim();
75
+ if (!claim) {
76
+ return {
77
+ error: "Error: finding needs a 'claim' — what is being asserted, in the words the user will read. " +
78
+ 'A finding with no claim records nothing.',
79
+ };
80
+ }
81
+ if (!outcome) {
82
+ return {
83
+ error: "Error: finding needs an 'outcome' — what became of the claim (verified, corrected, dropped, still open). " +
84
+ 'A finding with no outcome is a status report, not a finding.',
85
+ };
86
+ }
87
+ const evidence = (args.evidence ?? []);
88
+ // The gate, not the caller, decides. `confirmFinding` returns the finding
89
+ // STILL PLAUSIBLE (with the reason) when no usable evidence was supplied; that
90
+ // refusal is a normal outcome, so it is recorded in the outcome line rather
91
+ // than thrown.
92
+ const promotion = confirmFinding(plausibleFinding({ claim, outcome, source: 'agent', evidence }), [], { outcome });
93
+ const finding = promotion.promoted
94
+ ? promotion.finding
95
+ : promotion.reason
96
+ ? { ...promotion.finding, outcome: `${outcome} — ${promotion.reason}` }
97
+ : promotion.finding;
98
+ // Best-effort: a listener that is not there (a direct tool call, a test) must
99
+ // never break the tool, exactly like `plan_todo`'s snapshot emit.
100
+ try {
101
+ ctx?.emit?.(FINDING_EVENT, toWire(finding));
102
+ }
103
+ catch {
104
+ /* best-effort */
105
+ }
106
+ return { finding, text: describeFinding(finding) };
107
+ }
108
+ /** The `finding` tool as the registry takes it. */
109
+ export function createFindingTool() {
110
+ return {
111
+ name: FINDING_TOOL_NAME,
112
+ description: 'Record one finding — a claim about the world, with a verdict you do NOT set. Supply `claim` + `outcome`, and `evidence` for anything you actually CHECKED (a command and its real output, a path you read, a quote from the request, a value a probe returned): usable evidence records the finding CONFIRMED, and no usable evidence records it PLAUSIBLE (an honest, useful result — never a failure). Use it whenever your answer asserts something a second party could check, so the user can tell what was verified from what is a reasoned guess.',
113
+ category: 'experience',
114
+ inputSchema: findingSchema,
115
+ endsAgentStep: false,
116
+ run: async (args, ctx) => {
117
+ const parsed = findingSchema.parse(args);
118
+ const result = recordFinding(parsed, ctx);
119
+ if ('error' in result)
120
+ return result.error;
121
+ return result.text;
122
+ },
123
+ };
124
+ }
125
+ //# sourceMappingURL=finding-tool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finding-tool.js","sourceRoot":"","sources":["../../src/tools/finding-tool.ts"],"names":[],"mappings":"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"}
@@ -4,11 +4,24 @@
4
4
  * Hermes equivalent: send_message_tool.py + react_to_message_tool.py + feishu_doc_tool.py + feishu_drive_tool.py
5
5
  *
6
6
  * Provides:
7
- * - Send messages to various platforms
8
- * - React to messages
7
+ * - Message history bookkeeping for outbound sends
9
8
  * - Feishu document integration
10
9
  * - Feishu drive integration
10
+ *
11
+ * DOES NOT PROVIDE: delivery to Discord / Slack / Telegram / WhatsApp / Feishu /
12
+ * webhooks. Every one of those senders used to answer
13
+ * `{ success: true, messageId: '<platform>_<timestamp>' }` without contacting
14
+ * anything, and `reactToMessage` answered `{ success: true }` unconditionally —
15
+ * so an agent could tell the user, honestly from its own point of view, that a
16
+ * message had been delivered to a third party when nothing left the machine.
17
+ * The real, authorization-gated sender is `gateway_send`
18
+ * (`src/tools/gateway-send.ts`); it is the tool whose result the honesty guard in
19
+ * `tool-loop.ts` trusts. These senders now refuse with `not_configured` and name
20
+ * it, so the model is steered to the path that can actually deliver.
21
+ *
22
+ * See TOOL_TRUTHFULNESS_TRACKER.md (findings #3 and #9).
11
23
  */
24
+ import { type ToolRefusalCode } from './tool-refusal.js';
12
25
  export interface MessageTarget {
13
26
  /** Platform */
14
27
  platform: 'discord' | 'slack' | 'telegram' | 'whatsapp' | 'feishu' | 'webhook';
@@ -78,23 +91,40 @@ export interface FeishuDriveFile {
78
91
  /** Updated at */
79
92
  updatedAt: number;
80
93
  }
94
+ /**
95
+ * The result of an outbound send. `success: false` carries a typed `code` and the
96
+ * alternatives a caller can take instead — never a synthetic `messageId`.
97
+ */
98
+ export interface SendResult {
99
+ success: boolean;
100
+ /** Present ONLY when a platform adapter actually delivered the message. */
101
+ messageId?: string;
102
+ code?: ToolRefusalCode;
103
+ alternatives?: string[];
104
+ error?: string;
105
+ }
81
106
  export declare class MessagingManager {
82
107
  private messageHistory;
108
+ /**
109
+ * The one refusal every platform sender returns: this manager has no adapter.
110
+ * Kept in a single place so a future reader cannot re-introduce a per-platform
111
+ * fake success without deleting the shared reason that explains why.
112
+ */
113
+ private notConfigured;
83
114
  /**
84
115
  * Send a message to a platform.
116
+ *
117
+ * Records the attempt in history ONLY when a platform adapter reported success,
118
+ * so `getHistory()` can never list a message that was never delivered.
85
119
  */
86
- sendMessage(target: MessageTarget, options: SendMessageOptions): Promise<{
87
- success: boolean;
88
- messageId?: string;
89
- error?: string;
90
- }>;
120
+ sendMessage(target: MessageTarget, options: SendMessageOptions): Promise<SendResult>;
91
121
  /**
92
122
  * React to a message.
123
+ *
124
+ * No adapter exists for reactions, so this refuses. It used to return
125
+ * `{ success: true }` and the registry turned that into the string 'Reacted'.
93
126
  */
94
- reactToMessage(platform: string, channelId: string, messageId: string, emoji: string): Promise<{
95
- success: boolean;
96
- error?: string;
97
- }>;
127
+ reactToMessage(platform: string, channelId: string, messageId: string, emoji: string): Promise<SendResult>;
98
128
  /**
99
129
  * Get message history.
100
130
  */
@@ -1 +1 @@
1
- {"version":3,"file":"messaging-tools.d.ts","sourceRoot":"","sources":["../../src/tools/messaging-tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messaging-tools.d.ts","sourceRoot":"","sources":["../../src/tools/messaging-tools.ts"],"names":[],"mappings":"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"}
@@ -4,55 +4,107 @@
4
4
  * Hermes equivalent: send_message_tool.py + react_to_message_tool.py + feishu_doc_tool.py + feishu_drive_tool.py
5
5
  *
6
6
  * Provides:
7
- * - Send messages to various platforms
8
- * - React to messages
7
+ * - Message history bookkeeping for outbound sends
9
8
  * - Feishu document integration
10
9
  * - Feishu drive integration
10
+ *
11
+ * DOES NOT PROVIDE: delivery to Discord / Slack / Telegram / WhatsApp / Feishu /
12
+ * webhooks. Every one of those senders used to answer
13
+ * `{ success: true, messageId: '<platform>_<timestamp>' }` without contacting
14
+ * anything, and `reactToMessage` answered `{ success: true }` unconditionally —
15
+ * so an agent could tell the user, honestly from its own point of view, that a
16
+ * message had been delivered to a third party when nothing left the machine.
17
+ * The real, authorization-gated sender is `gateway_send`
18
+ * (`src/tools/gateway-send.ts`); it is the tool whose result the honesty guard in
19
+ * `tool-loop.ts` trusts. These senders now refuse with `not_configured` and name
20
+ * it, so the model is steered to the path that can actually deliver.
21
+ *
22
+ * See TOOL_TRUTHFULNESS_TRACKER.md (findings #3 and #9).
11
23
  */
12
24
  import { logger } from '../utils/logger.js';
25
+ import { refusalFields } from './tool-refusal.js';
13
26
  // ─── Messaging Manager ────────────────────────────────────────────────────
14
27
  export class MessagingManager {
15
28
  messageHistory = [];
29
+ /**
30
+ * The one refusal every platform sender returns: this manager has no adapter.
31
+ * Kept in a single place so a future reader cannot re-introduce a per-platform
32
+ * fake success without deleting the shared reason that explains why.
33
+ */
34
+ notConfigured(platform, channelId) {
35
+ return {
36
+ success: false,
37
+ error: `No messaging adapter is configured for ${platform} (channel ${channelId}), so nothing was sent. ` +
38
+ 'Use gateway_send — it delivers through the configured gateway and returns an explicit sent/refused result.',
39
+ ...refusalFields('not_configured', [
40
+ 'gateway_send — sends via the configured gateway (WhatsApp / Telegram / Slack / Discord by name or number)',
41
+ 'nuvira gateway send <platform:channel> <message> — the CLI equivalent',
42
+ ]),
43
+ };
44
+ }
16
45
  /**
17
46
  * Send a message to a platform.
47
+ *
48
+ * Records the attempt in history ONLY when a platform adapter reported success,
49
+ * so `getHistory()` can never list a message that was never delivered.
18
50
  */
19
51
  async sendMessage(target, options) {
20
- const historyEntry = {
21
- platform: target.platform,
22
- channelId: target.channelId,
23
- content: options.content,
24
- timestamp: Date.now(),
25
- };
26
- try {
27
- // Route to platform-specific handler
28
- switch (target.platform) {
29
- case 'discord':
30
- return await this.sendDiscord(target, options);
31
- case 'slack':
32
- return await this.sendSlack(target, options);
33
- case 'telegram':
34
- return await this.sendTelegram(target, options);
35
- case 'whatsapp':
36
- return await this.sendWhatsApp(target, options);
37
- case 'feishu':
38
- return await this.sendFeishu(target, options);
39
- case 'webhook':
40
- return await this.sendWebhook(target, options);
41
- default:
42
- return { success: false, error: `Unsupported platform: ${target.platform}` };
43
- }
52
+ let result;
53
+ switch (target.platform) {
54
+ case 'discord':
55
+ result = await this.sendDiscord(target, options);
56
+ break;
57
+ case 'slack':
58
+ result = await this.sendSlack(target, options);
59
+ break;
60
+ case 'telegram':
61
+ result = await this.sendTelegram(target, options);
62
+ break;
63
+ case 'whatsapp':
64
+ result = await this.sendWhatsApp(target, options);
65
+ break;
66
+ case 'feishu':
67
+ result = await this.sendFeishu(target, options);
68
+ break;
69
+ case 'webhook':
70
+ result = await this.sendWebhook(target, options);
71
+ break;
72
+ default:
73
+ result = {
74
+ success: false,
75
+ error: `Unsupported platform: ${target.platform}`,
76
+ ...refusalFields('unsupported_format'),
77
+ };
78
+ }
79
+ if (result.success) {
80
+ this.messageHistory.push({
81
+ platform: target.platform,
82
+ channelId: target.channelId,
83
+ content: options.content,
84
+ timestamp: Date.now(),
85
+ messageId: result.messageId,
86
+ });
44
87
  }
45
- finally {
46
- this.messageHistory.push(historyEntry);
88
+ else {
89
+ logger.warn(`Messaging: refused ${target.platform} send to ${target.channelId} — ${result.error}`);
47
90
  }
91
+ return result;
48
92
  }
49
93
  /**
50
94
  * React to a message.
95
+ *
96
+ * No adapter exists for reactions, so this refuses. It used to return
97
+ * `{ success: true }` and the registry turned that into the string 'Reacted'.
51
98
  */
52
99
  async reactToMessage(platform, channelId, messageId, emoji) {
53
- logger.info(`Messaging: Reacting with ${emoji} to message ${messageId} on ${platform}`);
54
- // In a real implementation, this would call the platform API
55
- return { success: true };
100
+ logger.warn(`Messaging: reaction not sent (no adapter) — ${emoji} on ${messageId} in ${platform}/${channelId}`);
101
+ return {
102
+ success: false,
103
+ error: `No messaging adapter is configured for ${platform}, so the reaction was NOT applied to ${messageId}.`,
104
+ ...refusalFields('not_configured', [
105
+ 'Report the reaction as not sent, or send the message text instead via gateway_send',
106
+ ]),
107
+ };
56
108
  }
57
109
  /**
58
110
  * Get message history.
@@ -66,30 +118,27 @@ export class MessagingManager {
66
118
  return history.slice(-limit);
67
119
  }
68
120
  // ─── Platform Handlers ─────────────────────────────────────────────
69
- async sendDiscord(target, options) {
70
- logger.info(`Discord: Sending message to channel ${target.channelId}`);
71
- // In production, this would call Discord API
72
- return { success: true, messageId: `discord_${Date.now()}` };
73
- }
74
- async sendSlack(target, options) {
75
- logger.info(`Slack: Sending message to channel ${target.channelId}`);
76
- return { success: true, messageId: `slack_${Date.now()}` };
77
- }
78
- async sendTelegram(target, options) {
79
- logger.info(`Telegram: Sending message to chat ${target.channelId}`);
80
- return { success: true, messageId: `telegram_${Date.now()}` };
81
- }
82
- async sendWhatsApp(target, options) {
83
- logger.info(`WhatsApp: Sending message to chat ${target.channelId}`);
84
- return { success: true, messageId: `whatsapp_${Date.now()}` };
85
- }
86
- async sendFeishu(target, options) {
87
- logger.info(`Feishu: Sending message to chat ${target.channelId}`);
88
- return { success: true, messageId: `feishu_${Date.now()}` };
89
- }
90
- async sendWebhook(target, options) {
91
- logger.info(`Webhook: Sending message to ${target.channelId}`);
92
- return { success: true, messageId: `webhook_${Date.now()}` };
121
+ //
122
+ // Each returns `notConfigured(...)`. The per-platform shape is kept so a real
123
+ // adapter can be dropped in per platform without touching the dispatcher; until
124
+ // one exists, the honest answer is the same for all six.
125
+ async sendDiscord(target, _options) {
126
+ return this.notConfigured('discord', target.channelId);
127
+ }
128
+ async sendSlack(target, _options) {
129
+ return this.notConfigured('slack', target.channelId);
130
+ }
131
+ async sendTelegram(target, _options) {
132
+ return this.notConfigured('telegram', target.channelId);
133
+ }
134
+ async sendWhatsApp(target, _options) {
135
+ return this.notConfigured('whatsapp', target.channelId);
136
+ }
137
+ async sendFeishu(target, _options) {
138
+ return this.notConfigured('feishu', target.channelId);
139
+ }
140
+ async sendWebhook(target, _options) {
141
+ return this.notConfigured('webhook', target.channelId);
93
142
  }
94
143
  }
95
144
  // ─── Feishu Document Manager ──────────────────────────────────────────────
@@ -1 +1 @@
1
- {"version":3,"file":"messaging-tools.js","sourceRoot":"","sources":["../../src/tools/messaging-tools.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"messaging-tools.js","sourceRoot":"","sources":["../../src/tools/messaging-tools.ts"],"names":[],"mappings":"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"}
@@ -1,14 +1,29 @@
1
1
  /**
2
- * NeuTTS Synthesis — High-quality text-to-speech.
2
+ * NeuTTS Synthesis — text-to-speech.
3
3
  *
4
4
  * Hermes equivalent: neutts_synth.py (110 lines)
5
5
  *
6
6
  * Provides:
7
- * - High-quality TTS synthesis
7
+ * - API-backed synthesis when NEUTTS_API_KEY (or an injected key) is set
8
8
  * - Multiple voice options
9
- * - SSML support
10
9
  * - Audio file output
10
+ *
11
+ * WHEN NO BACKEND IS CONFIGURED it does NOT fall back to writing audio: the old
12
+ * fallback wrote a valid, silent WAV (44-byte header + a zeroed sample buffer) and
13
+ * returned it as a successful synthesis with duration/voice/text metadata. Anything
14
+ * downstream — a gateway that sends the file, an agent that reports "the audio is
15
+ * ready" — then acted on silence that looked like speech. Silence is now an
16
+ * explicit opt-in (BUFF_NEUTTS_ALLOW_SILENT) and never the default.
17
+ *
18
+ * See TOOL_TRUTHFULNESS_TRACKER.md finding #5.
19
+ */
20
+ import { type ToolRefusal } from './tool-refusal.js';
21
+ /**
22
+ * Whether a silent placeholder WAV may stand in for speech. Opt-in only
23
+ * (`BUFF_NEUTTS_ALLOW_SILENT=1`) — the point of the refusal is that silence must
24
+ * never be mistaken for synthesis. Exported for tests.
11
25
  */
26
+ export declare function allowSilentFallback(): boolean;
12
27
  export interface NeuTTSConfig {
13
28
  /** API key for NeuTTS */
14
29
  apiKey?: string;
@@ -23,6 +38,15 @@ export interface SynthesisResult {
23
38
  durationMs: number;
24
39
  voice: string;
25
40
  text: string;
41
+ ok: boolean;
42
+ /**
43
+ * True when the audio is a silent placeholder rather than synthesised speech.
44
+ * Only ever set behind the BUFF_NEUTTS_ALLOW_SILENT opt-in.
45
+ */
46
+ silent?: boolean;
47
+ code?: ToolRefusal['code'];
48
+ alternatives?: string[];
49
+ error?: string;
26
50
  }
27
51
  export declare class NeuTTSSynthesizer {
28
52
  private config;
@@ -1 +1 @@
1
- {"version":3,"file":"neutts-synth.d.ts","sourceRoot":"","sources":["../../src/tools/neutts-synth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,GAAE,YAAiB;IAQrC;;OAEG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAChF,OAAO,CAAC,eAAe,CAAC;IAmB3B;;OAEG;YACW,gBAAgB;IAqC9B;;OAEG;YACW,eAAe;IAsC7B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAqBnF;AAMD,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAG7E;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
1
+ {"version":3,"file":"neutts-synth.d.ts","sourceRoot":"","sources":["../../src/tools/neutts-synth.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEpE;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAG7C;AAID,MAAM,WAAW,YAAY;IAC3B,yBAAyB;IACzB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ;;;OAGG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC3B,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,SAAS,CAAS;gBAEd,MAAM,GAAE,YAAiB;IAQrC;;OAEG;IACG,UAAU,CACd,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAO,GAChF,OAAO,CAAC,eAAe,CAAC;IA2C3B;;OAEG;YACW,gBAAgB;IAsC9B;;OAEG;YACW,eAAe;IAyC7B;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,KAAK,CAAC;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAmBnF;AAMD,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,YAAY,GAAG,iBAAiB,CAG7E;AAED,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C"}
@@ -1,19 +1,38 @@
1
1
  /**
2
- * NeuTTS Synthesis — High-quality text-to-speech.
2
+ * NeuTTS Synthesis — text-to-speech.
3
3
  *
4
4
  * Hermes equivalent: neutts_synth.py (110 lines)
5
5
  *
6
6
  * Provides:
7
- * - High-quality TTS synthesis
7
+ * - API-backed synthesis when NEUTTS_API_KEY (or an injected key) is set
8
8
  * - Multiple voice options
9
- * - SSML support
10
9
  * - Audio file output
10
+ *
11
+ * WHEN NO BACKEND IS CONFIGURED it does NOT fall back to writing audio: the old
12
+ * fallback wrote a valid, silent WAV (44-byte header + a zeroed sample buffer) and
13
+ * returned it as a successful synthesis with duration/voice/text metadata. Anything
14
+ * downstream — a gateway that sends the file, an agent that reports "the audio is
15
+ * ready" — then acted on silence that looked like speech. Silence is now an
16
+ * explicit opt-in (BUFF_NEUTTS_ALLOW_SILENT) and never the default.
17
+ *
18
+ * See TOOL_TRUTHFULNESS_TRACKER.md finding #5.
11
19
  */
12
20
  import { randomUUID } from 'node:crypto';
13
21
  import { writeFile } from 'node:fs/promises';
14
22
  import { join } from 'node:path';
15
23
  import { tmpdir } from 'node:os';
16
24
  import { logger } from '../utils/logger.js';
25
+ import { envBuff } from '../config/paths.js';
26
+ import { refusalFields } from './tool-refusal.js';
27
+ /**
28
+ * Whether a silent placeholder WAV may stand in for speech. Opt-in only
29
+ * (`BUFF_NEUTTS_ALLOW_SILENT=1`) — the point of the refusal is that silence must
30
+ * never be mistaken for synthesis. Exported for tests.
31
+ */
32
+ export function allowSilentFallback() {
33
+ const v = envBuff('NEUTTS_ALLOW_SILENT');
34
+ return v === '1' || v === 'true' || v === 'yes';
35
+ }
17
36
  // ─── NeuTTS Synthesizer ──────────────────────────────────────────────────
18
37
  export class NeuTTSSynthesizer {
19
38
  config;
@@ -33,17 +52,40 @@ export class NeuTTSSynthesizer {
33
52
  const voice = options.voice || this.config.defaultVoice;
34
53
  const format = options.format || 'wav';
35
54
  const audioPath = join(this.outputDir, `${id}.${format}`);
36
- // Try to use external TTS API if configured
55
+ // 1. The real backend, when one is configured.
56
+ let failureReason = 'No NeuTTS API key is configured (NEUTTS_API_KEY).';
37
57
  if (this.config.apiKey) {
38
58
  try {
39
59
  return await this.synthesizeViaAPI(text, voice, audioPath, options);
40
60
  }
41
61
  catch (err) {
42
- logger.warn(`[neutts] API synthesis failed, falling back to local: ${err}`);
62
+ failureReason = `NeuTTS API synthesis failed: ${err instanceof Error ? err.message : String(err)}`;
63
+ logger.warn(`[neutts] ${failureReason}`);
43
64
  }
44
65
  }
45
- // Fallback: generate placeholder audio
46
- return this.synthesizeLocal(text, voice, audioPath, options);
66
+ // 2. No real audio. Write a silent placeholder ONLY when the operator asked for
67
+ // it — a silent WAV reported as a successful synthesis is a lie the caller
68
+ // cannot detect, so it is never the default.
69
+ if (allowSilentFallback()) {
70
+ logger.warn(`[neutts] writing SILENT placeholder audio (BUFF_NEUTTS_ALLOW_SILENT is set) — ${failureReason}`);
71
+ return this.synthesizeLocal(text, voice, audioPath, options);
72
+ }
73
+ // 3. Refuse: say what is missing and what to use instead.
74
+ const reason = `No speech was synthesised. ${failureReason}`;
75
+ logger.warn(`[neutts] synthesis refused — ${failureReason}`);
76
+ return {
77
+ id,
78
+ audioPath: '',
79
+ durationMs: 0,
80
+ voice,
81
+ text,
82
+ ok: false,
83
+ error: reason,
84
+ ...refusalFields('not_configured', [
85
+ 'Set NEUTTS_API_KEY to enable API-backed synthesis',
86
+ 'Use the `speak` tool — it uses the configured local TTS backend (piper) when available',
87
+ ]),
88
+ };
47
89
  }
48
90
  /**
49
91
  * Synthesize via external API.
@@ -74,6 +116,7 @@ export class NeuTTSSynthesizer {
74
116
  durationMs: Math.round((buffer.byteLength / (16000 * 2)) * 1000),
75
117
  voice,
76
118
  text,
119
+ ok: true,
77
120
  };
78
121
  }
79
122
  /**
@@ -106,6 +149,9 @@ export class NeuTTSSynthesizer {
106
149
  durationMs: Math.round(durationSec * 1000),
107
150
  voice,
108
151
  text,
152
+ ok: true,
153
+ // Flagged so a caller (or the user) can see the file is silence, not speech.
154
+ silent: true,
109
155
  };
110
156
  }
111
157
  /**
@@ -125,12 +171,10 @@ export class NeuTTSSynthesizer {
125
171
  // Ignore
126
172
  }
127
173
  }
128
- // Default voices
129
- return [
130
- { id: 'default', name: 'Default', language: 'en-US' },
131
- { id: 'female-1', name: 'Female 1', language: 'en-US' },
132
- { id: 'male-1', name: 'Male 1', language: 'en-US' },
133
- ];
174
+ // No backend → no voices. This used to return three invented voice ids
175
+ // ('default', 'female-1', 'male-1') that no configured backend could honour, so
176
+ // a caller could pick one and only discover it was fictitious after synthesis.
177
+ return [];
134
178
  }
135
179
  }
136
180
  // ─── Singleton ─────────────────────────────────────────────────────────────