@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
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
* An MCP result has two views, and each consumer gets its own:
|
|
8
8
|
* - **The content array is the server's model-facing view.** Text stays text,
|
|
9
9
|
* and an inline image stays native when a provider can take it: one of the
|
|
10
|
-
* types providers accept, within
|
|
10
|
+
* types providers accept, within the framework's own per-image limit. That
|
|
11
|
+
* limit applies to every image this reading carries, whichever route it goes
|
|
12
|
+
* to: it's kept for providers that enforce one, though some routes take
|
|
13
|
+
* more. Anything else the
|
|
11
14
|
* provider format can't carry (audio, binary blobs, other images) is saved
|
|
12
15
|
* to the workspace, and a bounded stub says where it went. A stub tells the
|
|
13
16
|
* reader where the payload is; nothing is dropped silently. If a payload
|
|
@@ -48,8 +51,13 @@ const STUB_FIELD_POINTS = 200;
|
|
|
48
51
|
const URI_POINTS = 2048;
|
|
49
52
|
/** The image types providers take inline. Any other image is saved. */
|
|
50
53
|
const NATIVE_IMAGE_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
|
|
51
|
-
/**
|
|
52
|
-
*
|
|
54
|
+
/** This reading's per-image limit on decoded size, applied to every image it
|
|
55
|
+
* carries, whichever route it goes to: a larger image is shown as a stub, and
|
|
56
|
+
* saved to the workspace where it can be (payloadStub). It's kept for
|
|
57
|
+
* providers that enforce one, though some routes take more. The framework's
|
|
58
|
+
* read_image tool refuses an image past the same 5 MB. The RFC-005 lanes (an
|
|
59
|
+
* MCPL peer's or a module's content, and the push lanes) hold an image to no
|
|
60
|
+
* such limit. */
|
|
53
61
|
const NATIVE_IMAGE_MAX_BYTES = 5 * 1024 * 1024;
|
|
54
62
|
|
|
55
63
|
/** Why a payload isn't shown inline, unless said otherwise. */
|
|
@@ -136,13 +144,17 @@ export interface StandardToolResult {
|
|
|
136
144
|
* Content that is present but isn't a list of blocks makes it a malformed
|
|
137
145
|
* result, never an empty success. A tool's error result with no words, or
|
|
138
146
|
* only whitespace, reads as `noWords`, which the framework words for its
|
|
139
|
-
* server and tool.
|
|
147
|
+
* server and tool. A payload stub with no `save` says why nothing could
|
|
148
|
+
* keep it in `noSave`: no workspace mounted unless the caller words it
|
|
149
|
+
* otherwise, as the framework does for a host whose only writable mount
|
|
150
|
+
* is direct.
|
|
140
151
|
*/
|
|
141
152
|
export async function normalizeStandardToolResult(
|
|
142
153
|
result: StandardToolResult,
|
|
143
154
|
label: string,
|
|
144
155
|
save: SaveToolPayload | null,
|
|
145
156
|
noWords = 'Tool call failed',
|
|
157
|
+
noSave = 'no workspace is mounted to save it',
|
|
146
158
|
): Promise<ToolResult> {
|
|
147
159
|
const malformed = result.content !== undefined && !Array.isArray(result.content);
|
|
148
160
|
const raw: unknown[] = Array.isArray(result.content) ? result.content : [];
|
|
@@ -162,7 +174,7 @@ export async function normalizeStandardToolResult(
|
|
|
162
174
|
const what = `[${kind}${opts.origin ? ` ${bounded(opts.origin, URI_POINTS)}` : ''}: ${bounded(mimeType)}, ${size}`;
|
|
163
175
|
if (!save) {
|
|
164
176
|
lost++;
|
|
165
|
-
return `${what}. Not retained: ${why}, and
|
|
177
|
+
return `${what}. Not retained: ${why}, and ${noSave}]`;
|
|
166
178
|
}
|
|
167
179
|
const fileName = `${label}-${++saved}.${extensionFor(mimeType)}`;
|
|
168
180
|
const path = await save(fileName, Buffer.from(base64, 'base64'), mimeType).catch((error: unknown) => {
|
|
@@ -202,7 +214,7 @@ export async function normalizeStandardToolResult(
|
|
|
202
214
|
// provider may refuse, and with it the whole request.
|
|
203
215
|
blocks.push({ type: 'image', data: block.data.replace(/\s+/g, ''), mimeType: native });
|
|
204
216
|
} else {
|
|
205
|
-
const why = native ? `over the ${humanSize(NATIVE_IMAGE_MAX_BYTES)}
|
|
217
|
+
const why = native ? `over the ${humanSize(NATIVE_IMAGE_MAX_BYTES)} this host sends inline per image` : UNSUPPORTED;
|
|
206
218
|
blocks.push({ type: 'text', text: await payloadStub(kind, block.data, mimeType, { why }) });
|
|
207
219
|
}
|
|
208
220
|
break;
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a dynamic tool reads to a model when it reaches the conversation
|
|
3
|
+
* instead of the tool list (MCPL RFC-014 §8.3): a compact signature, its
|
|
4
|
+
* first sentence the first time a definition is shown, and on request its
|
|
5
|
+
* description, input schema and class. Also the host's own argument check
|
|
6
|
+
* against a tool's current definition (RFC-014 §6.1: "the host checks
|
|
7
|
+
* arguments for that instance against it").
|
|
8
|
+
*
|
|
9
|
+
* Ported from mcpl-cc-bridge's tool-render.ts and schema-check.ts, the
|
|
10
|
+
* reference host of RFC-014. Dependency-free.
|
|
11
|
+
*/
|
|
12
|
+
import { createHash } from 'node:crypto';
|
|
13
|
+
|
|
14
|
+
export type JsonSchema = Record<string, unknown>;
|
|
15
|
+
|
|
16
|
+
/** A tool definition as a server lists it (MCP), with its `_meta` hints. */
|
|
17
|
+
export interface HintedTool {
|
|
18
|
+
name: string;
|
|
19
|
+
description?: string;
|
|
20
|
+
inputSchema?: unknown;
|
|
21
|
+
annotations?: unknown;
|
|
22
|
+
_meta?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const isObj = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
26
|
+
|
|
27
|
+
/** How deep a server's value may nest and still be written out, the same on every runtime. */
|
|
28
|
+
const DEEPEST = 64;
|
|
29
|
+
|
|
30
|
+
function nestsWithin(value: unknown, depth = 0): boolean {
|
|
31
|
+
if (value === null || typeof value !== 'object') return true;
|
|
32
|
+
return depth <= DEEPEST && Object.values(value).every((v) => nestsWithin(v, depth + 1));
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/** A schema's literal value (an enum's, a const or a default) as JSON, or … where it's nested too deeply to write. */
|
|
36
|
+
function literal(value: unknown): string {
|
|
37
|
+
return nestsWithin(value) ? JSON.stringify(value) ?? 'null' : '…';
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function typeSig(schema: JsonSchema | undefined, depth = 0): string {
|
|
41
|
+
if (!schema || typeof schema !== 'object') return 'any';
|
|
42
|
+
if (depth > 8) return '…';
|
|
43
|
+
if (Array.isArray(schema.enum)) {
|
|
44
|
+
// The enum is often the menu (a decision's options): all of it unless it is long.
|
|
45
|
+
const vals = (schema.enum as unknown[]).map(literal);
|
|
46
|
+
if (vals.length <= 8 || vals.join('|').length <= 400) return vals.join('|');
|
|
47
|
+
let shown = 0;
|
|
48
|
+
let len = 0;
|
|
49
|
+
while (shown < vals.length && len + vals[shown]!.length < 300) {
|
|
50
|
+
len += vals[shown]!.length + 1;
|
|
51
|
+
shown++;
|
|
52
|
+
}
|
|
53
|
+
return `${vals.slice(0, Math.max(shown, 4)).join('|')}|…(${vals.length} in all)`;
|
|
54
|
+
}
|
|
55
|
+
if (schema.const !== undefined) return literal(schema.const);
|
|
56
|
+
const alts = (schema.oneOf ?? schema.anyOf) as JsonSchema[] | undefined;
|
|
57
|
+
if (Array.isArray(alts)) return alts.map((s) => typeSig(s, depth + 1)).join(' | ');
|
|
58
|
+
// Only text names a type: entries that aren't text are left out, and a type with none reads as no type.
|
|
59
|
+
const types = (Array.isArray(schema.type) ? schema.type : [schema.type]).filter((x): x is string => typeof x === 'string');
|
|
60
|
+
const t = types.length ? types.join('|') : undefined;
|
|
61
|
+
switch (t) {
|
|
62
|
+
case 'integer':
|
|
63
|
+
case 'number': {
|
|
64
|
+
const base = t === 'integer' ? 'int' : 'number';
|
|
65
|
+
const lo = typeof schema.minimum === 'number' ? schema.minimum : undefined;
|
|
66
|
+
const hi = typeof schema.maximum === 'number' ? schema.maximum : undefined;
|
|
67
|
+
if (lo !== undefined && hi !== undefined) return `${base} ${lo}..${hi}`;
|
|
68
|
+
if (lo !== undefined) return `${base} ≥${lo}`;
|
|
69
|
+
if (hi !== undefined) return `${base} ≤${hi}`;
|
|
70
|
+
return base;
|
|
71
|
+
}
|
|
72
|
+
case 'array': {
|
|
73
|
+
const inner = typeSig(schema.items as JsonSchema | undefined, depth + 1);
|
|
74
|
+
const wrapped = /[ |]/.test(inner) && !inner.startsWith('{') ? `(${inner})` : inner;
|
|
75
|
+
const max = typeof schema.maxItems === 'number' ? `≤${schema.maxItems}` : '';
|
|
76
|
+
return `${wrapped}[${max}]`;
|
|
77
|
+
}
|
|
78
|
+
case 'object': {
|
|
79
|
+
const props = schema.properties as Record<string, JsonSchema> | undefined;
|
|
80
|
+
if (!isObj(props) || Object.keys(props).length === 0) return 'object';
|
|
81
|
+
if (depth >= 3) return '{…}';
|
|
82
|
+
const req = new Set(Array.isArray(schema.required) ? (schema.required as string[]) : []);
|
|
83
|
+
return `{${Object.entries(props).map(([k, v]) => `${k}${req.has(k) ? '' : '?'}: ${typeSig(v, depth + 1)}`).join(', ')}}`;
|
|
84
|
+
}
|
|
85
|
+
case undefined:
|
|
86
|
+
return 'any';
|
|
87
|
+
default:
|
|
88
|
+
return t;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const schemaOf = (tool: HintedTool): JsonSchema => (isObj(tool.inputSchema) ? tool.inputSchema : {});
|
|
93
|
+
|
|
94
|
+
/** `play(point: string)`, `move(forward?: int -10..10 =0, turn?: int)` */
|
|
95
|
+
export function signature(tool: HintedTool): string {
|
|
96
|
+
const s = schemaOf(tool);
|
|
97
|
+
const props = (isObj(s.properties) ? s.properties : {}) as Record<string, JsonSchema>;
|
|
98
|
+
const req = new Set(Array.isArray(s.required) ? (s.required as string[]) : []);
|
|
99
|
+
const params = Object.entries(props).map(([k, v]) => {
|
|
100
|
+
const def = isObj(v) && v.default !== undefined ? ` =${literal(v.default)}` : '';
|
|
101
|
+
return `${k}${req.has(k) ? '' : '?'}: ${typeSig(v, 1)}${def}`;
|
|
102
|
+
});
|
|
103
|
+
return `${tool.name}(${params.join(', ')})`;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** An options schema as `{size?: 9|13|19 =9, …}` (a toolset's options). */
|
|
107
|
+
export function objectSignature(schema: unknown): string {
|
|
108
|
+
const inner = signature({ name: '', inputSchema: schema }).slice(1, -1);
|
|
109
|
+
return inner ? `{${inner}}` : '{}';
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** First sentence of a description, bounded. */
|
|
113
|
+
export function firstSentence(text: unknown, max = 140): string {
|
|
114
|
+
const t = (typeof text === 'string' ? text : '').trim().replace(/\s+/g, ' ');
|
|
115
|
+
// A sentence ends at . ! ? followed by a capital, a bracket, or the end, so "e.g. \"D4\"" does not end it.
|
|
116
|
+
const m = t.match(/^(.+?[.!?])(?=\s+[A-Z([]|$)/);
|
|
117
|
+
const s = [...(m ? m[1]! : t)];
|
|
118
|
+
return s.length > max ? s.slice(0, max - 1).join('') + '…' : s.join('');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function canonicalJson(value: unknown, depth = 0): string {
|
|
122
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value) ?? 'null';
|
|
123
|
+
if (depth > DEEPEST) return '"…"';
|
|
124
|
+
if (Array.isArray(value)) return `[${value.map((v) => canonicalJson(v, depth + 1)).join(',')}]`;
|
|
125
|
+
const obj = value as Record<string, unknown>;
|
|
126
|
+
return `{${Object.keys(obj)
|
|
127
|
+
.sort()
|
|
128
|
+
.filter((k) => obj[k] !== undefined)
|
|
129
|
+
.map((k) => `${JSON.stringify(k)}:${canonicalJson(obj[k], depth + 1)}`)
|
|
130
|
+
.join(',')}}`;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Identity of a definition as the model reads it (name, description, schema). */
|
|
134
|
+
export function toolDigest(tool: HintedTool): string {
|
|
135
|
+
return createHash('sha256')
|
|
136
|
+
.update(canonicalJson({ name: tool.name, description: tool.description ?? '', inputSchema: tool.inputSchema ?? null }))
|
|
137
|
+
.digest('base64url')
|
|
138
|
+
.slice(0, 22);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** The definitions a model has been shown, by digest: has and add are all rendering needs. */
|
|
142
|
+
export type Shown = { has(digest: string): boolean; add(digest: string): void };
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Tool lines as the model reads them. A definition the model has been shown
|
|
146
|
+
* gets its signature only; a new or changed one also gets its first
|
|
147
|
+
* sentence. `shown` is updated.
|
|
148
|
+
*/
|
|
149
|
+
export function renderToolLines(tools: HintedTool[], shown: Shown, opts: { describeAll?: boolean; indent?: string } = {}): string[] {
|
|
150
|
+
const indent = opts.indent ?? ' ';
|
|
151
|
+
return tools.map((t) => {
|
|
152
|
+
const d = toolDigest(t);
|
|
153
|
+
const describe = opts.describeAll || !shown.has(d);
|
|
154
|
+
shown.add(d);
|
|
155
|
+
const sentence = describe ? firstSentence(t.description) : '';
|
|
156
|
+
return `${indent}${signature(t)}${sentence ? ` — ${sentence}` : ''}`;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** A server's value as JSON, or a note where it's nested too deeply, or too long, to show. */
|
|
161
|
+
export function jsonText(value: unknown, space?: number): string {
|
|
162
|
+
if (!nestsWithin(value)) return '(nested too deeply to show)';
|
|
163
|
+
try {
|
|
164
|
+
return JSON.stringify(value, null, space) ?? '';
|
|
165
|
+
} catch {
|
|
166
|
+
return '(too long to show)';
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/** A tool's signature, description, class and input schema, for `look` naming a tool. */
|
|
171
|
+
export function renderToolDefinition(tool: HintedTool): string {
|
|
172
|
+
const cls = tool._meta?.['mcpl/class'];
|
|
173
|
+
const classes = Array.isArray(cls) ? cls.filter((c): c is string => typeof c === 'string') : [];
|
|
174
|
+
return [
|
|
175
|
+
signature(tool),
|
|
176
|
+
typeof tool.description === 'string' ? tool.description : '',
|
|
177
|
+
...(classes.length ? [`class: ${classes.join(', ')}`] : []),
|
|
178
|
+
'inputSchema:',
|
|
179
|
+
jsonText(tool.inputSchema ?? {}, 2),
|
|
180
|
+
]
|
|
181
|
+
.filter((l) => l !== '')
|
|
182
|
+
.join('\n');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// ── Argument checks ──────────────────────────────────────────────────────────
|
|
186
|
+
//
|
|
187
|
+
// A deliberate subset of JSON Schema: type, enum, const, required, properties,
|
|
188
|
+
// additionalProperties, items, min/maxItems, minimum, maximum,
|
|
189
|
+
// exclusiveMinimum/Maximum, min/maxLength, anyOf, oneOf, allOf. Anything else
|
|
190
|
+
// isn't checked, so the check can only fail to refuse what the server would
|
|
191
|
+
// refuse on those keywords, never refuse what it would accept; the server
|
|
192
|
+
// checks every call itself.
|
|
193
|
+
//
|
|
194
|
+
// The schema is the server's, so its cost is bounded here: `pattern` is never
|
|
195
|
+
// evaluated (a server's regular expression run on the host's event loop could
|
|
196
|
+
// backtrack for as long as it likes), and a schema nested deeper than
|
|
197
|
+
// MAX_CHECK_DEPTH, or whose check would take more than MAX_CHECK_STEPS steps
|
|
198
|
+
// (anyOf fan-out, a long enum), isn't checked at all.
|
|
199
|
+
|
|
200
|
+
/** Schema levels the check descends before it gives up and lets the server decide. */
|
|
201
|
+
export const MAX_CHECK_DEPTH = 24;
|
|
202
|
+
/** Schema nodes and enum entries the check visits before it gives up. */
|
|
203
|
+
export const MAX_CHECK_STEPS = 5_000;
|
|
204
|
+
|
|
205
|
+
const OVER_BUDGET: unique symbol = Symbol('over budget');
|
|
206
|
+
|
|
207
|
+
function typeOk(t: string, v: unknown): boolean {
|
|
208
|
+
switch (t) {
|
|
209
|
+
case 'object':
|
|
210
|
+
return isObj(v);
|
|
211
|
+
case 'array':
|
|
212
|
+
return Array.isArray(v);
|
|
213
|
+
case 'string':
|
|
214
|
+
return typeof v === 'string';
|
|
215
|
+
case 'number':
|
|
216
|
+
return typeof v === 'number' && Number.isFinite(v);
|
|
217
|
+
case 'integer':
|
|
218
|
+
return Number.isInteger(v);
|
|
219
|
+
case 'boolean':
|
|
220
|
+
return typeof v === 'boolean';
|
|
221
|
+
case 'null':
|
|
222
|
+
return v === null;
|
|
223
|
+
default:
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* The first problem with `value` against `schema`, as a short phrase naming
|
|
230
|
+
* where; null when it fits, or when the schema is past the check's bounds
|
|
231
|
+
* (the server decides those).
|
|
232
|
+
*/
|
|
233
|
+
export function checkArgs(schema: unknown, value: unknown): string | null {
|
|
234
|
+
const budget = { steps: 0 };
|
|
235
|
+
try {
|
|
236
|
+
return check(schema, value, 'args', 0, budget);
|
|
237
|
+
} catch (error) {
|
|
238
|
+
if (error === OVER_BUDGET) return null;
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function spend(budget: { steps: number }, steps: number): void {
|
|
244
|
+
budget.steps += steps;
|
|
245
|
+
if (budget.steps > MAX_CHECK_STEPS) throw OVER_BUDGET;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function check(schema: unknown, value: unknown, at: string, depth: number, budget: { steps: number }): string | null {
|
|
249
|
+
if (!isObj(schema)) return null;
|
|
250
|
+
if (depth > MAX_CHECK_DEPTH) throw OVER_BUDGET;
|
|
251
|
+
spend(budget, 1);
|
|
252
|
+
const s = schema;
|
|
253
|
+
if (s.type !== undefined) {
|
|
254
|
+
const types = Array.isArray(s.type) ? (s.type as string[]) : [s.type as string];
|
|
255
|
+
if (!types.some((t) => typeOk(t, value))) return `${at}: must be ${types.join(' or ')}`;
|
|
256
|
+
}
|
|
257
|
+
if (Array.isArray(s.enum) || s.const !== undefined) {
|
|
258
|
+
const own = canonicalJson(value);
|
|
259
|
+
if (Array.isArray(s.enum)) {
|
|
260
|
+
spend(budget, s.enum.length);
|
|
261
|
+
if (!s.enum.some((e) => canonicalJson(e) === own)) return `${at}: must be one of ${s.enum.map((e) => JSON.stringify(e)).join('|')}`;
|
|
262
|
+
}
|
|
263
|
+
if (s.const !== undefined && canonicalJson(s.const) !== own) return `${at}: must be ${JSON.stringify(s.const)}`;
|
|
264
|
+
}
|
|
265
|
+
if (typeof value === 'string') {
|
|
266
|
+
const n = [...value].length;
|
|
267
|
+
if (typeof s.minLength === 'number' && n < s.minLength) return `${at}: at least ${s.minLength} characters`;
|
|
268
|
+
if (typeof s.maxLength === 'number' && n > s.maxLength) return `${at}: at most ${s.maxLength} characters`;
|
|
269
|
+
}
|
|
270
|
+
if (typeof value === 'number') {
|
|
271
|
+
if (typeof s.minimum === 'number' && value < s.minimum) return `${at}: at least ${s.minimum}`;
|
|
272
|
+
if (typeof s.maximum === 'number' && value > s.maximum) return `${at}: at most ${s.maximum}`;
|
|
273
|
+
if (typeof s.exclusiveMinimum === 'number' && value <= s.exclusiveMinimum) return `${at}: more than ${s.exclusiveMinimum}`;
|
|
274
|
+
if (typeof s.exclusiveMaximum === 'number' && value >= s.exclusiveMaximum) return `${at}: less than ${s.exclusiveMaximum}`;
|
|
275
|
+
}
|
|
276
|
+
if (Array.isArray(value)) {
|
|
277
|
+
if (typeof s.minItems === 'number' && value.length < s.minItems) return `${at}: at least ${s.minItems} items`;
|
|
278
|
+
if (typeof s.maxItems === 'number' && value.length > s.maxItems) return `${at}: at most ${s.maxItems} items`;
|
|
279
|
+
if (isObj(s.items)) {
|
|
280
|
+
for (let i = 0; i < value.length; i++) {
|
|
281
|
+
const e = check(s.items, value[i], `${at}[${i}]`, depth + 1, budget);
|
|
282
|
+
if (e) return e;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
if (isObj(value)) {
|
|
287
|
+
const props = isObj(s.properties) ? s.properties : {};
|
|
288
|
+
for (const r of Array.isArray(s.required) ? (s.required as unknown[]) : []) {
|
|
289
|
+
if (typeof r === 'string' && !Object.hasOwn(value, r)) return `${at}.${r}: required`;
|
|
290
|
+
}
|
|
291
|
+
for (const [k, v] of Object.entries(value)) {
|
|
292
|
+
if (Object.hasOwn(props, k)) {
|
|
293
|
+
const e = check(props[k], v, `${at}.${k}`, depth + 1, budget);
|
|
294
|
+
if (e) return e;
|
|
295
|
+
} else if (s.additionalProperties === false) {
|
|
296
|
+
return `${at}.${k}: not an argument of this tool`;
|
|
297
|
+
} else if (isObj(s.additionalProperties)) {
|
|
298
|
+
const e = check(s.additionalProperties, v, `${at}.${k}`, depth + 1, budget);
|
|
299
|
+
if (e) return e;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
for (const k of ['anyOf', 'oneOf'] as const) {
|
|
304
|
+
const alts = s[k];
|
|
305
|
+
if (Array.isArray(alts) && alts.length && !alts.some((a) => check(a, value, at, depth + 1, budget) === null)) {
|
|
306
|
+
return check(alts[0], value, at, depth + 1, budget) ?? `${at}: fits none of the allowed forms`;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
if (Array.isArray(s.allOf)) {
|
|
310
|
+
for (const a of s.allOf) {
|
|
311
|
+
const e = check(a, value, at, depth + 1, budget);
|
|
312
|
+
if (e) return e;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|