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
package/dist/gateway/registry.js
CHANGED
|
@@ -26,6 +26,7 @@ import { ConfigManager } from '../config/manager.js';
|
|
|
26
26
|
import { ChannelDirectory, PLATFORM_ENV_VARS, PLATFORM_LABELS, } from './channel-directory.js';
|
|
27
27
|
import { DeliveryLedger } from './delivery.js';
|
|
28
28
|
import { InboxLedger } from './inbox.js';
|
|
29
|
+
import { inboundAttachmentPolicy } from './inbound-media.js';
|
|
29
30
|
import { InboundDedupLedger } from './dedup.js';
|
|
30
31
|
import { GatewayHeartbeat, HEARTBEAT_INTERVAL_MS } from './heartbeat.js';
|
|
31
32
|
import { logGatewayEvent, previewText } from './gateway-log.js';
|
|
@@ -36,6 +37,11 @@ import { createResilientCallLLM, markFailoverAttempts, modelBreadthReport, rende
|
|
|
36
37
|
// The intent audit: on a REPEATED failure, ask the model what the ask really
|
|
37
38
|
// needs and feed a confirmed correction back into the NLU (see learnings.ts).
|
|
38
39
|
import { confirmRoutedIntent, intentConfirmedNote, intentCorrectedNote, } from '../nlu/intent-confirm.js';
|
|
40
|
+
// The audit's verdict goes into the gateway's own durable record, in the SAME
|
|
41
|
+
// wire shape every other surface reports (WS1, `findings/verdicts.ts`): a
|
|
42
|
+
// messaging surface has no terminal to scroll, so "what we decided, and what it
|
|
43
|
+
// was checked against" has to be in the log or it does not exist.
|
|
44
|
+
import { toWire } from '../findings/verdicts.js';
|
|
39
45
|
// The retry queue behind the "Reply *yes* and I will keep trying" offer. LEAF
|
|
40
46
|
// import: a plain store + matcher, so the gateway does not pull routing in for it.
|
|
41
47
|
import { abandonedLine, acceptedLine, cancelTasksFor, confirmTask, deferTask, dueTasks, expiredTasks, getPendingTask, isRetryAcceptance, isRetryDecline, removeDeferredTask, retryingLine, updateDeferredTask, } from '../learning/deferred-task.js';
|
|
@@ -57,6 +63,17 @@ const DELIVERY_DRAIN_INTERVAL_MS = 30_000;
|
|
|
57
63
|
const RETRY_DRAIN_INTERVAL_MS = 15_000;
|
|
58
64
|
/** Cap the per-target send-failure map (diagnostics only — never grows). */
|
|
59
65
|
const MAX_TRACKED_SEND_ERRORS = 200;
|
|
66
|
+
/**
|
|
67
|
+
* How often the inbound artifact sandbox is swept (ms). Hourly: the sweep
|
|
68
|
+
* removes attachments past their TTL / over the size cap, and the 15s liveness
|
|
69
|
+
* tick that triggers it must not do directory work it does not need to.
|
|
70
|
+
*/
|
|
71
|
+
const INBOUND_PRUNE_INTERVAL_MS = 60 * 60 * 1000;
|
|
72
|
+
/**
|
|
73
|
+
* Longest answer spoken as a voice note (chars). A voice-note question expects a
|
|
74
|
+
* spoken reply, not a synthesized essay — past this the answer goes out as text.
|
|
75
|
+
*/
|
|
76
|
+
const VOICE_REPLY_MAX_CHARS = 700;
|
|
60
77
|
// ─── Response cleanup ──────────────────────────────────────────────────────
|
|
61
78
|
/**
|
|
62
79
|
* Strip leaked internal reasoning, planning blocks, and meta-commentary from
|
|
@@ -527,6 +544,8 @@ export class GatewayRegistry {
|
|
|
527
544
|
adapterHealth = new Map();
|
|
528
545
|
/** Earliest epoch-ms at which a not-yet-started adapter may be retried. */
|
|
529
546
|
adapterRetryAt = new Map();
|
|
547
|
+
/** Epoch ms of the last inbound-sandbox sweep (throttles the hourly prune). */
|
|
548
|
+
lastInboundPruneAt = 0;
|
|
530
549
|
/** The heartbeat + watchdog tick. */
|
|
531
550
|
livenessTimer = null;
|
|
532
551
|
chatEngine;
|
|
@@ -634,6 +653,38 @@ export class GatewayRegistry {
|
|
|
634
653
|
}
|
|
635
654
|
return this.sendToRef(ref, text, target);
|
|
636
655
|
}
|
|
656
|
+
/**
|
|
657
|
+
* Deliver an ANSWER, using a VOICE NOTE when the sender's own message was a
|
|
658
|
+
* voice note and a TTS backend is installed.
|
|
659
|
+
*
|
|
660
|
+
* Falls back to text whenever anything is missing — no TTS backend, an answer
|
|
661
|
+
* too long to speak sanely, or a platform that cannot send audio — so a voice
|
|
662
|
+
* reply is a courtesy and never a way for the answer to get lost. Returns true
|
|
663
|
+
* when a voice note was delivered, false when text was sent instead.
|
|
664
|
+
*/
|
|
665
|
+
async replyInKind(ref, text, opts = {}) {
|
|
666
|
+
if (opts.voice && text.length > 0 && text.length <= VOICE_REPLY_MAX_CHARS) {
|
|
667
|
+
try {
|
|
668
|
+
const voice = await import('../tools/modality/voice.js');
|
|
669
|
+
if (voice.isTtsAvailable()) {
|
|
670
|
+
const spoken = await voice.speak(text);
|
|
671
|
+
if (spoken.ok && spoken.file) {
|
|
672
|
+
const { readFileSync } = await import('node:fs');
|
|
673
|
+
const data = new Uint8Array(readFileSync(spoken.file));
|
|
674
|
+
const ext = spoken.file.toLowerCase().endsWith('.wav') ? 'wav' : 'mp3';
|
|
675
|
+
const ok = await this.sendMediaToRef(ref, { type: 'audio', data, filename: `reply.${ext}` });
|
|
676
|
+
if (ok)
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
catch {
|
|
682
|
+
/* fall back to text */
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
await this.sendToRef(ref, text);
|
|
686
|
+
return false;
|
|
687
|
+
}
|
|
637
688
|
/**
|
|
638
689
|
* P3 — send media to a channel ref. Adapters that implement the optional
|
|
639
690
|
* `sendMedia` (WhatsApp, Telegram, Discord) support it; others return false
|
|
@@ -871,6 +922,53 @@ export class GatewayRegistry {
|
|
|
871
922
|
if (!this.isAllowed(ref)) {
|
|
872
923
|
return refuse('This channel is not authorized to trigger the agent. Add it to BUFF_GATEWAY_ALLOW_IDS (platform:channelId).');
|
|
873
924
|
}
|
|
925
|
+
// ── INBOUND DOCUMENT HYDRATION ── A document/image arrives as BYTES, not
|
|
926
|
+
// text. Turn it into text BEFORE routing, because every downstream reader
|
|
927
|
+
// (the dedup ledger, the chat store, and finally the model) reads
|
|
928
|
+
// `msg.text`: this runs the SAME `read_extract` the agent uses for a file in
|
|
929
|
+
// the project folder and prepends the extracted section to the caption.
|
|
930
|
+
// Without it a document message had empty text and was dropped by the
|
|
931
|
+
// bridge — the sender's own file vanished with no reply.
|
|
932
|
+
//
|
|
933
|
+
// Placed AFTER the authorization gates on purpose: an unapproved sender must
|
|
934
|
+
// leave no trace, so their bytes are never written to the artifact sandbox
|
|
935
|
+
// or extracted. `parsed` above already ran on the CAPTION only, so a long
|
|
936
|
+
// document never pollutes the NLU route; the extracted text joins the turn
|
|
937
|
+
// for the model.
|
|
938
|
+
//
|
|
939
|
+
// Consumed ONCE (media is cleared) so a retry or an audit re-route of the
|
|
940
|
+
// same message never re-downloads or duplicates the section.
|
|
941
|
+
let mediaFailureReply = null;
|
|
942
|
+
// A voice note gets a voice reply when one was sent (see replyInKind).
|
|
943
|
+
let voiceReplyWanted = false;
|
|
944
|
+
if (msg.media) {
|
|
945
|
+
const media = msg.media;
|
|
946
|
+
msg.media = undefined;
|
|
947
|
+
const attachmentPolicy = inboundAttachmentPolicy(this.configManager);
|
|
948
|
+
if (!attachmentPolicy.enabled) {
|
|
949
|
+
// Policy lets the MESSAGE through but not the attachment. Say so to the
|
|
950
|
+
// model rather than silently dropping it — or extracting it.
|
|
951
|
+
const label = media.filename?.trim() || media.type;
|
|
952
|
+
msg.text = [msg.text, `[Attachment: ${label} — inbound attachment handling is disabled by configuration]`]
|
|
953
|
+
.filter(Boolean)
|
|
954
|
+
.join('\n\n');
|
|
955
|
+
}
|
|
956
|
+
else {
|
|
957
|
+
voiceReplyWanted = media.type === 'audio';
|
|
958
|
+
try {
|
|
959
|
+
const { hydrateInboundMedia, formatMediaFailureReply } = await import('./inbound-media.js');
|
|
960
|
+
const hydration = await hydrateInboundMedia(media, { maxBytes: attachmentPolicy.maxBytes });
|
|
961
|
+
if (hydration.section)
|
|
962
|
+
msg.text = [msg.text, hydration.section].filter(Boolean).join('\n\n');
|
|
963
|
+
if (hydration.failure)
|
|
964
|
+
mediaFailureReply = formatMediaFailureReply(hydration.failure);
|
|
965
|
+
logger.info(`gateway: hydrated inbound ${media.type} (${media.data.byteLength} bytes) for ${msg.platform}:${msg.channelId}`);
|
|
966
|
+
}
|
|
967
|
+
catch {
|
|
968
|
+
/* Never break handling on a media failure — the text turn still runs. */
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
}
|
|
874
972
|
// ── IDEMPOTENCY ── A messaging transport is at-least-once: the bridge
|
|
875
973
|
// reconnects and replays its offline backfill, a webhook retries, a device
|
|
876
974
|
// re-syncs. Observed live: ONE WhatsApp ask arrived 20+ times and was
|
|
@@ -898,6 +996,15 @@ export class GatewayRegistry {
|
|
|
898
996
|
record('duplicate', undefined, { key: dedupVerdict.key, count: dedupVerdict.count });
|
|
899
997
|
return 'duplicate';
|
|
900
998
|
}
|
|
999
|
+
// A document that produced NO text cannot be answered by routing it to the
|
|
1000
|
+
// model — the model would only invent an answer about a file it never read.
|
|
1001
|
+
// Answer the sender directly, naming why, and stop. Placed AFTER dedup so a
|
|
1002
|
+
// re-delivered message (bridge backfill / webhook retry) never re-sends it.
|
|
1003
|
+
if (mediaFailureReply) {
|
|
1004
|
+
await replyTo(mediaFailureReply);
|
|
1005
|
+
record('attachment_failed', mediaFailureReply);
|
|
1006
|
+
return mediaFailureReply;
|
|
1007
|
+
}
|
|
901
1008
|
// 7-DAY PER-CONTACT CONVERSATION MEMORY — record every AUTHORIZED inbound
|
|
902
1009
|
// message the moment it arrives, BEFORE the routing decision (chat,
|
|
903
1010
|
// pipeline, help). Placed AFTER the sender/channel gates: an unapproved
|
|
@@ -1000,7 +1107,9 @@ export class GatewayRegistry {
|
|
|
1000
1107
|
const attemptMark = markFailoverAttempts();
|
|
1001
1108
|
const answer = await this.runInboundChat(msg);
|
|
1002
1109
|
if (answer && answer.content.trim() && !answer.generationFailed) {
|
|
1003
|
-
|
|
1110
|
+
// Reply IN KIND: a spoken question gets a spoken answer when TTS is
|
|
1111
|
+
// available (falls back to text — see replyInKind).
|
|
1112
|
+
await this.replyInKind(ref, answer.content, { voice: voiceReplyWanted });
|
|
1004
1113
|
record('chat', answer.content);
|
|
1005
1114
|
// A retry that produced a real answer is DONE — the queue entry must go,
|
|
1006
1115
|
// or the drain would keep re-running a fulfilled ask.
|
|
@@ -1068,7 +1177,10 @@ export class GatewayRegistry {
|
|
|
1068
1177
|
const answer = await this.runInboundChat(msg);
|
|
1069
1178
|
const answered = !!answer && answer.content.trim().length > 0 && !answer.generationFailed;
|
|
1070
1179
|
const line = answered ? answer.content : this.generationFailureLine();
|
|
1071
|
-
|
|
1180
|
+
if (answered)
|
|
1181
|
+
await this.replyInKind(ref, line, { voice: voiceReplyWanted });
|
|
1182
|
+
else
|
|
1183
|
+
await replyTo(line);
|
|
1072
1184
|
record('pipeline', line);
|
|
1073
1185
|
if (answered && opts.retryOf)
|
|
1074
1186
|
removeDeferredTask(opts.retryOf);
|
|
@@ -1241,6 +1353,10 @@ export class GatewayRegistry {
|
|
|
1241
1353
|
routed,
|
|
1242
1354
|
probed: !verdict.failed,
|
|
1243
1355
|
reason: verdict.reason,
|
|
1356
|
+
// The verdict for THIS decision, with its evidence. A confirmed reading
|
|
1357
|
+
// now means the model justified it, so the log says which of the two it
|
|
1358
|
+
// was instead of leaving "probed: true" to imply it was checked.
|
|
1359
|
+
finding: toWire(verdict.finding),
|
|
1244
1360
|
}, 'info');
|
|
1245
1361
|
// The audit ran and confirmed the reading: say so, because "it failed" and
|
|
1246
1362
|
// "it failed and I checked that I understood you" are different promises.
|
|
@@ -1254,6 +1370,11 @@ export class GatewayRegistry {
|
|
|
1254
1370
|
to: verdict.kind,
|
|
1255
1371
|
reason: verdict.reason,
|
|
1256
1372
|
learningId: verdict.learning?.id,
|
|
1373
|
+
// Logged even when `learningId` is absent, and that is the case worth
|
|
1374
|
+
// recording: a correction the model could not justify is acted on but NOT
|
|
1375
|
+
// taught, so the log states the verdict (PLAUSIBLE) and its own outcome
|
|
1376
|
+
// rather than looking like a correction that simply failed to save.
|
|
1377
|
+
finding: toWire(verdict.finding),
|
|
1257
1378
|
}, 'warn');
|
|
1258
1379
|
const corrected = verdict.kind;
|
|
1259
1380
|
const line = intentCorrectedNote(corrected, verdict.reason);
|
|
@@ -1364,6 +1485,23 @@ export class GatewayRegistry {
|
|
|
1364
1485
|
return true;
|
|
1365
1486
|
}
|
|
1366
1487
|
}
|
|
1488
|
+
/**
|
|
1489
|
+
* One inbound chat turn, and the backend it was served by.
|
|
1490
|
+
*
|
|
1491
|
+
* The result carries `provider`/`model`/`transport` because this method is the
|
|
1492
|
+
* surface's boundary: the shared engine resolves all three, and keeping only
|
|
1493
|
+
* `content` + `generationFailed` is what made `run-attribution@gateway-chat`
|
|
1494
|
+
* the one capability cell the gateway could not prove. A messaging run is
|
|
1495
|
+
* also the hardest to inspect after the fact — there is no terminal to scroll
|
|
1496
|
+
* — so the same triple goes to the gateway log.
|
|
1497
|
+
*
|
|
1498
|
+
* It also carries the turn's per-call tool lifecycles (`toolCalls`), read from
|
|
1499
|
+
* the engine's `onToolCall` seam. Those are recorded, never sent to the
|
|
1500
|
+
* sender: a chat turn's `started`/`called` events are internal, exactly like
|
|
1501
|
+
* `onProgress`, but the OUTCOME of each call is a fact the surface should be
|
|
1502
|
+
* able to report — otherwise a gateway turn's tool work is unattributable
|
|
1503
|
+
* (`tool-call-lifecycle@gateway-chat`).
|
|
1504
|
+
*/
|
|
1367
1505
|
async runInboundChat(msg) {
|
|
1368
1506
|
try {
|
|
1369
1507
|
// Broadcast typing indicator start.
|
|
@@ -1437,10 +1575,44 @@ export class GatewayRegistry {
|
|
|
1437
1575
|
const routingDefault = this.configManager.getAll().defaultProvider;
|
|
1438
1576
|
const useAuto = !routingDefault || routingDefault === 'auto';
|
|
1439
1577
|
const { type: providerType, config: providerConfig } = this.configManager.getProviderConfig();
|
|
1578
|
+
// The turn's tool-call lifecycle. Collected from the SHARED engine seam
|
|
1579
|
+
// (the same `called` phase the CLI and dashboard read) so the gateway
|
|
1580
|
+
// reports what the turn DID, not what the answer text claims. Outcome is
|
|
1581
|
+
// optional: a call whose outcome never arrived is recorded as absent, the
|
|
1582
|
+
// same honest reading the other surfaces use, never up-graded to success.
|
|
1583
|
+
const toolCalls = [];
|
|
1584
|
+
/**
|
|
1585
|
+
* WS1 — the findings this turn recorded, in call order.
|
|
1586
|
+
*
|
|
1587
|
+
* Read from the shared engine seam like `toolCalls` above, and written to
|
|
1588
|
+
* the `inbound.chat` log record for the same reason: a messaging surface
|
|
1589
|
+
* has no terminal to scroll, so the log is where a turn's verdicts have to
|
|
1590
|
+
* live (and it is what the parity driver reads).
|
|
1591
|
+
*/
|
|
1592
|
+
const findings = [];
|
|
1440
1593
|
const answer = await engine.answerOnce(prompt, {
|
|
1441
1594
|
provider: useAuto ? 'auto' : providerType,
|
|
1442
1595
|
model: useAuto ? 'auto' : providerConfig.model,
|
|
1443
1596
|
history,
|
|
1597
|
+
// WS5 (#27) — isolation and resume are asked through the environment
|
|
1598
|
+
// (`NUVIRA_ISOLATE` / `NUVIRA_RESUME`), which is how a messaging gateway
|
|
1599
|
+
// is configured: an inbound WhatsApp message has no flags to carry, and
|
|
1600
|
+
// the operator decides once for the deployment. This is the code's own
|
|
1601
|
+
// record of that decision, on the log line that reports the turn.
|
|
1602
|
+
onToolCall: (phase, info) => {
|
|
1603
|
+
if (phase !== 'called')
|
|
1604
|
+
return;
|
|
1605
|
+
toolCalls.push({ tool: info.tool, ...(typeof info.ok === 'boolean' ? { ok: info.ok } : {}) });
|
|
1606
|
+
},
|
|
1607
|
+
// WS1 — every finding the turn recorded, with the gate's verdict. Kept
|
|
1608
|
+
// internal exactly like onToolCall: it belongs in the log and this
|
|
1609
|
+
// method's return, never in the channel sender's message.
|
|
1610
|
+
onFinding: (finding) => {
|
|
1611
|
+
findings.push(finding);
|
|
1612
|
+
},
|
|
1613
|
+
// WS2 (#24) — a messaging turn is the GATEWAY's; the session debug log's
|
|
1614
|
+
// header must name it that way rather than the shared engine's default.
|
|
1615
|
+
debugSurface: 'gateway-chat',
|
|
1444
1616
|
// Session 3 — the channel rules go in the STABLE layer, not the ask.
|
|
1445
1617
|
systemPolicy: CHANNEL_POLICY,
|
|
1446
1618
|
// P5 — a replied followup carries the continuation marker into the
|
|
@@ -1493,7 +1665,9 @@ export class GatewayRegistry {
|
|
|
1493
1665
|
// P3 note: the engine's onProgress is intentionally NOT wired here —
|
|
1494
1666
|
// internal progress lines (routed-to, raw tool calls) must never leak
|
|
1495
1667
|
// to the channel. Progress stays in the audit logs; the single
|
|
1496
|
-
// "working" line + final answer is the whole conversation.
|
|
1668
|
+
// "working" line + final answer is the whole conversation. The
|
|
1669
|
+
// structured onToolCall lifecycle above is wired, but only for the log
|
|
1670
|
+
// and this method's return — it is never rendered to the sender.
|
|
1497
1671
|
});
|
|
1498
1672
|
// Only the FINAL answer reaches the sender, in natural language — plus
|
|
1499
1673
|
// the model's suggested followups rendered as a readable numbered list
|
|
@@ -1584,7 +1758,36 @@ export class GatewayRegistry {
|
|
|
1584
1758
|
this.chatStore.append(historyKey, null, content);
|
|
1585
1759
|
this.onTypingCallback?.({ platform: msg.platform, channelId: msg.channelId, typing: false });
|
|
1586
1760
|
this.writeTypingFile({ platform: msg.platform, channelId: msg.channelId, typing: false });
|
|
1587
|
-
|
|
1761
|
+
// The run's own record, with the backend that served it. Best-effort by
|
|
1762
|
+
// the logger's own contract — an unwritable log must never lose a reply.
|
|
1763
|
+
logGatewayEvent('inbound.chat', {
|
|
1764
|
+
platform: msg.platform,
|
|
1765
|
+
channelId: msg.channelId,
|
|
1766
|
+
...(answer.provider ? { provider: answer.provider } : {}),
|
|
1767
|
+
...(answer.model ? { model: answer.model } : {}),
|
|
1768
|
+
...(answer.transport ? { transport: answer.transport } : {}),
|
|
1769
|
+
...(toolCalls.length > 0 ? { toolCalls } : {}),
|
|
1770
|
+
...(findings.length > 0 ? { findings } : {}),
|
|
1771
|
+
// WS5 (#27) — the isolation this turn had, and what it changed against
|
|
1772
|
+
// its base commit. Durable, for the same reason the tool lifecycle and
|
|
1773
|
+
// the findings are: a messaging surface has no terminal, so the log IS
|
|
1774
|
+
// where an operator can see that an isolated turn ran and what it
|
|
1775
|
+
// touched.
|
|
1776
|
+
...(answer.worktree ? { worktree: answer.worktree } : {}),
|
|
1777
|
+
...(answer.resume ? { resume: answer.resume } : {}),
|
|
1778
|
+
generationFailed: answer.generationFailed === true,
|
|
1779
|
+
});
|
|
1780
|
+
return {
|
|
1781
|
+
content,
|
|
1782
|
+
generationFailed: answer.generationFailed,
|
|
1783
|
+
...(answer.provider ? { provider: answer.provider } : {}),
|
|
1784
|
+
...(answer.model ? { model: answer.model } : {}),
|
|
1785
|
+
...(answer.transport ? { transport: answer.transport } : {}),
|
|
1786
|
+
...(toolCalls.length > 0 ? { toolCalls } : {}),
|
|
1787
|
+
...(findings.length > 0 ? { findings } : {}),
|
|
1788
|
+
...(answer.worktree ? { worktree: answer.worktree } : {}),
|
|
1789
|
+
...(answer.resume ? { resume: answer.resume } : {}),
|
|
1790
|
+
};
|
|
1588
1791
|
}
|
|
1589
1792
|
catch (err) {
|
|
1590
1793
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -1774,6 +1977,23 @@ export class GatewayRegistry {
|
|
|
1774
1977
|
supervisorPid: process.ppid || undefined,
|
|
1775
1978
|
adapters: [...this.adapterHealth.values()],
|
|
1776
1979
|
});
|
|
1980
|
+
// Scheduled sandbox cleanup: extracted inbound attachments are kept for
|
|
1981
|
+
// their TTL, then swept — throttled to hourly so the 15s liveness tick
|
|
1982
|
+
// never walks the directory unnecessarily.
|
|
1983
|
+
const now = Date.now();
|
|
1984
|
+
if (now - this.lastInboundPruneAt >= INBOUND_PRUNE_INTERVAL_MS) {
|
|
1985
|
+
this.lastInboundPruneAt = now;
|
|
1986
|
+
try {
|
|
1987
|
+
const { pruneInboundMedia } = await import('./inbound-media.js');
|
|
1988
|
+
const pruned = pruneInboundMedia({ now });
|
|
1989
|
+
if (pruned.removed > 0) {
|
|
1990
|
+
logger.info(`gateway: pruned ${pruned.removed} inbound attachment(s) — ${Math.round(pruned.bytesFreed / 1024)} KB freed`);
|
|
1991
|
+
}
|
|
1992
|
+
}
|
|
1993
|
+
catch {
|
|
1994
|
+
/* best-effort sweep — never take the gateway down over cleanup */
|
|
1995
|
+
}
|
|
1996
|
+
}
|
|
1777
1997
|
};
|
|
1778
1998
|
// First beat immediately, so `gateway status` is honest within a second of
|
|
1779
1999
|
// startup instead of reporting the previous run's stale beat.
|