@animalabs/agent-framework 0.22.1 → 0.22.3
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 +4 -2
- package/dist/src/agent.d.ts +266 -28
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +539 -104
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts +41 -0
- package/dist/src/api/mcp-server-core.d.ts.map +1 -0
- package/dist/src/api/mcp-server-core.js +593 -0
- package/dist/src/api/mcp-server-core.js.map +1 -0
- package/dist/src/api/mcp-server.d.ts +2 -36
- package/dist/src/api/mcp-server.d.ts.map +1 -1
- package/dist/src/api/mcp-server.js +15 -595
- package/dist/src/api/mcp-server.js.map +1 -1
- package/dist/src/api/server.d.ts +9 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +55 -27
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/api/types.d.ts +10 -2
- package/dist/src/api/types.d.ts.map +1 -1
- package/dist/src/branch-names.d.ts +14 -0
- package/dist/src/branch-names.d.ts.map +1 -0
- package/dist/src/branch-names.js +22 -0
- package/dist/src/branch-names.js.map +1 -0
- package/dist/src/closest-names.d.ts +28 -0
- package/dist/src/closest-names.d.ts.map +1 -0
- package/dist/src/closest-names.js +98 -0
- package/dist/src/closest-names.js.map +1 -0
- package/dist/src/code-execution/py-runner.d.ts +16 -5
- package/dist/src/code-execution/py-runner.d.ts.map +1 -1
- package/dist/src/code-execution/py-runner.js +186 -74
- package/dist/src/code-execution/py-runner.js.map +1 -1
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
- package/dist/src/code-execution/runtime-py.js +49 -3
- package/dist/src/code-execution/runtime-py.js.map +1 -1
- package/dist/src/code-execution/tool-definition.d.ts +12 -1
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +21 -3
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/config-checks.d.ts +28 -0
- package/dist/src/config-checks.d.ts.map +1 -0
- package/dist/src/config-checks.js +52 -0
- package/dist/src/config-checks.js.map +1 -0
- package/dist/src/deadline-timer.d.ts +21 -0
- package/dist/src/deadline-timer.d.ts.map +1 -0
- package/dist/src/deadline-timer.js +43 -0
- package/dist/src/deadline-timer.js.map +1 -0
- package/dist/src/error-message.d.ts +30 -0
- package/dist/src/error-message.d.ts.map +1 -0
- package/dist/src/error-message.js +50 -0
- package/dist/src/error-message.js.map +1 -0
- package/dist/src/framework.d.ts +1212 -192
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +6686 -1835
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +8 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +27 -3
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/gate-script.d.ts.map +1 -1
- package/dist/src/gate/gate-script.js.map +1 -1
- package/dist/src/index.d.ts +5 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +5 -3
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +170 -13
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +499 -258
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js +91 -30
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +19 -3
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +23 -8
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +20 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -0
- package/dist/src/mcpl/convert-block.js +89 -0
- package/dist/src/mcpl/convert-block.js.map +1 -0
- package/dist/src/mcpl/errors.d.ts +13 -0
- package/dist/src/mcpl/errors.d.ts.map +1 -1
- package/dist/src/mcpl/errors.js +28 -0
- package/dist/src/mcpl/errors.js.map +1 -1
- package/dist/src/mcpl/feature-set-manager.d.ts.map +1 -1
- package/dist/src/mcpl/feature-set-manager.js +4 -3
- package/dist/src/mcpl/feature-set-manager.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +83 -72
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +114 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
- package/dist/src/mcpl/inbound-source.js +83 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -0
- package/dist/src/mcpl/index.d.ts +3 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +3 -1
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +15 -11
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js +153 -84
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +54 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -0
- package/dist/src/mcpl/log-value.js +109 -0
- package/dist/src/mcpl/log-value.js.map +1 -0
- package/dist/src/mcpl/prose-stream-router.d.ts +6 -6
- package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
- package/dist/src/mcpl/prose-stream-router.js +4 -4
- package/dist/src/mcpl/prose-stream-router.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +64 -7
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +121 -24
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +38 -8
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +77 -78
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +14 -2
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +72 -30
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +49 -14
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +74 -21
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/refusal-lines.d.ts +37 -0
- package/dist/src/mcpl/refusal-lines.d.ts.map +1 -0
- package/dist/src/mcpl/refusal-lines.js +61 -0
- package/dist/src/mcpl/refusal-lines.js.map +1 -0
- package/dist/src/mcpl/scope-manager.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +107 -12
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +470 -139
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/server-registry.d.ts +10 -1
- package/dist/src/mcpl/server-registry.d.ts.map +1 -1
- package/dist/src/mcpl/server-registry.js +14 -3
- package/dist/src/mcpl/server-registry.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
- package/dist/src/mcpl/skip-reply-wake.js +55 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
- package/dist/src/mcpl/tool-classes.d.ts +1 -1
- package/dist/src/mcpl/tool-classes.d.ts.map +1 -1
- package/dist/src/mcpl/tool-classes.js +3 -2
- package/dist/src/mcpl/tool-classes.js.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +74 -7
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +209 -22
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +43 -28
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/mcpl/visible-content.d.ts +15 -0
- package/dist/src/mcpl/visible-content.d.ts.map +1 -1
- package/dist/src/mcpl/visible-content.js +25 -0
- package/dist/src/mcpl/visible-content.js.map +1 -1
- package/dist/src/module-registry.d.ts +19 -1
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +54 -25
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/api/index.d.ts.map +1 -1
- package/dist/src/modules/api/index.js +1 -1
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/discord-js-client.d.ts +1 -0
- package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
- package/dist/src/modules/discord/discord-js-client.js +25 -9
- package/dist/src/modules/discord/discord-js-client.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +29 -3
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +383 -145
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/discord/types.d.ts +14 -1
- package/dist/src/modules/discord/types.d.ts.map +1 -1
- package/dist/src/modules/health/index.d.ts.map +1 -1
- package/dist/src/modules/health/index.js +2 -1
- package/dist/src/modules/health/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +3 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +359 -127
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +28 -1
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +177 -32
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +10 -0
- package/dist/src/modules/unknown-tool.d.ts.map +1 -0
- package/dist/src/modules/unknown-tool.js +17 -0
- package/dist/src/modules/unknown-tool.js.map +1 -0
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.d.ts +54 -6
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +93 -27
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +64 -6
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +291 -44
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +127 -27
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +821 -248
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +117 -15
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +436 -51
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +75 -8
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +576 -68
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +42 -3
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +7 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js +28 -4
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/operator-log.d.ts.map +1 -1
- package/dist/src/operator-log.js.map +1 -1
- package/dist/src/prose-drafts.d.ts +240 -0
- package/dist/src/prose-drafts.d.ts.map +1 -0
- package/dist/src/prose-drafts.js +362 -0
- package/dist/src/prose-drafts.js.map +1 -0
- package/dist/src/prose-segments.d.ts +21 -2
- package/dist/src/prose-segments.d.ts.map +1 -1
- package/dist/src/prose-segments.js +46 -9
- package/dist/src/prose-segments.js.map +1 -1
- package/dist/src/provider-waits.d.ts.map +1 -1
- package/dist/src/provider-waits.js.map +1 -1
- package/dist/src/queue.d.ts.map +1 -1
- package/dist/src/record-journal.d.ts.map +1 -1
- package/dist/src/record-journal.js.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.d.ts.map +1 -1
- package/dist/src/recovery/discord-awareness-outbox.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +1 -0
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +32 -25
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/recovery/recover-cli.js.map +1 -1
- package/dist/src/runtime/liveness-watchdog.d.ts.map +1 -1
- package/dist/src/runtime/liveness-watchdog.js.map +1 -1
- package/dist/src/safe-slice.d.ts +5 -1
- package/dist/src/safe-slice.d.ts.map +1 -1
- package/dist/src/safe-slice.js +9 -1
- package/dist/src/safe-slice.js.map +1 -1
- package/dist/src/shutdown.d.ts.map +1 -1
- package/dist/src/shutdown.js.map +1 -1
- package/dist/src/stored-removal.d.ts +73 -0
- package/dist/src/stored-removal.d.ts.map +1 -0
- package/dist/src/stored-removal.js +100 -0
- package/dist/src/stored-removal.js.map +1 -0
- package/dist/src/thinking-token-stamp.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts +87 -19
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +135 -32
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts +9 -0
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +257 -60
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +7 -10
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +32 -3
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +106 -19
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +25 -1
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +260 -65
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +1 -1
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/types/agent.d.ts +59 -11
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +17 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +31 -5
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/inference-log.d.ts +1 -1
- package/dist/src/types/inference-log.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +30 -7
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +151 -11
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +5 -0
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +35 -8
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +10 -9
- package/src/agent.ts +572 -105
- package/src/api/mcp-server-core.ts +681 -0
- package/src/api/mcp-server.ts +16 -685
- package/src/api/server.ts +55 -30
- package/src/api/types.ts +10 -2
- package/src/branch-names.ts +19 -0
- package/src/closest-names.ts +94 -0
- package/src/code-execution/py-runner.ts +200 -76
- package/src/code-execution/runtime-py.ts +49 -3
- package/src/code-execution/tool-definition.ts +28 -4
- package/src/config-checks.ts +48 -0
- package/src/deadline-timer.ts +44 -0
- package/src/error-message.ts +48 -0
- package/src/framework.ts +7158 -1936
- package/src/gate/event-gate.ts +28 -3
- package/src/index.ts +12 -3
- package/src/mcpl/channel-registry.ts +615 -289
- package/src/mcpl/checkpoint-manager.ts +104 -29
- package/src/mcpl/conversation-router.ts +28 -8
- package/src/mcpl/convert-block.ts +97 -0
- package/src/mcpl/errors.ts +28 -0
- package/src/mcpl/feature-set-manager.ts +4 -3
- package/src/mcpl/hook-orchestrator.ts +84 -77
- package/src/mcpl/inbound-source.ts +156 -0
- package/src/mcpl/index.ts +10 -1
- package/src/mcpl/inference-router.ts +174 -99
- package/src/mcpl/log-value.ts +116 -0
- package/src/mcpl/prose-stream-router.ts +6 -6
- package/src/mcpl/push-coalescer.ts +124 -24
- package/src/mcpl/push-handler.ts +86 -84
- package/src/mcpl/reference-fetcher.ts +71 -26
- package/src/mcpl/references.ts +81 -22
- package/src/mcpl/refusal-lines.ts +59 -0
- package/src/mcpl/server-connection.ts +496 -142
- package/src/mcpl/server-registry.ts +15 -4
- package/src/mcpl/skip-reply-wake.ts +73 -0
- package/src/mcpl/tool-classes.ts +3 -2
- package/src/mcpl/transport.ts +219 -26
- package/src/mcpl/types.ts +18 -3
- package/src/mcpl/visible-content.ts +27 -0
- package/src/module-registry.ts +58 -23
- package/src/modules/api/index.ts +1 -1
- package/src/modules/discord/discord-js-client.ts +26 -10
- package/src/modules/discord/index.ts +395 -160
- package/src/modules/discord/types.ts +15 -2
- package/src/modules/health/index.ts +2 -1
- package/src/modules/history/index.ts +410 -120
- package/src/modules/history/semantic.ts +189 -32
- package/src/modules/unknown-tool.ts +16 -0
- package/src/modules/workspace/disk-agreement.ts +125 -21
- package/src/modules/workspace/effects.ts +279 -35
- package/src/modules/workspace/index.ts +841 -261
- package/src/modules/workspace/observe.ts +456 -56
- package/src/modules/workspace/reconcile.ts +688 -76
- package/src/modules/workspace/types.ts +41 -2
- package/src/modules/workspace/watcher.ts +27 -4
- package/src/prose-drafts.ts +481 -0
- package/src/prose-segments.ts +51 -8
- package/src/recovery/offline-branch.ts +36 -29
- package/src/safe-slice.ts +9 -1
- package/src/stored-removal.ts +126 -0
- package/src/tool-image-ledger.ts +153 -34
- package/src/tool-presentation.ts +224 -40
- package/src/tool-result-guard.ts +7 -8
- package/src/tool-result-history.ts +124 -20
- package/src/tune-out/coordinator.ts +259 -65
- package/src/types/agent.ts +59 -13
- package/src/types/events.ts +17 -0
- package/src/types/framework.ts +31 -5
- package/src/types/inference-log.ts +1 -1
- package/src/types/module.ts +31 -7
- package/src/types/trace.ts +158 -12
- package/src/usage/usage-tracker.ts +32 -8
- package/dist/test/activation-request-sanitize.test.d.ts +0 -2
- package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
- package/dist/test/activation-request-sanitize.test.js +0 -89
- package/dist/test/activation-request-sanitize.test.js.map +0 -1
- package/dist/test/agent-cache-ttl.test.d.ts +0 -2
- package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
- package/dist/test/agent-cache-ttl.test.js +0 -41
- package/dist/test/agent-cache-ttl.test.js.map +0 -1
- package/dist/test/agent-runtime-settings.test.d.ts +0 -2
- package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
- package/dist/test/agent-runtime-settings.test.js +0 -462
- package/dist/test/agent-runtime-settings.test.js.map +0 -1
- package/dist/test/api-admin-gate.test.d.ts +0 -2
- package/dist/test/api-admin-gate.test.d.ts.map +0 -1
- package/dist/test/api-admin-gate.test.js +0 -116
- package/dist/test/api-admin-gate.test.js.map +0 -1
- package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
- package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
- package/dist/test/assistant-persist-refusal.test.js +0 -63
- package/dist/test/assistant-persist-refusal.test.js.map +0 -1
- package/dist/test/batched-wake-locus.test.d.ts +0 -2
- package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
- package/dist/test/batched-wake-locus.test.js +0 -166
- package/dist/test/batched-wake-locus.test.js.map +0 -1
- package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
- package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
- package/dist/test/busy-agent-scheduler.test.js +0 -92
- package/dist/test/busy-agent-scheduler.test.js.map +0 -1
- package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
- package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
- package/dist/test/channel-incoming-targeting.test.js +0 -81
- package/dist/test/channel-incoming-targeting.test.js.map +0 -1
- package/dist/test/channel-label-history.test.d.ts +0 -2
- package/dist/test/channel-label-history.test.d.ts.map +0 -1
- package/dist/test/channel-label-history.test.js +0 -424
- package/dist/test/channel-label-history.test.js.map +0 -1
- package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
- package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
- package/dist/test/channel-lifecycle-provenance.test.js +0 -47
- package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
- package/dist/test/channel-registry-routing.test.d.ts +0 -2
- package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
- package/dist/test/channel-registry-routing.test.js +0 -446
- package/dist/test/channel-registry-routing.test.js.map +0 -1
- package/dist/test/channel-registry-typing.test.d.ts +0 -2
- package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
- package/dist/test/channel-registry-typing.test.js +0 -91
- package/dist/test/channel-registry-typing.test.js.map +0 -1
- package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
- package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
- package/dist/test/channels-changed-respond-first.test.js +0 -74
- package/dist/test/channels-changed-respond-first.test.js.map +0 -1
- package/dist/test/checkpoint-attribution.test.d.ts +0 -2
- package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
- package/dist/test/checkpoint-attribution.test.js +0 -200
- package/dist/test/checkpoint-attribution.test.js.map +0 -1
- package/dist/test/code-execution.test.d.ts +0 -11
- package/dist/test/code-execution.test.d.ts.map +0 -1
- package/dist/test/code-execution.test.js +0 -1272
- package/dist/test/code-execution.test.js.map +0 -1
- package/dist/test/component-defaults.test.d.ts +0 -2
- package/dist/test/component-defaults.test.d.ts.map +0 -1
- package/dist/test/component-defaults.test.js +0 -54
- package/dist/test/component-defaults.test.js.map +0 -1
- package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
- package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
- package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
- package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
- package/dist/test/conversation-router.test.d.ts +0 -2
- package/dist/test/conversation-router.test.d.ts.map +0 -1
- package/dist/test/conversation-router.test.js +0 -174
- package/dist/test/conversation-router.test.js.map +0 -1
- package/dist/test/conversation-routing.test.d.ts +0 -7
- package/dist/test/conversation-routing.test.d.ts.map +0 -1
- package/dist/test/conversation-routing.test.js +0 -387
- package/dist/test/conversation-routing.test.js.map +0 -1
- package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
- package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
- package/dist/test/deferred-wake-integrity.test.js +0 -320
- package/dist/test/deferred-wake-integrity.test.js.map +0 -1
- package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
- package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
- package/dist/test/discord-awareness-outbox.test.js +0 -267
- package/dist/test/discord-awareness-outbox.test.js.map +0 -1
- package/dist/test/discord-history-delete-window.test.d.ts +0 -2
- package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
- package/dist/test/discord-history-delete-window.test.js +0 -81
- package/dist/test/discord-history-delete-window.test.js.map +0 -1
- package/dist/test/discord-history-sync.test.d.ts +0 -2
- package/dist/test/discord-history-sync.test.d.ts.map +0 -1
- package/dist/test/discord-history-sync.test.js +0 -56
- package/dist/test/discord-history-sync.test.js.map +0 -1
- package/dist/test/ephemeral-settle.test.d.ts +0 -2
- package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
- package/dist/test/ephemeral-settle.test.js +0 -354
- package/dist/test/ephemeral-settle.test.js.map +0 -1
- package/dist/test/event-gate-passthrough.test.d.ts +0 -15
- package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
- package/dist/test/event-gate-passthrough.test.js +0 -289
- package/dist/test/event-gate-passthrough.test.js.map +0 -1
- package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
- package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
- package/dist/test/event-gate-policy-mutation.test.js +0 -137
- package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
- package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
- package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
- package/dist/test/event-gate-rate-limit.test.js +0 -627
- package/dist/test/event-gate-rate-limit.test.js.map +0 -1
- package/dist/test/event-gate-script.test.d.ts +0 -2
- package/dist/test/event-gate-script.test.d.ts.map +0 -1
- package/dist/test/event-gate-script.test.js +0 -95
- package/dist/test/event-gate-script.test.js.map +0 -1
- package/dist/test/event-gate-selfwake.test.d.ts +0 -15
- package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
- package/dist/test/event-gate-selfwake.test.js +0 -125
- package/dist/test/event-gate-selfwake.test.js.map +0 -1
- package/dist/test/event-gate-tags.test.d.ts +0 -2
- package/dist/test/event-gate-tags.test.d.ts.map +0 -1
- package/dist/test/event-gate-tags.test.js +0 -76
- package/dist/test/event-gate-tags.test.js.map +0 -1
- package/dist/test/event-gate.test.d.ts +0 -2
- package/dist/test/event-gate.test.d.ts.map +0 -1
- package/dist/test/event-gate.test.js +0 -919
- package/dist/test/event-gate.test.js.map +0 -1
- package/dist/test/explicit-prose-routing.test.d.ts +0 -11
- package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
- package/dist/test/explicit-prose-routing.test.js +0 -1394
- package/dist/test/explicit-prose-routing.test.js.map +0 -1
- package/dist/test/framework.test.d.ts +0 -5
- package/dist/test/framework.test.d.ts.map +0 -1
- package/dist/test/framework.test.js +0 -1048
- package/dist/test/framework.test.js.map +0 -1
- package/dist/test/gather-context-timeout.test.d.ts +0 -2
- package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
- package/dist/test/gather-context-timeout.test.js +0 -120
- package/dist/test/gather-context-timeout.test.js.map +0 -1
- package/dist/test/health-snapshot.test.d.ts +0 -2
- package/dist/test/health-snapshot.test.d.ts.map +0 -1
- package/dist/test/health-snapshot.test.js +0 -74
- package/dist/test/health-snapshot.test.js.map +0 -1
- package/dist/test/helpers/coalescing-fixture.d.ts +0 -72
- package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
- package/dist/test/helpers/coalescing-fixture.js +0 -146
- package/dist/test/helpers/coalescing-fixture.js.map +0 -1
- package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
- package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
- package/dist/test/helpers/coalescing-kill-child.js +0 -24
- package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
- package/dist/test/helpers/mock-membrane.d.ts +0 -53
- package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
- package/dist/test/helpers/mock-membrane.js +0 -168
- package/dist/test/helpers/mock-membrane.js.map +0 -1
- package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
- package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
- package/dist/test/helpers/pytc-stop-rows.js +0 -143
- package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
- package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
- package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
- package/dist/test/helpers/quiesce-crash-child.js +0 -156
- package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
- package/dist/test/history-module-overview.test.d.ts +0 -2
- package/dist/test/history-module-overview.test.d.ts.map +0 -1
- package/dist/test/history-module-overview.test.js +0 -711
- package/dist/test/history-module-overview.test.js.map +0 -1
- package/dist/test/history-module-realstore.test.d.ts +0 -2
- package/dist/test/history-module-realstore.test.d.ts.map +0 -1
- package/dist/test/history-module-realstore.test.js +0 -363
- package/dist/test/history-module-realstore.test.js.map +0 -1
- package/dist/test/history-module-semantic.test.d.ts +0 -2
- package/dist/test/history-module-semantic.test.d.ts.map +0 -1
- package/dist/test/history-module-semantic.test.js +0 -213
- package/dist/test/history-module-semantic.test.js.map +0 -1
- package/dist/test/history-module-ux.test.d.ts +0 -2
- package/dist/test/history-module-ux.test.d.ts.map +0 -1
- package/dist/test/history-module-ux.test.js +0 -304
- package/dist/test/history-module-ux.test.js.map +0 -1
- package/dist/test/history-module.test.d.ts +0 -2
- package/dist/test/history-module.test.d.ts.map +0 -1
- package/dist/test/history-module.test.js +0 -619
- package/dist/test/history-module.test.js.map +0 -1
- package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
- package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
- package/dist/test/history-semantic-review-findings.test.js +0 -338
- package/dist/test/history-semantic-review-findings.test.js.map +0 -1
- package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
- package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
- package/dist/test/history-semantic-sync-converges.test.js +0 -109
- package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
- package/dist/test/host-quiesce.test.d.ts +0 -2
- package/dist/test/host-quiesce.test.d.ts.map +0 -1
- package/dist/test/host-quiesce.test.js +0 -863
- package/dist/test/host-quiesce.test.js.map +0 -1
- package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
- package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
- package/dist/test/inference-exhaustion-rewind.test.js +0 -309
- package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
- package/dist/test/inference-failure-bounds.test.d.ts +0 -2
- package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
- package/dist/test/inference-failure-bounds.test.js +0 -1201
- package/dist/test/inference-failure-bounds.test.js.map +0 -1
- package/dist/test/inference-failure-observability.test.d.ts +0 -2
- package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
- package/dist/test/inference-failure-observability.test.js +0 -84
- package/dist/test/inference-failure-observability.test.js.map +0 -1
- package/dist/test/journal-tool.test.d.ts +0 -2
- package/dist/test/journal-tool.test.d.ts.map +0 -1
- package/dist/test/journal-tool.test.js +0 -33
- package/dist/test/journal-tool.test.js.map +0 -1
- package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
- package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
- package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
- package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
- package/dist/test/kv-unified-wiring.test.d.ts +0 -2
- package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
- package/dist/test/kv-unified-wiring.test.js +0 -95
- package/dist/test/kv-unified-wiring.test.js.map +0 -1
- package/dist/test/late-events-after-stop.test.d.ts +0 -2
- package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
- package/dist/test/late-events-after-stop.test.js +0 -122
- package/dist/test/late-events-after-stop.test.js.map +0 -1
- package/dist/test/liveness-watchdog.test.d.ts +0 -2
- package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
- package/dist/test/liveness-watchdog.test.js +0 -94
- package/dist/test/liveness-watchdog.test.js.map +0 -1
- package/dist/test/machine-close-provenance.test.d.ts +0 -2
- package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
- package/dist/test/machine-close-provenance.test.js +0 -116
- package/dist/test/machine-close-provenance.test.js.map +0 -1
- package/dist/test/maintenance-timer.test.d.ts +0 -2
- package/dist/test/maintenance-timer.test.d.ts.map +0 -1
- package/dist/test/maintenance-timer.test.js +0 -265
- package/dist/test/maintenance-timer.test.js.map +0 -1
- package/dist/test/mcpl-access-provider.test.d.ts +0 -2
- package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
- package/dist/test/mcpl-access-provider.test.js +0 -20
- package/dist/test/mcpl-access-provider.test.js.map +0 -1
- package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
- package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
- package/dist/test/mcpl-awareness-barrier.test.js +0 -769
- package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
- package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
- package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
- package/dist/test/mcpl-capability-grant.test.js +0 -111
- package/dist/test/mcpl-capability-grant.test.js.map +0 -1
- package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
- package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
- package/dist/test/mcpl-capability-scoping.test.js +0 -266
- package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
- package/dist/test/mcpl-child-env.test.d.ts +0 -2
- package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
- package/dist/test/mcpl-child-env.test.js +0 -158
- package/dist/test/mcpl-child-env.test.js.map +0 -1
- package/dist/test/mcpl-coalescing.test.d.ts +0 -2
- package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
- package/dist/test/mcpl-coalescing.test.js +0 -1125
- package/dist/test/mcpl-coalescing.test.js.map +0 -1
- package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
- package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
- package/dist/test/mcpl-config-diagnostics.test.js +0 -452
- package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
- package/dist/test/mcpl-empty-content.test.d.ts +0 -2
- package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
- package/dist/test/mcpl-empty-content.test.js +0 -368
- package/dist/test/mcpl-empty-content.test.js.map +0 -1
- package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
- package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
- package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
- package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
- package/dist/test/mcpl-list-status.test.d.ts +0 -2
- package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
- package/dist/test/mcpl-list-status.test.js +0 -82
- package/dist/test/mcpl-list-status.test.js.map +0 -1
- package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
- package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
- package/dist/test/mcpl-manifest-changed.test.js +0 -178
- package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
- package/dist/test/mcpl-push-convert.test.d.ts +0 -2
- package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
- package/dist/test/mcpl-push-convert.test.js +0 -42
- package/dist/test/mcpl-push-convert.test.js.map +0 -1
- package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
- package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
- package/dist/test/mcpl-reconnect-events.test.js +0 -144
- package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
- package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
- package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
- package/dist/test/mcpl-reconnect-reregistration.test.js +0 -236
- package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
- package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
- package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
- package/dist/test/mcpl-reference-fetcher.test.js +0 -427
- package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
- package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
- package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
- package/dist/test/mcpl-reference-fields.test.js +0 -149
- package/dist/test/mcpl-reference-fields.test.js.map +0 -1
- package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
- package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
- package/dist/test/mcpl-request-timeout.test.js +0 -138
- package/dist/test/mcpl-request-timeout.test.js.map +0 -1
- package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
- package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
- package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
- package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
- package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
- package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-class-listing.test.js +0 -147
- package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
- package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
- package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-classes.test.js +0 -80
- package/dist/test/mcpl-tool-classes.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
- package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
- package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
- package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
- package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
- package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
- package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
- package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
- package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
- package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
- package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
- package/dist/test/mcpl-ws-transport.test.js +0 -258
- package/dist/test/mcpl-ws-transport.test.js.map +0 -1
- package/dist/test/module-context-integration.test.d.ts +0 -18
- package/dist/test/module-context-integration.test.d.ts.map +0 -1
- package/dist/test/module-context-integration.test.js +0 -181
- package/dist/test/module-context-integration.test.js.map +0 -1
- package/dist/test/offline-recovery-branch.test.d.ts +0 -2
- package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
- package/dist/test/offline-recovery-branch.test.js +0 -226
- package/dist/test/offline-recovery-branch.test.js.map +0 -1
- package/dist/test/operator-surgery.test.d.ts +0 -2
- package/dist/test/operator-surgery.test.d.ts.map +0 -1
- package/dist/test/operator-surgery.test.js +0 -398
- package/dist/test/operator-surgery.test.js.map +0 -1
- package/dist/test/ops-alert.test.d.ts +0 -2
- package/dist/test/ops-alert.test.d.ts.map +0 -1
- package/dist/test/ops-alert.test.js +0 -153
- package/dist/test/ops-alert.test.js.map +0 -1
- package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
- package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
- package/dist/test/overbudget-drain-breaker.test.js +0 -197
- package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
- package/dist/test/per-agent-delivery.test.d.ts +0 -2
- package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
- package/dist/test/per-agent-delivery.test.js +0 -108
- package/dist/test/per-agent-delivery.test.js.map +0 -1
- package/dist/test/physical-window-restart.test.d.ts +0 -14
- package/dist/test/physical-window-restart.test.d.ts.map +0 -1
- package/dist/test/physical-window-restart.test.js +0 -222
- package/dist/test/physical-window-restart.test.js.map +0 -1
- package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
- package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
- package/dist/test/placed-reaction-baseline.test.js +0 -312
- package/dist/test/placed-reaction-baseline.test.js.map +0 -1
- package/dist/test/present-while-acting.test.d.ts +0 -19
- package/dist/test/present-while-acting.test.d.ts.map +0 -1
- package/dist/test/present-while-acting.test.js +0 -706
- package/dist/test/present-while-acting.test.js.map +0 -1
- package/dist/test/prose-segments.test.d.ts +0 -2
- package/dist/test/prose-segments.test.d.ts.map +0 -1
- package/dist/test/prose-segments.test.js +0 -52
- package/dist/test/prose-segments.test.js.map +0 -1
- package/dist/test/prose-stream-router.test.d.ts +0 -2
- package/dist/test/prose-stream-router.test.d.ts.map +0 -1
- package/dist/test/prose-stream-router.test.js +0 -171
- package/dist/test/prose-stream-router.test.js.map +0 -1
- package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
- package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
- package/dist/test/provider-acceleration-cooldown.test.js +0 -435
- package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
- package/dist/test/provider-waits.test.d.ts +0 -2
- package/dist/test/provider-waits.test.d.ts.map +0 -1
- package/dist/test/provider-waits.test.js +0 -2196
- package/dist/test/provider-waits.test.js.map +0 -1
- package/dist/test/puppet-tool-call.test.d.ts +0 -2
- package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
- package/dist/test/puppet-tool-call.test.js +0 -224
- package/dist/test/puppet-tool-call.test.js.map +0 -1
- package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
- package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
- package/dist/test/puppet-turn-reservation.test.js +0 -139
- package/dist/test/puppet-turn-reservation.test.js.map +0 -1
- package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
- package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
- package/dist/test/reaction-baseline-platform.test.js +0 -124
- package/dist/test/reaction-baseline-platform.test.js.map +0 -1
- package/dist/test/record-journal.test.d.ts +0 -6
- package/dist/test/record-journal.test.d.ts.map +0 -1
- package/dist/test/record-journal.test.js +0 -269
- package/dist/test/record-journal.test.js.map +0 -1
- package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
- package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
- package/dist/test/refusal-reaction-baseline.test.js +0 -81
- package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
- package/dist/test/refusal-rewind.test.d.ts +0 -2
- package/dist/test/refusal-rewind.test.d.ts.map +0 -1
- package/dist/test/refusal-rewind.test.js +0 -108
- package/dist/test/refusal-rewind.test.js.map +0 -1
- package/dist/test/refusal-single-call.test.d.ts +0 -2
- package/dist/test/refusal-single-call.test.d.ts.map +0 -1
- package/dist/test/refusal-single-call.test.js +0 -177
- package/dist/test/refusal-single-call.test.js.map +0 -1
- package/dist/test/release-changelog.test.d.ts +0 -2
- package/dist/test/release-changelog.test.d.ts.map +0 -1
- package/dist/test/release-changelog.test.js +0 -159
- package/dist/test/release-changelog.test.js.map +0 -1
- package/dist/test/same-round-think-policy.test.d.ts +0 -2
- package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
- package/dist/test/same-round-think-policy.test.js +0 -853
- package/dist/test/same-round-think-policy.test.js.map +0 -1
- package/dist/test/save-recent-image.test.d.ts +0 -26
- package/dist/test/save-recent-image.test.d.ts.map +0 -1
- package/dist/test/save-recent-image.test.js +0 -974
- package/dist/test/save-recent-image.test.js.map +0 -1
- package/dist/test/shutdown-errors.test.d.ts +0 -2
- package/dist/test/shutdown-errors.test.d.ts.map +0 -1
- package/dist/test/shutdown-errors.test.js +0 -662
- package/dist/test/shutdown-errors.test.js.map +0 -1
- package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
- package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
- package/dist/test/silent-heartbeat-rows.test.js +0 -451
- package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
- package/dist/test/silent-heartbeat.test.d.ts +0 -2
- package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
- package/dist/test/silent-heartbeat.test.js +0 -165
- package/dist/test/silent-heartbeat.test.js.map +0 -1
- package/dist/test/state-scaling-e2e.test.d.ts +0 -22
- package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
- package/dist/test/state-scaling-e2e.test.js +0 -206
- package/dist/test/state-scaling-e2e.test.js.map +0 -1
- package/dist/test/state-scaling.test.d.ts +0 -12
- package/dist/test/state-scaling.test.d.ts.map +0 -1
- package/dist/test/state-scaling.test.js +0 -251
- package/dist/test/state-scaling.test.js.map +0 -1
- package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
- package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
- package/dist/test/stop-with-work-in-flight.test.js +0 -672
- package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
- package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
- package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
- package/dist/test/surgery-marks-receipt.test.js +0 -540
- package/dist/test/surgery-marks-receipt.test.js.map +0 -1
- package/dist/test/thinking-token-stamp.test.d.ts +0 -12
- package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
- package/dist/test/thinking-token-stamp.test.js +0 -129
- package/dist/test/thinking-token-stamp.test.js.map +0 -1
- package/dist/test/timezone.test.d.ts +0 -2
- package/dist/test/timezone.test.d.ts.map +0 -1
- package/dist/test/timezone.test.js +0 -18
- package/dist/test/timezone.test.js.map +0 -1
- package/dist/test/tool-batch-hook.test.d.ts +0 -8
- package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
- package/dist/test/tool-batch-hook.test.js +0 -275
- package/dist/test/tool-batch-hook.test.js.map +0 -1
- package/dist/test/tool-policy.test.d.ts +0 -2
- package/dist/test/tool-policy.test.d.ts.map +0 -1
- package/dist/test/tool-policy.test.js +0 -51
- package/dist/test/tool-policy.test.js.map +0 -1
- package/dist/test/tool-presentation.test.d.ts +0 -2
- package/dist/test/tool-presentation.test.d.ts.map +0 -1
- package/dist/test/tool-presentation.test.js +0 -268
- package/dist/test/tool-presentation.test.js.map +0 -1
- package/dist/test/tool-result-content.test.d.ts +0 -2
- package/dist/test/tool-result-content.test.d.ts.map +0 -1
- package/dist/test/tool-result-content.test.js +0 -37
- package/dist/test/tool-result-content.test.js.map +0 -1
- package/dist/test/tool-result-guard.test.d.ts +0 -2
- package/dist/test/tool-result-guard.test.d.ts.map +0 -1
- package/dist/test/tool-result-guard.test.js +0 -3607
- package/dist/test/tool-result-guard.test.js.map +0 -1
- package/dist/test/tool-result-history.test.d.ts +0 -7
- package/dist/test/tool-result-history.test.d.ts.map +0 -1
- package/dist/test/tool-result-history.test.js +0 -156
- package/dist/test/tool-result-history.test.js.map +0 -1
- package/dist/test/tool-result-spill.test.d.ts +0 -13
- package/dist/test/tool-result-spill.test.d.ts.map +0 -1
- package/dist/test/tool-result-spill.test.js +0 -586
- package/dist/test/tool-result-spill.test.js.map +0 -1
- package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
- package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
- package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
- package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
- package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
- package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
- package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
- package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
- package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
- package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
- package/dist/test/tools-observe-parser-conformance.test.js +0 -129
- package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
- package/dist/test/trunk-channel-routing.test.d.ts +0 -19
- package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
- package/dist/test/trunk-channel-routing.test.js +0 -329
- package/dist/test/trunk-channel-routing.test.js.map +0 -1
- package/dist/test/tune-out-e2e.test.d.ts +0 -2
- package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
- package/dist/test/tune-out-e2e.test.js +0 -142
- package/dist/test/tune-out-e2e.test.js.map +0 -1
- package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
- package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
- package/dist/test/tune-out-gate-composition.test.js +0 -221
- package/dist/test/tune-out-gate-composition.test.js.map +0 -1
- package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
- package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
- package/dist/test/tune-out-lifecycle.test.js +0 -121
- package/dist/test/tune-out-lifecycle.test.js.map +0 -1
- package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
- package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
- package/dist/test/turn-trigger-provenance.test.js +0 -137
- package/dist/test/turn-trigger-provenance.test.js.map +0 -1
- package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
- package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
- package/dist/test/unconvertible-tool-result.test.js +0 -358
- package/dist/test/unconvertible-tool-result.test.js.map +0 -1
- package/dist/test/usage-accounting.test.d.ts +0 -2
- package/dist/test/usage-accounting.test.d.ts.map +0 -1
- package/dist/test/usage-accounting.test.js +0 -13
- package/dist/test/usage-accounting.test.js.map +0 -1
- package/dist/test/usage-tracker.test.d.ts +0 -2
- package/dist/test/usage-tracker.test.d.ts.map +0 -1
- package/dist/test/usage-tracker.test.js +0 -129
- package/dist/test/usage-tracker.test.js.map +0 -1
- package/dist/test/utils-surface.test.d.ts +0 -2
- package/dist/test/utils-surface.test.d.ts.map +0 -1
- package/dist/test/utils-surface.test.js +0 -145
- package/dist/test/utils-surface.test.js.map +0 -1
- package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
- package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
- package/dist/test/workspace-branch-continuation.test.js +0 -183
- package/dist/test/workspace-branch-continuation.test.js.map +0 -1
- package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
- package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
- package/dist/test/workspace-materialize-freshness.test.js +0 -252
- package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
- package/dist/test/workspace-path-containment.test.d.ts +0 -19
- package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
- package/dist/test/workspace-path-containment.test.js +0 -91
- package/dist/test/workspace-path-containment.test.js.map +0 -1
- package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
- package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
- package/dist/test/workspace-read-file-from-disk.test.js +0 -174
- package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
- package/dist/test/workspace-read-image.test.d.ts +0 -2
- package/dist/test/workspace-read-image.test.d.ts.map +0 -1
- package/dist/test/workspace-read-image.test.js +0 -597
- package/dist/test/workspace-read-image.test.js.map +0 -1
- package/dist/test/workspace-read-text.test.d.ts +0 -2
- package/dist/test/workspace-read-text.test.d.ts.map +0 -1
- package/dist/test/workspace-read-text.test.js +0 -101
- package/dist/test/workspace-read-text.test.js.map +0 -1
- package/dist/test/workspace-restore-order.test.d.ts +0 -16
- package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
- package/dist/test/workspace-restore-order.test.js +0 -140
- package/dist/test/workspace-restore-order.test.js.map +0 -1
- package/dist/test/workspace-three-way.test.d.ts +0 -12
- package/dist/test/workspace-three-way.test.d.ts.map +0 -1
- package/dist/test/workspace-three-way.test.js +0 -3194
- package/dist/test/workspace-three-way.test.js.map +0 -1
- package/dist/test/workspace-watcher.test.d.ts +0 -2
- package/dist/test/workspace-watcher.test.d.ts.map +0 -1
- package/dist/test/workspace-watcher.test.js +0 -281
- package/dist/test/workspace-watcher.test.js.map +0 -1
- package/dist/test/xml-round-persist.test.d.ts +0 -19
- package/dist/test/xml-round-persist.test.d.ts.map +0 -1
- package/dist/test/xml-round-persist.test.js +0 -235
- package/dist/test/xml-round-persist.test.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -14,8 +14,9 @@
|
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
16
|
import type { ContentBlock } from '@animalabs/membrane';
|
|
17
|
-
import {
|
|
17
|
+
import { convertBlock } from './convert-block.js';
|
|
18
18
|
import type { JsStore } from '@animalabs/chronicle';
|
|
19
|
+
import { ensureStateRegistered } from '../module-registry.js';
|
|
19
20
|
|
|
20
21
|
import type {
|
|
21
22
|
ChannelDescriptor,
|
|
@@ -30,16 +31,20 @@ import type {
|
|
|
30
31
|
ChannelsPublishParams,
|
|
31
32
|
ChannelsOpenResult,
|
|
32
33
|
ChannelHistoryRequest,
|
|
33
|
-
McplContentBlock,
|
|
34
34
|
} from './types.js';
|
|
35
35
|
|
|
36
36
|
import type { McplServerRegistry } from './server-registry.js';
|
|
37
37
|
import type { FeatureSetManager } from './feature-set-manager.js';
|
|
38
38
|
import type { ToolDefinition, ToolResult, ProcessEvent } from '../types/index.js';
|
|
39
39
|
import { expandCoreTags } from './tags.js';
|
|
40
|
-
import { EmptyContentError, validateCoalescedContent } from './push-coalescer.js';
|
|
41
|
-
import {
|
|
40
|
+
import { coalesceRejectionReason, EmptyContentError, validateCoalescedContent } from './push-coalescer.js';
|
|
41
|
+
import { isVisiblyEmptyConversion } from './visible-content.js';
|
|
42
|
+
import { logDetail, logValue } from './log-value.js';
|
|
43
|
+
import { RefusalLines } from './refusal-lines.js';
|
|
42
44
|
import { CapabilityGrant } from './capability-grant.js';
|
|
45
|
+
import type { InboundSource } from './inbound-source.js';
|
|
46
|
+
import { McplRequestError } from './server-connection.js';
|
|
47
|
+
import { readSkipReplyWake } from './skip-reply-wake.js';
|
|
43
48
|
|
|
44
49
|
// ============================================================================
|
|
45
50
|
// Typing indicator interval (Discord typing lasts ~10s, so 7s keeps it alive)
|
|
@@ -237,74 +242,10 @@ interface McplChannelIncomingEvent {
|
|
|
237
242
|
tags?: string[];
|
|
238
243
|
triggerInference?: boolean;
|
|
239
244
|
targetAgents?: string[];
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
// ============================================================================
|
|
245
|
-
|
|
246
|
-
/**
|
|
247
|
-
* Convert a single MCPL wire-format content block to a membrane ContentBlock.
|
|
248
|
-
*/
|
|
249
|
-
function convertBlock(block: McplContentBlock): ContentBlock {
|
|
250
|
-
switch (block.type) {
|
|
251
|
-
case 'text':
|
|
252
|
-
return { type: 'text', text: block.text };
|
|
253
|
-
|
|
254
|
-
case 'image':
|
|
255
|
-
if (isInlineContradiction(block)) {
|
|
256
|
-
// RFC-005 vector 2: inline data claiming bulk disposition — fail
|
|
257
|
-
// closed, withhold the data (checked BEFORE the data branch).
|
|
258
|
-
return { type: 'text', text: INLINE_WITHHELD_TEXT };
|
|
259
|
-
}
|
|
260
|
-
if (block.uri && block.disposition) {
|
|
261
|
-
// RFC-005 uri-form media with a disposition claim: stub, do not
|
|
262
|
-
// hand the URI to the provider or inline it.
|
|
263
|
-
return { type: 'text', text: referenceStubOrNull(block, 'attachment on channel message') ?? '[reference]' };
|
|
264
|
-
}
|
|
265
|
-
if (block.data && block.mimeType) {
|
|
266
|
-
return {
|
|
267
|
-
type: 'image',
|
|
268
|
-
source: { type: 'base64', data: block.data, mediaType: block.mimeType },
|
|
269
|
-
} as ContentBlock;
|
|
270
|
-
}
|
|
271
|
-
if (block.uri) {
|
|
272
|
-
return {
|
|
273
|
-
type: 'image',
|
|
274
|
-
source: { type: 'url', url: block.uri },
|
|
275
|
-
} as ContentBlock;
|
|
276
|
-
}
|
|
277
|
-
return { type: 'text', text: '[Image: no data]' };
|
|
278
|
-
|
|
279
|
-
case 'audio':
|
|
280
|
-
if (isInlineContradiction(block)) {
|
|
281
|
-
// RFC-005 vector 2: inline data claiming bulk disposition — fail
|
|
282
|
-
// closed, withhold the data (checked BEFORE the data branch).
|
|
283
|
-
return { type: 'text', text: INLINE_WITHHELD_TEXT };
|
|
284
|
-
}
|
|
285
|
-
if (block.uri && block.disposition) {
|
|
286
|
-
// RFC-005 uri-form media with a disposition claim: stub, do not
|
|
287
|
-
// hand the URI to the provider or inline it.
|
|
288
|
-
return { type: 'text', text: referenceStubOrNull(block, 'attachment on channel message') ?? '[reference]' };
|
|
289
|
-
}
|
|
290
|
-
if (block.data && block.mimeType) {
|
|
291
|
-
return {
|
|
292
|
-
type: 'audio',
|
|
293
|
-
source: { type: 'base64', data: block.data, mediaType: block.mimeType },
|
|
294
|
-
} as ContentBlock;
|
|
295
|
-
}
|
|
296
|
-
return { type: 'text', text: '[Audio: no data]' };
|
|
297
|
-
|
|
298
|
-
case 'resource':
|
|
299
|
-
// RFC-005: reference blocks become bounded stubs — never raw URIs
|
|
300
|
-
// (a signed URL is a bearer credential that looks like a location).
|
|
301
|
-
return { type: 'text', text: referenceStubOrNull(block, 'attachment on channel message') ?? '[reference]' };
|
|
302
|
-
|
|
303
|
-
default:
|
|
304
|
-
// Unknown wire block types previously fell off the exhaustive switch
|
|
305
|
-
// and propagated `undefined` into ContentBlock[]. Fail visibly.
|
|
306
|
-
return { type: 'text', text: `[unrecognized content block: ${(block as { type?: string }).type ?? 'untyped'}]` };
|
|
307
|
-
}
|
|
245
|
+
/** Host acceptance time (epoch ms), stamped where the message is admitted. */
|
|
246
|
+
acceptedAt?: number;
|
|
247
|
+
/** Source envelope frozen at admission (mcpl/inbound-source.ts). */
|
|
248
|
+
inboundSource?: InboundSource;
|
|
308
249
|
}
|
|
309
250
|
|
|
310
251
|
// ============================================================================
|
|
@@ -320,9 +261,8 @@ const CHANNEL_TOOL_DEFINITIONS: ToolDefinition[] = [
|
|
|
320
261
|
{
|
|
321
262
|
name: 'channel_open',
|
|
322
263
|
description:
|
|
323
|
-
'Open a channel
|
|
324
|
-
'
|
|
325
|
-
'history preceding the message that invited you into the channel.',
|
|
264
|
+
'Open a channel. What an open channel delivers to you depends on its MCPL server. ' +
|
|
265
|
+
'Optionally request history preceding the message that invited you into the channel.',
|
|
326
266
|
inputSchema: {
|
|
327
267
|
type: 'object' as const,
|
|
328
268
|
properties: {
|
|
@@ -362,7 +302,9 @@ const CHANNEL_TOOL_DEFINITIONS: ToolDefinition[] = [
|
|
|
362
302
|
},
|
|
363
303
|
{
|
|
364
304
|
name: 'channel_close',
|
|
365
|
-
description:
|
|
305
|
+
description:
|
|
306
|
+
'Close a channel. Messages that address you still reach you; what else stops reaching you ' +
|
|
307
|
+
'depends on its server.',
|
|
366
308
|
inputSchema: {
|
|
367
309
|
type: 'object' as const,
|
|
368
310
|
properties: {
|
|
@@ -441,8 +383,9 @@ const CHANNEL_TOOL_DEFINITIONS: ToolDefinition[] = [
|
|
|
441
383
|
type: 'number',
|
|
442
384
|
description:
|
|
443
385
|
'Optional self-wake: if nothing else wakes you first, you wake again after this ' +
|
|
444
|
-
'many seconds
|
|
445
|
-
'wake before then cancels it. Omit to stay idle until the
|
|
386
|
+
'many seconds, from 1 to 3600; a larger number waits 3600 (1 = go again almost ' +
|
|
387
|
+
'immediately). Any other wake before then cancels it. Omit to stay idle until the ' +
|
|
388
|
+
'next external wake.',
|
|
446
389
|
},
|
|
447
390
|
},
|
|
448
391
|
required: [],
|
|
@@ -454,7 +397,125 @@ const CHANNEL_TOOL_DEFINITIONS: ToolDefinition[] = [
|
|
|
454
397
|
// Constructor Options
|
|
455
398
|
// ============================================================================
|
|
456
399
|
|
|
400
|
+
/** Bound connector values for notices, logs and an outcome's reason. A
|
|
401
|
+
* PublishOutcome keeps the connector's structured data (`detail`) whole. */
|
|
402
|
+
export function connectorText(value: unknown): string {
|
|
403
|
+
let text: string;
|
|
404
|
+
try {
|
|
405
|
+
text = typeof value === 'string' ? value : JSON.stringify(value) ?? String(value);
|
|
406
|
+
} catch {
|
|
407
|
+
return '[unserializable connector value]';
|
|
408
|
+
}
|
|
409
|
+
const limit = 2000;
|
|
410
|
+
const suffix = '… [truncated]';
|
|
411
|
+
return text.length > limit ? text.slice(0, limit - suffix.length) + suffix : text;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/** Where a publish was resolved to go — named by the registry, never by
|
|
415
|
+
* the caller's spelling. */
|
|
416
|
+
export interface PublishDestination {
|
|
417
|
+
serverId: string;
|
|
418
|
+
channelId: string;
|
|
419
|
+
/** The channel's registered label when the attempt was made. */
|
|
420
|
+
label?: string;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* What one channels/publish attempt established (ChannelRegistry.publish).
|
|
425
|
+
* - `delivered`: the connector returned `delivered: true`. A historical
|
|
426
|
+
* receipt (confirmed at `at`, to `destination`, message `messageId` when
|
|
427
|
+
* the connector named one), not a claim the message still exists.
|
|
428
|
+
* - `failed`: nothing was posted: the request never left the host
|
|
429
|
+
* (unresolvable or shared channel id, missing grant, failed open, closed
|
|
430
|
+
* connection), or the connector answered `delivered: false` and named no
|
|
431
|
+
* message.
|
|
432
|
+
* - `unknown`: the request was dispatched and no valid receipt came back (an
|
|
433
|
+
* error response, a timeout, a lost connection, or a missing, malformed or
|
|
434
|
+
* contradictory receipt, such as `delivered: false` beside a message id).
|
|
435
|
+
* It may or may not have been posted.
|
|
436
|
+
*/
|
|
437
|
+
export interface PublishOutcome {
|
|
438
|
+
status: 'delivered' | 'failed' | 'unknown';
|
|
439
|
+
/** Absent only when no destination could be resolved. */
|
|
440
|
+
destination?: PublishDestination;
|
|
441
|
+
messageId?: string;
|
|
442
|
+
/** Why it failed, or why its outcome is unknown — for a connector error,
|
|
443
|
+
* its message, bounded (which may say what was already posted). */
|
|
444
|
+
reason?: string;
|
|
445
|
+
/** The connector error's structured `data`, verbatim, when it sent one. */
|
|
446
|
+
detail?: unknown;
|
|
447
|
+
/** When the outcome was established (epoch ms). */
|
|
448
|
+
at: number;
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
/**
|
|
452
|
+
* What a channels/publish request that threw establishes. Only a request
|
|
453
|
+
* that never left the host proves nothing was posted. An error response may
|
|
454
|
+
* follow a partial post (a multi-part send whose later part failed), so it
|
|
455
|
+
* is unknown, with the connector's own words, bounded, and its data kept for
|
|
456
|
+
* the resident to judge. The publish executor and channel_publish both read
|
|
457
|
+
* a failed request this way.
|
|
458
|
+
*/
|
|
459
|
+
function publishErrorOutcome(err: unknown, destination: PublishDestination, at: number): PublishOutcome {
|
|
460
|
+
const message = connectorText(err instanceof Error ? err.message : String(err));
|
|
461
|
+
const notSent = err instanceof McplRequestError && err.outcome === 'not-sent';
|
|
462
|
+
const detail = err instanceof McplRequestError ? err.data : undefined;
|
|
463
|
+
return {
|
|
464
|
+
status: notSent ? 'failed' : 'unknown',
|
|
465
|
+
destination,
|
|
466
|
+
reason: notSent ? message : `${message} (delivery uncertain)`,
|
|
467
|
+
...(detail !== undefined ? { detail } : {}),
|
|
468
|
+
at,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* What a channels/publish answer establishes. A final publish is a request,
|
|
474
|
+
* so success requires an explicit receipt; a missing or malformed one leaves
|
|
475
|
+
* delivery uncertain (anima-research/agent-framework#163's rule).
|
|
476
|
+
* `delivered: false` proves nothing went out only when the receipt names no
|
|
477
|
+
* message at all: a message id beside it, valid or malformed, contradicts it,
|
|
478
|
+
* since something may have been posted. The publish executor and
|
|
479
|
+
* channel_publish both read an answer this way.
|
|
480
|
+
*/
|
|
481
|
+
function publishReceiptOutcome(result: unknown, destination: PublishDestination, at: number): PublishOutcome {
|
|
482
|
+
const receipt = (result ?? {}) as { delivered?: unknown; messageId?: unknown };
|
|
483
|
+
const messageId = typeof receipt.messageId === 'string' && receipt.messageId ? receipt.messageId : undefined;
|
|
484
|
+
if (receipt.delivered === true) {
|
|
485
|
+
return { status: 'delivered', destination, ...(messageId ? { messageId } : {}), at };
|
|
486
|
+
}
|
|
487
|
+
if (receipt.delivered === false) {
|
|
488
|
+
if (receipt.messageId === undefined || receipt.messageId === null) {
|
|
489
|
+
return { status: 'failed', destination, reason: `server "${destination.serverId}" reported delivered:false`, at };
|
|
490
|
+
}
|
|
491
|
+
return {
|
|
492
|
+
status: 'unknown',
|
|
493
|
+
destination,
|
|
494
|
+
...(messageId ? { messageId } : {}),
|
|
495
|
+
reason: messageId
|
|
496
|
+
? `server "${destination.serverId}" reported delivered:false but named posted message ${connectorText(messageId)} (delivery uncertain)`
|
|
497
|
+
: `server "${destination.serverId}" reported delivered:false beside a malformed message id ` +
|
|
498
|
+
`${connectorText(receipt.messageId)} (contradictory receipt; delivery uncertain)`,
|
|
499
|
+
at,
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
return {
|
|
503
|
+
status: 'unknown',
|
|
504
|
+
destination,
|
|
505
|
+
...(messageId ? { messageId } : {}),
|
|
506
|
+
reason: `server "${destination.serverId}" returned no valid delivery receipt (delivery uncertain)`,
|
|
507
|
+
at,
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
|
|
457
511
|
interface ChannelRegistryOptions {
|
|
512
|
+
/**
|
|
513
|
+
* An ordinary (uncoalesced) `channels/incoming` message has just been
|
|
514
|
+
* admitted, before it is queued or acknowledged: return its source
|
|
515
|
+
* envelope, frozen now (mcpl/inbound-source.ts). The framework observes the
|
|
516
|
+
* acceptance here; coalesced work is stamped and observed by its own path.
|
|
517
|
+
*/
|
|
518
|
+
acceptInbound?: (event: McplChannelIncomingEvent) => InboundSource | undefined;
|
|
458
519
|
/**
|
|
459
520
|
* RFC-006: an admitted `channels/incoming` message carrying `coalesce`, with
|
|
460
521
|
* the event the ordinary path would have queued. The handler decides
|
|
@@ -483,15 +544,21 @@ interface ChannelRegistryOptions {
|
|
|
483
544
|
channelId: string | null;
|
|
484
545
|
reason: string;
|
|
485
546
|
textLen: number;
|
|
547
|
+
/** `failed`: nothing was posted; `unknown`: the request was dispatched
|
|
548
|
+
* and no valid receipt came back, so it may or may not have been. */
|
|
549
|
+
outcome?: 'failed' | 'unknown';
|
|
550
|
+
/** Bounded display of the connector's structured error data, when present. */
|
|
551
|
+
detail?: string;
|
|
486
552
|
}) => void;
|
|
487
553
|
/**
|
|
488
554
|
* Called when channels were opened WITHOUT the agent asking (subscription
|
|
489
555
|
* policy admitting a newly discovered channel, or delivery into a closed
|
|
490
556
|
* locus). The host wires this to drop a durable notice into the agent's
|
|
491
|
-
* window — the agent must always learn that
|
|
492
|
-
*
|
|
493
|
-
*
|
|
494
|
-
* durable, so reboots do not
|
|
557
|
+
* window — the agent must always learn that the channel opened, and that
|
|
558
|
+
* `channel_close` opts out (their decision outranks policy). What an open
|
|
559
|
+
* channel delivers is the server's to say (#406). Fires ONCE per channel
|
|
560
|
+
* ever: the desired-state decision is durable, so reboots do not
|
|
561
|
+
* re-announce. Must not trigger inference.
|
|
495
562
|
*/
|
|
496
563
|
onChannelAutoOpened?: (info: {
|
|
497
564
|
/** Agent whose action caused the open (delivery); absent for policy opens. */
|
|
@@ -512,19 +579,23 @@ interface ChannelRegistryOptions {
|
|
|
512
579
|
*/
|
|
513
580
|
homeChannelResolver?: (agentName: string) => string | undefined;
|
|
514
581
|
/**
|
|
515
|
-
* Resolve
|
|
516
|
-
*
|
|
582
|
+
* Resolve an agent's channel for its CURRENT inference turn, by agent name:
|
|
583
|
+
* the turn's locus once it has one, else the channel that triggered the
|
|
584
|
+
* turn. This is the fix for single-TRUNK agents (the only mode
|
|
517
585
|
* connectome-host runs — it never exposes conversation forks). A trunk agent
|
|
518
586
|
* has no fork home, so without this its plain-text speech falls back to the
|
|
519
587
|
* process-global `defaultPublishChannel`, which tracks the most-recent inbound
|
|
520
588
|
* across ALL channels and misroutes a reply to whichever channel last spoke
|
|
521
|
-
* under concurrency (item-3 redux). The framework
|
|
522
|
-
*
|
|
523
|
-
*
|
|
524
|
-
* global fallback
|
|
525
|
-
* wins), BEFORE
|
|
589
|
+
* under concurrency (item-3 redux). The framework keeps both on the live
|
|
590
|
+
* turn's routing state and exposes them here. For a heartbeat / no-trigger
|
|
591
|
+
* turn it resolves to undefined until the turn's locus is resolved, so that
|
|
592
|
+
* resolution takes the global fallback, which the turn then keeps.
|
|
593
|
+
* Consulted AFTER `homeChannelResolver` (a fork's home always wins), BEFORE
|
|
594
|
+
* `defaultPublishChannel`.
|
|
526
595
|
*/
|
|
527
596
|
activeChannelResolver?: (agentName: string) => string | undefined;
|
|
597
|
+
/** Whether this framework has EventGate and can honor skip_reply self-wakes. */
|
|
598
|
+
eventGatePresent?: boolean;
|
|
528
599
|
}
|
|
529
600
|
|
|
530
601
|
// ============================================================================
|
|
@@ -558,12 +629,7 @@ export class ChannelRegistry {
|
|
|
558
629
|
op?: 'start' | 'stop',
|
|
559
630
|
) => void;
|
|
560
631
|
private shouldTriggerInference?: (content: string, metadata: Record<string, unknown>) => boolean;
|
|
561
|
-
private onRouteFailure?:
|
|
562
|
-
conversationId: string;
|
|
563
|
-
channelId: string | null;
|
|
564
|
-
reason: string;
|
|
565
|
-
textLen: number;
|
|
566
|
-
}) => void;
|
|
632
|
+
private onRouteFailure?: ChannelRegistryOptions['onRouteFailure'];
|
|
567
633
|
private onChannelAutoOpened?: (info: {
|
|
568
634
|
conversationId?: string;
|
|
569
635
|
serverId: string;
|
|
@@ -577,6 +643,10 @@ export class ChannelRegistry {
|
|
|
577
643
|
/** Registered channels, keyed by `{serverId}:{channelId}`. */
|
|
578
644
|
private channels = new Map<string, ChannelEntry>();
|
|
579
645
|
|
|
646
|
+
/** Holds back repeats of the line for a message refused because its
|
|
647
|
+
* channel isn't registered (RefusalLines). */
|
|
648
|
+
private unknownChannelLines = new RefusalLines();
|
|
649
|
+
|
|
580
650
|
/**
|
|
581
651
|
* Most-recently-known label per channelId, replayed from
|
|
582
652
|
* `CHANNEL_LABEL_HISTORY_LOG_ID` (last sighting wins) and kept current by
|
|
@@ -658,6 +728,8 @@ export class ChannelRegistry {
|
|
|
658
728
|
private legacyPolicies = new Map<string, 'auto' | 'manual' | string[]>();
|
|
659
729
|
private migratedLegacyPolicies = new Set<string>();
|
|
660
730
|
private handleCoalescedIncoming?: ChannelRegistryOptions['handleCoalescedIncoming'];
|
|
731
|
+
private acceptInbound?: ChannelRegistryOptions['acceptInbound'];
|
|
732
|
+
private channelTools: ToolDefinition[];
|
|
661
733
|
|
|
662
734
|
constructor(
|
|
663
735
|
serverRegistry: McplServerRegistry,
|
|
@@ -674,6 +746,24 @@ export class ChannelRegistry {
|
|
|
674
746
|
},
|
|
675
747
|
) {
|
|
676
748
|
this.handleCoalescedIncoming = options?.handleCoalescedIncoming;
|
|
749
|
+
this.acceptInbound = options?.acceptInbound;
|
|
750
|
+
this.channelTools = CHANNEL_TOOL_DEFINITIONS.map((tool) => {
|
|
751
|
+
if (tool.name !== 'skip_reply' || options?.eventGatePresent === true) return tool;
|
|
752
|
+
const schema = tool.inputSchema as {
|
|
753
|
+
type: 'object';
|
|
754
|
+
properties: NonNullable<ToolDefinition['inputSchema']['properties']>;
|
|
755
|
+
required?: string[];
|
|
756
|
+
};
|
|
757
|
+
const { wake_in_seconds: _wake, ...properties } = schema.properties;
|
|
758
|
+
return {
|
|
759
|
+
...tool,
|
|
760
|
+
description: tool.description.replace(
|
|
761
|
+
' To end this turn but come back on your own shortly, set wake_in_seconds.',
|
|
762
|
+
'',
|
|
763
|
+
),
|
|
764
|
+
inputSchema: { ...schema, properties },
|
|
765
|
+
};
|
|
766
|
+
});
|
|
677
767
|
this.serverRegistry = serverRegistry;
|
|
678
768
|
this.featureSetManager = featureSetManager;
|
|
679
769
|
this.pushEventFn = pushEventFn;
|
|
@@ -848,6 +938,45 @@ export class ChannelRegistry {
|
|
|
848
938
|
});
|
|
849
939
|
}
|
|
850
940
|
|
|
941
|
+
/**
|
|
942
|
+
* A coalesced message the host refused. Until now the host said nothing, so
|
|
943
|
+
* a dropped message (agent-framework#266: every Discord message with a
|
|
944
|
+
* screenshot) left no trace where operators look. The sender gets the
|
|
945
|
+
* per-message result this lane gives: `coalesce_invalid` for a malformed
|
|
946
|
+
* item, or the thrown error's message for anything else. `answered` is the
|
|
947
|
+
* code that result stands for (-32602 for `coalesce_invalid`), and the
|
|
948
|
+
* reason follows it (coalesceRejectionReason): `coalesce-failed` when the
|
|
949
|
+
* host itself failed, `coalesce-invalid` when the sender's item was
|
|
950
|
+
* refused, with the failing `field` and the error's message as `detail`.
|
|
951
|
+
* The line prints the ids the sender sent, whatever their type; the trace
|
|
952
|
+
* carries them when they are strings.
|
|
953
|
+
*/
|
|
954
|
+
private traceCoalesceRejection(
|
|
955
|
+
serverId: string,
|
|
956
|
+
message: { channelId?: unknown; messageId?: unknown } | null | undefined,
|
|
957
|
+
error: { field?: unknown; message: string },
|
|
958
|
+
answered: number,
|
|
959
|
+
): void {
|
|
960
|
+
const reason = coalesceRejectionReason(answered);
|
|
961
|
+
const field = typeof error.field === 'string' && error.field ? error.field : undefined;
|
|
962
|
+
const channelId = typeof message?.channelId === 'string' ? message.channelId : '';
|
|
963
|
+
const messageId = typeof message?.messageId === 'string' && message.messageId ? message.messageId : undefined;
|
|
964
|
+
console.error(
|
|
965
|
+
`[channel-incoming-rejected] server=${serverId} channel=${logValue(message?.channelId ?? '')} ` +
|
|
966
|
+
`messageId=${logValue(message?.messageId ?? '')} ` +
|
|
967
|
+
`reason=${reason}${field ? ` field=${logValue(field)}` : ''}: ${logDetail(error.message)}`,
|
|
968
|
+
);
|
|
969
|
+
this.emitTraceFn({
|
|
970
|
+
type: 'mcpl:channel-incoming-rejected',
|
|
971
|
+
serverId,
|
|
972
|
+
channelId,
|
|
973
|
+
...(messageId ? { messageId } : {}),
|
|
974
|
+
reason,
|
|
975
|
+
...(field ? { field } : {}),
|
|
976
|
+
detail: error.message,
|
|
977
|
+
});
|
|
978
|
+
}
|
|
979
|
+
|
|
851
980
|
/**
|
|
852
981
|
* Handle `channels/incoming` from a server.
|
|
853
982
|
*
|
|
@@ -864,10 +993,20 @@ export class ChannelRegistry {
|
|
|
864
993
|
for (const message of params.messages) {
|
|
865
994
|
if (!message || typeof message.channelId !== 'string' || !message.channelId
|
|
866
995
|
|| typeof message.messageId !== 'string' || !message.messageId) {
|
|
996
|
+
// The same gate as admission below: with no coalescer wired, a
|
|
997
|
+
// message carrying `coalesce` is handled uncoalesced, and refused as
|
|
998
|
+
// any uncoalesced message without an identity is.
|
|
999
|
+
const coalescedItem = message?.coalesce !== undefined && !!this.handleCoalescedIncoming;
|
|
1000
|
+
if (coalescedItem) {
|
|
1001
|
+
this.traceCoalesceRejection(serverId, message, {
|
|
1002
|
+
field: typeof message.channelId !== 'string' || !message.channelId ? 'channelId' : 'messageId',
|
|
1003
|
+
message: 'a coalesced message needs a channelId and a messageId',
|
|
1004
|
+
}, -32602);
|
|
1005
|
+
}
|
|
867
1006
|
results.push({
|
|
868
1007
|
messageId: typeof message?.messageId === 'string' ? message.messageId : '',
|
|
869
1008
|
accepted: false,
|
|
870
|
-
reason:
|
|
1009
|
+
reason: coalescedItem ? 'coalesce_invalid' : 'invalid channel/message identity',
|
|
871
1010
|
});
|
|
872
1011
|
continue;
|
|
873
1012
|
}
|
|
@@ -899,11 +1038,24 @@ export class ChannelRegistry {
|
|
|
899
1038
|
// routable entry rather than an open self-attested one.
|
|
900
1039
|
const incomingKey = `${serverId}:${message.channelId}`;
|
|
901
1040
|
if (!this.channels.has(incomingKey)) {
|
|
1041
|
+
// Loud, coalesced or not, like every other refusal of a message, but
|
|
1042
|
+
// at most once a minute per channel (RefusalLines): a server that
|
|
1043
|
+
// never registered a busy channel would otherwise print a line for
|
|
1044
|
+
// every message in it. Every refusal is traced.
|
|
1045
|
+
const held = this.unknownChannelLines.admit(serverId, message.channelId);
|
|
1046
|
+
if (held !== null) {
|
|
1047
|
+
console.error(
|
|
1048
|
+
`[channel-incoming-rejected] server=${serverId} channel=${logValue(message.channelId)} ` +
|
|
1049
|
+
`messageId=${logValue(message.messageId)} reason=unknown-channel ` +
|
|
1050
|
+
`(not registered, §14.5${held ? `; ${held} more since the last line` : ''})`,
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
902
1053
|
this.emitTraceFn({
|
|
903
1054
|
type: 'mcpl:channel-incoming-rejected',
|
|
904
1055
|
serverId,
|
|
905
1056
|
channelId: message.channelId,
|
|
906
|
-
|
|
1057
|
+
messageId: message.messageId,
|
|
1058
|
+
reason: 'unknown-channel',
|
|
907
1059
|
});
|
|
908
1060
|
results.push({
|
|
909
1061
|
messageId: message.messageId,
|
|
@@ -921,7 +1073,7 @@ export class ChannelRegistry {
|
|
|
921
1073
|
// shows the model nothing would wake it with no visible cause.
|
|
922
1074
|
const emptyAllowed = coalesced && (message.coalesce as { retract?: unknown } | null)?.retract === true;
|
|
923
1075
|
const rejectEmpty = () => {
|
|
924
|
-
console.error(`[channel-incoming-rejected] server=${serverId} channel=${message.channelId} messageId=${message.messageId} reason=empty-content`);
|
|
1076
|
+
console.error(`[channel-incoming-rejected] server=${serverId} channel=${logValue(message.channelId)} messageId=${logValue(message.messageId)} reason=empty-content`);
|
|
925
1077
|
this.emitTraceFn({
|
|
926
1078
|
type: 'mcpl:channel-incoming-rejected',
|
|
927
1079
|
serverId,
|
|
@@ -935,16 +1087,20 @@ export class ChannelRegistry {
|
|
|
935
1087
|
// RFC-006 §13: malformed content on a coalesced item is that item's
|
|
936
1088
|
// failure, not the batch's — check the shape before converting.
|
|
937
1089
|
try {
|
|
938
|
-
validateCoalescedContent(message.content,
|
|
1090
|
+
validateCoalescedContent(message.content, { allowEmpty: emptyAllowed });
|
|
939
1091
|
} catch (error) {
|
|
940
1092
|
if (error instanceof EmptyContentError) rejectEmpty();
|
|
941
|
-
else
|
|
1093
|
+
else {
|
|
1094
|
+
// Answered coalesce_invalid whatever the error's code: -32602.
|
|
1095
|
+
this.traceCoalesceRejection(serverId, message, error as Error & { field?: string }, -32602);
|
|
1096
|
+
results.push({ messageId: message.messageId, accepted: false, reason: 'coalesce_invalid' });
|
|
1097
|
+
}
|
|
942
1098
|
continue;
|
|
943
1099
|
}
|
|
944
1100
|
}
|
|
945
1101
|
if (message.tags) message.tags = expandCoreTags(message.tags);
|
|
946
|
-
const convertedContent: ContentBlock[] = message.content.map(convertBlock);
|
|
947
|
-
if (!emptyAllowed &&
|
|
1102
|
+
const convertedContent: ContentBlock[] = message.content.map((block) => convertBlock(block, 'attachment on channel message', serverId));
|
|
1103
|
+
if (!emptyAllowed && isVisiblyEmptyConversion(message.content, convertedContent)) {
|
|
948
1104
|
rejectEmpty();
|
|
949
1105
|
continue;
|
|
950
1106
|
}
|
|
@@ -970,8 +1126,11 @@ export class ChannelRegistry {
|
|
|
970
1126
|
// Determine whether to trigger inference
|
|
971
1127
|
let triggerInference = true;
|
|
972
1128
|
if (this.shouldTriggerInference) {
|
|
973
|
-
|
|
974
|
-
|
|
1129
|
+
// The text the agent's context gets, as the push lane's filter reads
|
|
1130
|
+
// it: the converted text blocks, a placeholder or reference stub
|
|
1131
|
+
// among them, NON_STRING_TEXT_PLACEHOLDER included.
|
|
1132
|
+
const textContent = convertedContent
|
|
1133
|
+
.filter((b): b is ContentBlock & { type: 'text' } => b.type === 'text')
|
|
975
1134
|
.map((b) => b.text)
|
|
976
1135
|
.join('\n');
|
|
977
1136
|
triggerInference = this.shouldTriggerInference(
|
|
@@ -1002,6 +1161,7 @@ export class ChannelRegistry {
|
|
|
1002
1161
|
metadata: message.metadata,
|
|
1003
1162
|
...(message.tags ? { tags: message.tags } : {}),
|
|
1004
1163
|
triggerInference,
|
|
1164
|
+
acceptedAt: Date.now(),
|
|
1005
1165
|
};
|
|
1006
1166
|
|
|
1007
1167
|
if (coalesced) {
|
|
@@ -1014,7 +1174,10 @@ export class ChannelRegistry {
|
|
|
1014
1174
|
if (result.accepted) markAccepted();
|
|
1015
1175
|
results.push(result);
|
|
1016
1176
|
} catch (error) {
|
|
1017
|
-
const err = error as Error & { code?: number };
|
|
1177
|
+
const err = error as Error & { code?: number; field?: string };
|
|
1178
|
+
// -32602 is answered coalesce_invalid; anything else as its message,
|
|
1179
|
+
// a plain Error standing for an internal error (-32603).
|
|
1180
|
+
this.traceCoalesceRejection(serverId, message, err, typeof err.code === 'number' ? err.code : -32603);
|
|
1018
1181
|
results.push({
|
|
1019
1182
|
messageId: message.messageId,
|
|
1020
1183
|
accepted: false,
|
|
@@ -1024,6 +1187,12 @@ export class ChannelRegistry {
|
|
|
1024
1187
|
continue;
|
|
1025
1188
|
}
|
|
1026
1189
|
|
|
1190
|
+
// The source envelope is frozen here, at admission, before the message
|
|
1191
|
+
// is queued or acknowledged: a rename or rebind while it waits in the
|
|
1192
|
+
// queue cannot change where it says it came from.
|
|
1193
|
+
const inboundSource = this.acceptInbound?.(event);
|
|
1194
|
+
if (inboundSource) event.inboundSource = inboundSource;
|
|
1195
|
+
|
|
1027
1196
|
// Push to the processing queue
|
|
1028
1197
|
// Cast through unknown because McplChannelIncomingEvent matches the
|
|
1029
1198
|
// CustomEvent `${string}:${string}` type pattern but lacks an index signature.
|
|
@@ -1077,20 +1246,34 @@ export class ChannelRegistry {
|
|
|
1077
1246
|
(existing.descriptor.metadata as { lazyRegistered?: boolean } | undefined)?.lazyRegistered &&
|
|
1078
1247
|
label && existing.descriptor.label === channelId
|
|
1079
1248
|
) {
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
}
|
|
1249
|
+
const metadata = extraMetadata
|
|
1250
|
+
? { ...existing.descriptor.metadata, ...extraMetadata }
|
|
1251
|
+
: existing.descriptor.metadata;
|
|
1084
1252
|
// The channel now has a real label, not just the bare id — durable.
|
|
1085
|
-
this
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1253
|
+
// Recorded before the live descriptor takes it, since this branch's
|
|
1254
|
+
// guard reads the descriptor: an append that throws leaves the
|
|
1255
|
+
// placeholder, so the next push tries again.
|
|
1256
|
+
this.appendLabelSighting(existing.descriptor.id, label, extractDmMeta(metadata));
|
|
1257
|
+
existing.descriptor.label = label;
|
|
1258
|
+
existing.descriptor.metadata = metadata;
|
|
1090
1259
|
}
|
|
1091
1260
|
return;
|
|
1092
1261
|
}
|
|
1093
1262
|
|
|
1263
|
+
// Only persist a REAL label durably. Falling back to the bare
|
|
1264
|
+
// channelId as a placeholder (no server-supplied label at all — e.g. a
|
|
1265
|
+
// Discord DM push missing both channelName and an author name,
|
|
1266
|
+
// framework.ts's derivePushEventChannel) must never overwrite a real
|
|
1267
|
+
// label already on file from a previous boot: after a restart the live
|
|
1268
|
+
// `channels` map starts empty, so THIS is the very branch a
|
|
1269
|
+
// label-less post-restart event takes — recording the placeholder here
|
|
1270
|
+
// would clobber the good label initializeLabelHistoryStore() just
|
|
1271
|
+
// replayed, defeating the entire point of the durable log. The live
|
|
1272
|
+
// descriptor below still carries the placeholder for in-process
|
|
1273
|
+
// routing; only the durable write is skipped when there's no real
|
|
1274
|
+
// label to record. A real label is recorded before the entry exists:
|
|
1275
|
+
// an append that throws registers nothing, so the next push tries again.
|
|
1276
|
+
if (label) this.appendLabelSighting(channelId, label, extractDmMeta(extraMetadata));
|
|
1094
1277
|
const key = `${serverId}:${channelId}`;
|
|
1095
1278
|
this.channels.set(key, {
|
|
1096
1279
|
serverId,
|
|
@@ -1103,19 +1286,6 @@ export class ChannelRegistry {
|
|
|
1103
1286
|
},
|
|
1104
1287
|
open: false,
|
|
1105
1288
|
});
|
|
1106
|
-
// Only persist a REAL label durably. Falling back to the bare
|
|
1107
|
-
// channelId as a placeholder (no server-supplied label at all — e.g. a
|
|
1108
|
-
// Discord DM push missing both channelName and an author name,
|
|
1109
|
-
// framework.ts's derivePushEventChannel) must never overwrite a real
|
|
1110
|
-
// label already on file from a previous boot: after a restart the live
|
|
1111
|
-
// `channels` map starts empty, so THIS is the very branch a
|
|
1112
|
-
// label-less post-restart event takes — recording the placeholder here
|
|
1113
|
-
// would clobber the good label initializeLabelHistoryStore() just
|
|
1114
|
-
// replayed, defeating the entire point of the durable log. The live
|
|
1115
|
-
// descriptor above still carries the placeholder for in-process
|
|
1116
|
-
// routing; only the durable write is skipped when there's no real
|
|
1117
|
-
// label to record.
|
|
1118
|
-
if (label) this.appendLabelSighting(channelId, label, extractDmMeta(extraMetadata));
|
|
1119
1289
|
this.emitTraceFn({
|
|
1120
1290
|
type: 'mcpl:channel-lazy-registered',
|
|
1121
1291
|
serverId,
|
|
@@ -1250,6 +1420,13 @@ export class ChannelRegistry {
|
|
|
1250
1420
|
return this.findChannelEntry(channelId)?.descriptor;
|
|
1251
1421
|
}
|
|
1252
1422
|
|
|
1423
|
+
/** The registered label of `channelId` on exactly `serverId` (no
|
|
1424
|
+
* cross-server first match), or undefined when it has none. */
|
|
1425
|
+
getChannelLabel(serverId: string, channelId: string): string | undefined {
|
|
1426
|
+
const label = this.channels.get(`${serverId}:${channelId}`)?.descriptor.label;
|
|
1427
|
+
return typeof label === 'string' && label.length > 0 ? label : undefined;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1253
1430
|
isChannelOpen(channelId: string): boolean {
|
|
1254
1431
|
return this.findChannelEntry(channelId)?.open === true;
|
|
1255
1432
|
}
|
|
@@ -1279,7 +1456,7 @@ export class ChannelRegistry {
|
|
|
1279
1456
|
* Get synthesized tool definitions for channel operations.
|
|
1280
1457
|
*/
|
|
1281
1458
|
getChannelTools(): ToolDefinition[] {
|
|
1282
|
-
return
|
|
1459
|
+
return this.channelTools;
|
|
1283
1460
|
}
|
|
1284
1461
|
|
|
1285
1462
|
/**
|
|
@@ -1340,7 +1517,7 @@ export class ChannelRegistry {
|
|
|
1340
1517
|
return this.handleToolJournal(input as { content?: string });
|
|
1341
1518
|
|
|
1342
1519
|
case 'skip_reply':
|
|
1343
|
-
return this.handleToolSkipReply(input as { reason?: string; wake_in_seconds?:
|
|
1520
|
+
return this.handleToolSkipReply(input as { reason?: string; wake_in_seconds?: unknown });
|
|
1344
1521
|
|
|
1345
1522
|
default:
|
|
1346
1523
|
return { success: false, error: `Unknown channel tool: ${toolName}`, isError: true };
|
|
@@ -1361,8 +1538,9 @@ export class ChannelRegistry {
|
|
|
1361
1538
|
|
|
1362
1539
|
// Resolve the outbound locus the SAME way routeSpeech does, so the agent is
|
|
1363
1540
|
// told the channel its speech will actually land in: a conversation fork's
|
|
1364
|
-
// home channel, else this turn's
|
|
1365
|
-
//
|
|
1541
|
+
// home channel, else this turn's channel (single trunk agent — item-3
|
|
1542
|
+
// redux: its locus, else its triggering channel), else the global default
|
|
1543
|
+
// (heartbeats). Without this, a fork
|
|
1366
1544
|
// was advertised the global locus but published somewhere else; and a trunk
|
|
1367
1545
|
// agent was told the wrong channel under concurrency.
|
|
1368
1546
|
const home = agentName ? this.homeChannelResolver?.(agentName) : undefined;
|
|
@@ -1454,13 +1632,7 @@ export class ChannelRegistry {
|
|
|
1454
1632
|
private initializeLifecycleStore(): void {
|
|
1455
1633
|
if (!this.store) return;
|
|
1456
1634
|
|
|
1457
|
-
|
|
1458
|
-
this.store.registerState({ id: CHANNEL_LIFECYCLE_LOG_ID, strategy: 'append_log' });
|
|
1459
|
-
} catch (error) {
|
|
1460
|
-
if (!(error instanceof Error) || !error.message.includes('State already exists')) {
|
|
1461
|
-
throw error;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1635
|
+
ensureStateRegistered(this.store, { id: CHANNEL_LIFECYCLE_LOG_ID, strategy: 'append_log' });
|
|
1464
1636
|
|
|
1465
1637
|
const raw = this.store.getStateJson(CHANNEL_LIFECYCLE_LOG_ID);
|
|
1466
1638
|
if (!Array.isArray(raw)) return;
|
|
@@ -1503,6 +1675,15 @@ export class ChannelRegistry {
|
|
|
1503
1675
|
}
|
|
1504
1676
|
}
|
|
1505
1677
|
|
|
1678
|
+
/**
|
|
1679
|
+
* Each writer appends its record here before it changes memory for it, so
|
|
1680
|
+
* an append that throws, as on a full disk, fails the operation with that
|
|
1681
|
+
* change unmade, and memory and the log still agree. A retry then records
|
|
1682
|
+
* the change rather than finding it in memory already, where
|
|
1683
|
+
* setDesiredState's same-state return would record nothing, and a restart
|
|
1684
|
+
* replays what memory held. appendLabelSighting keeps the same order for
|
|
1685
|
+
* the label history.
|
|
1686
|
+
*/
|
|
1506
1687
|
private appendLifecycleEvent(event: ChannelLifecycleEvent): void {
|
|
1507
1688
|
this.store?.appendToStateJson(CHANNEL_LIFECYCLE_LOG_ID, event);
|
|
1508
1689
|
}
|
|
@@ -1521,13 +1702,7 @@ export class ChannelRegistry {
|
|
|
1521
1702
|
private initializeLabelHistoryStore(): void {
|
|
1522
1703
|
if (!this.store) return;
|
|
1523
1704
|
|
|
1524
|
-
|
|
1525
|
-
this.store.registerState({ id: CHANNEL_LABEL_HISTORY_LOG_ID, strategy: 'append_log' });
|
|
1526
|
-
} catch (error) {
|
|
1527
|
-
if (!(error instanceof Error) || !error.message.includes('State already exists')) {
|
|
1528
|
-
throw error;
|
|
1529
|
-
}
|
|
1530
|
-
}
|
|
1705
|
+
ensureStateRegistered(this.store, { id: CHANNEL_LABEL_HISTORY_LOG_ID, strategy: 'append_log' });
|
|
1531
1706
|
|
|
1532
1707
|
const raw = this.store.getStateJson(CHANNEL_LABEL_HISTORY_LOG_ID);
|
|
1533
1708
|
if (!Array.isArray(raw)) return;
|
|
@@ -1608,6 +1783,16 @@ export class ChannelRegistry {
|
|
|
1608
1783
|
const recipientNameUnchanged = recipientName === undefined || recipientName === this.dmRecipientNames.get(channelId);
|
|
1609
1784
|
const isDmUnchanged = isDm === undefined || this.dmClassified.get(channelId) === true;
|
|
1610
1785
|
if (labelUnchanged && recipientIdUnchanged && recipientNameUnchanged && isDmUnchanged) return;
|
|
1786
|
+
// The log first, as for lifecycle events: an append that throws leaves
|
|
1787
|
+
// the history in memory as it was, so the next sighting records it.
|
|
1788
|
+
this.store?.appendToStateJson(CHANNEL_LABEL_HISTORY_LOG_ID, {
|
|
1789
|
+
channelId,
|
|
1790
|
+
label,
|
|
1791
|
+
ts: Date.now(),
|
|
1792
|
+
...(recipientId ? { recipientId } : {}),
|
|
1793
|
+
...(recipientName ? { recipientName } : {}),
|
|
1794
|
+
...(isDm ? { isDm } : {}),
|
|
1795
|
+
} satisfies ChannelLabelSightingEvent);
|
|
1611
1796
|
this.labelHistory.set(channelId, label);
|
|
1612
1797
|
let seen = this.allLabelsSeen.get(channelId);
|
|
1613
1798
|
if (!seen) {
|
|
@@ -1618,14 +1803,6 @@ export class ChannelRegistry {
|
|
|
1618
1803
|
if (recipientId) this.dmRecipientIds.set(channelId, recipientId);
|
|
1619
1804
|
if (recipientName) this.dmRecipientNames.set(channelId, recipientName);
|
|
1620
1805
|
if (isDm) this.dmClassified.set(channelId, true);
|
|
1621
|
-
this.store?.appendToStateJson(CHANNEL_LABEL_HISTORY_LOG_ID, {
|
|
1622
|
-
channelId,
|
|
1623
|
-
label,
|
|
1624
|
-
ts: Date.now(),
|
|
1625
|
-
...(recipientId ? { recipientId } : {}),
|
|
1626
|
-
...(recipientName ? { recipientName } : {}),
|
|
1627
|
-
...(isDm ? { isDm } : {}),
|
|
1628
|
-
} satisfies ChannelLabelSightingEvent);
|
|
1629
1806
|
}
|
|
1630
1807
|
|
|
1631
1808
|
/**
|
|
@@ -1850,7 +2027,6 @@ export class ChannelRegistry {
|
|
|
1850
2027
|
): void {
|
|
1851
2028
|
const key = this.lifecycleKey(serverId, channelId);
|
|
1852
2029
|
if (this.desiredStates.get(key)?.state === desired) return;
|
|
1853
|
-
this.desiredStates.set(key, { state: desired, source });
|
|
1854
2030
|
this.appendLifecycleEvent({
|
|
1855
2031
|
kind: 'desired-state',
|
|
1856
2032
|
serverId,
|
|
@@ -1859,6 +2035,7 @@ export class ChannelRegistry {
|
|
|
1859
2035
|
source,
|
|
1860
2036
|
timestamp: new Date().toISOString(),
|
|
1861
2037
|
});
|
|
2038
|
+
this.desiredStates.set(key, { state: desired, source });
|
|
1862
2039
|
}
|
|
1863
2040
|
|
|
1864
2041
|
// ==========================================================================
|
|
@@ -1878,12 +2055,6 @@ export class ChannelRegistry {
|
|
|
1878
2055
|
source: string,
|
|
1879
2056
|
): void {
|
|
1880
2057
|
const key = this.lifecycleKey(serverId, channelId);
|
|
1881
|
-
this.desiredStates.set(key, {
|
|
1882
|
-
state: 'tuned-out',
|
|
1883
|
-
source,
|
|
1884
|
-
tuneOut: params,
|
|
1885
|
-
wakeCount: 0,
|
|
1886
|
-
});
|
|
1887
2058
|
this.appendLifecycleEvent({
|
|
1888
2059
|
kind: 'desired-state',
|
|
1889
2060
|
serverId,
|
|
@@ -1893,6 +2064,12 @@ export class ChannelRegistry {
|
|
|
1893
2064
|
source,
|
|
1894
2065
|
timestamp: new Date().toISOString(),
|
|
1895
2066
|
});
|
|
2067
|
+
this.desiredStates.set(key, {
|
|
2068
|
+
state: 'tuned-out',
|
|
2069
|
+
source,
|
|
2070
|
+
tuneOut: params,
|
|
2071
|
+
wakeCount: 0,
|
|
2072
|
+
});
|
|
1896
2073
|
}
|
|
1897
2074
|
|
|
1898
2075
|
/**
|
|
@@ -1911,7 +2088,6 @@ export class ChannelRegistry {
|
|
|
1911
2088
|
const current = this.desiredStates.get(key);
|
|
1912
2089
|
if (current?.state !== 'tuned-out' || !current.tuneOut) return null;
|
|
1913
2090
|
const ended = { params: current.tuneOut, wakeCount: current.wakeCount ?? 0 };
|
|
1914
|
-
this.desiredStates.set(key, { state: nextState, source });
|
|
1915
2091
|
this.appendLifecycleEvent({
|
|
1916
2092
|
kind: 'desired-state',
|
|
1917
2093
|
serverId,
|
|
@@ -1920,6 +2096,7 @@ export class ChannelRegistry {
|
|
|
1920
2096
|
source,
|
|
1921
2097
|
timestamp: new Date().toISOString(),
|
|
1922
2098
|
});
|
|
2099
|
+
this.desiredStates.set(key, { state: nextState, source });
|
|
1923
2100
|
return ended;
|
|
1924
2101
|
}
|
|
1925
2102
|
|
|
@@ -1937,16 +2114,17 @@ export class ChannelRegistry {
|
|
|
1937
2114
|
const key = this.lifecycleKey(serverId, channelId);
|
|
1938
2115
|
const current = this.desiredStates.get(key);
|
|
1939
2116
|
if (current?.state !== 'tuned-out' || !current.tuneOut) return null;
|
|
1940
|
-
|
|
2117
|
+
const wakeCount = (current.wakeCount ?? 0) + 1;
|
|
1941
2118
|
this.appendLifecycleEvent({
|
|
1942
2119
|
kind: 'tune-out-wake',
|
|
1943
2120
|
serverId,
|
|
1944
2121
|
channelId,
|
|
1945
2122
|
epochId: current.tuneOut.epochId,
|
|
1946
|
-
wakeCount
|
|
2123
|
+
wakeCount,
|
|
1947
2124
|
timestamp: new Date().toISOString(),
|
|
1948
2125
|
});
|
|
1949
|
-
|
|
2126
|
+
current.wakeCount = wakeCount;
|
|
2127
|
+
return { params: current.tuneOut, wakeCount };
|
|
1950
2128
|
}
|
|
1951
2129
|
|
|
1952
2130
|
/** Active tune-out params + wake count for a channel, or null. */
|
|
@@ -1974,17 +2152,13 @@ export class ChannelRegistry {
|
|
|
1974
2152
|
*/
|
|
1975
2153
|
readCoordinatorState(stateId: string): unknown {
|
|
1976
2154
|
if (!this.store) return null;
|
|
1977
|
-
|
|
1978
|
-
this.store.registerState({ id: stateId, strategy: 'snapshot' });
|
|
1979
|
-
} catch { /* already registered */ }
|
|
2155
|
+
ensureStateRegistered(this.store, { id: stateId, strategy: 'snapshot' });
|
|
1980
2156
|
return this.store.getStateJson(stateId);
|
|
1981
2157
|
}
|
|
1982
2158
|
|
|
1983
2159
|
writeCoordinatorState(stateId: string, value: unknown): void {
|
|
1984
2160
|
if (!this.store) return;
|
|
1985
|
-
|
|
1986
|
-
this.store.registerState({ id: stateId, strategy: 'snapshot' });
|
|
1987
|
-
} catch { /* already registered */ }
|
|
2161
|
+
ensureStateRegistered(this.store, { id: stateId, strategy: 'snapshot' });
|
|
1988
2162
|
this.store.setStateJson(stateId, value);
|
|
1989
2163
|
}
|
|
1990
2164
|
|
|
@@ -2021,13 +2195,13 @@ export class ChannelRegistry {
|
|
|
2021
2195
|
this.setDesiredState(serverId, channel.id, desired, 'legacy-recipe-migration');
|
|
2022
2196
|
}
|
|
2023
2197
|
|
|
2024
|
-
this.migratedLegacyPolicies.add(serverId);
|
|
2025
2198
|
this.appendLifecycleEvent({
|
|
2026
2199
|
kind: 'legacy-policy-migrated',
|
|
2027
2200
|
serverId,
|
|
2028
2201
|
source: Array.isArray(policy) ? 'allow-list' : policy,
|
|
2029
2202
|
timestamp: new Date().toISOString(),
|
|
2030
2203
|
});
|
|
2204
|
+
this.migratedLegacyPolicies.add(serverId);
|
|
2031
2205
|
}
|
|
2032
2206
|
|
|
2033
2207
|
/**
|
|
@@ -2156,9 +2330,9 @@ export class ChannelRegistry {
|
|
|
2156
2330
|
}
|
|
2157
2331
|
}
|
|
2158
2332
|
|
|
2159
|
-
// Announce policy admissions to the agent —
|
|
2160
|
-
//
|
|
2161
|
-
//
|
|
2333
|
+
// Announce policy admissions to the agent — no channel may open without
|
|
2334
|
+
// them being told, and told how to opt out (channel_close; their
|
|
2335
|
+
// decision outranks policy).
|
|
2162
2336
|
if (policyOpened.length > 0) {
|
|
2163
2337
|
try {
|
|
2164
2338
|
this.onChannelAutoOpened?.({
|
|
@@ -2575,11 +2749,13 @@ export class ChannelRegistry {
|
|
|
2575
2749
|
// A tuned-out channel is transport-open but attention-diverted; a plain
|
|
2576
2750
|
// open would silently discard the epoch (and its pending backlog dump).
|
|
2577
2751
|
// Cancelling is the tune-out coordinator's flow, reached via its own
|
|
2578
|
-
// tool — refuse with the pointer rather than eat the state.
|
|
2752
|
+
// tool — refuse with the pointer rather than eat the state. As an error
|
|
2753
|
+
// result, the agent reads the pointer itself; `data` names the refusal
|
|
2754
|
+
// for an in-process caller.
|
|
2579
2755
|
if (this.getDesiredState(entry.serverId, input.channelId) === 'tuned-out') {
|
|
2580
2756
|
return {
|
|
2581
2757
|
success: false,
|
|
2582
|
-
isError:
|
|
2758
|
+
isError: true,
|
|
2583
2759
|
error:
|
|
2584
2760
|
`Channel ${input.channelId} is tuned out. Cancel the tune-out ` +
|
|
2585
2761
|
`(tune_out with mode: 'cancel') to resume normal attention — ` +
|
|
@@ -2750,7 +2926,7 @@ export class ChannelRegistry {
|
|
|
2750
2926
|
if (entry.open || this.getDesiredState(entry.serverId, input.channelId) === 'open') {
|
|
2751
2927
|
return {
|
|
2752
2928
|
success: false,
|
|
2753
|
-
error: `Channel is already open: ${input.channelId}. Use channel_close to
|
|
2929
|
+
error: `Channel is already open: ${input.channelId}. Use channel_close to close it.`,
|
|
2754
2930
|
isError: true,
|
|
2755
2931
|
};
|
|
2756
2932
|
}
|
|
@@ -2858,14 +3034,15 @@ export class ChannelRegistry {
|
|
|
2858
3034
|
* tool, so any trailing prose this turn is NOT posted. Replaces the old
|
|
2859
3035
|
* overloaded use of `think` for staying silent.
|
|
2860
3036
|
*/
|
|
2861
|
-
private handleToolSkipReply(input: { reason?: string; wake_in_seconds?:
|
|
3037
|
+
private handleToolSkipReply(input: { reason?: string; wake_in_seconds?: unknown }): ToolResult {
|
|
2862
3038
|
// The self-wake itself is armed by the framework (which owns the
|
|
2863
|
-
// EventGate) BEFORE
|
|
2864
|
-
//
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
3039
|
+
// EventGate) BEFORE its dispatch reaches this handler, from the same
|
|
3040
|
+
// reading, and the framework refuses a wake the host can't set before
|
|
3041
|
+
// dispatching. A caller of this registry's handleChannelToolCall
|
|
3042
|
+
// (AgentFramework.channels) goes past both, so its note names a wake
|
|
3043
|
+
// nothing armed.
|
|
3044
|
+
const wake = readSkipReplyWake(input);
|
|
3045
|
+
const selfWake = wake.kind === 'wake' ? wake.seconds : undefined;
|
|
2869
3046
|
return {
|
|
2870
3047
|
success: true,
|
|
2871
3048
|
// The note says "ended the turn" — make it TRUE. Without endTurn the
|
|
@@ -2961,7 +3138,179 @@ export class ChannelRegistry {
|
|
|
2961
3138
|
return home ?? this.activeChannelResolver?.(conversationId) ?? this.defaultPublishChannel ?? null;
|
|
2962
3139
|
}
|
|
2963
3140
|
|
|
2964
|
-
|
|
3141
|
+
/**
|
|
3142
|
+
* Resolve a publish target to exactly one registered channel: `serverId`
|
|
3143
|
+
* plus `channelId` when the caller has the server, otherwise a channel id
|
|
3144
|
+
* registered by exactly one server. A shared id is refused, never resolved
|
|
3145
|
+
* to whichever server registered it first.
|
|
3146
|
+
*/
|
|
3147
|
+
resolveDestination(
|
|
3148
|
+
target: { serverId?: string; channelId: string },
|
|
3149
|
+
): { destination: PublishDestination } | { error: string } {
|
|
3150
|
+
const entry = this.findExactEntry(target);
|
|
3151
|
+
if ('error' in entry) return entry;
|
|
3152
|
+
return {
|
|
3153
|
+
destination: {
|
|
3154
|
+
serverId: entry.entry.serverId,
|
|
3155
|
+
channelId: entry.entry.descriptor.id,
|
|
3156
|
+
...(entry.entry.descriptor.label ? { label: entry.entry.descriptor.label } : {}),
|
|
3157
|
+
},
|
|
3158
|
+
};
|
|
3159
|
+
}
|
|
3160
|
+
|
|
3161
|
+
private findExactEntry(
|
|
3162
|
+
target: { serverId?: string; channelId: string },
|
|
3163
|
+
): { entry: ChannelEntry } | { error: string } {
|
|
3164
|
+
// A supplied selector is checked, never read as omission: an empty or
|
|
3165
|
+
// non-string serverId would otherwise widen to "any server".
|
|
3166
|
+
if (typeof target.channelId !== 'string' || !target.channelId) {
|
|
3167
|
+
return { error: 'the destination names no channel id' };
|
|
3168
|
+
}
|
|
3169
|
+
if (target.serverId !== undefined && (typeof target.serverId !== 'string' || !target.serverId)) {
|
|
3170
|
+
return { error: 'serverId must name a server (omit it to resolve the channel id alone)' };
|
|
3171
|
+
}
|
|
3172
|
+
const matches = [...this.channels.values()].filter(
|
|
3173
|
+
(e) => e.descriptor.id === target.channelId && (!target.serverId || e.serverId === target.serverId),
|
|
3174
|
+
);
|
|
3175
|
+
if (matches.length === 0) {
|
|
3176
|
+
return {
|
|
3177
|
+
error: target.serverId
|
|
3178
|
+
? `no registered channel "${target.channelId}" on server "${target.serverId}"`
|
|
3179
|
+
: `no registered channel "${target.channelId}"`,
|
|
3180
|
+
};
|
|
3181
|
+
}
|
|
3182
|
+
if (matches.length > 1) {
|
|
3183
|
+
return {
|
|
3184
|
+
error: `channel id "${target.channelId}" is registered by more than one MCPL server; the destination must name its server`,
|
|
3185
|
+
};
|
|
3186
|
+
}
|
|
3187
|
+
return { entry: matches[0]! };
|
|
3188
|
+
}
|
|
3189
|
+
|
|
3190
|
+
/**
|
|
3191
|
+
* Publish `text` to one registered channel and report what the attempt
|
|
3192
|
+
* established (PublishOutcome). The delivery executor behind plain speech
|
|
3193
|
+
* (deliverSpeech / routeSpeech) and resident resends of held drafts.
|
|
3194
|
+
* channel_publish (and publishForAgent, which shares its handler) resolves
|
|
3195
|
+
* and sends on its own path, and reads its answer through the same
|
|
3196
|
+
* publishReceiptOutcome and publishErrorOutcome.
|
|
3197
|
+
*
|
|
3198
|
+
* Resolution is exact (resolveDestination): `serverId` plus `channelId`
|
|
3199
|
+
* when the caller has the server, otherwise the channel id must be
|
|
3200
|
+
* registered by exactly one server (a shared id is refused, never routed
|
|
3201
|
+
* through whichever server came first). An omitted `serverId` means "not
|
|
3202
|
+
* in use"; a supplied one must be a non-empty server id, and an empty or
|
|
3203
|
+
* non-string selector is refused rather than read as omission. It is not
|
|
3204
|
+
* possible to send into a closed channel: a closed but registered
|
|
3205
|
+
* destination is opened first (`openSource` names why), once its server
|
|
3206
|
+
* and that server's channels.publish grant are known to take the send, so
|
|
3207
|
+
* a refused send opens nothing; and a failed open sends nothing.
|
|
3208
|
+
*
|
|
3209
|
+
* Only the connector's `delivered: true` confirms a post. `failed` means
|
|
3210
|
+
* nothing was posted: the attempt stopped before the request was written,
|
|
3211
|
+
* or the connector answered `delivered: false` and named no message (no
|
|
3212
|
+
* `messageId`, or null). Everything else is `unknown`: once the request
|
|
3213
|
+
* has been handed to the transport, an error response, a timeout, a lost
|
|
3214
|
+
* connection, or a missing, malformed or contradictory receipt (such as
|
|
3215
|
+
* `delivered: false` beside a message id, valid or not) means the post may
|
|
3216
|
+
* or may not exist, and the caller must not treat it as safe to retry
|
|
3217
|
+
* blindly.
|
|
3218
|
+
*/
|
|
3219
|
+
async publish(
|
|
3220
|
+
conversationId: string,
|
|
3221
|
+
text: string,
|
|
3222
|
+
target: {
|
|
3223
|
+
serverId?: string;
|
|
3224
|
+
channelId: string;
|
|
3225
|
+
/** Set by speech routing (deliverSpeech): opening a closed channel
|
|
3226
|
+
* for this publish is logged under `[routeSpeech]`, with speech
|
|
3227
|
+
* routing's other lines. */
|
|
3228
|
+
routed?: boolean;
|
|
3229
|
+
},
|
|
3230
|
+
openSource: 'opened-by-delivery' | 'opened-by-reply' = 'opened-by-delivery',
|
|
3231
|
+
): Promise<PublishOutcome> {
|
|
3232
|
+
const at = (): number => Date.now();
|
|
3233
|
+
const found = this.findExactEntry(target);
|
|
3234
|
+
if ('error' in found) return { status: 'failed', reason: found.error, at: at() };
|
|
3235
|
+
const entry = found.entry;
|
|
3236
|
+
const destination: PublishDestination = {
|
|
3237
|
+
serverId: entry.serverId,
|
|
3238
|
+
channelId: entry.descriptor.id,
|
|
3239
|
+
...(entry.descriptor.label ? { label: entry.descriptor.label } : {}),
|
|
3240
|
+
};
|
|
3241
|
+
|
|
3242
|
+
// A send that would be refused is refused before anything opens: a
|
|
3243
|
+
// closed channel opens only for words that can go out.
|
|
3244
|
+
const server = this.serverRegistry.getServer(entry.serverId);
|
|
3245
|
+
if (!server) {
|
|
3246
|
+
return { status: 'failed', destination, reason: `server "${entry.serverId}" not found`, at: at() };
|
|
3247
|
+
}
|
|
3248
|
+
// §14.1: channels/publish requires channels.publish in the grant. The
|
|
3249
|
+
// host not sending is the enforcement.
|
|
3250
|
+
if (!CapabilityGrant.of(server).has('channels.publish')) {
|
|
3251
|
+
return {
|
|
3252
|
+
status: 'failed',
|
|
3253
|
+
destination,
|
|
3254
|
+
reason: `channels.publish not in "${entry.serverId}"'s effective grant (§14.1)`,
|
|
3255
|
+
at: at(),
|
|
3256
|
+
};
|
|
3257
|
+
}
|
|
3258
|
+
|
|
3259
|
+
if (!entry.open) {
|
|
3260
|
+
try {
|
|
3261
|
+
await this.openChannelNow(entry, openSource);
|
|
3262
|
+
if (target.routed) {
|
|
3263
|
+
console.error(
|
|
3264
|
+
`[routeSpeech] ${conversationId}: locus ${logValue(entry.descriptor.id)} was closed — opened by delivery (speech implies engagement)`,
|
|
3265
|
+
);
|
|
3266
|
+
}
|
|
3267
|
+
this.emitTraceFn({
|
|
3268
|
+
type: 'mcpl:channel-opened-by-send',
|
|
3269
|
+
serverId: entry.serverId,
|
|
3270
|
+
channelId: entry.descriptor.id,
|
|
3271
|
+
});
|
|
3272
|
+
if (openSource === 'opened-by-delivery') {
|
|
3273
|
+
try {
|
|
3274
|
+
this.onChannelAutoOpened?.({
|
|
3275
|
+
conversationId,
|
|
3276
|
+
serverId: entry.serverId,
|
|
3277
|
+
source: 'opened-by-delivery',
|
|
3278
|
+
channels: [{ channelId: entry.descriptor.id, label: entry.descriptor.label }],
|
|
3279
|
+
});
|
|
3280
|
+
} catch (err) {
|
|
3281
|
+
console.error('onChannelAutoOpened (delivery) failed:', err);
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
} catch (err) {
|
|
3285
|
+
return {
|
|
3286
|
+
status: 'failed',
|
|
3287
|
+
destination,
|
|
3288
|
+
reason: `channel is closed and open failed: ${connectorText(err instanceof Error ? err.message : String(err))}`,
|
|
3289
|
+
at: at(),
|
|
3290
|
+
};
|
|
3291
|
+
}
|
|
3292
|
+
}
|
|
3293
|
+
|
|
3294
|
+
let result: unknown;
|
|
3295
|
+
try {
|
|
3296
|
+
result = await server.sendChannelsPublish({
|
|
3297
|
+
conversationId,
|
|
3298
|
+
channelId: entry.descriptor.id,
|
|
3299
|
+
content: [{ type: 'text', text }],
|
|
3300
|
+
});
|
|
3301
|
+
} catch (err) {
|
|
3302
|
+
return publishErrorOutcome(err, destination, at());
|
|
3303
|
+
}
|
|
3304
|
+
return publishReceiptOutcome(result, destination, at());
|
|
3305
|
+
}
|
|
3306
|
+
|
|
3307
|
+
/**
|
|
3308
|
+
* Plain speech for one turn segment: publish `text` to the turn's frozen
|
|
3309
|
+
* locus and report the PublishOutcome. A failure (or an uncertain outcome)
|
|
3310
|
+
* is surfaced as a trace and through onRouteFailure, so the agent learns
|
|
3311
|
+
* its words did not (or may not have) reached anyone.
|
|
3312
|
+
*/
|
|
3313
|
+
async deliverSpeech(
|
|
2965
3314
|
conversationId: string,
|
|
2966
3315
|
text: string,
|
|
2967
3316
|
/** The turn's FROZEN locus, snapshotted once by the caller (resolveLocus
|
|
@@ -2972,118 +3321,82 @@ export class ChannelRegistry {
|
|
|
2972
3321
|
* PR #32, and the 2026-07-22 Sol DM misroute). Explicit `null` means
|
|
2973
3322
|
* "this turn is pinned to no locus": fail loudly rather than guess. */
|
|
2974
3323
|
locusChannelId: string | null,
|
|
2975
|
-
|
|
2976
|
-
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
3324
|
+
/** `heldOnFailure`: the caller holds a `failed` delivery's words as a
|
|
3325
|
+
* draft with its own notice, so no failure marker is written for it.
|
|
3326
|
+
* An `unknown` outcome still gets its marker. */
|
|
3327
|
+
opts?: { heldOnFailure?: boolean },
|
|
3328
|
+
): Promise<PublishOutcome> {
|
|
3329
|
+
const fail = (channelId: string | null, reason: string, outcome: PublishOutcome): PublishOutcome => {
|
|
3330
|
+
const status = outcome.status === 'unknown' ? 'unknown' : 'failed';
|
|
3331
|
+
const detail = outcome.detail !== undefined ? connectorText(outcome.detail) : undefined;
|
|
3332
|
+
const detailText = detail !== undefined ? `; connector detail: ${detail}` : '';
|
|
3333
|
+
console.error(`[routeSpeech] ${conversationId}: ${reason}${detailText} — speech ${status === 'unknown' ? 'delivery NOT confirmed' : 'NOT routed'} (${text.length} chars stay in chronicle)`);
|
|
2981
3334
|
this.emitTraceFn({
|
|
2982
3335
|
type: 'mcpl:speech-route-failed',
|
|
2983
3336
|
conversationId,
|
|
2984
3337
|
channelId: channelId ?? '',
|
|
2985
3338
|
reason,
|
|
2986
3339
|
textLen: text.length,
|
|
3340
|
+
outcome: status,
|
|
3341
|
+
...(detail !== undefined ? { detail } : {}),
|
|
2987
3342
|
});
|
|
2988
|
-
|
|
2989
|
-
|
|
3343
|
+
if (status === 'unknown' || !opts?.heldOnFailure) {
|
|
3344
|
+
this.onRouteFailure?.({ conversationId, channelId, reason, textLen: text.length, outcome: status, ...(detail !== undefined ? { detail } : {}) });
|
|
3345
|
+
}
|
|
3346
|
+
return outcome;
|
|
2990
3347
|
};
|
|
2991
3348
|
|
|
2992
3349
|
// Runtime backstop for JS callers the compiler can't see: an omitted
|
|
2993
3350
|
// locus is a routing bug at the call site, never something to paper over
|
|
2994
3351
|
// with a live re-resolution.
|
|
2995
3352
|
if (locusChannelId === undefined) {
|
|
2996
|
-
|
|
3353
|
+
const reason = 'caller passed no locus (routing bug: every speech path must snapshot the turn locus)';
|
|
3354
|
+
return fail(null, reason, { status: 'failed', reason, at: Date.now() });
|
|
2997
3355
|
}
|
|
2998
|
-
|
|
2999
|
-
if (!channelId) {
|
|
3356
|
+
if (!locusChannelId) {
|
|
3000
3357
|
// The turn froze with no locus (no home, no triggering channel, no
|
|
3001
3358
|
// global inbound ever seen) — the agent was told its prose stays in
|
|
3002
3359
|
// the archive; honor that.
|
|
3003
|
-
|
|
3360
|
+
const reason = 'turn has no locus (no home/trigger channel; nothing to deliver into)';
|
|
3361
|
+
return fail(null, reason, { status: 'failed', reason, at: Date.now() });
|
|
3004
3362
|
}
|
|
3005
3363
|
|
|
3006
|
-
const
|
|
3007
|
-
|
|
3008
|
-
|
|
3364
|
+
const outcome = await this.publish(conversationId, text, { channelId: locusChannelId, routed: true });
|
|
3365
|
+
const channelId = outcome.destination?.channelId ?? locusChannelId;
|
|
3366
|
+
if (outcome.status !== 'delivered') {
|
|
3367
|
+
return fail(channelId, outcome.reason ?? 'delivery not confirmed', outcome);
|
|
3009
3368
|
}
|
|
3010
3369
|
|
|
3011
|
-
|
|
3012
|
-
// routed into a closed-but-registered locus (the canonical case: a DM
|
|
3013
|
-
// that woke the agent — DMs register closed) OPENS the channel first,
|
|
3014
|
-
// so typing indicators, reaction machinery, and inbound forwarding come
|
|
3015
|
-
// alive with the reply. If the open fails, the speech does NOT go out:
|
|
3016
|
-
// a half-alive delivery is worse than a loud marker.
|
|
3017
|
-
if (!entry.open) {
|
|
3018
|
-
try {
|
|
3019
|
-
await this.openChannelNow(entry, 'opened-by-delivery');
|
|
3020
|
-
console.error(
|
|
3021
|
-
`[routeSpeech] ${conversationId}: locus ${channelId} was closed — opened by delivery (speech implies engagement)`,
|
|
3022
|
-
);
|
|
3023
|
-
this.emitTraceFn({
|
|
3024
|
-
type: 'mcpl:channel-opened-by-send',
|
|
3025
|
-
serverId: entry.serverId,
|
|
3026
|
-
channelId,
|
|
3027
|
-
});
|
|
3028
|
-
try {
|
|
3029
|
-
this.onChannelAutoOpened?.({
|
|
3030
|
-
conversationId,
|
|
3031
|
-
serverId: entry.serverId,
|
|
3032
|
-
source: 'opened-by-delivery',
|
|
3033
|
-
channels: [{ channelId, label: entry.descriptor.label }],
|
|
3034
|
-
});
|
|
3035
|
-
} catch (err) {
|
|
3036
|
-
console.error('onChannelAutoOpened (delivery) failed:', err);
|
|
3037
|
-
}
|
|
3038
|
-
} catch (err) {
|
|
3039
|
-
return fail(channelId, `locus channel is closed and open failed: ${(err as Error).message}`);
|
|
3040
|
-
}
|
|
3041
|
-
}
|
|
3042
|
-
|
|
3043
|
-
const server = this.serverRegistry.getServer(entry.serverId);
|
|
3044
|
-
if (!server) {
|
|
3045
|
-
return fail(channelId, `server "${entry.serverId}" not found`);
|
|
3046
|
-
}
|
|
3047
|
-
// §14.1: channels/publish requires channels.publish in the grant. The
|
|
3048
|
-
// host not sending is the enforcement — a send to an ungranted server
|
|
3049
|
-
// would have it act on authority it was never told it has.
|
|
3050
|
-
if (!CapabilityGrant.of(server).has('channels.publish')) {
|
|
3051
|
-
return fail(channelId, `channels.publish not in "${entry.serverId}"'s effective grant (§14.1)`);
|
|
3052
|
-
}
|
|
3053
|
-
|
|
3054
|
-
const publishParams: ChannelsPublishParams = {
|
|
3055
|
-
conversationId,
|
|
3056
|
-
channelId,
|
|
3057
|
-
content: [{ type: 'text', text }],
|
|
3058
|
-
};
|
|
3059
|
-
const result = await server.sendChannelsPublish(publishParams);
|
|
3060
|
-
const delivered = (result as { delivered?: boolean } | undefined)?.delivered ?? true;
|
|
3061
|
-
// Surface the posted message's id (ChannelsPublishResult.messageId) so
|
|
3062
|
-
// trace consumers can act on the just-posted message — e.g. a TTS-relay
|
|
3063
|
-
// tap editing it down to the words actually voiced on interruption.
|
|
3064
|
-
// Previously this was silently dropped here.
|
|
3065
|
-
const messageId = (result as { messageId?: string } | undefined)?.messageId;
|
|
3066
|
-
|
|
3067
|
-
// The server accepted the publish RPC but reported the message was not
|
|
3068
|
-
// actually delivered (e.g. missing Send Messages permission). Previously
|
|
3069
|
-
// this returned `{ delivered: true }`, masking the failure. Surface it.
|
|
3070
|
-
if (delivered === false) {
|
|
3071
|
-
return fail(channelId, `server "${entry.serverId}" reported delivered:false for "${channelId}"`);
|
|
3072
|
-
}
|
|
3073
|
-
|
|
3074
|
-
console.error(`[routeSpeech] ${conversationId}: routed ${text.length} chars -> ${channelId} (server=${entry.serverId}, delivered=${delivered})`);
|
|
3370
|
+
console.error(`[routeSpeech] ${conversationId}: routed ${text.length} chars -> ${logValue(channelId)} (server=${outcome.destination!.serverId}, delivered=true)`);
|
|
3075
3371
|
this.emitTraceFn({
|
|
3076
3372
|
type: 'mcpl:speech-routed',
|
|
3077
3373
|
conversationId,
|
|
3078
|
-
serverId:
|
|
3374
|
+
serverId: outcome.destination!.serverId,
|
|
3079
3375
|
channelId,
|
|
3080
|
-
delivered,
|
|
3376
|
+
delivered: true,
|
|
3081
3377
|
textLen: text.length,
|
|
3082
3378
|
text,
|
|
3083
|
-
|
|
3379
|
+
// Surface the posted message's id (ChannelsPublishResult.messageId) so
|
|
3380
|
+
// trace consumers can act on the just-posted message — e.g. a TTS-relay
|
|
3381
|
+
// tap editing it down to the words actually voiced on interruption.
|
|
3382
|
+
...(outcome.messageId !== undefined ? { messageId: outcome.messageId } : {}),
|
|
3084
3383
|
});
|
|
3384
|
+
return outcome;
|
|
3385
|
+
}
|
|
3085
3386
|
|
|
3086
|
-
|
|
3387
|
+
/** deliverSpeech, reduced to the confirmed delivery (null when there was none). */
|
|
3388
|
+
async routeSpeech(
|
|
3389
|
+
conversationId: string,
|
|
3390
|
+
text: string,
|
|
3391
|
+
locusChannelId: string | null,
|
|
3392
|
+
): Promise<{ delivered: boolean; channelId: string; messageId?: string } | null> {
|
|
3393
|
+
const outcome = await this.deliverSpeech(conversationId, text, locusChannelId);
|
|
3394
|
+
if (outcome.status !== 'delivered') return null;
|
|
3395
|
+
return {
|
|
3396
|
+
delivered: true,
|
|
3397
|
+
channelId: outcome.destination!.channelId,
|
|
3398
|
+
...(outcome.messageId !== undefined ? { messageId: outcome.messageId } : {}),
|
|
3399
|
+
};
|
|
3087
3400
|
}
|
|
3088
3401
|
|
|
3089
3402
|
private async handleToolPublish(input: { channelId?: string; content?: string; text?: string }): Promise<ToolResult> {
|
|
@@ -3125,31 +3438,44 @@ export class ChannelRegistry {
|
|
|
3125
3438
|
};
|
|
3126
3439
|
}
|
|
3127
3440
|
|
|
3128
|
-
|
|
3129
|
-
if (!CapabilityGrant.of(server).has('channels.publish')) {
|
|
3130
|
-
return {
|
|
3131
|
-
success: false,
|
|
3132
|
-
error: `channels.publish not in "${server.id}"'s effective grant (§14.1)`,
|
|
3133
|
-
isError: true,
|
|
3134
|
-
};
|
|
3135
|
-
}
|
|
3136
|
-
const publishParams: ChannelsPublishParams = {
|
|
3137
|
-
conversationId: '', // Framework will fill this when wired
|
|
3138
|
-
channelId,
|
|
3139
|
-
content: [{ type: 'text', text: messageText }],
|
|
3140
|
-
};
|
|
3141
|
-
|
|
3142
|
-
const result = await server.sendChannelsPublish(publishParams);
|
|
3143
|
-
return {
|
|
3144
|
-
success: true,
|
|
3145
|
-
data: result ?? { delivered: true },
|
|
3146
|
-
};
|
|
3147
|
-
} catch (err) {
|
|
3441
|
+
if (!CapabilityGrant.of(server).has('channels.publish')) {
|
|
3148
3442
|
return {
|
|
3149
3443
|
success: false,
|
|
3150
|
-
error: `
|
|
3444
|
+
error: `channels.publish not in "${server.id}"'s effective grant (§14.1)`,
|
|
3151
3445
|
isError: true,
|
|
3152
3446
|
};
|
|
3153
3447
|
}
|
|
3448
|
+
const publishParams: ChannelsPublishParams = {
|
|
3449
|
+
conversationId: '', // Framework will fill this when wired
|
|
3450
|
+
channelId,
|
|
3451
|
+
content: [{ type: 'text', text: messageText }],
|
|
3452
|
+
};
|
|
3453
|
+
const destination: PublishDestination = {
|
|
3454
|
+
serverId: entry.serverId,
|
|
3455
|
+
channelId: entry.descriptor.id,
|
|
3456
|
+
...(entry.descriptor.label ? { label: entry.descriptor.label } : {}),
|
|
3457
|
+
};
|
|
3458
|
+
|
|
3459
|
+
// The answer counts by the same rule as plain speech's: only the
|
|
3460
|
+
// connector's delivered:true confirms a post.
|
|
3461
|
+
let result: unknown;
|
|
3462
|
+
let outcome: PublishOutcome;
|
|
3463
|
+
try {
|
|
3464
|
+
result = await server.sendChannelsPublish(publishParams);
|
|
3465
|
+
outcome = publishReceiptOutcome(result, destination, Date.now());
|
|
3466
|
+
} catch (err) {
|
|
3467
|
+
outcome = publishErrorOutcome(err, destination, Date.now());
|
|
3468
|
+
}
|
|
3469
|
+
if (outcome.status === 'delivered') return { success: true, data: result };
|
|
3470
|
+
// The connector's data may say what a multi-part send already posted.
|
|
3471
|
+
const detail = outcome.status === 'unknown' && outcome.detail !== undefined ? ` Connector detail: ${connectorText(outcome.detail)}` : '';
|
|
3472
|
+
return {
|
|
3473
|
+
success: false,
|
|
3474
|
+
error: (outcome.status === 'failed'
|
|
3475
|
+
? `Publish to ${channelId} failed: ${outcome.reason}. Nothing was posted.`
|
|
3476
|
+
: `Publish to ${channelId} wasn't confirmed: ${outcome.reason}. ` +
|
|
3477
|
+
'It may or may not have been posted, so sending it again could post it twice.') + detail,
|
|
3478
|
+
isError: true,
|
|
3479
|
+
};
|
|
3154
3480
|
}
|
|
3155
3481
|
}
|