@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,412 @@
1
+ /**
2
+ * Current-code invariants asserted (2026-04-21, ses_006 Phase 6 follow-up):
3
+ *
4
+ * This file pins the live mutation boundary that `src/advisory/*` tests
5
+ * intentionally do NOT cover: the advisory phase IS where advisories
6
+ * inject user messages into the run via `ctx.runMgr.pushMessage(...)`
7
+ * (Codex #6). A regression that drops the `pushMessage` call — silently
8
+ * dropping all advisor output — would pass `src/advisory` tests,
9
+ * typecheck, and lint. This file is the only thing that catches it.
10
+ *
11
+ * - **Early-return paths** (no side effects):
12
+ * - No `advisoryCtx` on the iteration ctx → returns immediately.
13
+ * - `advisoryCtx.checkBudget()` denies → returns; NO pushMessage.
14
+ * - Evaluator fires no triggers → returns; NO pushMessage.
15
+ * - Trigger fires but advisor not found in registry → warn log +
16
+ * return; NO pushMessage.
17
+ * - Executor throws → warn log + return; NO pushMessage (partial
18
+ * work NOT persisted).
19
+ * - **Happy path** — trigger fires + advisor resolves + executor
20
+ * succeeds:
21
+ * - Calls `executor.consult(advisor, request, callCtx)` exactly once.
22
+ * - Calls `evaluator.recordFiring(trigger.id, iteration)`.
23
+ * - Calls `advisoryCtx.recordCall(...)` with the full call record.
24
+ * - Calls `runMgr.pushMessage(createUserMessage(wrapped))` exactly
25
+ * once.
26
+ * - The wrapped message includes `<advisory-result advisor="..."
27
+ * trigger="...">` + the advice text + closing tag.
28
+ * - When the result carries `warnings`, they appear under a
29
+ * "Warnings:" section.
30
+ * - When the result carries `decisions`, they appear under a
31
+ * "Decisions:" section AND each decision is pushed to
32
+ * `workingStateManager.addDecision` (if a workingStateManager is
33
+ * present on ctx).
34
+ * - **Trigger selection**: only the first trigger from
35
+ * `evaluator.evaluate(state)[0]` is used per iteration; other fired
36
+ * triggers are discarded this round.
37
+ * - **Question resolution**: `trigger.questionTemplate` is used when
38
+ * set; otherwise the phase uses a default
39
+ * "Iteration N: Review the current progress..." string.
40
+ */
41
+
42
+ import { describe, expect, it, vi } from 'vitest'
43
+
44
+ import type { AdvisoryContext } from '../../../../advisory/context.js'
45
+ import type {
46
+ AdvisorDefinition,
47
+ AdvisoryResult,
48
+ AdvisoryTrigger,
49
+ } from '../../../../types/advisory/index.js'
50
+ import type { RunId } from '../../../../types/ids/index.js'
51
+ import type { Logger } from '../../../../utils/logger.js'
52
+
53
+ import { runAdvisoryPhase } from './advisory.js'
54
+ import type { IterationContext } from './context.js'
55
+
56
+ function makeLogger(): Logger {
57
+ const self = {
58
+ info: vi.fn(),
59
+ warn: vi.fn(),
60
+ error: vi.fn(),
61
+ debug: vi.fn(),
62
+ child: vi.fn(),
63
+ } as unknown as Logger
64
+ ;(self as { child: (ctx: unknown) => Logger }).child = vi.fn(() => self)
65
+ return self
66
+ }
67
+
68
+ interface MockAdvisoryCtxOptions {
69
+ budgetAllowed?: boolean
70
+ firedTriggers?: AdvisoryTrigger[]
71
+ advisor?: AdvisorDefinition
72
+ consultResult?: AdvisoryResult
73
+ consultThrows?: Error
74
+ }
75
+
76
+ function makeAdvisoryCtx(options: MockAdvisoryCtxOptions = {}) {
77
+ const {
78
+ budgetAllowed = true,
79
+ firedTriggers = [],
80
+ advisor,
81
+ consultResult = { advice: 'do the thing' },
82
+ consultThrows,
83
+ } = options
84
+
85
+ const consult = vi.fn(async () => {
86
+ if (consultThrows) throw consultThrows
87
+ return {
88
+ result: consultResult,
89
+ usage: {
90
+ promptTokens: 0,
91
+ completionTokens: 0,
92
+ totalTokens: 0,
93
+ cachedTokens: 0,
94
+ cacheWriteTokens: 0,
95
+ },
96
+ cost: { inputCostPer1M: 0, outputCostPer1M: 0, totalCost: 0, cacheDiscount: 0 },
97
+ durationMs: 1,
98
+ }
99
+ })
100
+ const evaluate = vi.fn(() => firedTriggers)
101
+ const recordFiring = vi.fn()
102
+ const resolve = vi.fn(() => advisor)
103
+ const checkBudget = vi.fn(() => ({
104
+ allowed: budgetAllowed,
105
+ reason: budgetAllowed ? undefined : 'exhausted',
106
+ }))
107
+ const recordCall = vi.fn()
108
+
109
+ return {
110
+ ctx: {
111
+ registry: { resolve },
112
+ executor: { consult },
113
+ evaluator: { evaluate, recordFiring },
114
+ checkBudget,
115
+ recordCall,
116
+ callHistory: [],
117
+ } as unknown as AdvisoryContext,
118
+ mocks: { consult, evaluate, recordFiring, resolve, checkBudget, recordCall },
119
+ }
120
+ }
121
+
122
+ interface MockCtxOptions {
123
+ advisoryCtx?: AdvisoryContext
124
+ withWorkingState?: boolean
125
+ }
126
+
127
+ function makeCtx(options: MockCtxOptions = {}): {
128
+ ctx: IterationContext
129
+ pushMessage: ReturnType<typeof vi.fn>
130
+ addDecision: ReturnType<typeof vi.fn>
131
+ } {
132
+ const pushMessage = vi.fn()
133
+ const addDecision = vi.fn()
134
+
135
+ const ctx = {
136
+ advisoryCtx: options.advisoryCtx,
137
+ runConfig: { tokenBudget: 100_000, costLimitUsd: undefined },
138
+ tools: {
139
+ get: vi.fn(() => undefined),
140
+ toLLMTools: vi.fn(() => []),
141
+ },
142
+ runMgr: {
143
+ id: 'run_1' as RunId,
144
+ messages: [],
145
+ tokenUsage: {
146
+ promptTokens: 0,
147
+ completionTokens: 0,
148
+ totalTokens: 0,
149
+ cachedTokens: 0,
150
+ cacheWriteTokens: 0,
151
+ },
152
+ costInfo: {
153
+ inputCostPer1M: 0,
154
+ outputCostPer1M: 0,
155
+ totalCost: 0,
156
+ cacheDiscount: 0,
157
+ },
158
+ pushMessage,
159
+ },
160
+ log: makeLogger(),
161
+ workingStateManager: options.withWorkingState
162
+ ? {
163
+ getState: vi.fn(() => ({
164
+ task: '',
165
+ plan: [],
166
+ files: new Map(),
167
+ decisions: [],
168
+ failures: [],
169
+ discoveries: [],
170
+ environment: [],
171
+ toolResults: [],
172
+ userRequirements: [],
173
+ assistantNotes: [],
174
+ })),
175
+ addDecision,
176
+ }
177
+ : undefined,
178
+ } as unknown as IterationContext
179
+
180
+ return { ctx, pushMessage, addDecision }
181
+ }
182
+
183
+ const response = {
184
+ id: 'r',
185
+ model: 'm',
186
+ message: { role: 'assistant' as const, content: 'text' },
187
+ usage: {
188
+ promptTokens: 0,
189
+ completionTokens: 0,
190
+ totalTokens: 0,
191
+ cachedTokens: 0,
192
+ cacheWriteTokens: 0,
193
+ },
194
+ finishReason: 'stop' as const,
195
+ }
196
+
197
+ const advisor: AdvisorDefinition = {
198
+ id: 'adv',
199
+ name: 'Advisor',
200
+ provider: {} as never,
201
+ model: 'opus',
202
+ }
203
+
204
+ const trigger: AdvisoryTrigger = {
205
+ id: 'trig',
206
+ condition: { type: 'on_iteration', everyN: 1 },
207
+ advisorId: 'adv',
208
+ }
209
+
210
+ describe('runAdvisoryPhase — early-return paths (no pushMessage)', () => {
211
+ it('returns immediately when advisoryCtx is absent', async () => {
212
+ const { ctx, pushMessage } = makeCtx()
213
+ await runAdvisoryPhase(ctx, 1, response)
214
+ expect(pushMessage).not.toHaveBeenCalled()
215
+ })
216
+
217
+ it('returns when budget is denied', async () => {
218
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({ budgetAllowed: false })
219
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
220
+ await runAdvisoryPhase(ctx, 1, response)
221
+ expect(mocks.checkBudget).toHaveBeenCalled()
222
+ expect(mocks.evaluate).not.toHaveBeenCalled()
223
+ expect(pushMessage).not.toHaveBeenCalled()
224
+ })
225
+
226
+ it('returns when evaluator fires no triggers', async () => {
227
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({ firedTriggers: [] })
228
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
229
+ await runAdvisoryPhase(ctx, 1, response)
230
+ expect(mocks.evaluate).toHaveBeenCalled()
231
+ expect(mocks.resolve).not.toHaveBeenCalled()
232
+ expect(pushMessage).not.toHaveBeenCalled()
233
+ })
234
+
235
+ it('returns (warn) when trigger fires but advisor is not resolved', async () => {
236
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({
237
+ firedTriggers: [trigger],
238
+ advisor: undefined,
239
+ })
240
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
241
+ await runAdvisoryPhase(ctx, 1, response)
242
+ expect(mocks.resolve).toHaveBeenCalledWith('adv')
243
+ expect(mocks.consult).not.toHaveBeenCalled()
244
+ expect(pushMessage).not.toHaveBeenCalled()
245
+ })
246
+
247
+ it('returns when executor.consult throws — does NOT pushMessage partial work', async () => {
248
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({
249
+ firedTriggers: [trigger],
250
+ advisor,
251
+ consultThrows: new Error('provider timeout'),
252
+ })
253
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
254
+ await runAdvisoryPhase(ctx, 1, response)
255
+ expect(mocks.consult).toHaveBeenCalled()
256
+ expect(mocks.recordFiring).not.toHaveBeenCalled()
257
+ expect(mocks.recordCall).not.toHaveBeenCalled()
258
+ expect(pushMessage).not.toHaveBeenCalled()
259
+ })
260
+ })
261
+
262
+ describe('runAdvisoryPhase — happy path', () => {
263
+ it('calls executor + recordFiring + recordCall + pushMessage exactly once', async () => {
264
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({
265
+ firedTriggers: [trigger],
266
+ advisor,
267
+ consultResult: { advice: 'do the thing' },
268
+ })
269
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
270
+
271
+ await runAdvisoryPhase(ctx, 3, response)
272
+
273
+ expect(mocks.consult).toHaveBeenCalledTimes(1)
274
+ expect(mocks.recordFiring).toHaveBeenCalledWith('trig', 3)
275
+ expect(mocks.recordCall).toHaveBeenCalledTimes(1)
276
+ expect(pushMessage).toHaveBeenCalledTimes(1)
277
+ })
278
+
279
+ it('pushMessage wraps advice in <advisory-result> envelope with role user', async () => {
280
+ const { ctx: advCtx } = makeAdvisoryCtx({
281
+ firedTriggers: [trigger],
282
+ advisor,
283
+ consultResult: { advice: 'specific advice text' },
284
+ })
285
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
286
+
287
+ await runAdvisoryPhase(ctx, 1, response)
288
+
289
+ const pushed = pushMessage.mock.calls[0]?.[0] as { role: string; content: string }
290
+ expect(pushed.role).toBe('user')
291
+ expect(pushed.content).toContain('<advisory-result advisor="Advisor" trigger="trig">')
292
+ expect(pushed.content).toContain('specific advice text')
293
+ expect(pushed.content).toContain('</advisory-result>')
294
+ })
295
+
296
+ it('includes Warnings section when the result carries warnings', async () => {
297
+ const { ctx: advCtx } = makeAdvisoryCtx({
298
+ firedTriggers: [trigger],
299
+ advisor,
300
+ consultResult: {
301
+ advice: 'proceed',
302
+ warnings: ['slow response', 'retry likely'],
303
+ },
304
+ })
305
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx })
306
+
307
+ await runAdvisoryPhase(ctx, 1, response)
308
+
309
+ const pushed = pushMessage.mock.calls[0]?.[0] as { content: string }
310
+ expect(pushed.content).toContain('Warnings:')
311
+ expect(pushed.content).toContain('- slow response')
312
+ expect(pushed.content).toContain('- retry likely')
313
+ })
314
+
315
+ it('includes Decisions section + pushes each decision to workingStateManager', async () => {
316
+ const { ctx: advCtx } = makeAdvisoryCtx({
317
+ firedTriggers: [trigger],
318
+ advisor,
319
+ consultResult: {
320
+ advice: 'go',
321
+ decisions: ['use sqlite', 'skip migration'],
322
+ },
323
+ })
324
+ const { ctx, pushMessage, addDecision } = makeCtx({
325
+ advisoryCtx: advCtx,
326
+ withWorkingState: true,
327
+ })
328
+
329
+ await runAdvisoryPhase(ctx, 1, response)
330
+
331
+ const pushed = pushMessage.mock.calls[0]?.[0] as { content: string }
332
+ expect(pushed.content).toContain('Decisions:')
333
+ expect(pushed.content).toContain('- use sqlite')
334
+ expect(pushed.content).toContain('- skip migration')
335
+
336
+ expect(addDecision).toHaveBeenCalledTimes(2)
337
+ expect(addDecision).toHaveBeenCalledWith('use sqlite')
338
+ expect(addDecision).toHaveBeenCalledWith('skip migration')
339
+ })
340
+
341
+ it('does NOT attempt to addDecision when no workingStateManager is present', async () => {
342
+ const { ctx: advCtx } = makeAdvisoryCtx({
343
+ firedTriggers: [trigger],
344
+ advisor,
345
+ consultResult: {
346
+ advice: 'go',
347
+ decisions: ['a'],
348
+ },
349
+ })
350
+ const { ctx, pushMessage } = makeCtx({ advisoryCtx: advCtx, withWorkingState: false })
351
+
352
+ await runAdvisoryPhase(ctx, 1, response)
353
+ // pushMessage still carries the Decisions section in content
354
+ expect((pushMessage.mock.calls[0]?.[0] as { content: string }).content).toContain('- a')
355
+ })
356
+ })
357
+
358
+ describe('runAdvisoryPhase — trigger selection + question', () => {
359
+ it('uses only the first fired trigger per iteration', async () => {
360
+ const other: AdvisoryTrigger = {
361
+ id: 'other',
362
+ condition: { type: 'on_iteration', everyN: 1 },
363
+ advisorId: 'adv',
364
+ }
365
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({
366
+ firedTriggers: [trigger, other],
367
+ advisor,
368
+ })
369
+ const { ctx } = makeCtx({ advisoryCtx: advCtx })
370
+
371
+ await runAdvisoryPhase(ctx, 1, response)
372
+
373
+ expect(mocks.recordFiring).toHaveBeenCalledTimes(1)
374
+ expect(mocks.recordFiring).toHaveBeenCalledWith('trig', 1)
375
+ })
376
+
377
+ it('uses trigger.questionTemplate when present', async () => {
378
+ const custom: AdvisoryTrigger = {
379
+ ...trigger,
380
+ questionTemplate: 'Custom question',
381
+ }
382
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({
383
+ firedTriggers: [custom],
384
+ advisor,
385
+ })
386
+ const { ctx } = makeCtx({ advisoryCtx: advCtx })
387
+
388
+ await runAdvisoryPhase(ctx, 7, response)
389
+ const consultArgs = mocks.consult.mock.calls[0] as unknown as [
390
+ unknown,
391
+ { question: string },
392
+ unknown,
393
+ ]
394
+ expect(consultArgs?.[1].question).toBe('Custom question')
395
+ })
396
+
397
+ it('falls back to the default "Iteration N: ..." question when no template', async () => {
398
+ const { ctx: advCtx, mocks } = makeAdvisoryCtx({
399
+ firedTriggers: [trigger],
400
+ advisor,
401
+ })
402
+ const { ctx } = makeCtx({ advisoryCtx: advCtx })
403
+
404
+ await runAdvisoryPhase(ctx, 7, response)
405
+ const consultArgs = mocks.consult.mock.calls[0] as unknown as [
406
+ unknown,
407
+ { question: string },
408
+ unknown,
409
+ ]
410
+ expect(consultArgs?.[1].question).toContain('Iteration 7')
411
+ })
412
+ })
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Vitest `setupFiles` entry for `@namzu/sdk`.
3
+ *
4
+ * Silences the root logger for the entire test run. Tests that assert on
5
+ * log output use their own mocked Logger instances (constructed via the
6
+ * `makeLogger()` helpers colocated with each test) — those are not
7
+ * affected by the root-level silence.
8
+ *
9
+ * The only thing this suppresses is the stderr spam produced by
10
+ * production code paths that fall through to `getRootLogger()` — e.g.
11
+ * `ToolRegistry.execute`'s zod-validation and thrown-error branches,
12
+ * `ConnectorToolRouter.getTools`' per-instance error catch, the
13
+ * AgentBus listener-throw handler, and every connector's `connect()`
14
+ * info log. GitHub Actions annotates any `[ERROR]` stderr line as a
15
+ * workflow error; silencing the root logger during tests keeps the CI
16
+ * log clean.
17
+ *
18
+ * This is test-only configuration. It runs before every test file and
19
+ * does not affect consumers.
20
+ */
21
+
22
+ import { configureLogger } from './utils/logger.js'
23
+
24
+ configureLogger({ level: 'silent' })
@@ -1,6 +1,8 @@
1
- import type { RunId } from '../ids/index.js'
1
+ import type { CredentialId, LockId, RunId, SandboxId, TenantId } from '../ids/index.js'
2
2
 
