agent-nuvira 3.3.3 → 3.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -5
- package/dist/agent-sdk/src/agent.d.ts +2 -0
- package/dist/agent-sdk/src/agent.d.ts.map +1 -1
- package/dist/agent-sdk/src/define.d.ts +64 -0
- package/dist/agent-sdk/src/define.d.ts.map +1 -0
- package/dist/agent-sdk/src/define.js +76 -0
- package/dist/agent-sdk/src/define.js.map +1 -0
- package/dist/agent-sdk/src/index.d.ts +9 -0
- package/dist/agent-sdk/src/index.d.ts.map +1 -1
- package/dist/agent-sdk/src/index.js +9 -0
- package/dist/agent-sdk/src/index.js.map +1 -1
- package/dist/agent-sdk/src/scaffold.d.ts +11 -0
- package/dist/agent-sdk/src/scaffold.d.ts.map +1 -1
- package/dist/agent-sdk/src/scaffold.js +16 -6
- package/dist/agent-sdk/src/scaffold.js.map +1 -1
- package/dist/agents/long-form-plan.d.ts.map +1 -1
- package/dist/agents/long-form-plan.js +2 -1
- package/dist/agents/long-form-plan.js.map +1 -1
- package/dist/agents/orchestrator.d.ts.map +1 -1
- package/dist/agents/orchestrator.js +5 -4
- package/dist/agents/orchestrator.js.map +1 -1
- package/dist/cli/agent.d.ts +2 -2
- package/dist/cli/agent.js +10 -10
- package/dist/cli/chat.d.ts +94 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +354 -20
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/cli-program.d.ts.map +1 -1
- package/dist/cli/cli-program.js +5 -0
- package/dist/cli/cli-program.js.map +1 -1
- package/dist/cli/config.d.ts.map +1 -1
- package/dist/cli/config.js +9 -1
- package/dist/cli/config.js.map +1 -1
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +3 -2
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/edit.js +2 -2
- package/dist/cli/eval.d.ts +17 -0
- package/dist/cli/eval.d.ts.map +1 -1
- package/dist/cli/eval.js +105 -2
- package/dist/cli/eval.js.map +1 -1
- package/dist/cli/execute.d.ts +16 -1
- package/dist/cli/execute.d.ts.map +1 -1
- package/dist/cli/execute.js +192 -22
- package/dist/cli/execute.js.map +1 -1
- package/dist/cli/loop-executor.d.ts +55 -0
- package/dist/cli/loop-executor.d.ts.map +1 -1
- package/dist/cli/loop-executor.js +212 -13
- package/dist/cli/loop-executor.js.map +1 -1
- package/dist/cli/model.d.ts.map +1 -1
- package/dist/cli/model.js +9 -8
- package/dist/cli/model.js.map +1 -1
- package/dist/cli/models.d.ts +1 -1
- package/dist/cli/models.js +4 -4
- package/dist/cli/parity.d.ts +85 -0
- package/dist/cli/parity.d.ts.map +1 -0
- package/dist/cli/parity.js +506 -0
- package/dist/cli/parity.js.map +1 -0
- package/dist/cli/plan.d.ts.map +1 -1
- package/dist/cli/plan.js +2 -1
- package/dist/cli/plan.js.map +1 -1
- package/dist/cli/retrieval.d.ts.map +1 -1
- package/dist/cli/retrieval.js +5 -4
- package/dist/cli/retrieval.js.map +1 -1
- package/dist/cli/sdk.js +4 -4
- package/dist/cli/sdk.js.map +1 -1
- package/dist/cli/trace.d.ts.map +1 -1
- package/dist/cli/trace.js +2 -1
- package/dist/cli/trace.js.map +1 -1
- package/dist/cli/workflow.js +2 -2
- package/dist/cli/workflow.js.map +1 -1
- package/dist/config/process-env.d.ts +136 -0
- package/dist/config/process-env.d.ts.map +1 -0
- package/dist/config/process-env.js +217 -0
- package/dist/config/process-env.js.map +1 -0
- package/dist/config/types.d.ts +44 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/findings/verdicts.d.ts +241 -0
- package/dist/findings/verdicts.d.ts.map +1 -0
- package/dist/findings/verdicts.js +284 -0
- package/dist/findings/verdicts.js.map +1 -0
- package/dist/gateway/adapters.d.ts +65 -0
- package/dist/gateway/adapters.d.ts.map +1 -1
- package/dist/gateway/adapters.js +216 -10
- package/dist/gateway/adapters.js.map +1 -1
- package/dist/gateway/channel-directory.d.ts +31 -0
- package/dist/gateway/channel-directory.d.ts.map +1 -1
- package/dist/gateway/channel-directory.js +40 -0
- package/dist/gateway/channel-directory.js.map +1 -1
- package/dist/gateway/gateway-log.d.ts +1 -1
- package/dist/gateway/gateway-log.d.ts.map +1 -1
- package/dist/gateway/gateway-log.js.map +1 -1
- package/dist/gateway/hooks.d.ts +87 -19
- package/dist/gateway/hooks.d.ts.map +1 -1
- package/dist/gateway/hooks.js +62 -23
- package/dist/gateway/hooks.js.map +1 -1
- package/dist/gateway/inbound-media.d.ts +147 -0
- package/dist/gateway/inbound-media.d.ts.map +1 -0
- package/dist/gateway/inbound-media.js +317 -0
- package/dist/gateway/inbound-media.js.map +1 -0
- package/dist/gateway/inbox.d.ts +8 -1
- package/dist/gateway/inbox.d.ts.map +1 -1
- package/dist/gateway/inbox.js.map +1 -1
- package/dist/gateway/platform-config.d.ts +14 -0
- package/dist/gateway/platform-config.d.ts.map +1 -1
- package/dist/gateway/platform-config.js +26 -8
- package/dist/gateway/platform-config.js.map +1 -1
- package/dist/gateway/realtime.d.ts +114 -0
- package/dist/gateway/realtime.d.ts.map +1 -0
- package/dist/gateway/realtime.js +402 -0
- package/dist/gateway/realtime.js.map +1 -0
- package/dist/gateway/registry.d.ts +31 -0
- package/dist/gateway/registry.d.ts.map +1 -1
- package/dist/gateway/registry.js +224 -4
- package/dist/gateway/registry.js.map +1 -1
- package/dist/gateway/whatsapp/baileys-bridge.d.ts +11 -1
- package/dist/gateway/whatsapp/baileys-bridge.d.ts.map +1 -1
- package/dist/gateway/whatsapp/baileys-bridge.js +123 -4
- package/dist/gateway/whatsapp/baileys-bridge.js.map +1 -1
- package/dist/gateway/whatsapp/bridge.d.ts +6 -2
- package/dist/gateway/whatsapp/bridge.d.ts.map +1 -1
- package/dist/gateway/whatsapp/bridge.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/inference/factory.d.ts +14 -0
- package/dist/inference/factory.d.ts.map +1 -1
- package/dist/inference/factory.js +17 -0
- package/dist/inference/factory.js.map +1 -1
- package/dist/inference/groq-adapter.d.ts +2 -0
- package/dist/inference/groq-adapter.d.ts.map +1 -1
- package/dist/inference/groq-adapter.js +16 -6
- package/dist/inference/groq-adapter.js.map +1 -1
- package/dist/inference/tools.d.ts.map +1 -1
- package/dist/inference/tools.js +29 -0
- package/dist/inference/tools.js.map +1 -1
- package/dist/learning/benchmark.d.ts.map +1 -1
- package/dist/learning/benchmark.js +3 -2
- package/dist/learning/benchmark.js.map +1 -1
- package/dist/learning/continuation.d.ts.map +1 -1
- package/dist/learning/continuation.js +2 -1
- package/dist/learning/continuation.js.map +1 -1
- package/dist/learning/cost-tracker.d.ts.map +1 -1
- package/dist/learning/cost-tracker.js +2 -1
- package/dist/learning/cost-tracker.js.map +1 -1
- package/dist/learning/deferred-task.d.ts.map +1 -1
- package/dist/learning/deferred-task.js +13 -4
- package/dist/learning/deferred-task.js.map +1 -1
- package/dist/learning/eval-framework.d.ts.map +1 -1
- package/dist/learning/eval-framework.js +2 -1
- package/dist/learning/eval-framework.js.map +1 -1
- package/dist/learning/long-form.d.ts.map +1 -1
- package/dist/learning/long-form.js +2 -1
- package/dist/learning/long-form.js.map +1 -1
- package/dist/learning/model-reachability.d.ts +95 -0
- package/dist/learning/model-reachability.d.ts.map +1 -0
- package/dist/learning/model-reachability.js +111 -0
- package/dist/learning/model-reachability.js.map +1 -0
- package/dist/learning/model-registry.d.ts +22 -0
- package/dist/learning/model-registry.d.ts.map +1 -1
- package/dist/learning/model-registry.js +26 -1
- package/dist/learning/model-registry.js.map +1 -1
- package/dist/learning/model-verify-job.d.ts +131 -0
- package/dist/learning/model-verify-job.d.ts.map +1 -0
- package/dist/learning/model-verify-job.js +221 -0
- package/dist/learning/model-verify-job.js.map +1 -0
- package/dist/learning/reasoning-cache.d.ts.map +1 -1
- package/dist/learning/reasoning-cache.js +2 -1
- package/dist/learning/reasoning-cache.js.map +1 -1
- package/dist/learning/reasoning-trace.d.ts +37 -1
- package/dist/learning/reasoning-trace.d.ts.map +1 -1
- package/dist/learning/reasoning-trace.js +66 -0
- package/dist/learning/reasoning-trace.js.map +1 -1
- package/dist/learning/resilient-call.d.ts.map +1 -1
- package/dist/learning/resilient-call.js +2 -1
- package/dist/learning/resilient-call.js.map +1 -1
- package/dist/learning/retrieval.d.ts.map +1 -1
- package/dist/learning/retrieval.js +2 -1
- package/dist/learning/retrieval.js.map +1 -1
- package/dist/learning/seeded-benchmark.d.ts +160 -0
- package/dist/learning/seeded-benchmark.d.ts.map +1 -0
- package/dist/learning/seeded-benchmark.js +321 -0
- package/dist/learning/seeded-benchmark.js.map +1 -0
- package/dist/learning/seeded-bugs.d.ts +142 -0
- package/dist/learning/seeded-bugs.d.ts.map +1 -0
- package/dist/learning/seeded-bugs.js +535 -0
- package/dist/learning/seeded-bugs.js.map +1 -0
- package/dist/learning/step-checkpoint.d.ts +127 -0
- package/dist/learning/step-checkpoint.d.ts.map +1 -0
- package/dist/learning/step-checkpoint.js +244 -0
- package/dist/learning/step-checkpoint.js.map +1 -0
- package/dist/nlu/intent-confirm.d.ts +23 -1
- package/dist/nlu/intent-confirm.d.ts.map +1 -1
- package/dist/nlu/intent-confirm.js +85 -2
- package/dist/nlu/intent-confirm.js.map +1 -1
- package/dist/nlu/learnings.d.ts +7 -0
- package/dist/nlu/learnings.d.ts.map +1 -1
- package/dist/nlu/learnings.js +7 -0
- package/dist/nlu/learnings.js.map +1 -1
- package/dist/observability/debug-log.d.ts +250 -0
- package/dist/observability/debug-log.d.ts.map +1 -0
- package/dist/observability/debug-log.js +500 -0
- package/dist/observability/debug-log.js.map +1 -0
- package/dist/observability/event-bus.d.ts.map +1 -1
- package/dist/observability/event-bus.js +4 -1
- package/dist/observability/event-bus.js.map +1 -1
- package/dist/observability/otel.d.ts +278 -0
- package/dist/observability/otel.d.ts.map +1 -0
- package/dist/observability/otel.js +590 -0
- package/dist/observability/otel.js.map +1 -0
- package/dist/parity/drivers.d.ts +99 -0
- package/dist/parity/drivers.d.ts.map +1 -0
- package/dist/parity/drivers.js +1362 -0
- package/dist/parity/drivers.js.map +1 -0
- package/dist/parity/graph.d.ts +73 -0
- package/dist/parity/graph.d.ts.map +1 -0
- package/dist/parity/graph.js +162 -0
- package/dist/parity/graph.js.map +1 -0
- package/dist/parity/matrix.d.ts +105 -0
- package/dist/parity/matrix.d.ts.map +1 -0
- package/dist/parity/matrix.js +352 -0
- package/dist/parity/matrix.js.map +1 -0
- package/dist/parity/observation.d.ts +444 -0
- package/dist/parity/observation.d.ts.map +1 -0
- package/dist/parity/observation.js +333 -0
- package/dist/parity/observation.js.map +1 -0
- package/dist/parity/scenarios.d.ts +229 -0
- package/dist/parity/scenarios.d.ts.map +1 -0
- package/dist/parity/scenarios.js +175 -0
- package/dist/parity/scenarios.js.map +1 -0
- package/dist/parity/surfaces.d.ts +122 -0
- package/dist/parity/surfaces.d.ts.map +1 -0
- package/dist/parity/surfaces.js +190 -0
- package/dist/parity/surfaces.js.map +1 -0
- package/dist/runtime/fault-injection.d.ts +173 -0
- package/dist/runtime/fault-injection.d.ts.map +1 -0
- package/dist/runtime/fault-injection.js +281 -0
- package/dist/runtime/fault-injection.js.map +1 -0
- package/dist/tools/child-agent-entry.d.ts +23 -0
- package/dist/tools/child-agent-entry.d.ts.map +1 -0
- package/dist/tools/child-agent-entry.js +129 -0
- package/dist/tools/child-agent-entry.js.map +1 -0
- package/dist/tools/child-agent-runtime.d.ts +124 -0
- package/dist/tools/child-agent-runtime.d.ts.map +1 -0
- package/dist/tools/child-agent-runtime.js +704 -0
- package/dist/tools/child-agent-runtime.js.map +1 -0
- package/dist/tools/coding-tools.d.ts.map +1 -1
- package/dist/tools/coding-tools.js +82 -10
- package/dist/tools/coding-tools.js.map +1 -1
- package/dist/tools/delegation-system.d.ts +31 -0
- package/dist/tools/delegation-system.d.ts.map +1 -1
- package/dist/tools/delegation-system.js +70 -9
- package/dist/tools/delegation-system.js.map +1 -1
- package/dist/tools/extract/docx.d.ts +27 -0
- package/dist/tools/extract/docx.d.ts.map +1 -0
- package/dist/tools/extract/docx.js +48 -0
- package/dist/tools/extract/docx.js.map +1 -0
- package/dist/tools/extract/html-text.d.ts +27 -0
- package/dist/tools/extract/html-text.d.ts.map +1 -0
- package/dist/tools/extract/html-text.js +86 -0
- package/dist/tools/extract/html-text.js.map +1 -0
- package/dist/tools/extract/pdf-ocr.d.ts +58 -0
- package/dist/tools/extract/pdf-ocr.d.ts.map +1 -0
- package/dist/tools/extract/pdf-ocr.js +116 -0
- package/dist/tools/extract/pdf-ocr.js.map +1 -0
- package/dist/tools/extract/pdf.d.ts +65 -0
- package/dist/tools/extract/pdf.d.ts.map +1 -0
- package/dist/tools/extract/pdf.js +197 -0
- package/dist/tools/extract/pdf.js.map +1 -0
- package/dist/tools/extract/pptx.d.ts +32 -0
- package/dist/tools/extract/pptx.d.ts.map +1 -0
- package/dist/tools/extract/pptx.js +77 -0
- package/dist/tools/extract/pptx.js.map +1 -0
- package/dist/tools/extract/xlsx.d.ts +47 -0
- package/dist/tools/extract/xlsx.d.ts.map +1 -0
- package/dist/tools/extract/xlsx.js +111 -0
- package/dist/tools/extract/xlsx.js.map +1 -0
- package/dist/tools/finding-tool.d.ts +76 -0
- package/dist/tools/finding-tool.d.ts.map +1 -0
- package/dist/tools/finding-tool.js +125 -0
- package/dist/tools/finding-tool.js.map +1 -0
- package/dist/tools/messaging-tools.d.ts +41 -11
- package/dist/tools/messaging-tools.d.ts.map +1 -1
- package/dist/tools/messaging-tools.js +104 -55
- package/dist/tools/messaging-tools.js.map +1 -1
- package/dist/tools/neutts-synth.d.ts +27 -3
- package/dist/tools/neutts-synth.d.ts.map +1 -1
- package/dist/tools/neutts-synth.js +57 -13
- package/dist/tools/neutts-synth.js.map +1 -1
- package/dist/tools/pipeline-tool.d.ts +43 -1
- package/dist/tools/pipeline-tool.d.ts.map +1 -1
- package/dist/tools/pipeline-tool.js +13 -2
- package/dist/tools/pipeline-tool.js.map +1 -1
- package/dist/tools/read-extract.d.ts +116 -45
- package/dist/tools/read-extract.d.ts.map +1 -1
- package/dist/tools/read-extract.js +494 -158
- package/dist/tools/read-extract.js.map +1 -1
- package/dist/tools/registry.d.ts +2 -2
- package/dist/tools/registry.d.ts.map +1 -1
- package/dist/tools/registry.js +152 -23
- package/dist/tools/registry.js.map +1 -1
- package/dist/tools/subagent-refusal.d.ts +15 -0
- package/dist/tools/subagent-refusal.d.ts.map +1 -0
- package/dist/tools/subagent-refusal.js +18 -0
- package/dist/tools/subagent-refusal.js.map +1 -0
- package/dist/tools/subagent-spawner.d.ts +122 -0
- package/dist/tools/subagent-spawner.d.ts.map +1 -1
- package/dist/tools/subagent-spawner.js +249 -28
- package/dist/tools/subagent-spawner.js.map +1 -1
- package/dist/tools/tool-hooks.d.ts +177 -0
- package/dist/tools/tool-hooks.d.ts.map +1 -0
- package/dist/tools/tool-hooks.js +427 -0
- package/dist/tools/tool-hooks.js.map +1 -0
- package/dist/tools/tool-loop.d.ts +82 -0
- package/dist/tools/tool-loop.d.ts.map +1 -1
- package/dist/tools/tool-loop.js +167 -9
- package/dist/tools/tool-loop.js.map +1 -1
- package/dist/tools/tool-refusal.d.ts +68 -0
- package/dist/tools/tool-refusal.d.ts.map +1 -0
- package/dist/tools/tool-refusal.js +78 -0
- package/dist/tools/tool-refusal.js.map +1 -0
- package/dist/tools/toolsets.d.ts +8 -0
- package/dist/tools/toolsets.d.ts.map +1 -1
- package/dist/tools/toolsets.js +12 -2
- package/dist/tools/toolsets.js.map +1 -1
- package/dist/tools/vision-tools.d.ts +88 -83
- package/dist/tools/vision-tools.d.ts.map +1 -1
- package/dist/tools/vision-tools.js +134 -103
- package/dist/tools/vision-tools.js.map +1 -1
- package/dist/tools/worktree.d.ts +210 -0
- package/dist/tools/worktree.d.ts.map +1 -0
- package/dist/tools/worktree.js +374 -0
- package/dist/tools/worktree.js.map +1 -0
- package/dist/utils/format.d.ts +3 -0
- package/dist/utils/format.d.ts.map +1 -0
- package/dist/utils/format.js +32 -0
- package/dist/utils/format.js.map +1 -0
- package/dist/web-dashboard/attachment-extract.d.ts +64 -0
- package/dist/web-dashboard/attachment-extract.d.ts.map +1 -0
- package/dist/web-dashboard/attachment-extract.js +154 -0
- package/dist/web-dashboard/attachment-extract.js.map +1 -0
- package/dist/web-dashboard/chat-console.d.ts +108 -1
- package/dist/web-dashboard/chat-console.d.ts.map +1 -1
- package/dist/web-dashboard/chat-console.js +36 -0
- package/dist/web-dashboard/chat-console.js.map +1 -1
- package/dist/web-dashboard/hub-data.d.ts +37 -0
- package/dist/web-dashboard/hub-data.d.ts.map +1 -1
- package/dist/web-dashboard/hub-data.js +61 -1
- package/dist/web-dashboard/hub-data.js.map +1 -1
- package/dist/web-dashboard/process-env-inventory.d.ts +57 -0
- package/dist/web-dashboard/process-env-inventory.d.ts.map +1 -0
- package/dist/web-dashboard/process-env-inventory.js +96 -0
- package/dist/web-dashboard/process-env-inventory.js.map +1 -0
- package/dist/web-dashboard/server.d.ts +14 -0
- package/dist/web-dashboard/server.d.ts.map +1 -1
- package/dist/web-dashboard/server.js +493 -30
- package/dist/web-dashboard/server.js.map +1 -1
- package/dist/web-dashboard/src/types.d.ts +261 -48
- package/dist/web-dashboard/src/types.d.ts.map +1 -1
- package/package.json +18 -3
- package/src/web-dashboard/public/assets/{index-Cyd6tIew.css → index-CIJ6FHHZ.css} +1 -1
- package/src/web-dashboard/public/assets/index-CsySzR41.js +207 -0
- package/src/web-dashboard/public/assets/index-CsySzR41.js.map +1 -0
- package/src/web-dashboard/public/index.html +2 -2
- package/dist/tools/child-agent-worker.js +0 -212
- package/src/web-dashboard/public/assets/index-CxDj7p6i.js +0 -207
- 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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,cAAc,EACd,eAAe,EACf,gBAAgB,EAChB,MAAM,GAGP,MAAM,yBAAyB,CAAC;AAGjC,oFAAoF;AACpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,kBAAkB,CAAC;AAEhD,qFAAqF;AACrF,MAAM,cAAc,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,CAAU,CAAC;AAE5E,iFAAiF;AACjF,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,QAAQ,CACP,gHAAgH,CACjH;IACH,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,QAAQ,CACP,kIAAkI,CACnI;IACH,QAAQ,EAAE,CAAC;SACR,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,QAAQ,CAAC,uCAAuC,CAAC;QAC9E,GAAG,EAAE,CAAC;aACH,MAAM,EAAE;aACR,QAAQ,CACP,uNAAuN,CACxN;QACH,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,6EAA6E,CAAC;KACtH,CAAC,CACH;SACA,QAAQ,EAAE;SACV,QAAQ,CACP,oNAAoN,CACrN;CACJ,CAAC,CAAC;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,aAAa,CAC3B,IAAqB,EACrB,GAA+B;IAE/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAC/C,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,OAAO,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IACnD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,KAAK,EACH,4FAA4F;gBAC5F,0CAA0C;SAC7C,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EACH,2GAA2G;gBAC3G,8DAA8D;SACjE,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAe,CAAC;IACrD,0EAA0E;IAC1E,+EAA+E;IAC/E,4EAA4E;IAC5E,eAAe;IACf,MAAM,SAAS,GAAG,cAAc,CAC9B,gBAAgB,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAC/D,EAAE,EACF,EAAE,OAAO,EAAE,CACZ,CAAC;IACF,MAAM,OAAO,GAAG,SAAS,CAAC,QAAQ;QAChC,CAAC,CAAC,SAAS,CAAC,OAAO;QACnB,CAAC,CAAC,SAAS,CAAC,MAAM;YAChB,CAAC,CAAC,EAAE,GAAG,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,MAAM,SAAS,CAAC,MAAM,EAAE,EAAE;YACvE,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC;IAExB,8EAA8E;IAC9E,kEAAkE;IAClE,IAAI,CAAC;QACH,GAAG,EAAE,IAAI,EAAE,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,iBAAiB;IACnB,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,CAAC;AACrD,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,IAAI,EAAE,iBAAiB;QACvB,WAAW,EACT,0hBAA0hB;QAC5hB,QAAQ,EAAE,YAAY;QACtB,WAAW,EAAE,aAAa;QAC1B,aAAa,EAAE,KAAK;QACpB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YACvB,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,CAAC,IAAI,CAAoB,CAAC;YAC5D,MAAM,MAAM,GAAG,aAAa,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC1C,IAAI,OAAO,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC,KAAK,CAAC;YAC3C,OAAO,MAAM,CAAC,IAAI,CAAC;QACrB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -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
|
-
* -
|
|
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":"AAAA
|
|
1
|
+
{"version":3,"file":"messaging-tools.d.ts","sourceRoot":"","sources":["../../src/tools/messaging-tools.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIxE,MAAM,WAAW,aAAa;IAC5B,eAAe;IACf,QAAQ,EAAE,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;IAC/E,sBAAsB;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,sBAAsB;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,CAAC;IACtC,kBAAkB;IAClB,WAAW,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAClE,gCAAgC;IAChC,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACxF;AAED,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,kBAAkB;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,WAAW;IAC1B,iBAAiB;IACjB,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;IAC/D,oBAAoB;IACpB,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED,MAAM,WAAW,eAAe;IAC9B,cAAc;IACd,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,uBAAuB;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;GAGG;AACH,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,2EAA2E;IAC3E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,eAAe,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAID,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,cAAc,CAMd;IAER;;;;OAIG;IACH,OAAO,CAAC,aAAa;IAarB;;;;;OAKG;IACG,WAAW,CACf,MAAM,EAAE,aAAa,EACrB,OAAO,EAAE,kBAAkB,GAC1B,OAAO,CAAC,UAAU,CAAC;IA2CtB;;;;;OAKG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,UAAU,CAAC;IAWtB;;OAEG;IACH,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,MAAW,GAAG,KAAK,CAAC;QAC3E,QAAQ,EAAE,MAAM,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,CAAC;YAaY,WAAW;YAIX,SAAS;YAIT,YAAY;YAIZ,YAAY;YAIZ,UAAU;YAIV,WAAW;CAG1B;AAID,qBAAa,qBAAqB;IAChC,OAAO,CAAC,SAAS,CAA0C;IAE3D;;OAEG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,WAAW,EAAO,GAAG,cAAc;IAYzE;;OAEG;IACH,WAAW,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI;IAItD;;OAEG;IACH,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO;IAQlE;;OAEG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IA0BnD;;OAEG;IACH,aAAa,IAAI,cAAc,EAAE;CAGlC;AAID,qBAAa,kBAAkB;IAC7B,OAAO,CAAC,KAAK,CAA2C;IAExD;;OAEG;IACH,SAAS,CAAC,QAAQ,GAAE,MAAe,GAAG,eAAe,EAAE;IAMvD;;OAEG;IACH,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,eAAe,GAAG,IAAI;IAI/C;;OAEG;IACH,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,EAAE;IAM7C;;OAEG;IACH,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,eAAe;IAcrG;;OAEG;IACH,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO;IAInC;;OAEG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,GAAG,OAAO;CAO7D;AAQD,wBAAgB,mBAAmB,IAAI,gBAAgB,CAGtD;AAED,wBAAgB,wBAAwB,IAAI,qBAAqB,CAGhE;AAED,wBAAgB,qBAAqB,IAAI,kBAAkB,CAG1D"}
|
|
@@ -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
|
-
* -
|
|
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
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
46
|
-
|
|
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.
|
|
54
|
-
|
|
55
|
-
|
|
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
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return
|
|
81
|
-
}
|
|
82
|
-
async sendWhatsApp(target,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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":"AAAA
|
|
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 —
|
|
2
|
+
* NeuTTS Synthesis — text-to-speech.
|
|
3
3
|
*
|
|
4
4
|
* Hermes equivalent: neutts_synth.py (110 lines)
|
|
5
5
|
*
|
|
6
6
|
* Provides:
|
|
7
|
-
* -
|
|
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
|
|
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 —
|
|
2
|
+
* NeuTTS Synthesis — text-to-speech.
|
|
3
3
|
*
|
|
4
4
|
* Hermes equivalent: neutts_synth.py (110 lines)
|
|
5
5
|
*
|
|
6
6
|
* Provides:
|
|
7
|
-
* -
|
|
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
|
-
//
|
|
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
|
-
|
|
62
|
+
failureReason = `NeuTTS API synthesis failed: ${err instanceof Error ? err.message : String(err)}`;
|
|
63
|
+
logger.warn(`[neutts] ${failureReason}`);
|
|
43
64
|
}
|
|
44
65
|
}
|
|
45
|
-
//
|
|
46
|
-
|
|
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
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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 ─────────────────────────────────────────────────────────────
|