@animalabs/agent-framework 0.26.2 → 0.28.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +99 -8
- package/dist/src/agent.d.ts +291 -23
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +596 -61
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +5 -4
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/auto-continue.d.ts +34 -0
- package/dist/src/auto-continue.d.ts.map +1 -0
- package/dist/src/auto-continue.js +36 -0
- package/dist/src/auto-continue.js.map +1 -0
- package/dist/src/code-execution/isolate/scripts.d.ts +11 -0
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +5 -1
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/cut-off-round.d.ts +24 -0
- package/dist/src/cut-off-round.d.ts.map +1 -0
- package/dist/src/cut-off-round.js +87 -0
- package/dist/src/cut-off-round.js.map +1 -0
- package/dist/src/framework.d.ts +1038 -193
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +5967 -1514
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +405 -46
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +2646 -399
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +3 -2
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +2 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/recipe-reconcile.d.ts +103 -0
- package/dist/src/gate/recipe-reconcile.d.ts.map +1 -0
- package/dist/src/gate/recipe-reconcile.js +325 -0
- package/dist/src/gate/recipe-reconcile.js.map +1 -0
- package/dist/src/gate/reply-judge.d.ts +116 -0
- package/dist/src/gate/reply-judge.d.ts.map +1 -0
- package/dist/src/gate/reply-judge.js +467 -0
- package/dist/src/gate/reply-judge.js.map +1 -0
- package/dist/src/gate/types.d.ts +229 -8
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +184 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -0
- package/dist/src/heartbeat/heartbeat.js +752 -0
- package/dist/src/heartbeat/heartbeat.js.map +1 -0
- package/dist/src/heartbeat/reminder-time.d.ts +5 -0
- package/dist/src/heartbeat/reminder-time.d.ts.map +1 -0
- package/dist/src/heartbeat/reminder-time.js +107 -0
- package/dist/src/heartbeat/reminder-time.js.map +1 -0
- package/dist/src/index.d.ts +10 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-mask.d.ts.map +1 -1
- package/dist/src/mcpl/capability-mask.js +3 -2
- package/dist/src/mcpl/capability-mask.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +433 -113
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +1154 -435
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +16 -8
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +29 -15
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +14 -2
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +7 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +32 -7
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +26 -10
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +40 -69
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/index.d.ts +5 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +4 -0
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +14 -2
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js +73 -28
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +4 -0
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
- package/dist/src/mcpl/prose-grammar.js +6 -0
- package/dist/src/mcpl/prose-grammar.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +3 -0
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +20 -2
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +33 -11
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +63 -42
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +177 -145
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +380 -46
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +736 -77
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +93 -4
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +176 -11
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/tags.d.ts +9 -2
- package/dist/src/mcpl/tags.d.ts.map +1 -1
- package/dist/src/mcpl/tags.js +12 -2
- package/dist/src/mcpl/tags.js.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.d.ts +11 -0
- package/dist/src/mcpl/tool-lifecycle.d.ts.map +1 -1
- package/dist/src/mcpl/tool-lifecycle.js +21 -0
- package/dist/src/mcpl/tool-lifecycle.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts +311 -0
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -0
- package/dist/src/mcpl/tool-presence.js +697 -0
- package/dist/src/mcpl/tool-presence.js.map +1 -0
- package/dist/src/mcpl/tool-result-normalize.d.ts +9 -3
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -1
- package/dist/src/mcpl/tool-result-normalize.js +14 -6
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts +46 -0
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -0
- package/dist/src/mcpl/tool-signature.js +321 -0
- package/dist/src/mcpl/tool-signature.js.map +1 -0
- package/dist/src/mcpl/toolset-host.d.ts +251 -0
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -0
- package/dist/src/mcpl/toolset-host.js +720 -0
- package/dist/src/mcpl/toolset-host.js.map +1 -0
- package/dist/src/mcpl/toolsets-module.d.ts +83 -0
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -0
- package/dist/src/mcpl/toolsets-module.js +523 -0
- package/dist/src/mcpl/toolsets-module.js.map +1 -0
- package/dist/src/mcpl/transport.d.ts +2 -2
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +3 -2
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +24 -2
- 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 +7 -9
- package/dist/src/mcpl/visible-content.d.ts.map +1 -1
- package/dist/src/mcpl/visible-content.js +21 -9
- package/dist/src/mcpl/visible-content.js.map +1 -1
- package/dist/src/module-registry.d.ts +27 -9
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +77 -17
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/discord/index.js +1 -1
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +2 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +73 -28
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +108 -6
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +273 -57
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/workspace/answers.d.ts +22 -0
- package/dist/src/modules/workspace/answers.d.ts.map +1 -0
- package/dist/src/modules/workspace/answers.js +123 -0
- package/dist/src/modules/workspace/answers.js.map +1 -0
- package/dist/src/modules/workspace/branch-intent.d.ts +5 -3
- package/dist/src/modules/workspace/branch-intent.d.ts.map +1 -1
- package/dist/src/modules/workspace/branch-intent.js +6 -2
- package/dist/src/modules/workspace/branch-intent.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts +184 -0
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -0
- package/dist/src/modules/workspace/direct-write.js +417 -0
- package/dist/src/modules/workspace/direct-write.js.map +1 -0
- package/dist/src/modules/workspace/disk-agreement.d.ts +33 -11
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +48 -17
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/edit-text.d.ts +27 -12
- package/dist/src/modules/workspace/edit-text.d.ts.map +1 -1
- package/dist/src/modules/workspace/edit-text.js +61 -29
- package/dist/src/modules/workspace/edit-text.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +10 -0
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +21 -14
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +308 -78
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +2103 -720
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +75 -63
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +366 -180
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/read-page.d.ts +41 -0
- package/dist/src/modules/workspace/read-page.d.ts.map +1 -0
- package/dist/src/modules/workspace/read-page.js +219 -0
- package/dist/src/modules/workspace/read-page.js.map +1 -0
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +26 -16
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/result-text.d.ts +68 -0
- package/dist/src/modules/workspace/result-text.d.ts.map +1 -0
- package/dist/src/modules/workspace/result-text.js +94 -0
- package/dist/src/modules/workspace/result-text.js.map +1 -0
- package/dist/src/modules/workspace/sync.d.ts +9 -0
- package/dist/src/modules/workspace/sync.d.ts.map +1 -1
- package/dist/src/modules/workspace/sync.js +14 -0
- package/dist/src/modules/workspace/sync.js.map +1 -1
- package/dist/src/modules/workspace/text.d.ts +29 -12
- package/dist/src/modules/workspace/text.d.ts.map +1 -1
- package/dist/src/modules/workspace/text.js +35 -33
- package/dist/src/modules/workspace/text.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +137 -60
- 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.map +1 -1
- package/dist/src/modules/workspace/watcher.js +8 -3
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/prose-drafts.d.ts +4 -3
- package/dist/src/prose-drafts.d.ts.map +1 -1
- package/dist/src/prose-drafts.js +3 -2
- package/dist/src/prose-drafts.js.map +1 -1
- package/dist/src/reasoning-loss-notice.d.ts +23 -0
- package/dist/src/reasoning-loss-notice.d.ts.map +1 -0
- package/dist/src/reasoning-loss-notice.js +50 -0
- package/dist/src/reasoning-loss-notice.js.map +1 -0
- package/dist/src/reasoning-loss.d.ts +24 -0
- package/dist/src/reasoning-loss.d.ts.map +1 -0
- package/dist/src/reasoning-loss.js +102 -0
- package/dist/src/reasoning-loss.js.map +1 -0
- package/dist/src/send-tools.d.ts +3 -2
- package/dist/src/send-tools.d.ts.map +1 -1
- package/dist/src/send-tools.js +3 -2
- package/dist/src/send-tools.js.map +1 -1
- package/dist/src/sent-rows.d.ts +59 -0
- package/dist/src/sent-rows.d.ts.map +1 -0
- package/dist/src/sent-rows.js +145 -0
- package/dist/src/sent-rows.js.map +1 -0
- package/dist/src/silent-heartbeat.d.ts +17 -10
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/stable-hash.d.ts +3 -0
- package/dist/src/stable-hash.d.ts.map +1 -0
- package/dist/src/stable-hash.js +15 -0
- package/dist/src/stable-hash.js.map +1 -0
- package/dist/src/stored-injections.d.ts +99 -0
- package/dist/src/stored-injections.d.ts.map +1 -0
- package/dist/src/stored-injections.js +106 -0
- package/dist/src/stored-injections.js.map +1 -0
- package/dist/src/text-as-stored.d.ts +4 -3
- package/dist/src/text-as-stored.d.ts.map +1 -1
- package/dist/src/text-as-stored.js +4 -3
- package/dist/src/text-as-stored.js.map +1 -1
- package/dist/src/thinking-drops.d.ts +74 -0
- package/dist/src/thinking-drops.d.ts.map +1 -0
- package/dist/src/thinking-drops.js +96 -0
- package/dist/src/thinking-drops.js.map +1 -0
- package/dist/src/tool-args.d.ts +12 -0
- package/dist/src/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +35 -1
- package/dist/src/tool-args.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts +9 -8
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +9 -8
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +3 -1
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts +12 -6
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +44 -17
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +176 -24
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +411 -91
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +17 -9
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +84 -37
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +4 -1
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/types/agent.d.ts +217 -7
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +33 -9
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +39 -3
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +95 -9
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +91 -3
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/agent.ts +661 -67
- package/src/api/server.ts +5 -4
- package/src/auto-continue.ts +43 -0
- package/src/code-execution/isolate/scripts.ts +11 -3
- package/src/cut-off-round.ts +98 -0
- package/src/framework.ts +6168 -1540
- package/src/gate/event-gate.ts +2895 -405
- package/src/gate/index.ts +10 -1
- package/src/gate/recipe-reconcile.ts +355 -0
- package/src/gate/reply-judge.ts +512 -0
- package/src/gate/types.ts +234 -9
- package/src/heartbeat/heartbeat.ts +804 -0
- package/src/heartbeat/reminder-time.ts +107 -0
- package/src/index.ts +11 -4
- package/src/mcpl/capability-mask.ts +3 -2
- package/src/mcpl/channel-registry.ts +1222 -468
- package/src/mcpl/conversation-router.ts +34 -16
- package/src/mcpl/convert-block.ts +14 -1
- package/src/mcpl/hook-orchestrator.ts +33 -6
- package/src/mcpl/inbound-source.ts +42 -69
- package/src/mcpl/index.ts +6 -1
- package/src/mcpl/inference-router.ts +79 -34
- package/src/mcpl/prose-grammar.ts +7 -0
- package/src/mcpl/protocol-family.ts +2 -0
- package/src/mcpl/push-coalescer.ts +51 -13
- package/src/mcpl/reference-fetcher.ts +201 -162
- package/src/mcpl/references.ts +851 -77
- package/src/mcpl/server-connection.ts +189 -11
- package/src/mcpl/tags.ts +13 -2
- package/src/mcpl/tool-lifecycle.ts +21 -0
- package/src/mcpl/tool-presence.ts +716 -0
- package/src/mcpl/tool-result-normalize.ts +18 -6
- package/src/mcpl/tool-signature.ts +316 -0
- package/src/mcpl/toolset-host.ts +727 -0
- package/src/mcpl/toolsets-module.ts +545 -0
- package/src/mcpl/transport.ts +3 -2
- package/src/mcpl/types.ts +25 -2
- package/src/mcpl/visible-content.ts +22 -9
- package/src/module-registry.ts +85 -26
- package/src/modules/discord/index.ts +1 -1
- package/src/modules/history/index.ts +70 -30
- package/src/modules/history/semantic.ts +308 -54
- package/src/modules/workspace/answers.ts +133 -0
- package/src/modules/workspace/branch-intent.ts +10 -5
- package/src/modules/workspace/direct-write.ts +460 -0
- package/src/modules/workspace/disk-agreement.ts +52 -21
- package/src/modules/workspace/edit-text.ts +84 -35
- package/src/modules/workspace/effects.ts +22 -13
- package/src/modules/workspace/index.ts +2142 -723
- package/src/modules/workspace/observe.ts +381 -177
- package/src/modules/workspace/read-page.ts +228 -0
- package/src/modules/workspace/reconcile.ts +27 -15
- package/src/modules/workspace/result-text.ts +121 -0
- package/src/modules/workspace/sync.ts +16 -0
- package/src/modules/workspace/text.ts +58 -32
- package/src/modules/workspace/types.ts +137 -60
- package/src/modules/workspace/watcher.ts +8 -3
- package/src/prose-drafts.ts +4 -3
- package/src/reasoning-loss-notice.ts +62 -0
- package/src/reasoning-loss.ts +120 -0
- package/src/send-tools.ts +3 -2
- package/src/sent-rows.ts +162 -0
- package/src/silent-heartbeat.ts +17 -10
- package/src/stable-hash.ts +14 -0
- package/src/stored-injections.ts +131 -0
- package/src/text-as-stored.ts +4 -3
- package/src/thinking-drops.ts +135 -0
- package/src/tool-args.ts +34 -1
- package/src/tool-image-ledger.ts +9 -8
- package/src/tool-presentation.ts +3 -1
- package/src/tool-result-guard.ts +45 -17
- package/src/tool-result-history.ts +471 -90
- package/src/tune-out/coordinator.ts +80 -37
- package/src/tune-out/tools.ts +4 -1
- package/src/types/agent.ts +220 -7
- package/src/types/events.ts +33 -9
- package/src/types/framework.ts +36 -3
- package/src/types/module.ts +91 -9
- package/src/types/trace.ts +94 -3
|
@@ -219,6 +219,51 @@ function protocolVersionRejection(config: McplServerConfig, error: { code: numbe
|
|
|
219
219
|
|
|
220
220
|
const errorOf = (value: unknown): Error => (value instanceof Error ? value : new Error(String(value)));
|
|
221
221
|
|
|
222
|
+
/**
|
|
223
|
+
* The RFC-014 members of a server's advertisement (`toolHints`, `toolsets`,
|
|
224
|
+
* `surface`), read from it as the server sent it. They are declarations, not
|
|
225
|
+
* §6.2 capabilities: the host's capability mask, which reads every member as
|
|
226
|
+
* a capability, never applies to them. Null when the server advertised none
|
|
227
|
+
* of them, or no MCPL at all.
|
|
228
|
+
*/
|
|
229
|
+
export function toolsetDeclarationsOf(advertised: unknown): Record<string, unknown> | null {
|
|
230
|
+
if (advertised === null || typeof advertised !== 'object' || Array.isArray(advertised)) return null;
|
|
231
|
+
const { toolHints, toolsets, surface } = advertised as Record<string, unknown>;
|
|
232
|
+
if (toolHints === undefined && toolsets === undefined && surface === undefined) return null;
|
|
233
|
+
return {
|
|
234
|
+
...(toolHints !== undefined ? { toolHints } : {}),
|
|
235
|
+
...(toolsets !== undefined ? { toolsets } : {}),
|
|
236
|
+
...(surface !== undefined ? { surface } : {}),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/** What the RFC-014 read tap is handed as the connection reads a message
|
|
241
|
+
* that can carry hint changes (see McplServerConnection.setReadTap). */
|
|
242
|
+
export type HintRead =
|
|
243
|
+
/** A response to a request that can carry hints (RFC-014 §6.1 carrier 1),
|
|
244
|
+
* or a `tools/list`'s whole inventory (§4.1), its pages joined by
|
|
245
|
+
* sendToolsList, `straddled` when its pages carry different revs.
|
|
246
|
+
* `awaited`: whoever sent it still waits for it; false for a
|
|
247
|
+
* result that arrives after its timeout. A JSON-RPC error carries no state
|
|
248
|
+
* and isn't tapped. */
|
|
249
|
+
| { kind: 'result'; method: string; params: Record<string, unknown>; result: unknown; awaited: boolean; straddled?: boolean }
|
|
250
|
+
/** A push/event (carrier 2), as read, before the plane gate or the grant
|
|
251
|
+
* admit or refuse it. */
|
|
252
|
+
| { kind: 'push'; params: unknown }
|
|
253
|
+
/** A standalone tools/hints (carrier 3). */
|
|
254
|
+
| { kind: 'hints'; params: unknown };
|
|
255
|
+
|
|
256
|
+
/** Requests whose results can carry hint state, remembered for a late answer (RFC-014 §6.1). */
|
|
257
|
+
const HINTED_METHODS: ReadonlySet<string> = new Set(['tools/call', 'toolsets/open', 'toolsets/close', 'toolsets/list']);
|
|
258
|
+
|
|
259
|
+
function hintedParams(method: string, params: Record<string, unknown>): { toolset?: string; instance?: string } {
|
|
260
|
+
if (method !== 'toolsets/open' && method !== 'toolsets/close') return {};
|
|
261
|
+
return {
|
|
262
|
+
...(typeof params.toolset === 'string' ? { toolset: params.toolset } : {}),
|
|
263
|
+
...(typeof params.instance === 'string' ? { instance: params.instance } : {}),
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
222
267
|
/**
|
|
223
268
|
* A handshake that failed, and whose cleanup couldn't confirm that the child
|
|
224
269
|
* exited. The transport goes to whoever owns the launch.
|
|
@@ -295,6 +340,7 @@ interface PendingRequest {
|
|
|
295
340
|
resolve: (result: unknown) => void;
|
|
296
341
|
reject: (error: Error) => void;
|
|
297
342
|
method: string;
|
|
343
|
+
onRead?: (result: unknown) => void;
|
|
298
344
|
/** Per-request timeout timer; cleared on response/close/timeout. */
|
|
299
345
|
timer?: ReturnType<typeof setTimeout>;
|
|
300
346
|
}
|
|
@@ -304,6 +350,9 @@ interface RequestOptions {
|
|
|
304
350
|
timeoutMs?: number;
|
|
305
351
|
/** Surface a late response even when it carries no checkpoint state. */
|
|
306
352
|
surfaceOrphanedResponse?: boolean;
|
|
353
|
+
/** Called with a successful result as its response is read, before
|
|
354
|
+
* anything read after it and before the request's promise settles. */
|
|
355
|
+
onRead?: (result: unknown) => void;
|
|
307
356
|
}
|
|
308
357
|
|
|
309
358
|
/** A server→host message held while its plane is closed. `kept`: it came on
|
|
@@ -404,6 +453,49 @@ export class McplServerConnection extends EventEmitter {
|
|
|
404
453
|
* the epoch their opening went to, never across a reconnect. */
|
|
405
454
|
transportEpoch = 0;
|
|
406
455
|
|
|
456
|
+
/**
|
|
457
|
+
* RFC-014: the server's `toolHints`, `toolsets` and `surface` members as it
|
|
458
|
+
* advertised them at the last handshake (toolsetDeclarationsOf), or null.
|
|
459
|
+
* Read by the host's toolset controller; they grant nothing.
|
|
460
|
+
*/
|
|
461
|
+
toolsetDeclarations: Record<string, unknown> | null = null;
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* RFC-014 §6.1: hint changes apply as each message carrying them is read,
|
|
465
|
+
* in rev order (arrival order on stdio and WebSocket), whatever becomes of
|
|
466
|
+
* the message: a push the plane holds or the grant refuses, a result its
|
|
467
|
+
* caller stopped waiting for. The tap sees every such message of the
|
|
468
|
+
* current transport, synchronously, before anything routes it; a late
|
|
469
|
+
* answer's request is remembered past its timeout (hintedRequests, while
|
|
470
|
+
* no more than 1,000 hinted requests await an answer) so its hints still
|
|
471
|
+
* apply. Null (the default) taps nothing, and the connection
|
|
472
|
+
* behaves as it always has.
|
|
473
|
+
*/
|
|
474
|
+
private readTap: ((read: HintRead, epoch: number) => void) | null = null;
|
|
475
|
+
/** The hinted requests sent on this transport, by id, kept past a timeout
|
|
476
|
+
* so a late result is still tapped: each one's method, and an open's or
|
|
477
|
+
* close's toolset and instance, which are all the read of its result
|
|
478
|
+
* uses; never a call's arguments. Bounded. Cleared at each boundary,
|
|
479
|
+
* since the next transport numbers its requests afresh. */
|
|
480
|
+
private hintedRequests = new Map<string | number, { method: string; params: { toolset?: string; instance?: string } }>();
|
|
481
|
+
|
|
482
|
+
/** Install (or, with null, remove) the RFC-014 read tap (see readTap). */
|
|
483
|
+
setReadTap(tap: ((read: HintRead, epoch: number) => void) | null): void {
|
|
484
|
+
this.readTap = tap;
|
|
485
|
+
if (!tap) this.hintedRequests.clear();
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/** Hand a read to the tap, contained: a tap that throws is logged, and the
|
|
489
|
+
* message goes on its way as if there were none. */
|
|
490
|
+
private tap(read: HintRead): void {
|
|
491
|
+
if (!this.readTap) return;
|
|
492
|
+
try {
|
|
493
|
+
this.readTap(read, this.transportEpoch);
|
|
494
|
+
} catch (error) {
|
|
495
|
+
console.error(`[mcpl] ${this.id}: the tool-hints tap failed: ${logDetail(describeCause(error))}`);
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
407
499
|
/**
|
|
408
500
|
* §17 manifest tracking (host side of RFC-003): what this host actually
|
|
409
501
|
* fetched and acted on — never the server's announcement log (§17.10:
|
|
@@ -454,6 +546,8 @@ export class McplServerConnection extends EventEmitter {
|
|
|
454
546
|
// (connect-failed, reconnect-failed), the server's stderr, and
|
|
455
547
|
// orphaned-response audits.
|
|
456
548
|
this.replaceHeld(this.keepAcrossBoundary(this.bufferedEvents));
|
|
549
|
+
// The next transport numbers its requests afresh (RFC-014's tap).
|
|
550
|
+
this.hintedRequests.clear();
|
|
457
551
|
// RFC-007 §6.5: a filter is per connection epoch — after a reconnect the
|
|
458
552
|
// server sends it again, and until then receives metadata only.
|
|
459
553
|
this.toolObserveFilter = null;
|
|
@@ -1116,9 +1210,10 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1116
1210
|
owner.holdUnreaped(error.transport, error.cleanup);
|
|
1117
1211
|
throw new McplUnreapedLaunchError(owner, error.failure, error.cleanup);
|
|
1118
1212
|
}
|
|
1119
|
-
const { transport, capabilities, droppedCapabilities, mcpToolsAdvertised, protocolVersion } = established;
|
|
1213
|
+
const { transport, capabilities, droppedCapabilities, mcpToolsAdvertised, protocolVersion, toolsetDeclarations } = established;
|
|
1120
1214
|
|
|
1121
1215
|
const connection = new McplServerConnection(config.id, capabilities, transport);
|
|
1216
|
+
connection.toolsetDeclarations = toolsetDeclarations;
|
|
1122
1217
|
connection.droppedCapabilities = droppedCapabilities;
|
|
1123
1218
|
connection.mcpToolsAdvertised = mcpToolsAdvertised;
|
|
1124
1219
|
connection.protocolVersion = protocolVersion;
|
|
@@ -1172,7 +1267,7 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1172
1267
|
config: McplServerConfig,
|
|
1173
1268
|
hostCapabilities: McplHostCapabilities,
|
|
1174
1269
|
signal?: AbortSignal,
|
|
1175
|
-
): Promise<{ transport: McplTransport; capabilities: McplCapabilities | null; droppedCapabilities: ReadonlySet<string>; mcpToolsAdvertised: boolean; protocolVersion: string }> {
|
|
1270
|
+
): Promise<{ transport: McplTransport; capabilities: McplCapabilities | null; droppedCapabilities: ReadonlySet<string>; mcpToolsAdvertised: boolean; protocolVersion: string; toolsetDeclarations: Record<string, unknown> | null }> {
|
|
1176
1271
|
const closedWhileConnecting = () => new Error(`MCPL server "${config.id}" was closed while connecting`);
|
|
1177
1272
|
if (signal?.aborted) throw closedWhileConnecting();
|
|
1178
1273
|
let transport: McplTransport;
|
|
@@ -1362,7 +1457,10 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1362
1457
|
// listener of its own, in the continuation of this return, before any
|
|
1363
1458
|
// I/O callback can emit.
|
|
1364
1459
|
transport.off('error', logAfterSettled);
|
|
1365
|
-
return {
|
|
1460
|
+
return {
|
|
1461
|
+
transport, capabilities: scoped, droppedCapabilities: new Set(dropped), mcpToolsAdvertised, protocolVersion,
|
|
1462
|
+
toolsetDeclarations: toolsetDeclarationsOf(rawCapabilities),
|
|
1463
|
+
};
|
|
1366
1464
|
} catch (err) {
|
|
1367
1465
|
// Never leak the child / socket if the handshake fails. A cleanup that
|
|
1368
1466
|
// can't confirm the child exited is part of the failure, never
|
|
@@ -1538,7 +1636,7 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1538
1636
|
}
|
|
1539
1637
|
|
|
1540
1638
|
/** Send `channels/open` request and await result. It keeps a deadline as
|
|
1541
|
-
* channels/publish does: a delivery
|
|
1639
|
+
* channels/publish does: a delivery can open a closed channel before it
|
|
1542
1640
|
* publishes, so an open that is never answered would hold the delivery,
|
|
1543
1641
|
* and the turn that waits for it, for good. */
|
|
1544
1642
|
sendChannelsOpen(params: ChannelsOpenParams): Promise<ChannelsOpenResult> {
|
|
@@ -1627,22 +1725,40 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1627
1725
|
* read it as a complete page). A page that isn't well formed (no `tools` array, a cursor
|
|
1628
1726
|
* that isn't a string), or cursors that don't terminate (a repeat, or more
|
|
1629
1727
|
* than {@link MAX_TOOL_LIST_PAGES} pages), are errors, never a partial or
|
|
1630
|
-
* empty inventory published as complete.
|
|
1728
|
+
* empty inventory published as complete. The read tap (RFC-014) is handed
|
|
1729
|
+
* the complete inventory once, with the last page's `_meta`, as the last
|
|
1730
|
+
* page's response is read, before anything read after it; a list that
|
|
1731
|
+
* fails or times out hands it nothing. It's `straddled` when its pages
|
|
1732
|
+
* carry different `mcpl/rev`s.
|
|
1631
1733
|
*/
|
|
1632
1734
|
async sendToolsList(): Promise<{ tools: McpToolDefinition[] }> {
|
|
1633
1735
|
const tools: McpToolDefinition[] = [];
|
|
1634
1736
|
const seen = new Set<string>();
|
|
1635
1737
|
let cursor: string | undefined;
|
|
1636
1738
|
let first: Record<string, unknown> | undefined;
|
|
1739
|
+
const read: McpToolDefinition[] = [];
|
|
1740
|
+
const revs = new Set<unknown>();
|
|
1741
|
+
const onRead = (result: unknown) => {
|
|
1742
|
+
if (!result || typeof result !== 'object' || !Array.isArray((result as { tools?: unknown }).tools)) return;
|
|
1743
|
+
const r = result as { tools: McpToolDefinition[]; nextCursor?: unknown; _meta?: unknown };
|
|
1744
|
+
for (const t of r.tools) read.push(t);
|
|
1745
|
+
const rev = (r._meta as Record<string, unknown> | undefined)?.['mcpl/rev'];
|
|
1746
|
+
if (typeof rev === 'number') revs.add(rev);
|
|
1747
|
+
if (r.nextCursor !== undefined && r.nextCursor !== null) return;
|
|
1748
|
+
this.tap({
|
|
1749
|
+
kind: 'result', method: 'tools/list', params: {}, ...(revs.size > 1 ? { straddled: true } : {}),
|
|
1750
|
+
result: { tools: read, ...(r._meta !== undefined ? { _meta: r._meta } : {}) }, awaited: true,
|
|
1751
|
+
});
|
|
1752
|
+
};
|
|
1637
1753
|
for (let page = 0; page < MAX_TOOL_LIST_PAGES; page++) {
|
|
1638
|
-
const result = await this.sendRequest('tools/list', cursor === undefined ? {} : { cursor }) as Record<string, unknown> | null;
|
|
1754
|
+
const result = await this.sendRequest('tools/list', cursor === undefined ? {} : { cursor }, { onRead }) as Record<string, unknown> | null;
|
|
1639
1755
|
const malformed = (why: string) =>
|
|
1640
1756
|
new Error(`MCPL server "${this.id}" sent a malformed tools/list page ${page + 1}: ${why}`);
|
|
1641
1757
|
if (!result || typeof result !== 'object' || !Array.isArray(result.tools)) {
|
|
1642
1758
|
throw malformed('no tools array');
|
|
1643
1759
|
}
|
|
1644
1760
|
first ??= result;
|
|
1645
|
-
|
|
1761
|
+
for (const t of result.tools as McpToolDefinition[]) tools.push(t);
|
|
1646
1762
|
if (result.nextCursor === undefined || result.nextCursor === null) {
|
|
1647
1763
|
// The first page's other fields are kept as they came, so a
|
|
1648
1764
|
// single-page answer is returned exactly as before.
|
|
@@ -1662,18 +1778,39 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1662
1778
|
throw new Error(`MCPL server "${this.id}" tools/list did not finish within ${MAX_TOOL_LIST_PAGES} pages`);
|
|
1663
1779
|
}
|
|
1664
1780
|
|
|
1665
|
-
/** Send `tools/call` and return the result. Optionally includes
|
|
1781
|
+
/** Send `tools/call` and return the result. Optionally includes
|
|
1782
|
+
* state/checkpoint for stateful tools, and `_meta` (RFC-014 §5.5: the
|
|
1783
|
+
* instance a call is for rides in `_meta["mcpl/instance"]`). */
|
|
1666
1784
|
sendToolsCall(
|
|
1667
1785
|
name: string,
|
|
1668
1786
|
args: Record<string, unknown>,
|
|
1669
1787
|
stateParams?: { state?: unknown; checkpoint?: string },
|
|
1788
|
+
meta?: Record<string, unknown>,
|
|
1670
1789
|
): Promise<McpToolCallResult> {
|
|
1671
1790
|
const params: Record<string, unknown> = { name, arguments: args };
|
|
1672
1791
|
if (stateParams?.state !== undefined) params.state = stateParams.state;
|
|
1673
1792
|
if (stateParams?.checkpoint !== undefined) params.checkpoint = stateParams.checkpoint;
|
|
1793
|
+
if (meta !== undefined) params._meta = meta;
|
|
1674
1794
|
return this.sendRequest('tools/call', params) as Promise<McpToolCallResult>;
|
|
1675
1795
|
}
|
|
1676
1796
|
|
|
1797
|
+
/** RFC-014 §5.2 `toolsets/open` (Host → Server). The server's refusal
|
|
1798
|
+
* rejects, as any error answer does. */
|
|
1799
|
+
sendToolsetsOpen(params: { toolset: string; instance?: string; options?: Record<string, unknown> }, timeoutMs?: number): Promise<Record<string, unknown> | null> {
|
|
1800
|
+
return this.sendRequest('toolsets/open', { ...params }, timeoutMs === undefined ? {} : { timeoutMs }) as Promise<Record<string, unknown> | null>;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1803
|
+
/** RFC-014 §5.2 `toolsets/close` (Host → Server). */
|
|
1804
|
+
sendToolsetsClose(params: { toolset: string; instance?: string }, timeoutMs?: number): Promise<Record<string, unknown> | null> {
|
|
1805
|
+
return this.sendRequest('toolsets/close', { ...params }, timeoutMs === undefined ? {} : { timeoutMs }) as Promise<Record<string, unknown> | null>;
|
|
1806
|
+
}
|
|
1807
|
+
|
|
1808
|
+
/** RFC-014 §5.3 `toolsets/list` (Host → Server): what the principal has
|
|
1809
|
+
* open, and the full hint state of its dynamic tools. */
|
|
1810
|
+
sendToolsetsList(timeoutMs?: number): Promise<Record<string, unknown> | null> {
|
|
1811
|
+
return this.sendRequest('toolsets/list', {}, timeoutMs === undefined ? {} : { timeoutMs }) as Promise<Record<string, unknown> | null>;
|
|
1812
|
+
}
|
|
1813
|
+
|
|
1677
1814
|
/**
|
|
1678
1815
|
* Send a tools/call with a mandatory request-local deadline. This is used by
|
|
1679
1816
|
* durable external-side-effect accounting, whose safety bound must remain in
|
|
@@ -1940,7 +2077,7 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1940
2077
|
if (!permanent) this.scheduleReconnect();
|
|
1941
2078
|
return;
|
|
1942
2079
|
}
|
|
1943
|
-
const { transport, capabilities, droppedCapabilities, mcpToolsAdvertised, protocolVersion } = established;
|
|
2080
|
+
const { transport, capabilities, droppedCapabilities, mcpToolsAdvertised, protocolVersion, toolsetDeclarations } = established;
|
|
1944
2081
|
|
|
1945
2082
|
if (signal.aborted) {
|
|
1946
2083
|
// Closed by the host while the handshake finished: this launch never
|
|
@@ -1968,6 +2105,7 @@ export class McplServerConnection extends EventEmitter {
|
|
|
1968
2105
|
this.resetPolicyForTransportBoundary();
|
|
1969
2106
|
this.transport = transport;
|
|
1970
2107
|
this.capabilities = capabilities;
|
|
2108
|
+
this.toolsetDeclarations = toolsetDeclarations;
|
|
1971
2109
|
this.droppedCapabilities = droppedCapabilities;
|
|
1972
2110
|
this.mcpToolsAdvertised = mcpToolsAdvertised;
|
|
1973
2111
|
this.protocolVersion = protocolVersion;
|
|
@@ -2073,7 +2211,7 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2073
2211
|
}
|
|
2074
2212
|
|
|
2075
2213
|
return new Promise((resolve, reject) => {
|
|
2076
|
-
const pending: PendingRequest = { resolve, reject, method };
|
|
2214
|
+
const pending: PendingRequest = { resolve, reject, method, ...(options.onRead ? { onRead: options.onRead } : {}) };
|
|
2077
2215
|
const timeoutMs = options.timeoutMs ?? this.requestTimeoutMs;
|
|
2078
2216
|
if (timeoutMs > 0) {
|
|
2079
2217
|
pending.timer = setTimeout(() => {
|
|
@@ -2112,6 +2250,12 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2112
2250
|
pending.timer.unref?.();
|
|
2113
2251
|
}
|
|
2114
2252
|
this.pendingRequests.set(id, pending);
|
|
2253
|
+
// RFC-014: a request whose result can carry hints is remembered past
|
|
2254
|
+
// its timeout, so a late result's hints still apply (readTap).
|
|
2255
|
+
if (this.readTap && HINTED_METHODS.has(method)) {
|
|
2256
|
+
this.hintedRequests.set(id, { method, params: hintedParams(method, params) });
|
|
2257
|
+
if (this.hintedRequests.size > 1000) this.hintedRequests.delete(this.hintedRequests.keys().next().value!);
|
|
2258
|
+
}
|
|
2115
2259
|
try {
|
|
2116
2260
|
this.transport!.writeLine(line);
|
|
2117
2261
|
} catch (err) {
|
|
@@ -2120,6 +2264,7 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2120
2264
|
// method, id and the transport's words are the operator's, logged
|
|
2121
2265
|
// after the refusal, as refused() logs.
|
|
2122
2266
|
this.pendingRequests.delete(id);
|
|
2267
|
+
this.hintedRequests.delete(id);
|
|
2123
2268
|
if (pending.timer) clearTimeout(pending.timer);
|
|
2124
2269
|
reject(new McplRequestError(
|
|
2125
2270
|
`The request wasn't sent: this host couldn't write it to the "${this.id}" server, so nothing ran. Try again later.`,
|
|
@@ -2258,7 +2403,12 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2258
2403
|
private dispatchMessage(msg: JsonRpcRequest | JsonRpcResponse, epoch: number): void {
|
|
2259
2404
|
// Is this a response to one of our outbound requests?
|
|
2260
2405
|
if ('id' in msg && msg.id != null && !('method' in msg)) {
|
|
2261
|
-
|
|
2406
|
+
const late = epoch !== this.transportEpoch;
|
|
2407
|
+
// RFC-014: its hints apply as it's read, whether or not anyone still
|
|
2408
|
+
// waits for it. A dead transport's revs are its own, so a response
|
|
2409
|
+
// read after its boundary is never tapped.
|
|
2410
|
+
if (!late) this.tapResponse(msg as JsonRpcResponse);
|
|
2411
|
+
this.handleResponse(msg as JsonRpcResponse, late);
|
|
2262
2412
|
return;
|
|
2263
2413
|
}
|
|
2264
2414
|
|
|
@@ -2282,6 +2432,17 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2282
2432
|
return;
|
|
2283
2433
|
}
|
|
2284
2434
|
|
|
2435
|
+
// RFC-014 §6.1: a push's hints apply as it's read, before the plane gate
|
|
2436
|
+
// holds it or the grant refuses it. A standalone tools/hints is consumed
|
|
2437
|
+
// here when a tap listens (it needs no grant), and answered if it came as
|
|
2438
|
+
// a request; with no tap it stays a method this host doesn't handle.
|
|
2439
|
+
if (request.method === 'push/event') this.tap({ kind: 'push', params: request.params });
|
|
2440
|
+
else if (request.method === 'tools/hints' && this.readTap) {
|
|
2441
|
+
this.tap({ kind: 'hints', params: request.params });
|
|
2442
|
+
if (request.id != null) this.sendResponse(request.id, {});
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
|
|
2285
2446
|
const eventName = typeof request.method === 'string' && Object.hasOwn(McplServerConnection.METHOD_TO_EVENT, request.method)
|
|
2286
2447
|
? McplServerConnection.METHOD_TO_EVENT[request.method] : undefined;
|
|
2287
2448
|
|
|
@@ -2427,6 +2588,18 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2427
2588
|
return true;
|
|
2428
2589
|
}
|
|
2429
2590
|
|
|
2591
|
+
/** Tap a response to a hinted request (RFC-014): its result's hints, or a
|
|
2592
|
+
* list's statement, apply now, awaited or not. */
|
|
2593
|
+
private tapResponse(response: JsonRpcResponse): void {
|
|
2594
|
+
if (!this.readTap) return;
|
|
2595
|
+
const sent = this.hintedRequests.get(response.id);
|
|
2596
|
+
if (!sent) return;
|
|
2597
|
+
this.hintedRequests.delete(response.id);
|
|
2598
|
+
const result = response.result;
|
|
2599
|
+
if (response.error || result === null || typeof result !== 'object' || Array.isArray(result)) return;
|
|
2600
|
+
this.tap({ kind: 'result', method: sent.method, params: sent.params, result, awaited: this.pendingRequests.has(response.id) });
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2430
2603
|
/**
|
|
2431
2604
|
* Handle a JSON-RPC response by resolving/rejecting the corresponding pending request.
|
|
2432
2605
|
*/
|
|
@@ -2516,6 +2689,11 @@ export class McplServerConnection extends EventEmitter {
|
|
|
2516
2689
|
logValueRedacted(response.error.message, redact),
|
|
2517
2690
|
);
|
|
2518
2691
|
} else {
|
|
2692
|
+
try {
|
|
2693
|
+
pending.onRead?.(response.result);
|
|
2694
|
+
} catch (error) {
|
|
2695
|
+
console.error(`MCPL server "${this.id}": reading ${pending.method}'s result failed: ${logDetail(describeCause(error))}`);
|
|
2696
|
+
}
|
|
2519
2697
|
pending.resolve(response.result);
|
|
2520
2698
|
}
|
|
2521
2699
|
}
|
package/src/mcpl/tags.ts
CHANGED
|
@@ -21,8 +21,10 @@ const CORE_IMPLIES: Readonly<Record<string, readonly string[]>> = {
|
|
|
21
21
|
/**
|
|
22
22
|
* RFC-001 core tags that mark a message as being ABOUT the conversation
|
|
23
23
|
* rather than part of it: reactions (added or removed), edits and deletions
|
|
24
|
-
* of an existing message
|
|
25
|
-
*
|
|
24
|
+
* of an existing message, and (revision 3) `chat:system` notices from the
|
|
25
|
+
* platform or the place: a join, a pin, the weather changing in a world.
|
|
26
|
+
* These are markers, not turns — they must not clear explicit-send
|
|
27
|
+
* suppression, count as a new conversational round, or
|
|
26
28
|
* retarget the default publish channel. An edit can also be the first
|
|
27
29
|
* version of a message the agent sees, and then counts as that message:
|
|
28
30
|
* isMarkerTagged reads the host's mark for the case the coalescer knows
|
|
@@ -36,6 +38,7 @@ export const NON_CONVERSATIONAL_TAGS: ReadonlySet<string> = new Set([
|
|
|
36
38
|
'chat:reaction-remove',
|
|
37
39
|
'chat:edited',
|
|
38
40
|
'chat:deleted',
|
|
41
|
+
'chat:system',
|
|
39
42
|
]);
|
|
40
43
|
|
|
41
44
|
/** True when a (possibly untyped) tag list carries a non-conversational marker tag. */
|
|
@@ -54,11 +57,19 @@ export function isMarkerTagged(tags: unknown, firstView: boolean): boolean {
|
|
|
54
57
|
return hasNonConversationalTag(firstView && Array.isArray(tags) ? tags.filter((t) => t !== 'chat:edited') : tags);
|
|
55
58
|
}
|
|
56
59
|
|
|
60
|
+
/** True when a (possibly untyped) tag list marks a `chat:system` notice: an
|
|
61
|
+
* event about the place, not a message anyone sent (RFC-001 rev 3). */
|
|
62
|
+
export function isSystemNotice(tags: unknown): boolean {
|
|
63
|
+
return Array.isArray(tags) && tags.includes('chat:system');
|
|
64
|
+
}
|
|
65
|
+
|
|
57
66
|
/**
|
|
58
67
|
* Expand a raw tag list over the normative core closure, then resolve the
|
|
59
68
|
* §16.2 mutual exclusion: `chat:addressed` and `chat:ambient` cannot both
|
|
60
69
|
* stand after expansion, and addressed wins — a message that is both
|
|
61
70
|
* specifically-to-you and background noise is specifically-to-you.
|
|
71
|
+
* `chat:system` is another facet (kind, not addressing) and stands beside
|
|
72
|
+
* either: a pin in a DM is addressed by its place and still a notice.
|
|
62
73
|
*
|
|
63
74
|
* Pure; input order is preserved for the tags that survive, with implied
|
|
64
75
|
* tags appended in first-cause order. Unknown and producer-namespaced tags
|
|
@@ -705,6 +705,27 @@ export class ToolLifecycleEmitter {
|
|
|
705
705
|
});
|
|
706
706
|
}
|
|
707
707
|
|
|
708
|
+
/**
|
|
709
|
+
* A call the host routes to another tool before it executes it: RFC-014's
|
|
710
|
+
* `toolsets--act`, which calls a server's dynamic tool. Until it opens, the
|
|
711
|
+
* call is described as that tool, with that tool's arguments, class and
|
|
712
|
+
* provider, so observers see (and narrowing, filters and class rules apply
|
|
713
|
+
* to) what actually runs, as for a direct call of it. Its ids stay.
|
|
714
|
+
*/
|
|
715
|
+
retarget(agentName: string, callId: string, call: { name: string; input: unknown }): void {
|
|
716
|
+
const tracked = this.calls.get(callKey(agentName, callId));
|
|
717
|
+
if (!tracked || tracked.opened) return;
|
|
718
|
+
const described = this.host.describe(call.name);
|
|
719
|
+
const { serverId: _serverId, serverTool: _serverTool, ...kept } = tracked.call;
|
|
720
|
+
tracked.call = {
|
|
721
|
+
...kept,
|
|
722
|
+
tool: call.name,
|
|
723
|
+
class: described.class,
|
|
724
|
+
...(described.serverId !== undefined ? { serverId: described.serverId, serverTool: described.serverTool } : {}),
|
|
725
|
+
input: call.input,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
|
|
708
729
|
/**
|
|
709
730
|
* The host refused the call before executing it — its provider is gone,
|
|
710
731
|
* host tool policy denies it, a conversation-bound agent reached outside
|