@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.
Files changed (310) hide show
  1. package/CHANGELOG.md +46 -0
  2. package/dist/advisory/context.test.d.ts +16 -0
  3. package/dist/advisory/context.test.d.ts.map +1 -0
  4. package/dist/advisory/context.test.js +92 -0
  5. package/dist/advisory/context.test.js.map +1 -0
  6. package/dist/advisory/evaluator.test.d.ts +34 -0
  7. package/dist/advisory/evaluator.test.d.ts.map +1 -0
  8. package/dist/advisory/evaluator.test.js +172 -0
  9. package/dist/advisory/evaluator.test.js.map +1 -0
  10. package/dist/advisory/executor.test.d.ts +35 -0
  11. package/dist/advisory/executor.test.d.ts.map +1 -0
  12. package/dist/advisory/executor.test.js +233 -0
  13. package/dist/advisory/executor.test.js.map +1 -0
  14. package/dist/advisory/registry.test.d.ts +16 -0
  15. package/dist/advisory/registry.test.d.ts.map +1 -0
  16. package/dist/advisory/registry.test.js +62 -0
  17. package/dist/advisory/registry.test.js.map +1 -0
  18. package/dist/bridge/a2a/agent-card.test.d.ts +24 -0
  19. package/dist/bridge/a2a/agent-card.test.d.ts.map +1 -0
  20. package/dist/bridge/a2a/agent-card.test.js +118 -0
  21. package/dist/bridge/a2a/agent-card.test.js.map +1 -0
  22. package/dist/bridge/a2a/mapper.test.d.ts +29 -0
  23. package/dist/bridge/a2a/mapper.test.d.ts.map +1 -0
  24. package/dist/bridge/a2a/mapper.test.js +265 -0
  25. package/dist/bridge/a2a/mapper.test.js.map +1 -0
  26. package/dist/bridge/a2a/message.test.d.ts +20 -0
  27. package/dist/bridge/a2a/message.test.d.ts.map +1 -0
  28. package/dist/bridge/a2a/message.test.js +116 -0
  29. package/dist/bridge/a2a/message.test.js.map +1 -0
  30. package/dist/bridge/a2a/task.test.d.ts +29 -0
  31. package/dist/bridge/a2a/task.test.d.ts.map +1 -0
  32. package/dist/bridge/a2a/task.test.js +198 -0
  33. package/dist/bridge/a2a/task.test.js.map +1 -0
  34. package/dist/bridge/mcp/connector/adapter.test.d.ts +27 -0
  35. package/dist/bridge/mcp/connector/adapter.test.d.ts.map +1 -0
  36. package/dist/bridge/mcp/connector/adapter.test.js +203 -0
  37. package/dist/bridge/mcp/connector/adapter.test.js.map +1 -0
  38. package/dist/bridge/sse/mapper.test.d.ts +27 -0
  39. package/dist/bridge/sse/mapper.test.d.ts.map +1 -0
  40. package/dist/bridge/sse/mapper.test.js +271 -0
  41. package/dist/bridge/sse/mapper.test.js.map +1 -0
  42. package/dist/bridge/tools/connector/adapter.d.ts +2 -2
  43. package/dist/bridge/tools/connector/adapter.test.d.ts +28 -0
  44. package/dist/bridge/tools/connector/adapter.test.d.ts.map +1 -0
  45. package/dist/bridge/tools/connector/adapter.test.js +182 -0
  46. package/dist/bridge/tools/connector/adapter.test.js.map +1 -0
  47. package/dist/bridge/tools/connector/definitions.test.d.ts +23 -0
  48. package/dist/bridge/tools/connector/definitions.test.d.ts.map +1 -0
  49. package/dist/bridge/tools/connector/definitions.test.js +158 -0
  50. package/dist/bridge/tools/connector/definitions.test.js.map +1 -0
  51. package/dist/bridge/tools/connector/router.test.d.ts +21 -0
  52. package/dist/bridge/tools/connector/router.test.d.ts.map +1 -0
  53. package/dist/bridge/tools/connector/router.test.js +139 -0
  54. package/dist/bridge/tools/connector/router.test.js.map +1 -0
  55. package/dist/bus/breaker.test.d.ts +41 -0
  56. package/dist/bus/breaker.test.d.ts.map +1 -0
  57. package/dist/bus/breaker.test.js +242 -0
  58. package/dist/bus/breaker.test.js.map +1 -0
  59. package/dist/bus/index.d.ts +3 -1
  60. package/dist/bus/index.d.ts.map +1 -1
  61. package/dist/bus/index.js +18 -11
  62. package/dist/bus/index.js.map +1 -1
  63. package/dist/bus/index.test.d.ts +25 -0
  64. package/dist/bus/index.test.d.ts.map +1 -0
  65. package/dist/bus/index.test.js +151 -0
  66. package/dist/bus/index.test.js.map +1 -0
  67. package/dist/bus/lock.test.d.ts +44 -0
  68. package/dist/bus/lock.test.d.ts.map +1 -0
  69. package/dist/bus/lock.test.js +226 -0
  70. package/dist/bus/lock.test.js.map +1 -0
  71. package/dist/bus/ownership.test.d.ts +26 -0
  72. package/dist/bus/ownership.test.d.ts.map +1 -0
  73. package/dist/bus/ownership.test.js +205 -0
  74. package/dist/bus/ownership.test.js.map +1 -0
  75. package/dist/config/runtime.d.ts +28 -28
  76. package/dist/connector/BaseConnector.test.d.ts +21 -0
  77. package/dist/connector/BaseConnector.test.d.ts.map +1 -0
  78. package/dist/connector/BaseConnector.test.js +108 -0
  79. package/dist/connector/BaseConnector.test.js.map +1 -0
  80. package/dist/connector/builtins/http.test.d.ts +30 -0
  81. package/dist/connector/builtins/http.test.d.ts.map +1 -0
  82. package/dist/connector/builtins/http.test.js +232 -0
  83. package/dist/connector/builtins/http.test.js.map +1 -0
  84. package/dist/connector/builtins/webhook.test.d.ts +20 -0
  85. package/dist/connector/builtins/webhook.test.d.ts.map +1 -0
  86. package/dist/connector/builtins/webhook.test.js +113 -0
  87. package/dist/connector/builtins/webhook.test.js.map +1 -0
  88. package/dist/connector/execution/factory.test.d.ts +16 -0
  89. package/dist/connector/execution/factory.test.d.ts.map +1 -0
  90. package/dist/connector/execution/factory.test.js +64 -0
  91. package/dist/connector/execution/factory.test.js.map +1 -0
  92. package/dist/connector/execution/remote.test.d.ts +16 -0
  93. package/dist/connector/execution/remote.test.d.ts.map +1 -0
  94. package/dist/connector/execution/remote.test.js +53 -0
  95. package/dist/connector/execution/remote.test.js.map +1 -0
  96. package/dist/connector/mcp/adapter.test.d.ts +34 -0
  97. package/dist/connector/mcp/adapter.test.d.ts.map +1 -0
  98. package/dist/connector/mcp/adapter.test.js +199 -0
  99. package/dist/connector/mcp/adapter.test.js.map +1 -0
  100. package/dist/probe/context.d.ts +8 -0
  101. package/dist/probe/context.d.ts.map +1 -0
  102. package/dist/probe/context.js +7 -0
  103. package/dist/probe/context.js.map +1 -0
  104. package/dist/probe/errors.d.ts +12 -0
  105. package/dist/probe/errors.d.ts.map +1 -0
  106. package/dist/probe/errors.js +21 -0
  107. package/dist/probe/errors.js.map +1 -0
  108. package/dist/probe/index.d.ts +5 -0
  109. package/dist/probe/index.d.ts.map +1 -0
  110. package/dist/probe/index.js +4 -0
  111. package/dist/probe/index.js.map +1 -0
  112. package/dist/probe/registry.d.ts +24 -0
  113. package/dist/probe/registry.d.ts.map +1 -0
  114. package/dist/probe/registry.js +228 -0
  115. package/dist/probe/registry.js.map +1 -0
  116. package/dist/probe/registry.test.d.ts +7 -0
  117. package/dist/probe/registry.test.d.ts.map +1 -0
  118. package/dist/probe/registry.test.js +310 -0
  119. package/dist/probe/registry.test.js.map +1 -0
  120. package/dist/provider/instrumentation.d.ts +9 -0
  121. package/dist/provider/instrumentation.d.ts.map +1 -0
  122. package/dist/provider/instrumentation.js +104 -0
  123. package/dist/provider/instrumentation.js.map +1 -0
  124. package/dist/provider/instrumentation.test.d.ts +2 -0
  125. package/dist/provider/instrumentation.test.d.ts.map +1 -0
  126. package/dist/provider/instrumentation.test.js +152 -0
  127. package/dist/provider/instrumentation.test.js.map +1 -0
  128. package/dist/public-runtime.d.ts +5 -0
  129. package/dist/public-runtime.d.ts.map +1 -1
  130. package/dist/public-runtime.js +4 -0
  131. package/dist/public-runtime.js.map +1 -1
  132. package/dist/public-types.d.ts +3 -0
  133. package/dist/public-types.d.ts.map +1 -1
  134. package/dist/rag/chunking.test.d.ts +20 -0
  135. package/dist/rag/chunking.test.d.ts.map +1 -0
  136. package/dist/rag/chunking.test.js +92 -0
  137. package/dist/rag/chunking.test.js.map +1 -0
  138. package/dist/rag/context-assembler.test.d.ts +19 -0
  139. package/dist/rag/context-assembler.test.d.ts.map +1 -0
  140. package/dist/rag/context-assembler.test.js +98 -0
  141. package/dist/rag/context-assembler.test.js.map +1 -0
  142. package/dist/rag/embedding.test.d.ts +19 -0
  143. package/dist/rag/embedding.test.d.ts.map +1 -0
  144. package/dist/rag/embedding.test.js +115 -0
  145. package/dist/rag/embedding.test.js.map +1 -0
  146. package/dist/rag/ingestion.test.d.ts +22 -0
  147. package/dist/rag/ingestion.test.d.ts.map +1 -0
  148. package/dist/rag/ingestion.test.js +99 -0
  149. package/dist/rag/ingestion.test.js.map +1 -0
  150. package/dist/rag/knowledge-base.test.d.ts +17 -0
  151. package/dist/rag/knowledge-base.test.d.ts.map +1 -0
  152. package/dist/rag/knowledge-base.test.js +77 -0
  153. package/dist/rag/knowledge-base.test.js.map +1 -0
  154. package/dist/rag/rag-tool.test.d.ts +21 -0
  155. package/dist/rag/rag-tool.test.d.ts.map +1 -0
  156. package/dist/rag/rag-tool.test.js +149 -0
  157. package/dist/rag/rag-tool.test.js.map +1 -0
  158. package/dist/rag/retriever.test.d.ts +26 -0
  159. package/dist/rag/retriever.test.d.ts.map +1 -0
  160. package/dist/rag/retriever.test.js +180 -0
  161. package/dist/rag/retriever.test.js.map +1 -0
  162. package/dist/rag/vector-store.test.d.ts +38 -0
  163. package/dist/rag/vector-store.test.d.ts.map +1 -0
  164. package/dist/rag/vector-store.test.js +175 -0
  165. package/dist/rag/vector-store.test.js.map +1 -0
  166. package/dist/registry/ManagedRegistry.test.d.ts +21 -0
  167. package/dist/registry/ManagedRegistry.test.d.ts.map +1 -0
  168. package/dist/registry/ManagedRegistry.test.js +98 -0
  169. package/dist/registry/ManagedRegistry.test.js.map +1 -0
  170. package/dist/registry/Registry.test.d.ts +18 -0
  171. package/dist/registry/Registry.test.d.ts.map +1 -0
  172. package/dist/registry/Registry.test.js +79 -0
  173. package/dist/registry/Registry.test.js.map +1 -0
  174. package/dist/registry/agent/definitions.test.d.ts +15 -0
  175. package/dist/registry/agent/definitions.test.d.ts.map +1 -0
  176. package/dist/registry/agent/definitions.test.js +84 -0
  177. package/dist/registry/agent/definitions.test.js.map +1 -0
  178. package/dist/registry/connector/definitions.test.d.ts +13 -0
  179. package/dist/registry/connector/definitions.test.d.ts.map +1 -0
  180. package/dist/registry/connector/definitions.test.js +41 -0
  181. package/dist/registry/connector/definitions.test.js.map +1 -0
  182. package/dist/registry/connector/scoped.test.d.ts +21 -0
  183. package/dist/registry/connector/scoped.test.d.ts.map +1 -0
  184. package/dist/registry/connector/scoped.test.js +115 -0
  185. package/dist/registry/connector/scoped.test.js.map +1 -0
  186. package/dist/registry/plugin/index.test.d.ts +12 -0
  187. package/dist/registry/plugin/index.test.d.ts.map +1 -0
  188. package/dist/registry/plugin/index.test.js +69 -0
  189. package/dist/registry/plugin/index.test.js.map +1 -0
  190. package/dist/registry/tool/execute.test.d.ts +42 -0
  191. package/dist/registry/tool/execute.test.d.ts.map +1 -0
  192. package/dist/registry/tool/execute.test.js +281 -0
  193. package/dist/registry/tool/execute.test.js.map +1 -0
  194. package/dist/runtime/query/events.d.ts +3 -1
  195. package/dist/runtime/query/events.d.ts.map +1 -1
  196. package/dist/runtime/query/events.js +6 -1
  197. package/dist/runtime/query/events.js.map +1 -1
  198. package/dist/runtime/query/executor.d.ts +3 -1
  199. package/dist/runtime/query/executor.d.ts.map +1 -1
  200. package/dist/runtime/query/executor.js +30 -1
  201. package/dist/runtime/query/executor.js.map +1 -1
  202. package/dist/runtime/query/iteration/phases/advisory.test.d.ts +42 -0
  203. package/dist/runtime/query/iteration/phases/advisory.test.d.ts.map +1 -0
  204. package/dist/runtime/query/iteration/phases/advisory.test.js +334 -0
  205. package/dist/runtime/query/iteration/phases/advisory.test.js.map +1 -0
  206. package/dist/test-setup.d.ts +22 -0
  207. package/dist/test-setup.d.ts.map +1 -0
  208. package/dist/test-setup.js +23 -0
  209. package/dist/test-setup.js.map +1 -0
  210. package/dist/types/bus/index.d.ts +46 -2
  211. package/dist/types/bus/index.d.ts.map +1 -1
  212. package/dist/types/doctor/check.d.ts +41 -0
  213. package/dist/types/doctor/check.d.ts.map +1 -0
  214. package/dist/types/doctor/check.js +2 -0
  215. package/dist/types/doctor/check.js.map +1 -0
  216. package/dist/types/doctor/index.d.ts +2 -0
  217. package/dist/types/doctor/index.d.ts.map +1 -0
  218. package/dist/types/doctor/index.js +2 -0
  219. package/dist/types/doctor/index.js.map +1 -0
  220. package/dist/types/probe/event-kind.d.ts +6 -0
  221. package/dist/types/probe/event-kind.d.ts.map +1 -0
  222. package/dist/types/probe/event-kind.js +2 -0
  223. package/dist/types/probe/event-kind.js.map +1 -0
  224. package/dist/types/probe/event-of.d.ts +5 -0
  225. package/dist/types/probe/event-of.d.ts.map +1 -0
  226. package/dist/types/probe/event-of.js +2 -0
  227. package/dist/types/probe/event-of.js.map +1 -0
  228. package/dist/types/probe/index.d.ts +4 -0
  229. package/dist/types/probe/index.d.ts.map +1 -0
  230. package/dist/types/probe/index.js +2 -0
  231. package/dist/types/probe/index.js.map +1 -0
  232. package/dist/types/probe/registry.d.ts +27 -0
  233. package/dist/types/probe/registry.d.ts.map +1 -0
  234. package/dist/types/probe/registry.js +2 -0
  235. package/dist/types/probe/registry.js.map +1 -0
  236. package/dist/utils/logger.d.ts +1 -1
  237. package/dist/utils/logger.d.ts.map +1 -1
  238. package/dist/utils/logger.js +5 -0
  239. package/dist/utils/logger.js.map +1 -1
  240. package/dist/vault/instrumentation.d.ts +11 -0
  241. package/dist/vault/instrumentation.d.ts.map +1 -0
  242. package/dist/vault/instrumentation.js +32 -0
  243. package/dist/vault/instrumentation.js.map +1 -0
  244. package/dist/vault/instrumentation.test.d.ts +2 -0
  245. package/dist/vault/instrumentation.test.d.ts.map +1 -0
  246. package/dist/vault/instrumentation.test.js +80 -0
  247. package/dist/vault/instrumentation.test.js.map +1 -0
  248. package/package.json +4 -1
  249. package/src/advisory/context.test.ts +109 -0
  250. package/src/advisory/evaluator.test.ts +192 -0
  251. package/src/advisory/executor.test.ts +272 -0
  252. package/src/advisory/registry.test.ts +75 -0
  253. package/src/bridge/a2a/agent-card.test.ts +140 -0
  254. package/src/bridge/a2a/mapper.test.ts +293 -0
  255. package/src/bridge/a2a/message.test.ts +138 -0
  256. package/src/bridge/a2a/task.test.ts +235 -0
  257. package/src/bridge/mcp/connector/adapter.test.ts +230 -0
  258. package/src/bridge/sse/mapper.test.ts +422 -0
  259. package/src/bridge/tools/connector/adapter.test.ts +224 -0
  260. package/src/bridge/tools/connector/definitions.test.ts +183 -0
  261. package/src/bridge/tools/connector/router.test.ts +159 -0
  262. package/src/bus/breaker.test.ts +274 -0
  263. package/src/bus/index.test.ts +183 -0
  264. package/src/bus/index.ts +21 -10
  265. package/src/bus/lock.test.ts +265 -0
  266. package/src/bus/ownership.test.ts +243 -0
  267. package/src/connector/BaseConnector.test.ts +130 -0
  268. package/src/connector/builtins/http.test.ts +290 -0
  269. package/src/connector/builtins/webhook.test.ts +138 -0
  270. package/src/connector/execution/factory.test.ts +75 -0
  271. package/src/connector/execution/remote.test.ts +63 -0
  272. package/src/connector/mcp/adapter.test.ts +249 -0
  273. package/src/probe/context.ts +14 -0
  274. package/src/probe/errors.ts +27 -0
  275. package/src/probe/index.ts +4 -0
  276. package/src/probe/registry.test.ts +480 -0
  277. package/src/probe/registry.ts +276 -0
  278. package/src/provider/instrumentation.test.ts +192 -0
  279. package/src/provider/instrumentation.ts +139 -0
  280. package/src/public-runtime.ts +17 -0
  281. package/src/public-types.ts +3 -0
  282. package/src/rag/chunking.test.ts +107 -0
  283. package/src/rag/context-assembler.test.ts +114 -0
  284. package/src/rag/embedding.test.ts +130 -0
  285. package/src/rag/ingestion.test.ts +114 -0
  286. package/src/rag/knowledge-base.test.ts +106 -0
  287. package/src/rag/rag-tool.test.ts +167 -0
  288. package/src/rag/retriever.test.ts +210 -0
  289. package/src/rag/vector-store.test.ts +196 -0
  290. package/src/registry/ManagedRegistry.test.ts +118 -0
  291. package/src/registry/Registry.test.ts +91 -0
  292. package/src/registry/agent/definitions.test.ts +100 -0
  293. package/src/registry/connector/definitions.test.ts +51 -0
  294. package/src/registry/connector/scoped.test.ts +129 -0
  295. package/src/registry/plugin/index.test.ts +85 -0
  296. package/src/registry/tool/execute.test.ts +330 -0
  297. package/src/runtime/query/events.ts +6 -1
  298. package/src/runtime/query/executor.ts +34 -0
  299. package/src/runtime/query/iteration/phases/advisory.test.ts +412 -0
  300. package/src/test-setup.ts +24 -0
  301. package/src/types/bus/index.ts +54 -2
  302. package/src/types/doctor/check.ts +53 -0
  303. package/src/types/doctor/index.ts +9 -0
  304. package/src/types/probe/event-kind.ts +8 -0
  305. package/src/types/probe/event-of.ts +3 -0
  306. package/src/types/probe/index.ts +11 -0
  307. package/src/types/probe/registry.ts +36 -0
  308. package/src/utils/logger.ts +6 -1
  309. package/src/vault/instrumentation.test.ts +98 -0
  310. 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
+ })