@namzu/sdk 0.4.2 → 0.4.4
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/CHANGELOG.md +46 -0
- package/dist/advisory/context.test.d.ts +16 -0
- package/dist/advisory/context.test.d.ts.map +1 -0
- package/dist/advisory/context.test.js +92 -0
- package/dist/advisory/context.test.js.map +1 -0
- package/dist/advisory/evaluator.test.d.ts +34 -0
- package/dist/advisory/evaluator.test.d.ts.map +1 -0
- package/dist/advisory/evaluator.test.js +172 -0
- package/dist/advisory/evaluator.test.js.map +1 -0
- package/dist/advisory/executor.test.d.ts +35 -0
- package/dist/advisory/executor.test.d.ts.map +1 -0
- package/dist/advisory/executor.test.js +233 -0
- package/dist/advisory/executor.test.js.map +1 -0
- package/dist/advisory/registry.test.d.ts +16 -0
- package/dist/advisory/registry.test.d.ts.map +1 -0
- package/dist/advisory/registry.test.js +62 -0
- package/dist/advisory/registry.test.js.map +1 -0
- package/dist/bridge/a2a/agent-card.test.d.ts +24 -0
- package/dist/bridge/a2a/agent-card.test.d.ts.map +1 -0
- package/dist/bridge/a2a/agent-card.test.js +118 -0
- package/dist/bridge/a2a/agent-card.test.js.map +1 -0
- package/dist/bridge/a2a/mapper.test.d.ts +29 -0
- package/dist/bridge/a2a/mapper.test.d.ts.map +1 -0
- package/dist/bridge/a2a/mapper.test.js +265 -0
- package/dist/bridge/a2a/mapper.test.js.map +1 -0
- package/dist/bridge/a2a/message.test.d.ts +20 -0
- package/dist/bridge/a2a/message.test.d.ts.map +1 -0
- package/dist/bridge/a2a/message.test.js +116 -0
- package/dist/bridge/a2a/message.test.js.map +1 -0
- package/dist/bridge/a2a/task.test.d.ts +29 -0
- package/dist/bridge/a2a/task.test.d.ts.map +1 -0
- package/dist/bridge/a2a/task.test.js +198 -0
- package/dist/bridge/a2a/task.test.js.map +1 -0
- package/dist/bridge/mcp/connector/adapter.test.d.ts +27 -0
- package/dist/bridge/mcp/connector/adapter.test.d.ts.map +1 -0
- package/dist/bridge/mcp/connector/adapter.test.js +203 -0
- package/dist/bridge/mcp/connector/adapter.test.js.map +1 -0
- package/dist/bridge/sse/mapper.test.d.ts +27 -0
- package/dist/bridge/sse/mapper.test.d.ts.map +1 -0
- package/dist/bridge/sse/mapper.test.js +271 -0
- package/dist/bridge/sse/mapper.test.js.map +1 -0
- package/dist/bridge/tools/connector/adapter.d.ts +2 -2
- package/dist/bridge/tools/connector/adapter.test.d.ts +28 -0
- package/dist/bridge/tools/connector/adapter.test.d.ts.map +1 -0
- package/dist/bridge/tools/connector/adapter.test.js +182 -0
- package/dist/bridge/tools/connector/adapter.test.js.map +1 -0
- package/dist/bridge/tools/connector/definitions.test.d.ts +23 -0
- package/dist/bridge/tools/connector/definitions.test.d.ts.map +1 -0
- package/dist/bridge/tools/connector/definitions.test.js +158 -0
- package/dist/bridge/tools/connector/definitions.test.js.map +1 -0
- package/dist/bridge/tools/connector/router.test.d.ts +21 -0
- package/dist/bridge/tools/connector/router.test.d.ts.map +1 -0
- package/dist/bridge/tools/connector/router.test.js +139 -0
- package/dist/bridge/tools/connector/router.test.js.map +1 -0
- package/dist/bus/breaker.test.d.ts +41 -0
- package/dist/bus/breaker.test.d.ts.map +1 -0
- package/dist/bus/breaker.test.js +242 -0
- package/dist/bus/breaker.test.js.map +1 -0
- package/dist/bus/index.d.ts +3 -1
- package/dist/bus/index.d.ts.map +1 -1
- package/dist/bus/index.js +18 -11
- package/dist/bus/index.js.map +1 -1
- package/dist/bus/index.test.d.ts +25 -0
- package/dist/bus/index.test.d.ts.map +1 -0
- package/dist/bus/index.test.js +151 -0
- package/dist/bus/index.test.js.map +1 -0
- package/dist/bus/lock.test.d.ts +44 -0
- package/dist/bus/lock.test.d.ts.map +1 -0
- package/dist/bus/lock.test.js +226 -0
- package/dist/bus/lock.test.js.map +1 -0
- package/dist/bus/ownership.test.d.ts +26 -0
- package/dist/bus/ownership.test.d.ts.map +1 -0
- package/dist/bus/ownership.test.js +205 -0
- package/dist/bus/ownership.test.js.map +1 -0
- package/dist/config/runtime.d.ts +28 -28
- package/dist/connector/BaseConnector.test.d.ts +21 -0
- package/dist/connector/BaseConnector.test.d.ts.map +1 -0
- package/dist/connector/BaseConnector.test.js +108 -0
- package/dist/connector/BaseConnector.test.js.map +1 -0
- package/dist/connector/builtins/http.test.d.ts +30 -0
- package/dist/connector/builtins/http.test.d.ts.map +1 -0
- package/dist/connector/builtins/http.test.js +232 -0
- package/dist/connector/builtins/http.test.js.map +1 -0
- package/dist/connector/builtins/webhook.test.d.ts +20 -0
- package/dist/connector/builtins/webhook.test.d.ts.map +1 -0
- package/dist/connector/builtins/webhook.test.js +113 -0
- package/dist/connector/builtins/webhook.test.js.map +1 -0
- package/dist/connector/execution/factory.test.d.ts +16 -0
- package/dist/connector/execution/factory.test.d.ts.map +1 -0
- package/dist/connector/execution/factory.test.js +64 -0
- package/dist/connector/execution/factory.test.js.map +1 -0
- package/dist/connector/execution/remote.test.d.ts +16 -0
- package/dist/connector/execution/remote.test.d.ts.map +1 -0
- package/dist/connector/execution/remote.test.js +53 -0
- package/dist/connector/execution/remote.test.js.map +1 -0
- package/dist/connector/mcp/adapter.test.d.ts +34 -0
- package/dist/connector/mcp/adapter.test.d.ts.map +1 -0
- package/dist/connector/mcp/adapter.test.js +199 -0
- package/dist/connector/mcp/adapter.test.js.map +1 -0
- package/dist/probe/context.d.ts +8 -0
- package/dist/probe/context.d.ts.map +1 -0
- package/dist/probe/context.js +7 -0
- package/dist/probe/context.js.map +1 -0
- package/dist/probe/errors.d.ts +12 -0
- package/dist/probe/errors.d.ts.map +1 -0
- package/dist/probe/errors.js +21 -0
- package/dist/probe/errors.js.map +1 -0
- package/dist/probe/index.d.ts +5 -0
- package/dist/probe/index.d.ts.map +1 -0
- package/dist/probe/index.js +4 -0
- package/dist/probe/index.js.map +1 -0
- package/dist/probe/registry.d.ts +24 -0
- package/dist/probe/registry.d.ts.map +1 -0
- package/dist/probe/registry.js +228 -0
- package/dist/probe/registry.js.map +1 -0
- package/dist/probe/registry.test.d.ts +7 -0
- package/dist/probe/registry.test.d.ts.map +1 -0
- package/dist/probe/registry.test.js +310 -0
- package/dist/probe/registry.test.js.map +1 -0
- package/dist/provider/instrumentation.d.ts +9 -0
- package/dist/provider/instrumentation.d.ts.map +1 -0
- package/dist/provider/instrumentation.js +104 -0
- package/dist/provider/instrumentation.js.map +1 -0
- package/dist/provider/instrumentation.test.d.ts +2 -0
- package/dist/provider/instrumentation.test.d.ts.map +1 -0
- package/dist/provider/instrumentation.test.js +152 -0
- package/dist/provider/instrumentation.test.js.map +1 -0
- package/dist/public-runtime.d.ts +5 -0
- package/dist/public-runtime.d.ts.map +1 -1
- package/dist/public-runtime.js +4 -0
- package/dist/public-runtime.js.map +1 -1
- package/dist/public-types.d.ts +3 -0
- package/dist/public-types.d.ts.map +1 -1
- package/dist/rag/chunking.test.d.ts +20 -0
- package/dist/rag/chunking.test.d.ts.map +1 -0
- package/dist/rag/chunking.test.js +92 -0
- package/dist/rag/chunking.test.js.map +1 -0
- package/dist/rag/context-assembler.test.d.ts +19 -0
- package/dist/rag/context-assembler.test.d.ts.map +1 -0
- package/dist/rag/context-assembler.test.js +98 -0
- package/dist/rag/context-assembler.test.js.map +1 -0
- package/dist/rag/embedding.test.d.ts +19 -0
- package/dist/rag/embedding.test.d.ts.map +1 -0
- package/dist/rag/embedding.test.js +115 -0
- package/dist/rag/embedding.test.js.map +1 -0
- package/dist/rag/ingestion.test.d.ts +22 -0
- package/dist/rag/ingestion.test.d.ts.map +1 -0
- package/dist/rag/ingestion.test.js +99 -0
- package/dist/rag/ingestion.test.js.map +1 -0
- package/dist/rag/knowledge-base.test.d.ts +17 -0
- package/dist/rag/knowledge-base.test.d.ts.map +1 -0
- package/dist/rag/knowledge-base.test.js +77 -0
- package/dist/rag/knowledge-base.test.js.map +1 -0
- package/dist/rag/rag-tool.test.d.ts +21 -0
- package/dist/rag/rag-tool.test.d.ts.map +1 -0
- package/dist/rag/rag-tool.test.js +149 -0
- package/dist/rag/rag-tool.test.js.map +1 -0
- package/dist/rag/retriever.test.d.ts +26 -0
- package/dist/rag/retriever.test.d.ts.map +1 -0
- package/dist/rag/retriever.test.js +180 -0
- package/dist/rag/retriever.test.js.map +1 -0
- package/dist/rag/vector-store.test.d.ts +38 -0
- package/dist/rag/vector-store.test.d.ts.map +1 -0
- package/dist/rag/vector-store.test.js +175 -0
- package/dist/rag/vector-store.test.js.map +1 -0
- package/dist/registry/ManagedRegistry.test.d.ts +21 -0
- package/dist/registry/ManagedRegistry.test.d.ts.map +1 -0
- package/dist/registry/ManagedRegistry.test.js +98 -0
- package/dist/registry/ManagedRegistry.test.js.map +1 -0
- package/dist/registry/Registry.test.d.ts +18 -0
- package/dist/registry/Registry.test.d.ts.map +1 -0
- package/dist/registry/Registry.test.js +79 -0
- package/dist/registry/Registry.test.js.map +1 -0
- package/dist/registry/agent/definitions.test.d.ts +15 -0
- package/dist/registry/agent/definitions.test.d.ts.map +1 -0
- package/dist/registry/agent/definitions.test.js +84 -0
- package/dist/registry/agent/definitions.test.js.map +1 -0
- package/dist/registry/connector/definitions.test.d.ts +13 -0
- package/dist/registry/connector/definitions.test.d.ts.map +1 -0
- package/dist/registry/connector/definitions.test.js +41 -0
- package/dist/registry/connector/definitions.test.js.map +1 -0
- package/dist/registry/connector/scoped.test.d.ts +21 -0
- package/dist/registry/connector/scoped.test.d.ts.map +1 -0
- package/dist/registry/connector/scoped.test.js +115 -0
- package/dist/registry/connector/scoped.test.js.map +1 -0
- package/dist/registry/plugin/index.test.d.ts +12 -0
- package/dist/registry/plugin/index.test.d.ts.map +1 -0
- package/dist/registry/plugin/index.test.js +69 -0
- package/dist/registry/plugin/index.test.js.map +1 -0
- package/dist/registry/tool/execute.test.d.ts +42 -0
- package/dist/registry/tool/execute.test.d.ts.map +1 -0
- package/dist/registry/tool/execute.test.js +281 -0
- package/dist/registry/tool/execute.test.js.map +1 -0
- package/dist/runtime/query/events.d.ts +3 -1
- package/dist/runtime/query/events.d.ts.map +1 -1
- package/dist/runtime/query/events.js +6 -1
- package/dist/runtime/query/events.js.map +1 -1
- package/dist/runtime/query/executor.d.ts +3 -1
- package/dist/runtime/query/executor.d.ts.map +1 -1
- package/dist/runtime/query/executor.js +30 -1
- package/dist/runtime/query/executor.js.map +1 -1
- package/dist/runtime/query/iteration/phases/advisory.test.d.ts +42 -0
- package/dist/runtime/query/iteration/phases/advisory.test.d.ts.map +1 -0
- package/dist/runtime/query/iteration/phases/advisory.test.js +334 -0
- package/dist/runtime/query/iteration/phases/advisory.test.js.map +1 -0
- package/dist/test-setup.d.ts +22 -0
- package/dist/test-setup.d.ts.map +1 -0
- package/dist/test-setup.js +23 -0
- package/dist/test-setup.js.map +1 -0
- package/dist/types/bus/index.d.ts +46 -2
- package/dist/types/bus/index.d.ts.map +1 -1
- package/dist/types/doctor/check.d.ts +41 -0
- package/dist/types/doctor/check.d.ts.map +1 -0
- package/dist/types/doctor/check.js +2 -0
- package/dist/types/doctor/check.js.map +1 -0
- package/dist/types/doctor/index.d.ts +2 -0
- package/dist/types/doctor/index.d.ts.map +1 -0
- package/dist/types/doctor/index.js +2 -0
- package/dist/types/doctor/index.js.map +1 -0
- package/dist/types/probe/event-kind.d.ts +6 -0
- package/dist/types/probe/event-kind.d.ts.map +1 -0
- package/dist/types/probe/event-kind.js +2 -0
- package/dist/types/probe/event-kind.js.map +1 -0
- package/dist/types/probe/event-of.d.ts +5 -0
- package/dist/types/probe/event-of.d.ts.map +1 -0
- package/dist/types/probe/event-of.js +2 -0
- package/dist/types/probe/event-of.js.map +1 -0
- package/dist/types/probe/index.d.ts +4 -0
- package/dist/types/probe/index.d.ts.map +1 -0
- package/dist/types/probe/index.js +2 -0
- package/dist/types/probe/index.js.map +1 -0
- package/dist/types/probe/registry.d.ts +27 -0
- package/dist/types/probe/registry.d.ts.map +1 -0
- package/dist/types/probe/registry.js +2 -0
- package/dist/types/probe/registry.js.map +1 -0
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +5 -0
- package/dist/utils/logger.js.map +1 -1
- package/dist/vault/instrumentation.d.ts +11 -0
- package/dist/vault/instrumentation.d.ts.map +1 -0
- package/dist/vault/instrumentation.js +32 -0
- package/dist/vault/instrumentation.js.map +1 -0
- package/dist/vault/instrumentation.test.d.ts +2 -0
- package/dist/vault/instrumentation.test.d.ts.map +1 -0
- package/dist/vault/instrumentation.test.js +80 -0
- package/dist/vault/instrumentation.test.js.map +1 -0
- package/package.json +4 -1
- package/src/advisory/context.test.ts +109 -0
- package/src/advisory/evaluator.test.ts +192 -0
- package/src/advisory/executor.test.ts +272 -0
- package/src/advisory/registry.test.ts +75 -0
- package/src/bridge/a2a/agent-card.test.ts +140 -0
- package/src/bridge/a2a/mapper.test.ts +293 -0
- package/src/bridge/a2a/message.test.ts +138 -0
- package/src/bridge/a2a/task.test.ts +235 -0
- package/src/bridge/mcp/connector/adapter.test.ts +230 -0
- package/src/bridge/sse/mapper.test.ts +422 -0
- package/src/bridge/tools/connector/adapter.test.ts +224 -0
- package/src/bridge/tools/connector/definitions.test.ts +183 -0
- package/src/bridge/tools/connector/router.test.ts +159 -0
- package/src/bus/breaker.test.ts +274 -0
- package/src/bus/index.test.ts +183 -0
- package/src/bus/index.ts +21 -10
- package/src/bus/lock.test.ts +265 -0
- package/src/bus/ownership.test.ts +243 -0
- package/src/connector/BaseConnector.test.ts +130 -0
- package/src/connector/builtins/http.test.ts +290 -0
- package/src/connector/builtins/webhook.test.ts +138 -0
- package/src/connector/execution/factory.test.ts +75 -0
- package/src/connector/execution/remote.test.ts +63 -0
- package/src/connector/mcp/adapter.test.ts +249 -0
- package/src/probe/context.ts +14 -0
- package/src/probe/errors.ts +27 -0
- package/src/probe/index.ts +4 -0
- package/src/probe/registry.test.ts +480 -0
- package/src/probe/registry.ts +276 -0
- package/src/provider/instrumentation.test.ts +192 -0
- package/src/provider/instrumentation.ts +139 -0
- package/src/public-runtime.ts +17 -0
- package/src/public-types.ts +3 -0
- package/src/rag/chunking.test.ts +107 -0
- package/src/rag/context-assembler.test.ts +114 -0
- package/src/rag/embedding.test.ts +130 -0
- package/src/rag/ingestion.test.ts +114 -0
- package/src/rag/knowledge-base.test.ts +106 -0
- package/src/rag/rag-tool.test.ts +167 -0
- package/src/rag/retriever.test.ts +210 -0
- package/src/rag/vector-store.test.ts +196 -0
- package/src/registry/ManagedRegistry.test.ts +118 -0
- package/src/registry/Registry.test.ts +91 -0
- package/src/registry/agent/definitions.test.ts +100 -0
- package/src/registry/connector/definitions.test.ts +51 -0
- package/src/registry/connector/scoped.test.ts +129 -0
- package/src/registry/plugin/index.test.ts +85 -0
- package/src/registry/tool/execute.test.ts +330 -0
- package/src/runtime/query/events.ts +6 -1
- package/src/runtime/query/executor.ts +34 -0
- package/src/runtime/query/iteration/phases/advisory.test.ts +412 -0
- package/src/test-setup.ts +24 -0
- package/src/types/bus/index.ts +54 -2
- package/src/types/doctor/check.ts +53 -0
- package/src/types/doctor/index.ts +9 -0
- package/src/types/probe/event-kind.ts +8 -0
- package/src/types/probe/event-of.ts +3 -0
- package/src/types/probe/index.ts +11 -0
- package/src/types/probe/registry.ts +36 -0
- package/src/utils/logger.ts +6 -1
- package/src/vault/instrumentation.test.ts +98 -0
- package/src/vault/instrumentation.ts +56 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Current-code invariants asserted (2026-04-21, ses_006 Phase 2):
|
|
3
|
+
*
|
|
4
|
+
* - `connectorMethodToTool(connectorId, instanceId, method, manager)`
|
|
5
|
+
* produces a `ToolDefinition` with:
|
|
6
|
+
* - `name: '<connectorId>_<methodName>'`
|
|
7
|
+
* - `description: '[<connectorId>] <method.description>'`
|
|
8
|
+
* - `category: 'network'`, `permissions: ['network_access']`,
|
|
9
|
+
* all read/destructive/concurrency flags set (readOnly:false,
|
|
10
|
+
* destructive:false, concurrencySafe:true) — current behavior,
|
|
11
|
+
* regardless of what the underlying method actually does.
|
|
12
|
+
* - `execute(input, ctx)` calls `manager.execute` and wraps the
|
|
13
|
+
* result; output is JSON-stringified on success, empty string
|
|
14
|
+
* on failure; `_context` is ignored (§2.7).
|
|
15
|
+
* - `connectorInstanceToTools(instanceId, manager)` throws when the
|
|
16
|
+
* instance is missing; returns one tool per method otherwise.
|
|
17
|
+
* - `allConnectorTools(manager)` enumerates
|
|
18
|
+
* `manager.listConnectedInstances()` and flattens per-instance tool
|
|
19
|
+
* lists.
|
|
20
|
+
* - `createConnectorRouterTool(manager)` returns a single
|
|
21
|
+
* `connector_execute` tool that routes by
|
|
22
|
+
* `{connectorId, instanceId, method, input}`; returns
|
|
23
|
+
* `{success: false}` results (not thrown errors) for missing
|
|
24
|
+
* instance or connectorId mismatch. The description enumerates
|
|
25
|
+
* currently connected instances.
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
29
|
+
import { z } from 'zod'
|
|
30
|
+
|
|
31
|
+
import type { ConnectorManager } from '../../../manager/connector/lifecycle.js'
|
|
32
|
+
import type { ConnectorRegistry } from '../../../registry/connector/definitions.js'
|
|
33
|
+
import type {
|
|
34
|
+
ConnectorDefinition,
|
|
35
|
+
ConnectorExecuteResult,
|
|
36
|
+
ConnectorInstance,
|
|
37
|
+
} from '../../../types/connector/index.js'
|
|
38
|
+
import type { ConnectorId, ConnectorInstanceId } from '../../../types/ids/index.js'
|
|
39
|
+
import type { ToolContext } from '../../../types/tool/index.js'
|
|
40
|
+
|
|
41
|
+
import {
|
|
42
|
+
allConnectorTools,
|
|
43
|
+
connectorInstanceToTools,
|
|
44
|
+
connectorMethodToTool,
|
|
45
|
+
createConnectorRouterTool,
|
|
46
|
+
} from './adapter.js'
|
|
47
|
+
|
|
48
|
+
const CID = 'conn_http' as ConnectorId
|
|
49
|
+
const IID1 = 'ci_abc123' as ConnectorInstanceId
|
|
50
|
+
const IID2 = 'ci_def456' as ConnectorInstanceId
|
|
51
|
+
|
|
52
|
+
function makeMethod(name: string, description = `${name} description`) {
|
|
53
|
+
return { name, description, inputSchema: z.object({}) }
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function makeManager(overrides: Partial<ConnectorManager> = {}): ConnectorManager {
|
|
57
|
+
const execute = vi.fn<() => Promise<ConnectorExecuteResult>>()
|
|
58
|
+
const def: ConnectorDefinition = {
|
|
59
|
+
id: CID,
|
|
60
|
+
name: 'HTTP',
|
|
61
|
+
description: 'HTTP connector',
|
|
62
|
+
connectionType: 'http',
|
|
63
|
+
configSchema: z.object({}),
|
|
64
|
+
methods: [makeMethod('request'), makeMethod('send')],
|
|
65
|
+
}
|
|
66
|
+
const registry = {
|
|
67
|
+
getOrThrow: vi.fn(() => def),
|
|
68
|
+
get: vi.fn(() => def),
|
|
69
|
+
} as unknown as ConnectorRegistry
|
|
70
|
+
const instance: ConnectorInstance = {
|
|
71
|
+
id: IID1,
|
|
72
|
+
connectorId: CID,
|
|
73
|
+
config: { connectorId: CID, name: 'default' },
|
|
74
|
+
status: 'connected',
|
|
75
|
+
createdAt: Date.now(),
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
getInstance: vi.fn(() => instance),
|
|
79
|
+
getRegistry: vi.fn(() => registry),
|
|
80
|
+
listConnectedInstances: vi.fn(() => [instance]),
|
|
81
|
+
listInstances: vi.fn(() => [instance]),
|
|
82
|
+
execute,
|
|
83
|
+
...overrides,
|
|
84
|
+
} as unknown as ConnectorManager
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const ctx: ToolContext = {} as ToolContext
|
|
88
|
+
|
|
89
|
+
describe('connectorMethodToTool', () => {
|
|
90
|
+
it('produces the expected name + description + flags', () => {
|
|
91
|
+
const manager = makeManager()
|
|
92
|
+
const tool = connectorMethodToTool(CID, IID1, makeMethod('request'), manager)
|
|
93
|
+
expect(tool.name).toBe(`${CID}_request`)
|
|
94
|
+
expect(tool.description).toBe(`[${CID}] request description`)
|
|
95
|
+
expect(tool.category).toBe('network')
|
|
96
|
+
expect(tool.permissions).toEqual(['network_access'])
|
|
97
|
+
expect(tool.isReadOnly?.({})).toBe(false)
|
|
98
|
+
expect(tool.isDestructive?.({})).toBe(false)
|
|
99
|
+
expect(tool.isConcurrencySafe?.({})).toBe(true)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
it('execute wraps manager.execute success into a ToolResult with stringified output', async () => {
|
|
103
|
+
const manager = makeManager()
|
|
104
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
105
|
+
success: true,
|
|
106
|
+
output: { answer: 42 },
|
|
107
|
+
durationMs: 10,
|
|
108
|
+
})
|
|
109
|
+
const tool = connectorMethodToTool(CID, IID1, makeMethod('request'), manager)
|
|
110
|
+
const result = await tool.execute({}, ctx)
|
|
111
|
+
expect(result.success).toBe(true)
|
|
112
|
+
expect(result.output).toBe(JSON.stringify({ answer: 42 }, null, 2))
|
|
113
|
+
expect(result.data).toEqual({ answer: 42 })
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('execute carries through failure, leaves output as empty string', async () => {
|
|
117
|
+
const manager = makeManager()
|
|
118
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
119
|
+
success: false,
|
|
120
|
+
output: undefined,
|
|
121
|
+
durationMs: 5,
|
|
122
|
+
error: 'boom',
|
|
123
|
+
})
|
|
124
|
+
const tool = connectorMethodToTool(CID, IID1, makeMethod('request'), manager)
|
|
125
|
+
const result = await tool.execute({}, ctx)
|
|
126
|
+
expect(result.success).toBe(false)
|
|
127
|
+
expect(result.output).toBe('')
|
|
128
|
+
expect(result.error).toBe('boom')
|
|
129
|
+
})
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
describe('connectorInstanceToTools', () => {
|
|
133
|
+
it('returns one tool per method on the definition', () => {
|
|
134
|
+
const manager = makeManager()
|
|
135
|
+
const tools = connectorInstanceToTools(IID1, manager)
|
|
136
|
+
expect(tools.map((t) => t.name)).toEqual([`${CID}_request`, `${CID}_send`])
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
it('throws when the instance is not found', () => {
|
|
140
|
+
const manager = makeManager({
|
|
141
|
+
getInstance: vi.fn(() => undefined),
|
|
142
|
+
} as unknown as Partial<ConnectorManager>)
|
|
143
|
+
expect(() => connectorInstanceToTools(IID2, manager)).toThrow(/not found/)
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
describe('allConnectorTools', () => {
|
|
148
|
+
it('enumerates every connected instance', () => {
|
|
149
|
+
const manager = makeManager()
|
|
150
|
+
const tools = allConnectorTools(manager)
|
|
151
|
+
expect(tools).toHaveLength(2)
|
|
152
|
+
expect(manager.listConnectedInstances).toHaveBeenCalled()
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
it('returns empty array when no connected instances', () => {
|
|
156
|
+
const manager = makeManager({
|
|
157
|
+
listConnectedInstances: vi.fn(() => []),
|
|
158
|
+
} as unknown as Partial<ConnectorManager>)
|
|
159
|
+
expect(allConnectorTools(manager)).toEqual([])
|
|
160
|
+
})
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
describe('createConnectorRouterTool', () => {
|
|
164
|
+
it('returns a single connector_execute tool', () => {
|
|
165
|
+
const tool = createConnectorRouterTool(makeManager())
|
|
166
|
+
expect(tool.name).toBe('connector_execute')
|
|
167
|
+
expect(tool.category).toBe('network')
|
|
168
|
+
})
|
|
169
|
+
|
|
170
|
+
it('description enumerates currently connected instances', () => {
|
|
171
|
+
const tool = createConnectorRouterTool(makeManager())
|
|
172
|
+
expect(tool.description).toContain(CID)
|
|
173
|
+
expect(tool.description).toContain(IID1)
|
|
174
|
+
expect(tool.description).toContain('request')
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
it('description notes "No connectors are currently connected" when empty', () => {
|
|
178
|
+
const manager = makeManager({
|
|
179
|
+
listConnectedInstances: vi.fn(() => []),
|
|
180
|
+
} as unknown as Partial<ConnectorManager>)
|
|
181
|
+
const tool = createConnectorRouterTool(manager)
|
|
182
|
+
expect(tool.description).toContain('No connectors are currently connected')
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
it('execute returns {success: false} when instance is missing', async () => {
|
|
186
|
+
const manager = makeManager({
|
|
187
|
+
getInstance: vi.fn(() => undefined),
|
|
188
|
+
} as unknown as Partial<ConnectorManager>)
|
|
189
|
+
const tool = createConnectorRouterTool(manager)
|
|
190
|
+
const result = await tool.execute(
|
|
191
|
+
{ connectorId: CID, instanceId: IID2, method: 'request', input: {} },
|
|
192
|
+
ctx,
|
|
193
|
+
)
|
|
194
|
+
expect(result.success).toBe(false)
|
|
195
|
+
expect(result.error).toMatch(/not found/)
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
it('execute returns {success: false} when connectorId mismatches the instance', async () => {
|
|
199
|
+
const manager = makeManager()
|
|
200
|
+
const tool = createConnectorRouterTool(manager)
|
|
201
|
+
const result = await tool.execute(
|
|
202
|
+
{ connectorId: 'conn_other' as ConnectorId, instanceId: IID1, method: 'request', input: {} },
|
|
203
|
+
ctx,
|
|
204
|
+
)
|
|
205
|
+
expect(result.success).toBe(false)
|
|
206
|
+
expect(result.error).toMatch(/belongs to connector/)
|
|
207
|
+
})
|
|
208
|
+
|
|
209
|
+
it('execute delegates to manager.execute on happy path', async () => {
|
|
210
|
+
const manager = makeManager()
|
|
211
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
212
|
+
success: true,
|
|
213
|
+
output: 'hello',
|
|
214
|
+
durationMs: 1,
|
|
215
|
+
})
|
|
216
|
+
const tool = createConnectorRouterTool(manager)
|
|
217
|
+
const result = await tool.execute(
|
|
218
|
+
{ connectorId: CID, instanceId: IID1, method: 'request', input: { k: 'v' } },
|
|
219
|
+
ctx,
|
|
220
|
+
)
|
|
221
|
+
expect(result.success).toBe(true)
|
|
222
|
+
expect(result.data).toBe('hello')
|
|
223
|
+
})
|
|
224
|
+
})
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Current-code invariants asserted (2026-04-21, ses_006 Phase 2):
|
|
3
|
+
*
|
|
4
|
+
* - `createConnectorExecuteTool(config)` returns a `defineTool`-wrapped
|
|
5
|
+
* tool named `connector_execute` that:
|
|
6
|
+
* - Returns `{success: false, error: '... not found'}` when instance
|
|
7
|
+
* is missing.
|
|
8
|
+
* - Returns `{success: false, error: '... not connected'}` when the
|
|
9
|
+
* instance exists but `status !== 'connected'`.
|
|
10
|
+
* - Returns `{success: false, error: ...}` when `manager.execute`
|
|
11
|
+
* itself reports failure; falls back to 'Connector execution
|
|
12
|
+
* failed' when the execute error is undefined.
|
|
13
|
+
* - On success, stringifies non-string outputs to JSON; strings pass
|
|
14
|
+
* through as-is.
|
|
15
|
+
* - Attaches `data: { durationMs, metadata }` on success.
|
|
16
|
+
* - `createConnectorListTool(config)` returns a tool named
|
|
17
|
+
* `connector_list` that:
|
|
18
|
+
* - Emits "No connector instances configured." when none exist.
|
|
19
|
+
* - Lists each instance with `- <id> (<connectorId>): <name> [<status>]`.
|
|
20
|
+
* - `createConnectorTools(config)` returns the pair of tools above.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
24
|
+
|
|
25
|
+
import type { ConnectorManager } from '../../../manager/connector/lifecycle.js'
|
|
26
|
+
import type { ConnectorExecuteResult, ConnectorInstance } from '../../../types/connector/index.js'
|
|
27
|
+
import type { ConnectorId, ConnectorInstanceId } from '../../../types/ids/index.js'
|
|
28
|
+
import type { ToolContext } from '../../../types/tool/index.js'
|
|
29
|
+
|
|
30
|
+
import {
|
|
31
|
+
createConnectorExecuteTool,
|
|
32
|
+
createConnectorListTool,
|
|
33
|
+
createConnectorTools,
|
|
34
|
+
} from './definitions.js'
|
|
35
|
+
|
|
36
|
+
const CID = 'conn_http' as ConnectorId
|
|
37
|
+
const IID = 'ci_abc123' as ConnectorInstanceId
|
|
38
|
+
|
|
39
|
+
function makeInstance(overrides: Partial<ConnectorInstance> = {}): ConnectorInstance {
|
|
40
|
+
return {
|
|
41
|
+
id: IID,
|
|
42
|
+
connectorId: CID,
|
|
43
|
+
config: { connectorId: CID, name: 'default' },
|
|
44
|
+
status: 'connected',
|
|
45
|
+
createdAt: Date.now(),
|
|
46
|
+
...overrides,
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function makeManager(overrides: Partial<ConnectorManager> = {}): ConnectorManager {
|
|
51
|
+
return {
|
|
52
|
+
getInstance: vi.fn(() => makeInstance()),
|
|
53
|
+
listInstances: vi.fn(() => [makeInstance()]),
|
|
54
|
+
execute: vi.fn<() => Promise<ConnectorExecuteResult>>(),
|
|
55
|
+
...overrides,
|
|
56
|
+
} as unknown as ConnectorManager
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const ctx: ToolContext = {} as ToolContext
|
|
60
|
+
|
|
61
|
+
describe('createConnectorExecuteTool', () => {
|
|
62
|
+
it('is named connector_execute', () => {
|
|
63
|
+
const tool = createConnectorExecuteTool({ manager: makeManager() })
|
|
64
|
+
expect(tool.name).toBe('connector_execute')
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('returns error when instance is missing', async () => {
|
|
68
|
+
const manager = makeManager({
|
|
69
|
+
getInstance: vi.fn(() => undefined),
|
|
70
|
+
} as unknown as Partial<ConnectorManager>)
|
|
71
|
+
const tool = createConnectorExecuteTool({ manager })
|
|
72
|
+
const result = await tool.execute({ instance_id: IID, method: 'request', input: {} }, ctx)
|
|
73
|
+
expect(result.success).toBe(false)
|
|
74
|
+
expect(result.error).toMatch(/not found/)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
it('returns error when instance status is not "connected"', async () => {
|
|
78
|
+
const manager = makeManager({
|
|
79
|
+
getInstance: vi.fn(() => makeInstance({ status: 'disconnected' })),
|
|
80
|
+
} as unknown as Partial<ConnectorManager>)
|
|
81
|
+
const tool = createConnectorExecuteTool({ manager })
|
|
82
|
+
const result = await tool.execute({ instance_id: IID, method: 'request', input: {} }, ctx)
|
|
83
|
+
expect(result.success).toBe(false)
|
|
84
|
+
expect(result.error).toMatch(/not connected/)
|
|
85
|
+
expect(result.error).toMatch(/disconnected/)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('wraps manager.execute failure; falls back to "Connector execution failed" on undefined error', async () => {
|
|
89
|
+
const manager = makeManager()
|
|
90
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
91
|
+
success: false,
|
|
92
|
+
output: undefined,
|
|
93
|
+
durationMs: 1,
|
|
94
|
+
})
|
|
95
|
+
const tool = createConnectorExecuteTool({ manager })
|
|
96
|
+
const result = await tool.execute({ instance_id: IID, method: 'request', input: {} }, ctx)
|
|
97
|
+
expect(result.success).toBe(false)
|
|
98
|
+
expect(result.error).toBe('Connector execution failed')
|
|
99
|
+
})
|
|
100
|
+
|
|
101
|
+
it('carries the explicit error message when provided by manager.execute', async () => {
|
|
102
|
+
const manager = makeManager()
|
|
103
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
104
|
+
success: false,
|
|
105
|
+
output: undefined,
|
|
106
|
+
durationMs: 1,
|
|
107
|
+
error: 'timeout',
|
|
108
|
+
})
|
|
109
|
+
const tool = createConnectorExecuteTool({ manager })
|
|
110
|
+
const result = await tool.execute({ instance_id: IID, method: 'request', input: {} }, ctx)
|
|
111
|
+
expect(result.error).toBe('timeout')
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
it('passes through string outputs as-is', async () => {
|
|
115
|
+
const manager = makeManager()
|
|
116
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
117
|
+
success: true,
|
|
118
|
+
output: 'hi there',
|
|
119
|
+
durationMs: 10,
|
|
120
|
+
})
|
|
121
|
+
const tool = createConnectorExecuteTool({ manager })
|
|
122
|
+
const result = await tool.execute({ instance_id: IID, method: 'request', input: {} }, ctx)
|
|
123
|
+
expect(result.success).toBe(true)
|
|
124
|
+
expect(result.output).toBe('hi there')
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
it('stringifies non-string outputs + attaches durationMs + metadata to data', async () => {
|
|
128
|
+
const manager = makeManager()
|
|
129
|
+
vi.mocked(manager.execute).mockResolvedValueOnce({
|
|
130
|
+
success: true,
|
|
131
|
+
output: { answer: 42 },
|
|
132
|
+
durationMs: 15,
|
|
133
|
+
metadata: { region: 'us-east-1' },
|
|
134
|
+
})
|
|
135
|
+
const tool = createConnectorExecuteTool({ manager })
|
|
136
|
+
const result = await tool.execute({ instance_id: IID, method: 'request', input: {} }, ctx)
|
|
137
|
+
expect(result.output).toBe(JSON.stringify({ answer: 42 }, null, 2))
|
|
138
|
+
expect(result.data).toEqual({ durationMs: 15, metadata: { region: 'us-east-1' } })
|
|
139
|
+
})
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
describe('createConnectorListTool', () => {
|
|
143
|
+
it('is named connector_list + read-only', () => {
|
|
144
|
+
const tool = createConnectorListTool({ manager: makeManager() })
|
|
145
|
+
expect(tool.name).toBe('connector_list')
|
|
146
|
+
expect(tool.isReadOnly?.({})).toBe(true)
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
it('emits "No connector instances configured." when none', async () => {
|
|
150
|
+
const manager = makeManager({
|
|
151
|
+
listInstances: vi.fn(() => []),
|
|
152
|
+
} as unknown as Partial<ConnectorManager>)
|
|
153
|
+
const tool = createConnectorListTool({ manager })
|
|
154
|
+
const result = await tool.execute({}, ctx)
|
|
155
|
+
expect(result.success).toBe(true)
|
|
156
|
+
expect(result.output).toBe('No connector instances configured.')
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
it('lists every instance with id / connectorId / name / status', async () => {
|
|
160
|
+
const manager = makeManager({
|
|
161
|
+
listInstances: vi.fn(() => [
|
|
162
|
+
makeInstance({ id: IID }),
|
|
163
|
+
makeInstance({
|
|
164
|
+
id: 'ci_def' as ConnectorInstanceId,
|
|
165
|
+
status: 'disconnected',
|
|
166
|
+
}),
|
|
167
|
+
]),
|
|
168
|
+
} as unknown as Partial<ConnectorManager>)
|
|
169
|
+
const tool = createConnectorListTool({ manager })
|
|
170
|
+
const result = await tool.execute({}, ctx)
|
|
171
|
+
expect(result.success).toBe(true)
|
|
172
|
+
expect(result.output).toContain(`- ${IID} (${CID}): default [connected]`)
|
|
173
|
+
expect(result.output).toContain(`- ci_def (${CID}): default [disconnected]`)
|
|
174
|
+
expect(result.data).toBeDefined()
|
|
175
|
+
})
|
|
176
|
+
})
|
|
177
|
+
|
|
178
|
+
describe('createConnectorTools', () => {
|
|
179
|
+
it('returns both execute + list tools', () => {
|
|
180
|
+
const tools = createConnectorTools({ manager: makeManager() })
|
|
181
|
+
expect(tools.map((t) => t.name)).toEqual(['connector_execute', 'connector_list'])
|
|
182
|
+
})
|
|
183
|
+
})
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Current-code invariants asserted (2026-04-21, ses_006 Phase 2):
|
|
3
|
+
*
|
|
4
|
+
* - `new ConnectorToolRouter({ manager })` defaults strategy to
|
|
5
|
+
* `'per-method'`.
|
|
6
|
+
* - `getTools()` with strategy `'router'`:
|
|
7
|
+
* - Returns `[]` when there are no connected instances.
|
|
8
|
+
* - Returns a single `connector_execute` routing tool otherwise.
|
|
9
|
+
* - `getTools()` with strategy `'per-method'`:
|
|
10
|
+
* - Emits one tool per method per connected instance.
|
|
11
|
+
* - Catches errors per-instance (logs + skips) — a broken instance
|
|
12
|
+
* does not poison the entire tool list.
|
|
13
|
+
* - `registerTools(registry)` delegates to `registry.register` for
|
|
14
|
+
* every tool and returns the list of names.
|
|
15
|
+
* - `unregisterTools(registry, names)` calls `registry.unregister`
|
|
16
|
+
* for each name.
|
|
17
|
+
* - `refreshTools(registry, previous)` is unregister-then-register in
|
|
18
|
+
* one call; returns the new names list.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
22
|
+
import { z } from 'zod'
|
|
23
|
+
|
|
24
|
+
import type { ConnectorManager } from '../../../manager/connector/lifecycle.js'
|
|
25
|
+
import type { ConnectorRegistry } from '../../../registry/connector/definitions.js'
|
|
26
|
+
import type { ConnectorDefinition, ConnectorInstance } from '../../../types/connector/index.js'
|
|
27
|
+
import type { ConnectorId, ConnectorInstanceId } from '../../../types/ids/index.js'
|
|
28
|
+
import type { ToolRegistryContract } from '../../../types/tool/index.js'
|
|
29
|
+
|
|
30
|
+
import { ConnectorToolRouter } from './router.js'
|
|
31
|
+
|
|
32
|
+
const CID = 'conn_http' as ConnectorId
|
|
33
|
+
const IID1 = 'ci_a' as ConnectorInstanceId
|
|
34
|
+
const IID2 = 'ci_b' as ConnectorInstanceId
|
|
35
|
+
|
|
36
|
+
function makeDefinition(): ConnectorDefinition {
|
|
37
|
+
return {
|
|
38
|
+
id: CID,
|
|
39
|
+
name: 'HTTP',
|
|
40
|
+
description: 'x',
|
|
41
|
+
connectionType: 'http',
|
|
42
|
+
configSchema: z.object({}),
|
|
43
|
+
methods: [
|
|
44
|
+
{ name: 'request', description: 'd', inputSchema: z.object({}) },
|
|
45
|
+
{ name: 'send', description: 'd', inputSchema: z.object({}) },
|
|
46
|
+
],
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function makeInstance(id: ConnectorInstanceId): ConnectorInstance {
|
|
51
|
+
return {
|
|
52
|
+
id,
|
|
53
|
+
connectorId: CID,
|
|
54
|
+
config: { connectorId: CID, name: 'x' },
|
|
55
|
+
status: 'connected',
|
|
56
|
+
createdAt: Date.now(),
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function makeManager(instances: ConnectorInstance[]): ConnectorManager {
|
|
61
|
+
const def = makeDefinition()
|
|
62
|
+
const registry = {
|
|
63
|
+
getOrThrow: vi.fn(() => def),
|
|
64
|
+
get: vi.fn(() => def),
|
|
65
|
+
} as unknown as ConnectorRegistry
|
|
66
|
+
return {
|
|
67
|
+
getInstance: vi.fn((id) => instances.find((i) => i.id === id)),
|
|
68
|
+
getRegistry: vi.fn(() => registry),
|
|
69
|
+
listConnectedInstances: vi.fn(() => instances),
|
|
70
|
+
listInstances: vi.fn(() => instances),
|
|
71
|
+
execute: vi.fn(),
|
|
72
|
+
} as unknown as ConnectorManager
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function makeToolRegistry(): ToolRegistryContract {
|
|
76
|
+
return {
|
|
77
|
+
register: vi.fn(),
|
|
78
|
+
unregister: vi.fn(() => true),
|
|
79
|
+
clear: vi.fn(),
|
|
80
|
+
} as unknown as ToolRegistryContract
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
describe('ConnectorToolRouter', () => {
|
|
84
|
+
it('defaults strategy to per-method', () => {
|
|
85
|
+
const router = new ConnectorToolRouter({ manager: makeManager([makeInstance(IID1)]) })
|
|
86
|
+
const tools = router.getTools()
|
|
87
|
+
expect(tools.map((t) => t.name)).toEqual([`${CID}_request`, `${CID}_send`])
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('router strategy with connected instances emits one connector_execute tool', () => {
|
|
91
|
+
const router = new ConnectorToolRouter({
|
|
92
|
+
manager: makeManager([makeInstance(IID1)]),
|
|
93
|
+
strategy: 'router',
|
|
94
|
+
})
|
|
95
|
+
const tools = router.getTools()
|
|
96
|
+
expect(tools).toHaveLength(1)
|
|
97
|
+
expect(tools[0]?.name).toBe('connector_execute')
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('router strategy with no connected instances returns empty array', () => {
|
|
101
|
+
const router = new ConnectorToolRouter({
|
|
102
|
+
manager: makeManager([]),
|
|
103
|
+
strategy: 'router',
|
|
104
|
+
})
|
|
105
|
+
expect(router.getTools()).toEqual([])
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
it('per-method strategy with multiple instances emits methods per-instance', () => {
|
|
109
|
+
const router = new ConnectorToolRouter({
|
|
110
|
+
manager: makeManager([makeInstance(IID1), makeInstance(IID2)]),
|
|
111
|
+
})
|
|
112
|
+
const tools = router.getTools()
|
|
113
|
+
expect(tools).toHaveLength(4) // 2 methods * 2 instances
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
it('per-method strategy skips a broken instance + continues with others', () => {
|
|
117
|
+
const good = makeInstance(IID1)
|
|
118
|
+
const bad = makeInstance(IID2)
|
|
119
|
+
const manager = makeManager([good, bad])
|
|
120
|
+
// make instance IID2 "not found" by overriding getInstance
|
|
121
|
+
vi.mocked(manager.getInstance).mockImplementation((id) => (id === IID1 ? good : undefined))
|
|
122
|
+
const router = new ConnectorToolRouter({ manager })
|
|
123
|
+
const tools = router.getTools()
|
|
124
|
+
// 2 from IID1; IID2 threw + got caught
|
|
125
|
+
expect(tools.map((t) => t.name)).toEqual([`${CID}_request`, `${CID}_send`])
|
|
126
|
+
})
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
describe('ConnectorToolRouter.registerTools', () => {
|
|
130
|
+
it('registers every tool and returns the names', () => {
|
|
131
|
+
const router = new ConnectorToolRouter({ manager: makeManager([makeInstance(IID1)]) })
|
|
132
|
+
const reg = makeToolRegistry()
|
|
133
|
+
const names = router.registerTools(reg)
|
|
134
|
+
expect(names).toEqual([`${CID}_request`, `${CID}_send`])
|
|
135
|
+
expect(reg.register).toHaveBeenCalledTimes(2)
|
|
136
|
+
})
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
describe('ConnectorToolRouter.unregisterTools', () => {
|
|
140
|
+
it('unregisters each named tool', () => {
|
|
141
|
+
const router = new ConnectorToolRouter({ manager: makeManager([]) })
|
|
142
|
+
const reg = makeToolRegistry()
|
|
143
|
+
router.unregisterTools(reg, ['a', 'b'])
|
|
144
|
+
expect(reg.unregister).toHaveBeenCalledWith('a')
|
|
145
|
+
expect(reg.unregister).toHaveBeenCalledWith('b')
|
|
146
|
+
expect(reg.unregister).toHaveBeenCalledTimes(2)
|
|
147
|
+
})
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
describe('ConnectorToolRouter.refreshTools', () => {
|
|
151
|
+
it('unregisters previous names then registers new ones', () => {
|
|
152
|
+
const router = new ConnectorToolRouter({ manager: makeManager([makeInstance(IID1)]) })
|
|
153
|
+
const reg = makeToolRegistry()
|
|
154
|
+
const newNames = router.refreshTools(reg, [`${CID}_old_method`])
|
|
155
|
+
expect(reg.unregister).toHaveBeenCalledWith(`${CID}_old_method`)
|
|
156
|
+
expect(newNames).toEqual([`${CID}_request`, `${CID}_send`])
|
|
157
|
+
expect(reg.register).toHaveBeenCalledTimes(2)
|
|
158
|
+
})
|
|
159
|
+
})
|