3
- export type LockId = `lock_${string}`
3
+ export type { LockId } from '../ids/index.js'
4
+
5
+ export type ProviderCallId = `pcall_${string}`
4
6
 
5
7
  export type CircuitBreakerState = 'closed' | 'open' | 'half_open'
6
8
 
@@ -35,6 +37,15 @@ export type OwnershipClaimResult =
35
37
  | { claimed: true; ownership: FileOwnership }
36
38
  | { claimed: false; currentOwner: RunId; filePath: string }
37
39
 
40
+ export interface ProviderCallUsage {
41
+ readonly inputTokens?: number
42
+ readonly outputTokens?: number
43
+ readonly totalTokens?: number
44
+ readonly costUsd?: number
45
+ }
46
+
47
+ export type SandboxDecisionAction = 'allow' | 'deny'
48
+
38
49
  export type AgentBusEvent =
39
50
  | { type: 'lock_acquired'; lockId: LockId; filePath: string; owner: RunId }
40
51
  | { type: 'lock_released'; lockId: LockId; filePath: string; owner: RunId }
@@ -49,5 +60,46 @@ export type AgentBusEvent =
49
60
  | { type: 'breaker_half_open'; agentRunId: RunId }
50
61
  | { type: 'breaker_probe_success'; agentRunId: RunId }
