@animalabs/agent-framework 0.28.0 → 0.30.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 +88 -25
- package/dist/src/admission/admit.d.ts +90 -0
- package/dist/src/admission/admit.d.ts.map +1 -0
- package/dist/src/admission/admit.js +43 -0
- package/dist/src/admission/admit.js.map +1 -0
- package/dist/src/agent.d.ts +21 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +47 -7
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.d.ts.map +1 -1
- package/dist/src/api/mcp-server-core.js +3 -12
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +7 -3
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/author-presentation.d.ts +50 -0
- package/dist/src/author-presentation.d.ts.map +1 -0
- package/dist/src/author-presentation.js +58 -0
- package/dist/src/author-presentation.js.map +1 -0
- package/dist/src/auto-continue.d.ts +2 -0
- package/dist/src/auto-continue.d.ts.map +1 -1
- package/dist/src/auto-continue.js +5 -2
- package/dist/src/auto-continue.js.map +1 -1
- package/dist/src/code-execution/isolate/runner.d.ts +7 -5
- package/dist/src/code-execution/isolate/runner.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/runner.js +7 -5
- package/dist/src/code-execution/isolate/runner.js.map +1 -1
- package/dist/src/code-execution/isolate/scripts.d.ts.map +1 -1
- package/dist/src/code-execution/isolate/scripts.js +3 -2
- package/dist/src/code-execution/isolate/scripts.js.map +1 -1
- package/dist/src/dendrite/index.d.ts +6 -0
- package/dist/src/dendrite/index.d.ts.map +1 -0
- package/dist/src/dendrite/index.js +3 -0
- package/dist/src/dendrite/index.js.map +1 -0
- package/dist/src/dendrite/presets.d.ts +60 -0
- package/dist/src/dendrite/presets.d.ts.map +1 -0
- package/dist/src/dendrite/presets.js +117 -0
- package/dist/src/dendrite/presets.js.map +1 -0
- package/dist/src/dendrite/registry.d.ts +260 -0
- package/dist/src/dendrite/registry.d.ts.map +1 -0
- package/dist/src/dendrite/registry.js +742 -0
- package/dist/src/dendrite/registry.js.map +1 -0
- package/dist/src/dendrite/types.d.ts +392 -0
- package/dist/src/dendrite/types.d.ts.map +1 -0
- package/dist/src/dendrite/types.js +24 -0
- package/dist/src/dendrite/types.js.map +1 -0
- package/dist/src/framework.d.ts +846 -67
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +4213 -924
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +46 -14
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +143 -53
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/gate/index.d.ts +1 -1
- package/dist/src/gate/index.d.ts.map +1 -1
- package/dist/src/gate/index.js +1 -1
- package/dist/src/gate/index.js.map +1 -1
- package/dist/src/gate/types.d.ts +12 -2
- package/dist/src/gate/types.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.d.ts +18 -0
- package/dist/src/heartbeat/heartbeat.d.ts.map +1 -1
- package/dist/src/heartbeat/heartbeat.js +34 -8
- package/dist/src/heartbeat/heartbeat.js.map +1 -1
- package/dist/src/held-writes.d.ts +3 -3
- package/dist/src/held-writes.js +3 -3
- package/dist/src/host-presentation.d.ts +174 -0
- package/dist/src/host-presentation.d.ts.map +1 -0
- package/dist/src/host-presentation.js +565 -0
- package/dist/src/host-presentation.js.map +1 -0
- package/dist/src/index.d.ts +7 -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/line-reader.d.ts +4 -0
- package/dist/src/line-reader.d.ts.map +1 -0
- package/dist/src/line-reader.js +59 -0
- package/dist/src/line-reader.js.map +1 -0
- package/dist/src/mcpl/channel-registry.d.ts +118 -15
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +266 -110
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +2 -1
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +1 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -1
- package/dist/src/mcpl/convert-block.js +16 -4
- package/dist/src/mcpl/convert-block.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +4 -3
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +3 -1
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -1
- package/dist/src/mcpl/inbound-source.js +3 -1
- package/dist/src/mcpl/inbound-source.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -1
- package/dist/src/mcpl/modern-connection.js +11 -7
- package/dist/src/mcpl/modern-connection.js.map +1 -1
- package/dist/src/mcpl/protocol-family.d.ts +3 -2
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -1
- package/dist/src/mcpl/protocol-family.js +25 -3
- package/dist/src/mcpl/protocol-family.js.map +1 -1
- package/dist/src/mcpl/push-coalescer.d.ts +9 -0
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +21 -0
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.js +2 -2
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +12 -40
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +29 -23
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +20 -20
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +25 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.js +25 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -1
- package/dist/src/mcpl/tool-presence.d.ts.map +1 -1
- package/dist/src/mcpl/tool-presence.js +18 -17
- package/dist/src/mcpl/tool-presence.js.map +1 -1
- package/dist/src/mcpl/tool-signature.d.ts.map +1 -1
- package/dist/src/mcpl/tool-signature.js +17 -16
- package/dist/src/mcpl/tool-signature.js.map +1 -1
- package/dist/src/mcpl/toolset-host.d.ts +8 -26
- package/dist/src/mcpl/toolset-host.d.ts.map +1 -1
- package/dist/src/mcpl/toolset-host.js +16 -6
- package/dist/src/mcpl/toolset-host.js.map +1 -1
- package/dist/src/mcpl/toolsets-module.d.ts +14 -25
- package/dist/src/mcpl/toolsets-module.d.ts.map +1 -1
- package/dist/src/mcpl/toolsets-module.js +187 -50
- package/dist/src/mcpl/toolsets-module.js.map +1 -1
- package/dist/src/mcpl/transport.d.ts +1 -1
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +16 -16
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +28 -12
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/module-registry.d.ts +6 -7
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +6 -7
- 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 +4 -2
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +33 -25
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/history/index.js +8 -6
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/sender-name.d.ts +7 -0
- package/dist/src/modules/sender-name.d.ts.map +1 -0
- package/dist/src/modules/sender-name.js +10 -0
- package/dist/src/modules/sender-name.js.map +1 -0
- package/dist/src/modules/workspace/answers.d.ts +5 -1
- package/dist/src/modules/workspace/answers.d.ts.map +1 -1
- package/dist/src/modules/workspace/answers.js +16 -1
- package/dist/src/modules/workspace/answers.js.map +1 -1
- package/dist/src/modules/workspace/direct-write.d.ts.map +1 -1
- package/dist/src/modules/workspace/direct-write.js +6 -4
- package/dist/src/modules/workspace/direct-write.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +4 -2
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +50 -40
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +1 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +66 -36
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +51 -20
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +120 -82
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +7 -1
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +133 -37
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/notice-tags.d.ts +81 -0
- package/dist/src/notice-tags.d.ts.map +1 -0
- package/dist/src/notice-tags.js +85 -0
- package/dist/src/notice-tags.js.map +1 -0
- package/dist/src/reasoning-loss-notice.d.ts.map +1 -1
- package/dist/src/reasoning-loss-notice.js +5 -3
- package/dist/src/reasoning-loss-notice.js.map +1 -1
- package/dist/src/silent-heartbeat.d.ts +5 -55
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +63 -7
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/stored-injections.d.ts +4 -0
- package/dist/src/stored-injections.d.ts.map +1 -1
- package/dist/src/stored-injections.js +6 -0
- package/dist/src/stored-injections.js.map +1 -1
- package/dist/src/supplied-text.d.ts +35 -0
- package/dist/src/supplied-text.d.ts.map +1 -0
- package/dist/src/supplied-text.js +141 -0
- package/dist/src/supplied-text.js.map +1 -0
- package/dist/src/tool-args.d.ts.map +1 -1
- package/dist/src/tool-args.js +9 -8
- package/dist/src/tool-args.js.map +1 -1
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +2 -1
- 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 +5 -4
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +382 -11
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +1100 -119
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/tune-out/tools.d.ts +101 -5
- package/dist/src/tune-out/tools.d.ts.map +1 -1
- package/dist/src/tune-out/tools.js +55 -18
- package/dist/src/tune-out/tools.js.map +1 -1
- package/dist/src/types/agent.d.ts +48 -9
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +142 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +22 -11
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +136 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/admission/admit.ts +113 -0
- package/src/agent.ts +52 -7
- package/src/api/mcp-server-core.ts +3 -14
- package/src/api/server.ts +7 -3
- package/src/author-presentation.ts +81 -0
- package/src/auto-continue.ts +8 -2
- package/src/code-execution/isolate/runner.ts +7 -5
- package/src/code-execution/isolate/scripts.ts +3 -2
- package/src/dendrite/index.ts +32 -0
- package/src/dendrite/presets.ts +149 -0
- package/src/dendrite/registry.ts +808 -0
- package/src/dendrite/types.ts +397 -0
- package/src/framework.ts +4362 -852
- package/src/gate/event-gate.ts +159 -52
- package/src/gate/index.ts +1 -1
- package/src/gate/types.ts +12 -2
- package/src/heartbeat/heartbeat.ts +48 -9
- package/src/held-writes.ts +3 -3
- package/src/host-presentation.ts +612 -0
- package/src/index.ts +17 -4
- package/src/line-reader.ts +58 -0
- package/src/mcpl/channel-registry.ts +306 -111
- package/src/mcpl/conversation-router.ts +2 -1
- package/src/mcpl/convert-block.ts +17 -4
- package/src/mcpl/hook-orchestrator.ts +4 -3
- package/src/mcpl/inbound-source.ts +3 -1
- package/src/mcpl/modern-connection.ts +11 -7
- package/src/mcpl/protocol-family.ts +24 -3
- package/src/mcpl/push-coalescer.ts +19 -0
- package/src/mcpl/push-handler.ts +2 -2
- package/src/mcpl/references.ts +31 -23
- package/src/mcpl/server-connection.ts +20 -18
- package/src/mcpl/skip-reply-wake.ts +35 -0
- package/src/mcpl/tool-presence.ts +18 -17
- package/src/mcpl/tool-signature.ts +17 -16
- package/src/mcpl/toolset-host.ts +18 -6
- package/src/mcpl/toolsets-module.ts +149 -50
- package/src/mcpl/transport.ts +18 -14
- package/src/mcpl/types.ts +29 -12
- package/src/module-registry.ts +6 -7
- package/src/modules/api/index.ts +4 -2
- package/src/modules/discord/index.ts +37 -25
- package/src/modules/history/index.ts +8 -6
- package/src/modules/sender-name.ts +9 -0
- package/src/modules/workspace/answers.ts +20 -2
- package/src/modules/workspace/direct-write.ts +4 -3
- package/src/modules/workspace/effects.ts +50 -40
- package/src/modules/workspace/index.ts +58 -34
- package/src/modules/workspace/observe.ts +139 -88
- package/src/modules/workspace/reconcile.ts +159 -36
- package/src/notice-tags.ts +86 -0
- package/src/reasoning-loss-notice.ts +5 -3
- package/src/silent-heartbeat.ts +11 -7
- package/src/stored-injections.ts +7 -0
- package/src/supplied-text.ts +154 -0
- package/src/tool-args.ts +9 -8
- package/src/tool-image-ledger.ts +2 -1
- package/src/tool-presentation.ts +5 -4
- package/src/tune-out/coordinator.ts +1252 -123
- package/src/tune-out/tools.ts +152 -11
- package/src/types/agent.ts +51 -9
- package/src/types/framework.ts +146 -0
- package/src/types/module.ts +23 -11
- package/src/types/trace.ts +150 -0
|
@@ -1,31 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The host's own interface to MCPL dynamic tools (RFC-014 §8.2): four tools,
|
|
3
|
-
* constant and static, aggregated across every server that presents
|
|
4
|
-
* toolsets.
|
|
5
|
-
*
|
|
6
|
-
* toolsets--open {server?, toolset?, instance?, options?}
|
|
7
|
-
* toolsets--act {server?, tool, instance?, args?}
|
|
8
|
-
* toolsets--look {server?, toolset?, instance?, tool?}
|
|
9
|
-
* toolsets--close {server?, toolset?, instance?}
|
|
10
|
-
*
|
|
11
|
-
* Dynamic tools never enter the API tool list: changing it rebuilds the
|
|
12
|
-
* prompt cache. They're announced in the conversation (in these tools'
|
|
13
|
-
* results, in the results of calls that changed them, in push events and in
|
|
14
|
-
* notices) and called through `toolsets--act`, which this module only
|
|
15
|
-
* resolves (resolveAct): the framework dispatches the call it resolves to
|
|
16
|
-
* down the same path as a direct call of the server's tool. The module is registered when a server is
|
|
17
|
-
* configured with `toolHints: true`; its tools never change after that.
|
|
18
|
-
*
|
|
19
|
-
* Its gatherContext publishes the RFC §8.3 reminder, as a stored `afterUser`
|
|
20
|
-
* injection, when an agent's earlier announcements of an open toolset have
|
|
21
|
-
* left its context (ToolsetHub.observeCompile).
|
|
22
|
-
*
|
|
23
|
-
* Ported from mcpl-cc-bridge's meta-tools.ts, the reference host.
|
|
24
|
-
*/
|
|
25
1
|
import type { EventResponse, Module, ModuleContext, ModuleContextInjection, ProcessState } from '../types/module.js';
|
|
26
2
|
import type { ProcessEvent, ToolCall, ToolDefinition, ToolResult } from '../types/events.js';
|
|
27
3
|
import { type ToolsetController, type ToolsetHub } from './toolset-host.js';
|
|
28
4
|
import { type ChangeSet } from './tool-presence.js';
|
|
5
|
+
import { type HostPresentation } from '../host-presentation.js';
|
|
29
6
|
/** The namespace a reminder's stored injection carries. */
|
|
30
7
|
export declare const TOOLSETS_REMINDER_NAMESPACE = "mcpl-toolsets";
|
|
31
8
|
/** A failure whose outcome is unknown, with how to find it out. */
|
|
@@ -50,11 +27,15 @@ export declare function resolveAct(hub: ToolsetHub, input: unknown): ActTarget;
|
|
|
50
27
|
export declare class ToolsetsModule implements Module {
|
|
51
28
|
private readonly hub;
|
|
52
29
|
private readonly takerFor;
|
|
30
|
+
/** The host's own toolsets (the built-in "settings" and server tabs), when the framework presents them. */
|
|
31
|
+
private readonly host;
|
|
53
32
|
readonly name = "toolsets";
|
|
54
33
|
/** `takerFor`: who shows a call's result to an agent, taking the tool
|
|
55
34
|
* change rendered into it; null when the result may reach none, and its
|
|
56
35
|
* change is left to a notice (RFC-014 §6.1: told once). */
|
|
57
|
-
constructor(hub: ToolsetHub, takerFor: (call: ToolCall) => ((taken: TakenChange) => void) | null
|
|
36
|
+
constructor(hub: ToolsetHub, takerFor: (call: ToolCall) => ((taken: TakenChange) => void) | null,
|
|
37
|
+
/** The host's own toolsets (the built-in "settings" and server tabs), when the framework presents them. */
|
|
38
|
+
host?: HostPresentation | null);
|
|
58
39
|
start(_ctx: ModuleContext): Promise<void>;
|
|
59
40
|
stop(): Promise<void>;
|
|
60
41
|
getTools(): ToolDefinition[];
|
|
@@ -62,6 +43,14 @@ export declare class ToolsetsModule implements Module {
|
|
|
62
43
|
/** RFC §8.3: the reminder due for this agent, stored where compile() would place it. */
|
|
63
44
|
gatherContext(agentName: string): Promise<ModuleContextInjection[]>;
|
|
64
45
|
handleToolCall(call: ToolCall): Promise<ToolResult>;
|
|
46
|
+
/**
|
|
47
|
+
* The host's own toolsets: `toolset: "settings"` alone, or `server` alone
|
|
48
|
+
* (a server's tab), for open, close and look; a tool a host toolset has, for
|
|
49
|
+
* look. Null for everything else, which the servers' toolsets answer.
|
|
50
|
+
*/
|
|
51
|
+
private hostCall;
|
|
52
|
+
/** What the host's own toolsets add ahead of the servers' look: everything, or one presenting server's tab. */
|
|
53
|
+
private hostLookLead;
|
|
65
54
|
private toolsAt;
|
|
66
55
|
/** A change set rendered without the key the caller already showed whole. */
|
|
67
56
|
private renderOthers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolsets-module.d.ts","sourceRoot":"","sources":["../../../src/mcpl/toolsets-module.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"toolsets-module.d.ts","sourceRoot":"","sources":["../../../src/mcpl/toolsets-module.ts"],"names":[],"mappings":"AA0BA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,EAAE,sBAAsB,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACrH,OAAO,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAE7F,OAAO,EAAoC,KAAK,iBAAiB,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC9G,OAAO,EAAS,KAAK,SAAS,EAAqB,MAAM,oBAAoB,CAAC;AAG9E,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAEjF,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,kBAAkB,CAAC;AAkG3D,mEAAmE;AACnE,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAGnE;AAQD,gGAAgG;AAChG,MAAM,MAAM,WAAW,GAAG;IAAE,QAAQ,EAAE,iBAAiB,CAAC;IAAC,EAAE,EAAE,SAAS,CAAA;CAAE,CAAC;AA0EzE,8FAA8F;AAC9F,MAAM,MAAM,SAAS,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAmBtJ,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,CAuCrE;AAED,qBAAa,cAAe,YAAW,MAAM;IAOzC,OAAO,CAAC,QAAQ,CAAC,GAAG;IACpB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,2GAA2G;IAC3G,OAAO,CAAC,QAAQ,CAAC,IAAI;IATvB,QAAQ,CAAC,IAAI,cAAmB;IAEhC;;gEAE4D;IAC5D,YACmB,GAAG,EAAE,UAAU,EACf,QAAQ,EAAE,CAAC,IAAI,EAAE,QAAQ,KAAK,CAAC,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC,GAAG,IAAI;IACpF,2GAA2G;IAC1F,IAAI,GAAE,gBAAgB,GAAG,IAAW,EACnD;IAEE,KAAK,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAG;IAC5C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAG;IAE9B,QAAQ,IAAI,cAAc,EAAE,CAE3B;IAEK,SAAS,CAAC,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,CAElF;IAED,wFAAwF;IAClF,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,EAAE,CAAC,CAIxE;IAEK,cAAc,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,UAAU,CAAC,CAkCxD;IAED;;;;OAIG;YACW,QAAQ;IAyCtB,+GAA+G;IAC/G,OAAO,CAAC,YAAY;IASpB,OAAO,CAAC,OAAO;IAIf,6EAA6E;IAC7E,OAAO,CAAC,YAAY;YAMN,IAAI;IAwDlB;;;;;;OAMG;IACH,OAAO,CAAC,GAAG;IAMX,2GAA2G;YAC7F,IAAI;IAoClB,OAAO,CAAC,OAAO;IAyDf,OAAO,CAAC,QAAQ;YAWF,KAAK;CAqDpB"}
|
|
@@ -1,30 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The host's own interface to MCPL dynamic tools (RFC-014 §8.2): four tools,
|
|
3
|
+
* constant and static, aggregated across every server that presents
|
|
4
|
+
* toolsets.
|
|
5
|
+
*
|
|
6
|
+
* toolsets--open {server?, toolset?, instance?, options?}
|
|
7
|
+
* toolsets--act {server?, tool, instance?, args?}
|
|
8
|
+
* toolsets--look {server?, toolset?, instance?, tool?}
|
|
9
|
+
* toolsets--close {server?, toolset?, instance?}
|
|
10
|
+
*
|
|
11
|
+
* Dynamic tools never enter the API tool list: changing it rebuilds the
|
|
12
|
+
* prompt cache. They're announced in the conversation (in these tools'
|
|
13
|
+
* results, in the results of calls that changed them, in push events and in
|
|
14
|
+
* notices) and called through `toolsets--act`, which this module only
|
|
15
|
+
* resolves (resolveAct): the framework dispatches the call it resolves to
|
|
16
|
+
* down the same path as a direct call of the server's tool. The module is registered at create(),
|
|
17
|
+
* for every agent (the host's own toolsets use it too), unless a module given to create() holds
|
|
18
|
+
* the name; its tools never change after that.
|
|
19
|
+
*
|
|
20
|
+
* Its gatherContext publishes the RFC §8.3 reminder, as a stored `afterUser`
|
|
21
|
+
* injection, when an agent's earlier announcements of an open toolset have
|
|
22
|
+
* left its context (ToolsetHub.observeCompile).
|
|
23
|
+
*
|
|
24
|
+
* Ported from mcpl-cc-bridge's meta-tools.ts, the reference host.
|
|
25
|
+
*/
|
|
26
|
+
import { nameToTypeBack, quotedValue, suppliedValue } from '../supplied-text.js';
|
|
1
27
|
import { unknownToolMessage } from '../modules/unknown-tool.js';
|
|
2
28
|
import { META_TOOL_NAMES, TOOLSETS_MODULE } from './toolset-host.js';
|
|
3
29
|
import { keyOf } from './tool-presence.js';
|
|
4
30
|
import { checkArgs, jsonText, renderToolDefinition } from './tool-signature.js';
|
|
5
31
|
import { McplRequestError } from './server-connection.js';
|
|
32
|
+
import { BUILTIN_TOOLSET } from '../host-presentation.js';
|
|
6
33
|
/** The namespace a reminder's stored injection carries. */
|
|
7
34
|
export const TOOLSETS_REMINDER_NAMESPACE = 'mcpl-toolsets';
|
|
8
35
|
const META_TOOLS = [
|
|
9
36
|
{
|
|
10
37
|
name: 'open',
|
|
11
|
-
description: 'Open a toolset
|
|
12
|
-
'
|
|
13
|
-
'
|
|
38
|
+
description: 'Open a toolset so its tools can be called with toolsets--act: the host\'s own settings and controls (toolset "settings"), ' +
|
|
39
|
+
'an MCPL server\'s tab (server alone: its tools without putting them in your tool list; a closed tab is connected again; ' +
|
|
40
|
+
'full: true puts the server back in your tool list), or a toolset an MCPL server declares (a game, a building mode, a card table: ' +
|
|
41
|
+
'server and toolset). Returns the tools available now. instance names a separate copy where a toolset allows several; ' +
|
|
14
42
|
'options as toolsets--look lists them.',
|
|
15
43
|
inputSchema: {
|
|
16
44
|
type: 'object',
|
|
17
45
|
properties: {
|
|
18
46
|
server: { type: 'string', description: 'the MCPL server id' },
|
|
19
|
-
toolset: { type: 'string' },
|
|
47
|
+
toolset: { type: 'string', description: '"settings" for the host\'s own; a server\'s toolset with server' },
|
|
20
48
|
instance: { type: 'string', description: 'a name for this copy (toolsets with instances only)' },
|
|
21
49
|
options: { type: 'object', description: 'toolset options, as toolsets--look shows them' },
|
|
50
|
+
full: { type: 'boolean', description: 'with server alone: put the server\'s tools back in your tool list' },
|
|
22
51
|
},
|
|
23
52
|
},
|
|
24
53
|
},
|
|
25
54
|
{
|
|
26
55
|
name: 'act',
|
|
27
|
-
description: 'Call a tool
|
|
56
|
+
description: 'Call a tool of an open toolset (the host\'s "settings", a server\'s tab, or a server\'s own toolset) or another dynamic tool, as announced in the conversation; they are not in your tool list. ' +
|
|
28
57
|
'args are the arguments its signature shows; instance picks the open copy when several are open; server is needed only when two servers have the tool. ' +
|
|
29
58
|
'Returns the server\'s result, then any change it made in which tools are available, unless that change already went out as a notice. toolsets--look shows what is available now.',
|
|
30
59
|
inputSchema: {
|
|
@@ -40,7 +69,7 @@ const META_TOOLS = [
|
|
|
40
69
|
},
|
|
41
70
|
{
|
|
42
71
|
name: 'look',
|
|
43
|
-
description: 'Show what is open and what can be opened
|
|
72
|
+
description: 'Show what is open and what can be opened (the host\'s "settings", each MCPL server\'s tab, servers\' own toolsets), with the tools usable now: announcements earlier in the conversation may be out of date. ' +
|
|
44
73
|
'With tool: that tool\'s full description and input schema. With toolset or instance: just that one.',
|
|
45
74
|
inputSchema: {
|
|
46
75
|
type: 'object',
|
|
@@ -54,18 +83,31 @@ const META_TOOLS = [
|
|
|
54
83
|
},
|
|
55
84
|
{
|
|
56
85
|
name: 'close',
|
|
57
|
-
description: 'Close an open toolset or instance: its tools stop, and for a toolset the server declares, the server is told and stops its events too. Closing a game in progress may count as leaving it.'
|
|
86
|
+
description: 'Close an open toolset or instance: its tools stop, and for a toolset the server declares, the server is told and stops its events too. Closing a game in progress may count as leaving it. ' +
|
|
87
|
+
'server alone moves a server out of your tool list into a tab (connected, its events still come), or hides its open tab; with disconnect: true it is disconnected until you open it again.',
|
|
58
88
|
inputSchema: {
|
|
59
89
|
type: 'object',
|
|
60
90
|
properties: {
|
|
61
91
|
server: { type: 'string', description: 'the MCPL server id (may be left out when one server has the toolset open)' },
|
|
62
|
-
toolset: { type: 'string', description: 'may be left out when only one thing is open on the server' },
|
|
92
|
+
toolset: { type: 'string', description: '"settings" for the host\'s own; may be left out when only one thing is open on the server' },
|
|
63
93
|
instance: { type: 'string' },
|
|
94
|
+
disconnect: { type: 'boolean', description: 'with server alone: disconnect it as a closed tab until it is opened again' },
|
|
64
95
|
},
|
|
65
96
|
},
|
|
66
97
|
},
|
|
67
98
|
];
|
|
68
99
|
const str = (v) => (typeof v === 'string' && v.trim() ? v.trim() : undefined);
|
|
100
|
+
const selector = (v, has) => typeof v === 'string' && v !== v.trim() && v.trim() !== '' && has(v) ? v : str(v);
|
|
101
|
+
const presentersOf = (hub, server) => {
|
|
102
|
+
const id = str(server);
|
|
103
|
+
if (!id)
|
|
104
|
+
return hub.presenting();
|
|
105
|
+
const c = hub.get(id);
|
|
106
|
+
return c ? [c] : [];
|
|
107
|
+
};
|
|
108
|
+
const toolNamed = (hub, server, v) => selector(v, (name) => presentersOf(hub, server).some((c) => !!c.presence.tool(name)));
|
|
109
|
+
const toolsetNamed = (hub, server, v) => selector(v, (name) => presentersOf(hub, server).some((c) => c.presence.isDeclared(name) || c.presence.undeclaredGroups.includes(name)));
|
|
110
|
+
const instanceNamed = (presenters, toolset, v) => selector(v, (name) => presenters.some((c) => c.presence.openRecords(toolset).some((o) => o.instance === name)));
|
|
69
111
|
const SELECTORS = ['server', 'toolset', 'instance', 'tool'];
|
|
70
112
|
function checkSelectors(args) {
|
|
71
113
|
for (const key of SELECTORS) {
|
|
@@ -82,7 +124,7 @@ export function withLookHint(serverId, text) {
|
|
|
82
124
|
return `${said}${/[.!?]$/.test(said) ? '' : '.'} ${META_TOOL_NAMES.look} {server:"${serverId}"} asks it what's open, or says it couldn't.`;
|
|
83
125
|
}
|
|
84
126
|
function requestFailure(serverId, did, unconfirmed, error) {
|
|
85
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
127
|
+
const message = suppliedValue(error instanceof Error ? error.message : String(error));
|
|
86
128
|
if (error instanceof McplRequestError && error.outcome === 'not-sent')
|
|
87
129
|
return fail(`${serverId} ${did}: ${message}`);
|
|
88
130
|
return fail(withLookHint(serverId, `${serverId} ${unconfirmed}: ${message}`));
|
|
@@ -154,7 +196,7 @@ function owner(hub, server, has, what) {
|
|
|
154
196
|
const NONE_PRESENTS = 'no MCPL server presents toolsets now: MCPL tools are called directly, by name';
|
|
155
197
|
function noToolset(c, toolset) {
|
|
156
198
|
const names = [...Object.keys(c.presence.declared), ...c.presence.undeclaredGroups];
|
|
157
|
-
return `${c.serverId} has no toolset "${toolset}"; ${names.length ? `it has ${names.join(', ')}` : 'it has none'}`;
|
|
199
|
+
return `${c.serverId} has no toolset "${toolset}"; ${names.length ? `it has ${names.map(nameToTypeBack).join(', ')}` : 'it has none'}`;
|
|
158
200
|
}
|
|
159
201
|
/**
|
|
160
202
|
* Resolve a `toolsets--act` call (RFC §8.2) to the dynamic tool it calls,
|
|
@@ -175,18 +217,18 @@ export function resolveAct(hub, input) {
|
|
|
175
217
|
try {
|
|
176
218
|
const args = isObj(input) ? input : {};
|
|
177
219
|
checkSelectors(args);
|
|
178
|
-
const tool =
|
|
220
|
+
const tool = toolNamed(hub, args.server, args.tool) ?? fail('name the tool');
|
|
179
221
|
const c = owner(hub, args.server, (x) => !!x.presence.tool(tool), `a tool "${tool}"`);
|
|
180
222
|
const p = c.presence;
|
|
181
223
|
if (!p.tool(tool))
|
|
182
224
|
fail(`${c.serverId} has no tool "${tool}": ${META_TOOL_NAMES.look} {server:"${c.serverId}"} shows what's available`);
|
|
183
225
|
if (!p.shownAs(tool, 'dynamic'))
|
|
184
|
-
fail(`${tool} is not a dynamic tool: ${p.toolStatus(tool)}. Call it there.`);
|
|
226
|
+
fail(`${nameToTypeBack(tool)} is not a dynamic tool: ${p.toolStatus(tool)}. Call it there.`);
|
|
185
227
|
if (args.args !== undefined && !isObj(args.args))
|
|
186
228
|
fail('args must be an object of the tool\'s arguments');
|
|
187
229
|
const callArgs = (args.args ?? {});
|
|
188
|
-
let instance = str(args.instance);
|
|
189
230
|
const ts = p.toolsetOf(tool);
|
|
231
|
+
let instance = instanceNamed([c], ts, args.instance);
|
|
190
232
|
const declared = ts !== undefined && p.isDeclared(ts);
|
|
191
233
|
const withInstances = hasInstances(p, ts);
|
|
192
234
|
if (withInstances && !instance) {
|
|
@@ -195,23 +237,23 @@ export function resolveAct(hub, input) {
|
|
|
195
237
|
if (open.length === 1)
|
|
196
238
|
instance = open[0].instance;
|
|
197
239
|
else if (!open.length)
|
|
198
|
-
fail(`${tool} belongs to ${ts}, which isn't open: ${p.openHint(ts)}`);
|
|
240
|
+
fail(`${nameToTypeBack(tool)} belongs to ${nameToTypeBack(ts)}, which isn't open: ${p.openHint(ts)}`);
|
|
199
241
|
else
|
|
200
|
-
fail(`several ${ts} instances are open (${open.map((o) => o.instance).join(', ')}): say which with instance`);
|
|
242
|
+
fail(`several ${nameToTypeBack(ts)} instances are open (${open.map((o) => nameToTypeBack(o.instance)).join(', ')}): say which with instance`);
|
|
201
243
|
}
|
|
202
244
|
if (instance && !withInstances)
|
|
203
|
-
fail(`${tool} ${ts ? `belongs to ${ts}, which has no instances` : 'belongs to no toolset'}: call it without instance`);
|
|
245
|
+
fail(`${nameToTypeBack(tool)} ${ts ? `belongs to ${nameToTypeBack(ts)}, which has no instances` : 'belongs to no toolset'}: call it without instance`);
|
|
204
246
|
// RFC §5.4: the host gates calls into an undeclared group it has closed.
|
|
205
247
|
if (ts && !declared && !p.isOpen(ts))
|
|
206
|
-
fail(`${tool} is in ${ts}, which isn't open: ${p.openHint(ts)}`);
|
|
248
|
+
fail(`${nameToTypeBack(tool)} is in ${nameToTypeBack(ts)}, which isn't open: ${p.openHint(ts)}`);
|
|
207
249
|
// RFC §6.1: arguments are checked against the definition in force for
|
|
208
250
|
// that instance: its own from hints (the legal moves of one game), else
|
|
209
251
|
// the toolset's, else the listed one.
|
|
210
252
|
const key = actKey(p, tool, instance);
|
|
211
253
|
const problem = checkArgs(p.defOf(key, tool).inputSchema, callArgs);
|
|
212
254
|
if (problem) {
|
|
213
|
-
fail(`Invalid arguments for ${tool} in ${p.label(key)}: ${problem}. Nothing was sent; ` +
|
|
214
|
-
`${META_TOOL_NAMES.look} {server:"${c.serverId}", tool
|
|
255
|
+
fail(`Invalid arguments for ${nameToTypeBack(tool)} in ${p.label(key)}: ${problem}. Nothing was sent; ` +
|
|
256
|
+
`${META_TOOL_NAMES.look} {server:"${c.serverId}", tool:${quotedValue(tool)}${instance ? `, instance:${quotedValue(instance)}` : ''}} shows its current definition.`);
|
|
215
257
|
}
|
|
216
258
|
return { ok: true, serverId: c.serverId, tool, ...(instance ? { instance } : {}), args: callArgs };
|
|
217
259
|
}
|
|
@@ -224,13 +266,17 @@ export function resolveAct(hub, input) {
|
|
|
224
266
|
export class ToolsetsModule {
|
|
225
267
|
hub;
|
|
226
268
|
takerFor;
|
|
269
|
+
host;
|
|
227
270
|
name = TOOLSETS_MODULE;
|
|
228
271
|
/** `takerFor`: who shows a call's result to an agent, taking the tool
|
|
229
272
|
* change rendered into it; null when the result may reach none, and its
|
|
230
273
|
* change is left to a notice (RFC-014 §6.1: told once). */
|
|
231
|
-
constructor(hub, takerFor
|
|
274
|
+
constructor(hub, takerFor,
|
|
275
|
+
/** The host's own toolsets (the built-in "settings" and server tabs), when the framework presents them. */
|
|
276
|
+
host = null) {
|
|
232
277
|
this.hub = hub;
|
|
233
278
|
this.takerFor = takerFor;
|
|
279
|
+
this.host = host;
|
|
234
280
|
}
|
|
235
281
|
async start(_ctx) { }
|
|
236
282
|
async stop() { }
|
|
@@ -251,7 +297,26 @@ export class ToolsetsModule {
|
|
|
251
297
|
const args = isObj(call.input) ? call.input : {};
|
|
252
298
|
try {
|
|
253
299
|
checkSelectors(args);
|
|
300
|
+
// An agent shown another's tool list can't switch it: what it opened
|
|
301
|
+
// or closed would change its owner's list, or nothing it is shown.
|
|
302
|
+
const caller = call.callerAgentName;
|
|
303
|
+
const owner = caller && this.host ? this.host.ownerOf(caller) : caller;
|
|
304
|
+
if ((call.name === 'open' || call.name === 'close') && caller && owner !== caller) {
|
|
305
|
+
fail(`${caller} is shown ${owner}'s tools and can't ${call.name} a toolset; it reaches the toolsets ${owner} has open. Nothing changed.`);
|
|
306
|
+
}
|
|
307
|
+
const hosted = await this.hostCall(call.name, args, call.callerAgentName);
|
|
308
|
+
if (hosted)
|
|
309
|
+
return hosted;
|
|
254
310
|
const take = this.takerFor(call);
|
|
311
|
+
const lead = call.name === 'look' ? this.hostLookLead(args, call.callerAgentName) : null;
|
|
312
|
+
if (lead !== null) {
|
|
313
|
+
if (!this.hub.presenting().length)
|
|
314
|
+
return textResult(lead);
|
|
315
|
+
const theirs = await this.look(args, take);
|
|
316
|
+
if (theirs.isError || typeof theirs.data !== 'string')
|
|
317
|
+
return theirs;
|
|
318
|
+
return textResult(`${lead}\n\n${theirs.data}`);
|
|
319
|
+
}
|
|
255
320
|
switch (call.name) {
|
|
256
321
|
case 'open': return await this.open(args, take);
|
|
257
322
|
case 'act': return this.act(args);
|
|
@@ -267,6 +332,76 @@ export class ToolsetsModule {
|
|
|
267
332
|
return { success: false, isError: true, error: message };
|
|
268
333
|
}
|
|
269
334
|
}
|
|
335
|
+
/**
|
|
336
|
+
* The host's own toolsets: `toolset: "settings"` alone, or `server` alone
|
|
337
|
+
* (a server's tab), for open, close and look; a tool a host toolset has, for
|
|
338
|
+
* look. Null for everything else, which the servers' toolsets answer.
|
|
339
|
+
*/
|
|
340
|
+
async hostCall(name, args, agentName) {
|
|
341
|
+
const host = this.host;
|
|
342
|
+
if (!host || !agentName || !host.active(agentName))
|
|
343
|
+
return null;
|
|
344
|
+
const server = str(args.server);
|
|
345
|
+
const toolset = str(args.toolset);
|
|
346
|
+
const instance = str(args.instance);
|
|
347
|
+
const tool = str(args.tool);
|
|
348
|
+
const builtin = toolset === BUILTIN_TOOLSET && !server && !instance;
|
|
349
|
+
const tab = !!server && !toolset && !instance && args.options === undefined;
|
|
350
|
+
if (args.full !== undefined && typeof args.full !== 'boolean')
|
|
351
|
+
fail('full must be true or false');
|
|
352
|
+
if (args.disconnect !== undefined && typeof args.disconnect !== 'boolean')
|
|
353
|
+
fail('disconnect must be true or false');
|
|
354
|
+
if (tab && !host.knows(server) && !this.hub.get(server))
|
|
355
|
+
fail(`no MCPL server "${server}" is configured here`);
|
|
356
|
+
switch (name) {
|
|
357
|
+
case 'open':
|
|
358
|
+
if (builtin)
|
|
359
|
+
return textResult(host.openBuiltin(agentName));
|
|
360
|
+
if (tab)
|
|
361
|
+
return textResult(await host.openServer(agentName, server, { full: args.full === true }));
|
|
362
|
+
if (args.full !== undefined)
|
|
363
|
+
fail('full goes with server alone');
|
|
364
|
+
return null;
|
|
365
|
+
case 'close':
|
|
366
|
+
if (builtin)
|
|
367
|
+
return textResult(host.closeBuiltin(agentName));
|
|
368
|
+
if (tab)
|
|
369
|
+
return textResult(await host.closeServer(agentName, server, { disconnect: args.disconnect === true }));
|
|
370
|
+
if (args.disconnect !== undefined)
|
|
371
|
+
fail('disconnect goes with server alone');
|
|
372
|
+
return null;
|
|
373
|
+
case 'look': {
|
|
374
|
+
// A host toolset's tool, with or without its server named (as act takes it).
|
|
375
|
+
if (tool && !toolset && !instance) {
|
|
376
|
+
const shown = host.lookTool(agentName, tool, server);
|
|
377
|
+
if (shown)
|
|
378
|
+
return textResult(shown);
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
if (builtin)
|
|
382
|
+
return textResult(host.lookToolset(agentName, { builtin: true }));
|
|
383
|
+
// A server's tab, and every host toolset with no selector, go first in
|
|
384
|
+
// what the servers' own look says (handleToolCall adds them).
|
|
385
|
+
if (tab && !tool && !this.hub.get(server)?.presents)
|
|
386
|
+
return textResult(host.lookToolset(agentName, { serverId: server }));
|
|
387
|
+
return null;
|
|
388
|
+
}
|
|
389
|
+
default:
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
/** What the host's own toolsets add ahead of the servers' look: everything, or one presenting server's tab. */
|
|
394
|
+
hostLookLead(args, agentName) {
|
|
395
|
+
const host = this.host;
|
|
396
|
+
if (!host || !agentName || !host.active(agentName))
|
|
397
|
+
return null;
|
|
398
|
+
const server = str(args.server);
|
|
399
|
+
if (str(args.toolset) || str(args.instance) || str(args.tool))
|
|
400
|
+
return null;
|
|
401
|
+
if (!server)
|
|
402
|
+
return host.catalog(agentName).join('\n');
|
|
403
|
+
return host.knows(server) ? host.lookToolset(agentName, { serverId: server }) : null;
|
|
404
|
+
}
|
|
270
405
|
toolsAt(c, key) {
|
|
271
406
|
return [...(c.presence.view().get(key)?.tools.values() ?? [])];
|
|
272
407
|
}
|
|
@@ -277,7 +412,7 @@ export class ToolsetsModule {
|
|
|
277
412
|
// ── the tools ──
|
|
278
413
|
async open(args, take) {
|
|
279
414
|
const shown = take !== null;
|
|
280
|
-
let toolset =
|
|
415
|
+
let toolset = toolsetNamed(this.hub, args.server, args.toolset);
|
|
281
416
|
const c = toolset && !str(args.server)
|
|
282
417
|
? owner(this.hub, undefined, (x) => x.presence.isDeclared(toolset) || x.presence.undeclaredGroups.includes(toolset), `a toolset "${toolset}"`)
|
|
283
418
|
: pick(this.hub, args.server);
|
|
@@ -285,32 +420,32 @@ export class ToolsetsModule {
|
|
|
285
420
|
const openable = [...Object.keys(p.declared), ...p.undeclaredGroups];
|
|
286
421
|
if (!toolset) {
|
|
287
422
|
if (openable.length !== 1)
|
|
288
|
-
fail(`${c.serverId} has ${openable.length ? `several toolsets: name one of ${openable.join(', ')}` : 'no toolsets'}`);
|
|
423
|
+
fail(`${c.serverId} has ${openable.length ? `several toolsets: name one of ${openable.map(nameToTypeBack).join(', ')}` : 'no toolsets'}`);
|
|
289
424
|
toolset = openable[0];
|
|
290
425
|
}
|
|
291
|
-
const instance =
|
|
426
|
+
const instance = instanceNamed([c], toolset, args.instance);
|
|
292
427
|
if (args.options !== undefined && !isObj(args.options))
|
|
293
428
|
fail('options must be an object');
|
|
294
429
|
const options = args.options;
|
|
295
430
|
if (p.isDeclared(toolset)) {
|
|
296
431
|
if (instance && !p.declared[toolset].instances)
|
|
297
|
-
fail(`${c.serverId}/${toolset} has no instances: open it without one`);
|
|
432
|
+
fail(`${c.serverId}/${nameToTypeBack(toolset)} has no instances: open it without one`);
|
|
298
433
|
let opened;
|
|
299
434
|
try {
|
|
300
435
|
opened = await c.open(toolset, instance, options, { shown });
|
|
301
436
|
}
|
|
302
437
|
catch (error) {
|
|
303
|
-
return requestFailure(c.serverId, `did not open ${toolset}`, `didn't confirm opening ${toolset}`, error);
|
|
438
|
+
return requestFailure(c.serverId, `did not open ${nameToTypeBack(toolset)}`, `didn't confirm opening ${nameToTypeBack(toolset)}`, error);
|
|
304
439
|
}
|
|
305
440
|
// RFC §5.2: opening what is open adopts it; its content says which options weren't applied.
|
|
306
441
|
const blocks = [
|
|
307
|
-
{ type: 'text', text: `${p.label(opened.key)}${opened.title ? ` ${opened.title}` : ''}${opened.adopted ? ' (already open)' : ''}` },
|
|
442
|
+
{ type: 'text', text: `${p.label(opened.key)}${opened.title ? ` ${suppliedValue(opened.title)}` : ''}${opened.adopted ? ' (already open)' : ''}` },
|
|
308
443
|
...asBlocks(opened.content),
|
|
309
444
|
];
|
|
310
445
|
const tail = [...p.toolBlock(opened.key, this.toolsAt(c, opened.key), { headed: false, describeAll: !shown, seen: shown ? undefined : new Set() })];
|
|
311
446
|
const gone = opened.change.changes.find((ch) => ch.key === opened.key)?.gone ?? [];
|
|
312
447
|
if (gone.length)
|
|
313
|
-
tail.push(`now unavailable: ${gone.join(', ')}`);
|
|
448
|
+
tail.push(`now unavailable: ${gone.map(suppliedValue).join(', ')}`);
|
|
314
449
|
const others = this.renderOthers(c, opened.change, opened.key, shown);
|
|
315
450
|
if (others)
|
|
316
451
|
tail.push(others);
|
|
@@ -324,7 +459,7 @@ export class ToolsetsModule {
|
|
|
324
459
|
if (p.undeclaredGroups.includes(toolset)) {
|
|
325
460
|
// RFC §5.4: a grouping the server offers but doesn't track: the host opens it, the server isn't told.
|
|
326
461
|
if (instance || options)
|
|
327
|
-
fail(`${c.serverId}/${toolset} takes no instance or options (the server doesn't declare it)`);
|
|
462
|
+
fail(`${c.serverId}/${nameToTypeBack(toolset)} takes no instance or options (the server doesn't declare it)`);
|
|
328
463
|
const cs = c.setGroupOpen(toolset, true);
|
|
329
464
|
const key = keyOf(toolset);
|
|
330
465
|
const lines = [`${p.label(key)} open.`, ...p.toolBlock(key, this.toolsAt(c, key), { headed: false, describeAll: !shown, seen: shown ? undefined : new Set() })];
|
|
@@ -368,7 +503,7 @@ export class ToolsetsModule {
|
|
|
368
503
|
};
|
|
369
504
|
let result;
|
|
370
505
|
try {
|
|
371
|
-
result = this.lookNow(args, server,
|
|
506
|
+
result = this.lookNow(args, server, toolNamed(this.hub, server, args.tool), shown);
|
|
372
507
|
}
|
|
373
508
|
catch (error) {
|
|
374
509
|
giveBack();
|
|
@@ -396,12 +531,14 @@ export class ToolsetsModule {
|
|
|
396
531
|
}
|
|
397
532
|
lookNow(args, server, tool, mark) {
|
|
398
533
|
if (!server) {
|
|
399
|
-
if (tool)
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
534
|
+
if (tool) {
|
|
535
|
+
const c = owner(this.hub, undefined, (x) => !!x.presence.tool(tool), `a tool "${tool}"`);
|
|
536
|
+
return this.lookTool(c, tool, instanceNamed([c], c.presence.toolsetOf(tool), args.instance));
|
|
537
|
+
}
|
|
538
|
+
const ts = toolsetNamed(this.hub, undefined, args.toolset);
|
|
539
|
+
const inst = instanceNamed(this.hub.presenting(), ts, args.instance);
|
|
403
540
|
if (ts || inst) {
|
|
404
|
-
const c = owner(this.hub, undefined, (x) => (ts ? x.presence.isDeclared(ts) || x.presence.undeclaredGroups.includes(ts) : true) && (!inst || x.presence.openRecords().some((o) => o.instance === inst)), ts ? `a toolset "${ts}"${inst ? ` with instance "${inst}"` : ''}` : `an open instance "${inst}"`);
|
|
541
|
+
const c = owner(this.hub, undefined, (x) => (ts ? x.presence.isDeclared(ts) || x.presence.undeclaredGroups.includes(ts) : true) && (!inst || x.presence.openRecords(ts).some((o) => o.instance === inst)), ts ? `a toolset "${ts}"${inst ? ` with instance "${inst}"` : ''}` : `an open instance "${inst}"`);
|
|
405
542
|
return this.lookNow(args, c.serverId, tool, mark);
|
|
406
543
|
}
|
|
407
544
|
const all = this.hub.presenting();
|
|
@@ -411,14 +548,14 @@ export class ToolsetsModule {
|
|
|
411
548
|
}
|
|
412
549
|
const c = pick(this.hub, server);
|
|
413
550
|
if (tool)
|
|
414
|
-
return this.lookTool(c, tool,
|
|
551
|
+
return this.lookTool(c, tool, instanceNamed([c], c.presence.toolsetOf(tool), args.instance));
|
|
415
552
|
const p = c.presence;
|
|
416
|
-
let toolset =
|
|
417
|
-
const instance =
|
|
553
|
+
let toolset = toolsetNamed(this.hub, server, args.toolset);
|
|
554
|
+
const instance = instanceNamed([c], toolset, args.instance);
|
|
418
555
|
if (!toolset && instance) {
|
|
419
556
|
const open = p.openRecords().filter((o) => o.instance !== undefined);
|
|
420
557
|
toolset = open.find((o) => o.instance === instance)?.toolset
|
|
421
|
-
?? fail(`no open instance "${instance}" on ${c.serverId}; ${open.length ? `open: ${open.map((o) => `${o.toolset}:${o.instance}`).join(', ')}` : 'no instance is open there'}`);
|
|
558
|
+
?? fail(`no open instance "${instance}" on ${c.serverId}; ${open.length ? `open: ${open.map((o) => `${nameToTypeBack(o.toolset)}:${nameToTypeBack(String(o.instance))}`).join(', ')}` : 'no instance is open there'}`);
|
|
422
559
|
}
|
|
423
560
|
if (!toolset)
|
|
424
561
|
return textResult(p.catalog({ mark }));
|
|
@@ -435,8 +572,8 @@ export class ToolsetsModule {
|
|
|
435
572
|
if (d) {
|
|
436
573
|
const open = p.openRecords(toolset);
|
|
437
574
|
return textResult([
|
|
438
|
-
`${c.serverId}/${toolset}${d.title ? ` — ${d.title}` : ''}${d.summary ? `: ${d.summary}` : ''}`,
|
|
439
|
-
open.length ? `open: ${open.map((o) => o.instance ?? toolset).join(', ')}` : 'not open',
|
|
575
|
+
`${c.serverId}/${nameToTypeBack(toolset)}${d.title ? ` — ${suppliedValue(d.title)}` : ''}${d.summary ? `: ${suppliedValue(d.summary)}` : ''}`,
|
|
576
|
+
open.length ? `open: ${open.map((o) => nameToTypeBack(o.instance ?? toolset)).join(', ')}` : 'not open',
|
|
440
577
|
...(d.instances ? ['several can be open at once; name each with instance'] : []),
|
|
441
578
|
...(d.options ? [`options: ${jsonText(d.options)}`] : []),
|
|
442
579
|
`${p.openHint(toolset)} opens it.`,
|
|
@@ -444,7 +581,7 @@ export class ToolsetsModule {
|
|
|
444
581
|
}
|
|
445
582
|
if (p.undeclaredGroups.includes(toolset)) {
|
|
446
583
|
const names = p.allTools.filter((t) => p.toolsetOf(t.name) === toolset).map((t) => t.name);
|
|
447
|
-
return textResult(`${c.serverId}/${toolset}: ${names.join(', ')}; not open: ${p.openHint(toolset)} opens it.`);
|
|
584
|
+
return textResult(`${c.serverId}/${nameToTypeBack(toolset)}: ${names.map(nameToTypeBack).join(', ')}; not open: ${p.openHint(toolset)} opens it.`);
|
|
448
585
|
}
|
|
449
586
|
return fail(noToolset(c, toolset));
|
|
450
587
|
}
|
|
@@ -461,13 +598,13 @@ export class ToolsetsModule {
|
|
|
461
598
|
}
|
|
462
599
|
async close(args, take) {
|
|
463
600
|
const shown = take !== null;
|
|
464
|
-
const named =
|
|
601
|
+
const named = toolsetNamed(this.hub, args.server, args.toolset);
|
|
465
602
|
const c = named && !str(args.server)
|
|
466
|
-
? owner(this.hub, undefined, (x) => x.presence.isOpen(named,
|
|
603
|
+
? owner(this.hub, undefined, (x) => x.presence.isOpen(named, instanceNamed([x], named, args.instance)) || x.presence.openRecords(named).length > 0, `an open toolset "${named}"`)
|
|
467
604
|
: pick(this.hub, args.server);
|
|
468
605
|
const p = c.presence;
|
|
469
606
|
let toolset = named;
|
|
470
|
-
let instance =
|
|
607
|
+
let instance = instanceNamed([c], named, args.instance);
|
|
471
608
|
if (!toolset) {
|
|
472
609
|
const open = [
|
|
473
610
|
...p.openRecords().filter((o) => !instance || o.instance === instance),
|
|
@@ -475,7 +612,7 @@ export class ToolsetsModule {
|
|
|
475
612
|
];
|
|
476
613
|
if (open.length !== 1) {
|
|
477
614
|
fail(open.length
|
|
478
|
-
? `several are open on ${c.serverId}: name one of ${open.map((o) => `${o.toolset}${o.instance ? `:${o.instance}` : ''}`).join(', ')}`
|
|
615
|
+
? `several are open on ${c.serverId}: name one of ${open.map((o) => `${nameToTypeBack(o.toolset)}${o.instance ? `:${nameToTypeBack(o.instance)}` : ''}`).join(', ')}`
|
|
479
616
|
: `nothing is open on ${c.serverId}`);
|
|
480
617
|
}
|
|
481
618
|
toolset = open[0].toolset;
|
|
@@ -484,11 +621,11 @@ export class ToolsetsModule {
|
|
|
484
621
|
if (p.isDeclared(toolset)) {
|
|
485
622
|
// As open refuses one: a toolset without instances is closed without one.
|
|
486
623
|
if (instance && !p.declared[toolset].instances)
|
|
487
|
-
fail(`${c.serverId}/${toolset} has no instances: close it without one`);
|
|
624
|
+
fail(`${c.serverId}/${nameToTypeBack(toolset)} has no instances: close it without one`);
|
|
488
625
|
if (p.declared[toolset].instances && !instance) {
|
|
489
626
|
const open = p.openRecords(toolset);
|
|
490
627
|
if (open.length !== 1)
|
|
491
|
-
fail(open.length ? `several ${toolset} instances are open (${open.map((o) => o.instance).join(', ')}): say which` : `${toolset} is not open`);
|
|
628
|
+
fail(open.length ? `several ${nameToTypeBack(toolset)} instances are open (${open.map((o) => nameToTypeBack(String(o.instance))).join(', ')}): say which` : `${nameToTypeBack(toolset)} is not open`);
|
|
492
629
|
instance = open[0].instance;
|
|
493
630
|
}
|
|
494
631
|
let closed;
|
|
@@ -496,7 +633,7 @@ export class ToolsetsModule {
|
|
|
496
633
|
closed = await c.close(toolset, instance, { shown });
|
|
497
634
|
}
|
|
498
635
|
catch (error) {
|
|
499
|
-
const what = `${toolset}${instance ? `:${instance}` : ''}`;
|
|
636
|
+
const what = `${nameToTypeBack(toolset)}${instance ? `:${nameToTypeBack(instance)}` : ''}`;
|
|
500
637
|
return requestFailure(c.serverId, `did not close ${what}`, `didn't confirm closing ${what}`, error);
|
|
501
638
|
}
|
|
502
639
|
const key = keyOf(toolset, instance);
|
|
@@ -506,9 +643,9 @@ export class ToolsetsModule {
|
|
|
506
643
|
}
|
|
507
644
|
if (p.undeclaredGroups.includes(toolset)) {
|
|
508
645
|
if (instance)
|
|
509
|
-
fail(`${c.serverId}/${toolset} takes no instance (the server doesn't declare it)`);
|
|
646
|
+
fail(`${c.serverId}/${nameToTypeBack(toolset)} takes no instance (the server doesn't declare it)`);
|
|
510
647
|
if (!p.isOpen(toolset))
|
|
511
|
-
fail(`${c.serverId}/${toolset} is not open`);
|
|
648
|
+
fail(`${c.serverId}/${nameToTypeBack(toolset)} is not open`);
|
|
512
649
|
const cs = c.setGroupOpen(toolset, false);
|
|
513
650
|
const text = p.render(cs, { mark: shown, describeAll: !shown }) || `${p.label(keyOf(toolset))} closed.`;
|
|
514
651
|
if (take)
|