51
62
  | { type: 'breaker_probe_failure'; agentRunId: RunId }
63
+ | {
64
+ type: 'provider_call_start'
65
+ providerId: string
66
+ model: string
67
+ callId: ProviderCallId
68
+ runId?: RunId
69
+ }
70
+ | {
71
+ type: 'provider_call_completed'
72
+ providerId: string
73
+ model: string
74
+ callId: ProviderCallId
75
+ runId?: RunId
76
+ durationMs: number
77
+ usage?: ProviderCallUsage
78
+ }
79
+ | {
80
+ type: 'provider_call_failed'
81
+ providerId: string
82
+ model: string
83
+ callId: ProviderCallId
84
+ runId?: RunId
85
+ durationMs: number
86
+ error: string
87
+ }
88
+ | {
89
+ type: 'vault_lookup'
90
+ vaultId: string
91
+ credentialId?: CredentialId
92
+ tenantId?: TenantId
93
+ found: boolean
94
+ runId?: RunId
95
+ }
96
+ | {
97
+ type: 'sandbox_decision'
98
+ sandboxId: SandboxId
99
+ action: SandboxDecisionAction
100
+ resource: string
101
+ ruleId?: string
102
+ runId?: RunId
103
+ }
52
104
 
53
105
  export type AgentBusEventListener = (event: AgentBusEvent) => void
@@ -0,0 +1,53 @@
1
+ export type DoctorStatus = 'pass' | 'fail' | 'inconclusive' | 'warn'
2
+
3
+ export type DoctorCategory =
4
+ | 'sandbox'
5
+ | 'providers'
6
+ | 'vault'
7
+ | 'telemetry'
8
+ | 'runtime'
9
+ | 'plugins'
10
+ | 'custom'
11
+
12
+ export interface DoctorCheckContext {
13
+ readonly cwd: string
14
+ readonly env: Readonly<Record<string, string | undefined>>
15
+ readonly projectRoot: string | null
16
+ }
17
+
18
+ export interface DoctorCheckResult {
19
+ readonly status: DoctorStatus
20
+ readonly message?: string
21
+ readonly remediation?: string
22
+ readonly durationMs?: number
23
+ }
24
+
25
+ export interface DoctorCheck {
26
+ readonly id: string
27
+ readonly category: DoctorCategory
28
+ readonly run: (ctx: DoctorCheckContext) => Promise<DoctorCheckResult>
29
+ readonly fix?: (ctx: DoctorCheckContext) => Promise<DoctorCheckResult>
30
+ }
31
+
32
+ export interface DoctorCheckRecord {
33
+ readonly id: string
34
+ readonly category: DoctorCategory
35
+ readonly status: DoctorStatus
36
+ readonly message?: string
37
+ readonly remediation?: string
38
+ readonly durationMs: number
39
+ }
40
+
41
+ export interface DoctorReport {
42
+ readonly version: string
43
+ readonly timestamp: string
44
+ readonly checks: readonly DoctorCheckRecord[]
45
+ readonly summary: {
46
+ readonly pass: number
47
+ readonly fail: number
48
+ readonly inconclusive: number
49
+ readonly warn: number
50
+ readonly total: number
51
+ }
52
+ readonly exit: 0 | 1 | 2 | 70
53
+ }
@@ -0,0 +1,9 @@
1
+ export type {
2
+ DoctorCategory,
3
+ DoctorCheck,
4
+ DoctorCheckContext,
5
+ DoctorCheckRecord,
6
+ DoctorCheckResult,
7
+ DoctorReport,
8
+ DoctorStatus,
9
+ } from './check.js'
@@ -0,0 +1,8 @@
1
+ import type { AgentBusEvent } from '../bus/index.js'
2
+ import type { RunEvent } from '../run/events.js'
3
+
4
+ export type ProbeEventKind = RunEvent['type'] | AgentBusEvent['type']
5
+
6
+ export type VetoableEventKind = 'tool_executing'
7
+
8
+ export type ProbeEvent = RunEvent | AgentBusEvent
@@ -0,0 +1,3 @@
1
+ import type { ProbeEvent, ProbeEventKind } from './event-kind.js'
2
+
3
+ export type ProbeEventOf<K extends ProbeEventKind> = Extract<ProbeEvent, { type: K }>
@@ -0,0 +1,11 @@
1
+ export type { ProbeEvent, ProbeEventKind, VetoableEventKind } from './event-kind.js'
2
+ export type { ProbeEventOf } from './event-of.js'
3
+ export type {
4
+ ProbeContext,
5
+ ProbeHandler,
6
+ ProbeOptions,
7
+ Unsubscribe,
8
+ VetoDecision,
9
+ VetoHandler,
10
+ VetoOutcome,
11
+ } from './registry.js'
@@ -0,0 +1,36 @@
1
+ import type { RunId } from '../ids/index.js'
2
+ import type { ProbeEventKind, VetoableEventKind } from './event-kind.js'
3
+ import type { ProbeEventOf } from './event-of.js'
4
+
5
+ export type Unsubscribe = () => void
6
+
7
+ export interface ProbeContext {
8
+ readonly runId?: RunId
9
+ readonly isReplay: boolean
10
+ }
11
+
12
+ export type ProbeHandler<K extends ProbeEventKind> = (
13
+ event: ProbeEventOf<K>,
14
+ ctx: ProbeContext,
15
+ ) => void
16
+
17
+ export type VetoDecision = 'allow' | 'deny' | { readonly action: 'deny'; readonly reason: string }
18
+
19
+ export type VetoHandler<K extends VetoableEventKind> = (
20
+ event: ProbeEventOf<K>,
21
+ ctx: ProbeContext,
22
+ ) => VetoDecision
23
+
24
+ export interface VetoOutcome {
25
+ readonly action: 'allow' | 'deny'
26
+ readonly probeName?: string
27
+ readonly reason?: string
28
+ }
29
+
30
+ export interface ProbeOptions<K extends ProbeEventKind = ProbeEventKind> {
31
+ readonly where?: (event: ProbeEventOf<K>) => boolean
32
+ readonly priority?: number
33
+ readonly name?: string
34
+ readonly otel?: boolean
35
+ readonly override?: boolean
36
+ }
@@ -1,4 +1,4 @@
1
- export type LogLevel = 'debug' | 'info' | 'warn' | 'error'
1
+ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'silent'
2
2
 
3
3
  export type LogContext = Record<string, unknown>
4
4
 
@@ -7,6 +7,11 @@ const LOG_LEVELS: Record<LogLevel, number> = {
7
7
  info: 1,
8
8
  warn: 2,
9
9
  error: 3,
10
+ // `silent` sits above every emit level so the `level < minLevelNum`
11
+ // guard in `log()` always short-circuits when configured. Used by
12
+ // test harnesses to suppress unmocked `getRootLogger()` stderr
13
+ // writes; see packages/sdk/src/test-setup.ts.
14
+ silent: 4,
10
15
  }
11
16
 
12
17
  export interface Logger {