@retinue/agentkit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (405) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +310 -0
  3. package/dist/adapters/bullmq/consumer.d.ts +33 -0
  4. package/dist/adapters/bullmq/consumer.js +41 -0
  5. package/dist/adapters/bullmq/dispatcher.d.ts +74 -0
  6. package/dist/adapters/bullmq/dispatcher.js +160 -0
  7. package/dist/adapters/bullmq/export.d.ts +31 -0
  8. package/dist/adapters/bullmq/export.js +53 -0
  9. package/dist/adapters/bullmq/extraction.d.ts +42 -0
  10. package/dist/adapters/bullmq/extraction.js +63 -0
  11. package/dist/adapters/bullmq/index.d.ts +13 -0
  12. package/dist/adapters/bullmq/index.js +13 -0
  13. package/dist/adapters/bullmq/lock.d.ts +77 -0
  14. package/dist/adapters/bullmq/lock.js +126 -0
  15. package/dist/adapters/bullmq/queue.d.ts +50 -0
  16. package/dist/adapters/bullmq/queue.js +81 -0
  17. package/dist/adapters/memory/artifact-exports.d.ts +11 -0
  18. package/dist/adapters/memory/artifact-exports.js +102 -0
  19. package/dist/adapters/memory/artifacts.d.ts +15 -0
  20. package/dist/adapters/memory/artifacts.js +134 -0
  21. package/dist/adapters/memory/blobs.d.ts +7 -0
  22. package/dist/adapters/memory/blobs.js +27 -0
  23. package/dist/adapters/memory/evaluation.d.ts +18 -0
  24. package/dist/adapters/memory/evaluation.js +148 -0
  25. package/dist/adapters/memory/files.d.ts +27 -0
  26. package/dist/adapters/memory/files.js +0 -0
  27. package/dist/adapters/memory/flows.d.ts +16 -0
  28. package/dist/adapters/memory/flows.js +117 -0
  29. package/dist/adapters/memory/hitl.d.ts +9 -0
  30. package/dist/adapters/memory/hitl.js +130 -0
  31. package/dist/adapters/memory/idempotency.d.ts +13 -0
  32. package/dist/adapters/memory/idempotency.js +32 -0
  33. package/dist/adapters/memory/index.d.ts +39 -0
  34. package/dist/adapters/memory/index.js +107 -0
  35. package/dist/adapters/memory/knowledge.d.ts +43 -0
  36. package/dist/adapters/memory/knowledge.js +248 -0
  37. package/dist/adapters/memory/mcp.d.ts +9 -0
  38. package/dist/adapters/memory/mcp.js +37 -0
  39. package/dist/adapters/memory/message-store.d.ts +17 -0
  40. package/dist/adapters/memory/message-store.js +70 -0
  41. package/dist/adapters/memory/principal-memory.d.ts +7 -0
  42. package/dist/adapters/memory/principal-memory.js +83 -0
  43. package/dist/adapters/memory/runtime.d.ts +29 -0
  44. package/dist/adapters/memory/runtime.js +0 -0
  45. package/dist/adapters/memory/sessions.d.ts +29 -0
  46. package/dist/adapters/memory/sessions.js +0 -0
  47. package/dist/adapters/memory/skills.d.ts +10 -0
  48. package/dist/adapters/memory/skills.js +41 -0
  49. package/dist/adapters/memory/thread-summary.d.ts +7 -0
  50. package/dist/adapters/memory/thread-summary.js +29 -0
  51. package/dist/adapters/memory/usage-limits.d.ts +13 -0
  52. package/dist/adapters/memory/usage-limits.js +72 -0
  53. package/dist/adapters/memory/usage.d.ts +16 -0
  54. package/dist/adapters/memory/usage.js +279 -0
  55. package/dist/adapters/otel/index.d.ts +111 -0
  56. package/dist/adapters/otel/index.js +133 -0
  57. package/dist/adapters/postgres/artifact-exports.d.ts +12 -0
  58. package/dist/adapters/postgres/artifact-exports.js +117 -0
  59. package/dist/adapters/postgres/artifacts.d.ts +16 -0
  60. package/dist/adapters/postgres/artifacts.js +172 -0
  61. package/dist/adapters/postgres/checkpoint-store.d.ts +16 -0
  62. package/dist/adapters/postgres/checkpoint-store.js +34 -0
  63. package/dist/adapters/postgres/config.d.ts +15 -0
  64. package/dist/adapters/postgres/config.js +187 -0
  65. package/dist/adapters/postgres/conversation-store.d.ts +4 -0
  66. package/dist/adapters/postgres/conversation-store.js +82 -0
  67. package/dist/adapters/postgres/evaluation.d.ts +17 -0
  68. package/dist/adapters/postgres/evaluation.js +193 -0
  69. package/dist/adapters/postgres/file-content.d.ts +30 -0
  70. package/dist/adapters/postgres/file-content.js +111 -0
  71. package/dist/adapters/postgres/files.d.ts +19 -0
  72. package/dist/adapters/postgres/files.js +209 -0
  73. package/dist/adapters/postgres/flows.d.ts +20 -0
  74. package/dist/adapters/postgres/flows.js +206 -0
  75. package/dist/adapters/postgres/hitl.d.ts +5 -0
  76. package/dist/adapters/postgres/hitl.js +247 -0
  77. package/dist/adapters/postgres/index.d.ts +35 -0
  78. package/dist/adapters/postgres/index.js +35 -0
  79. package/dist/adapters/postgres/knowledge.d.ts +48 -0
  80. package/dist/adapters/postgres/knowledge.js +255 -0
  81. package/dist/adapters/postgres/memory.d.ts +14 -0
  82. package/dist/adapters/postgres/memory.js +194 -0
  83. package/dist/adapters/postgres/message-store.d.ts +11 -0
  84. package/dist/adapters/postgres/message-store.js +145 -0
  85. package/dist/adapters/postgres/migrations.d.ts +69 -0
  86. package/dist/adapters/postgres/migrations.js +1594 -0
  87. package/dist/adapters/postgres/pg-executor.d.ts +19 -0
  88. package/dist/adapters/postgres/pg-executor.js +32 -0
  89. package/dist/adapters/postgres/retention.d.ts +26 -0
  90. package/dist/adapters/postgres/retention.js +59 -0
  91. package/dist/adapters/postgres/rollups.d.ts +17 -0
  92. package/dist/adapters/postgres/rollups.js +267 -0
  93. package/dist/adapters/postgres/run-coordinator.d.ts +5 -0
  94. package/dist/adapters/postgres/run-coordinator.js +98 -0
  95. package/dist/adapters/postgres/run-event-log.d.ts +26 -0
  96. package/dist/adapters/postgres/run-event-log.js +30 -0
  97. package/dist/adapters/postgres/run-store.d.ts +4 -0
  98. package/dist/adapters/postgres/run-store.js +199 -0
  99. package/dist/adapters/postgres/schema.d.ts +39 -0
  100. package/dist/adapters/postgres/schema.js +70 -0
  101. package/dist/adapters/postgres/session-state.d.ts +7 -0
  102. package/dist/adapters/postgres/session-state.js +99 -0
  103. package/dist/adapters/postgres/sql.d.ts +8 -0
  104. package/dist/adapters/postgres/sql.js +2 -0
  105. package/dist/adapters/postgres/transaction.d.ts +37 -0
  106. package/dist/adapters/postgres/transaction.js +93 -0
  107. package/dist/adapters/postgres/unit-of-work.d.ts +18 -0
  108. package/dist/adapters/postgres/unit-of-work.js +8 -0
  109. package/dist/adapters/postgres/usage-limits.d.ts +15 -0
  110. package/dist/adapters/postgres/usage-limits.js +136 -0
  111. package/dist/adapters/postgres/usage.d.ts +15 -0
  112. package/dist/adapters/postgres/usage.js +226 -0
  113. package/dist/adapters/redis/index.d.ts +9 -0
  114. package/dist/adapters/redis/index.js +9 -0
  115. package/dist/adapters/redis/realtime.d.ts +74 -0
  116. package/dist/adapters/redis/realtime.js +112 -0
  117. package/dist/adapters/supabase/index.d.ts +88 -0
  118. package/dist/adapters/supabase/index.js +84 -0
  119. package/dist/adapters/supabase/realtime.d.ts +30 -0
  120. package/dist/adapters/supabase/realtime.js +53 -0
  121. package/dist/adapters/supabase/rls.d.ts +99 -0
  122. package/dist/adapters/supabase/rls.js +216 -0
  123. package/dist/adapters/supabase/storage.d.ts +50 -0
  124. package/dist/adapters/supabase/storage.js +207 -0
  125. package/dist/agents/agent.d.ts +66 -0
  126. package/dist/agents/agent.js +209 -0
  127. package/dist/agents/define.d.ts +21 -0
  128. package/dist/agents/define.js +63 -0
  129. package/dist/agents/engine.d.ts +98 -0
  130. package/dist/agents/engine.js +462 -0
  131. package/dist/agents/index.d.ts +50 -0
  132. package/dist/agents/index.js +17 -0
  133. package/dist/artifacts/index.d.ts +114 -0
  134. package/dist/artifacts/index.js +219 -0
  135. package/dist/authorization/index.d.ts +76 -0
  136. package/dist/authorization/index.js +76 -0
  137. package/dist/capabilities/index.d.ts +120 -0
  138. package/dist/capabilities/index.js +167 -0
  139. package/dist/capabilities/runtime.d.ts +89 -0
  140. package/dist/capabilities/runtime.js +84 -0
  141. package/dist/citations/index.d.ts +161 -0
  142. package/dist/citations/index.js +182 -0
  143. package/dist/context/assembler.d.ts +82 -0
  144. package/dist/context/assembler.js +129 -0
  145. package/dist/context/compaction.d.ts +45 -0
  146. package/dist/context/compaction.js +55 -0
  147. package/dist/context/index.d.ts +75 -0
  148. package/dist/context/index.js +17 -0
  149. package/dist/core/content-parts.d.ts +194 -0
  150. package/dist/core/content-parts.js +23 -0
  151. package/dist/core/context.d.ts +51 -0
  152. package/dist/core/context.js +9 -0
  153. package/dist/core/env.d.ts +25 -0
  154. package/dist/core/env.js +41 -0
  155. package/dist/core/errors.d.ts +30 -0
  156. package/dist/core/errors.js +65 -0
  157. package/dist/core/events.d.ts +139 -0
  158. package/dist/core/events.js +99 -0
  159. package/dist/core/ids.d.ts +52 -0
  160. package/dist/core/ids.js +13 -0
  161. package/dist/core/index.d.ts +9 -0
  162. package/dist/core/index.js +9 -0
  163. package/dist/core/tokens.d.ts +22 -0
  164. package/dist/core/tokens.js +22 -0
  165. package/dist/core/validation.d.ts +34 -0
  166. package/dist/core/validation.js +176 -0
  167. package/dist/documents/extraction.d.ts +121 -0
  168. package/dist/documents/extraction.js +293 -0
  169. package/dist/documents/index.d.ts +199 -0
  170. package/dist/documents/index.js +65 -0
  171. package/dist/documents/parsers/pdf.d.ts +47 -0
  172. package/dist/documents/parsers/pdf.js +508 -0
  173. package/dist/documents/parsers/text.d.ts +59 -0
  174. package/dist/documents/parsers/text.js +325 -0
  175. package/dist/documents/read-tool.d.ts +52 -0
  176. package/dist/documents/read-tool.js +109 -0
  177. package/dist/documents/render.d.ts +29 -0
  178. package/dist/documents/render.js +59 -0
  179. package/dist/documents/vision.d.ts +159 -0
  180. package/dist/documents/vision.js +214 -0
  181. package/dist/entries/adapters-bullmq.d.ts +8 -0
  182. package/dist/entries/adapters-bullmq.js +8 -0
  183. package/dist/entries/adapters-otel.d.ts +13 -0
  184. package/dist/entries/adapters-otel.js +13 -0
  185. package/dist/entries/adapters-postgres.d.ts +10 -0
  186. package/dist/entries/adapters-postgres.js +10 -0
  187. package/dist/entries/adapters-redis.d.ts +3 -0
  188. package/dist/entries/adapters-redis.js +3 -0
  189. package/dist/entries/context.d.ts +20 -0
  190. package/dist/entries/context.js +20 -0
  191. package/dist/entries/flows.d.ts +15 -0
  192. package/dist/entries/flows.js +15 -0
  193. package/dist/entries/hitl.d.ts +10 -0
  194. package/dist/entries/hitl.js +10 -0
  195. package/dist/entries/knowledge.d.ts +18 -0
  196. package/dist/entries/knowledge.js +19 -0
  197. package/dist/entries/mcp.d.ts +10 -0
  198. package/dist/entries/mcp.js +10 -0
  199. package/dist/entries/observability.d.ts +14 -0
  200. package/dist/entries/observability.js +16 -0
  201. package/dist/entries/persistence.d.ts +11 -0
  202. package/dist/entries/persistence.js +11 -0
  203. package/dist/entries/providers.d.ts +14 -0
  204. package/dist/entries/providers.js +14 -0
  205. package/dist/entries/runtime.d.ts +13 -0
  206. package/dist/entries/runtime.js +13 -0
  207. package/dist/entries/server.d.ts +24 -0
  208. package/dist/entries/server.js +24 -0
  209. package/dist/entries/tools.d.ts +21 -0
  210. package/dist/entries/tools.js +21 -0
  211. package/dist/entries/usage.d.ts +10 -0
  212. package/dist/entries/usage.js +10 -0
  213. package/dist/evaluation/gate.d.ts +168 -0
  214. package/dist/evaluation/gate.js +180 -0
  215. package/dist/evaluation/graders.d.ts +125 -0
  216. package/dist/evaluation/graders.js +203 -0
  217. package/dist/evaluation/index.d.ts +120 -0
  218. package/dist/evaluation/index.js +183 -0
  219. package/dist/evaluation/judge.d.ts +75 -0
  220. package/dist/evaluation/judge.js +111 -0
  221. package/dist/export/index.d.ts +162 -0
  222. package/dist/export/index.js +363 -0
  223. package/dist/export/markdown.d.ts +19 -0
  224. package/dist/export/markdown.js +29 -0
  225. package/dist/export/pdf.d.ts +73 -0
  226. package/dist/export/pdf.js +407 -0
  227. package/dist/files/context.d.ts +97 -0
  228. package/dist/files/context.js +185 -0
  229. package/dist/files/index.d.ts +210 -0
  230. package/dist/files/index.js +338 -0
  231. package/dist/files/read-tool.d.ts +81 -0
  232. package/dist/files/read-tool.js +163 -0
  233. package/dist/files/turn-parts.d.ts +96 -0
  234. package/dist/files/turn-parts.js +171 -0
  235. package/dist/flows/index.d.ts +270 -0
  236. package/dist/flows/index.js +62 -0
  237. package/dist/flows/interpreter.d.ts +146 -0
  238. package/dist/flows/interpreter.js +426 -0
  239. package/dist/flows/runner.d.ts +145 -0
  240. package/dist/flows/runner.js +270 -0
  241. package/dist/graphql/index.d.ts +8 -0
  242. package/dist/graphql/index.js +8 -0
  243. package/dist/graphql/resolvers.d.ts +237 -0
  244. package/dist/graphql/resolvers.js +253 -0
  245. package/dist/graphql/schema.d.ts +11 -0
  246. package/dist/graphql/schema.js +258 -0
  247. package/dist/graphql/sse.d.ts +77 -0
  248. package/dist/graphql/sse.js +100 -0
  249. package/dist/hitl/approved-execution.d.ts +127 -0
  250. package/dist/hitl/approved-execution.js +177 -0
  251. package/dist/hitl/index.d.ts +79 -0
  252. package/dist/hitl/index.js +12 -0
  253. package/dist/hitl/service.d.ts +221 -0
  254. package/dist/hitl/service.js +268 -0
  255. package/dist/idempotency/index.d.ts +70 -0
  256. package/dist/idempotency/index.js +59 -0
  257. package/dist/index.d.ts +103 -0
  258. package/dist/index.js +60 -0
  259. package/dist/knowledge/chunking.d.ts +57 -0
  260. package/dist/knowledge/chunking.js +158 -0
  261. package/dist/knowledge/index.d.ts +119 -0
  262. package/dist/knowledge/index.js +166 -0
  263. package/dist/knowledge/retrieval.d.ts +146 -0
  264. package/dist/knowledge/retrieval.js +170 -0
  265. package/dist/loadtest/harness.d.ts +168 -0
  266. package/dist/loadtest/harness.js +507 -0
  267. package/dist/loadtest/index.d.ts +13 -0
  268. package/dist/loadtest/index.js +13 -0
  269. package/dist/loadtest/injection.d.ts +89 -0
  270. package/dist/loadtest/injection.js +147 -0
  271. package/dist/loadtest/metrics.d.ts +197 -0
  272. package/dist/loadtest/metrics.js +160 -0
  273. package/dist/loadtest/runbooks.d.ts +28 -0
  274. package/dist/loadtest/runbooks.js +159 -0
  275. package/dist/loadtest/scenario.d.ts +104 -0
  276. package/dist/loadtest/scenario.js +208 -0
  277. package/dist/mcp/egress.d.ts +53 -0
  278. package/dist/mcp/egress.js +115 -0
  279. package/dist/mcp/index.d.ts +93 -0
  280. package/dist/mcp/index.js +33 -0
  281. package/dist/mcp/provider.d.ts +62 -0
  282. package/dist/mcp/provider.js +0 -0
  283. package/dist/models/index.d.ts +98 -0
  284. package/dist/models/index.js +74 -0
  285. package/dist/models/pricing.d.ts +24 -0
  286. package/dist/models/pricing.js +37 -0
  287. package/dist/models/provider-factory.d.ts +31 -0
  288. package/dist/models/provider-factory.js +67 -0
  289. package/dist/models/streaming.d.ts +145 -0
  290. package/dist/models/streaming.js +272 -0
  291. package/dist/models/vision.d.ts +38 -0
  292. package/dist/models/vision.js +62 -0
  293. package/dist/persistence/index.d.ts +1654 -0
  294. package/dist/persistence/index.js +226 -0
  295. package/dist/principal-memory/index.d.ts +106 -0
  296. package/dist/principal-memory/index.js +89 -0
  297. package/dist/retention/index.d.ts +89 -0
  298. package/dist/retention/index.js +70 -0
  299. package/dist/runtime/checkpoint.d.ts +37 -0
  300. package/dist/runtime/checkpoint.js +22 -0
  301. package/dist/runtime/index.d.ts +118 -0
  302. package/dist/runtime/index.js +69 -0
  303. package/dist/runtime/retry.d.ts +95 -0
  304. package/dist/runtime/retry.js +126 -0
  305. package/dist/runtime/serialization.d.ts +85 -0
  306. package/dist/runtime/serialization.js +95 -0
  307. package/dist/runtime/streaming.d.ts +54 -0
  308. package/dist/runtime/streaming.js +115 -0
  309. package/dist/runtime/worker.d.ts +130 -0
  310. package/dist/runtime/worker.js +405 -0
  311. package/dist/security/checklist.d.ts +53 -0
  312. package/dist/security/checklist.js +204 -0
  313. package/dist/security/findings.d.ts +56 -0
  314. package/dist/security/findings.js +168 -0
  315. package/dist/security/index.d.ts +14 -0
  316. package/dist/security/index.js +14 -0
  317. package/dist/security/prompt-safety.d.ts +100 -0
  318. package/dist/security/prompt-safety.js +133 -0
  319. package/dist/server/boot.d.ts +32 -0
  320. package/dist/server/boot.js +36 -0
  321. package/dist/server/cli-worker.d.ts +37 -0
  322. package/dist/server/cli-worker.js +151 -0
  323. package/dist/server/cli.d.ts +27 -0
  324. package/dist/server/cli.js +74 -0
  325. package/dist/server/config.d.ts +42 -0
  326. package/dist/server/config.js +127 -0
  327. package/dist/server/health.d.ts +59 -0
  328. package/dist/server/health.js +90 -0
  329. package/dist/server/host.d.ts +39 -0
  330. package/dist/server/host.js +124 -0
  331. package/dist/server/index.d.ts +15 -0
  332. package/dist/server/index.js +15 -0
  333. package/dist/server/main.d.ts +16 -0
  334. package/dist/server/main.js +31 -0
  335. package/dist/server/sse-route.d.ts +21 -0
  336. package/dist/server/sse-route.js +282 -0
  337. package/dist/skills/index.d.ts +67 -0
  338. package/dist/skills/index.js +31 -0
  339. package/dist/skills/resolver.d.ts +54 -0
  340. package/dist/skills/resolver.js +121 -0
  341. package/dist/teams/index.d.ts +93 -0
  342. package/dist/teams/index.js +207 -0
  343. package/dist/telemetry/index.d.ts +157 -0
  344. package/dist/telemetry/index.js +71 -0
  345. package/dist/telemetry/instrument.d.ts +108 -0
  346. package/dist/telemetry/instrument.js +232 -0
  347. package/dist/telemetry/log-events.d.ts +17 -0
  348. package/dist/telemetry/log-events.js +58 -0
  349. package/dist/telemetry/metrics.d.ts +123 -0
  350. package/dist/telemetry/metrics.js +135 -0
  351. package/dist/telemetry/noop.d.ts +39 -0
  352. package/dist/telemetry/noop.js +143 -0
  353. package/dist/telemetry/redaction.d.ts +64 -0
  354. package/dist/telemetry/redaction.js +153 -0
  355. package/dist/telemetry/spans.d.ts +56 -0
  356. package/dist/telemetry/spans.js +78 -0
  357. package/dist/telemetry/trace-context.d.ts +55 -0
  358. package/dist/telemetry/trace-context.js +60 -0
  359. package/dist/toolkit/compute.d.ts +53 -0
  360. package/dist/toolkit/compute.js +152 -0
  361. package/dist/toolkit/data.d.ts +98 -0
  362. package/dist/toolkit/data.js +235 -0
  363. package/dist/toolkit/http.d.ts +113 -0
  364. package/dist/toolkit/http.js +205 -0
  365. package/dist/toolkit/index.d.ts +21 -0
  366. package/dist/toolkit/index.js +17 -0
  367. package/dist/toolkit/web.d.ts +107 -0
  368. package/dist/toolkit/web.js +147 -0
  369. package/dist/tools/define.d.ts +25 -0
  370. package/dist/tools/define.js +45 -0
  371. package/dist/tools/delegating.d.ts +132 -0
  372. package/dist/tools/delegating.js +211 -0
  373. package/dist/tools/index.d.ts +129 -0
  374. package/dist/tools/index.js +33 -0
  375. package/dist/tools/library/compute.d.ts +11 -0
  376. package/dist/tools/library/compute.js +46 -0
  377. package/dist/tools/library/data.d.ts +16 -0
  378. package/dist/tools/library/data.js +92 -0
  379. package/dist/tools/library/http.d.ts +28 -0
  380. package/dist/tools/library/http.js +71 -0
  381. package/dist/tools/library/index.d.ts +97 -0
  382. package/dist/tools/library/index.js +134 -0
  383. package/dist/tools/library/knowledge.d.ts +39 -0
  384. package/dist/tools/library/knowledge.js +58 -0
  385. package/dist/tools/library/web.d.ts +19 -0
  386. package/dist/tools/library/web.js +65 -0
  387. package/dist/tools/meta-tools.d.ts +19 -0
  388. package/dist/tools/meta-tools.js +36 -0
  389. package/dist/tools/registry.d.ts +146 -0
  390. package/dist/tools/registry.js +291 -0
  391. package/dist/usage/index.d.ts +105 -0
  392. package/dist/usage/index.js +20 -0
  393. package/dist/usage/quota.d.ts +258 -0
  394. package/dist/usage/quota.js +510 -0
  395. package/dist/usage/recorder.d.ts +29 -0
  396. package/dist/usage/recorder.js +96 -0
  397. package/dist/usage/rollups.d.ts +121 -0
  398. package/dist/usage/rollups.js +157 -0
  399. package/dist/worker/export.d.ts +57 -0
  400. package/dist/worker/export.js +81 -0
  401. package/dist/worker/extraction.d.ts +57 -0
  402. package/dist/worker/extraction.js +84 -0
  403. package/dist/worker/main.d.ts +103 -0
  404. package/dist/worker/main.js +159 -0
  405. package/package.json +187 -0
@@ -0,0 +1,282 @@
1
+ /**
2
+ * HTTP SSE endpoint for run events (#109).
3
+ *
4
+ * `@retinue/agentkit`'s `graphql/sse.ts` already produces ready-to-write frames and maps
5
+ * `Last-Event-ID` to a resume cursor, deliberately without an HTTP dependency. This is the route that
6
+ * serves it, in the workspace where the server dependency already lives.
7
+ *
8
+ * Two design decisions carry the weight, and they pull against each other:
9
+ *
10
+ * **Backpressure (AC-6) wants a pull-based stream** — produce only when the consumer asks.
11
+ * **Keep-alives (AC-5) want the server to emit without being asked.** Resolved by racing inside
12
+ * `pull`: each pull awaits the next event *or* a keep-alive timeout. Nothing is produced without
13
+ * demand, so a slow client stops being pulled and backpressure reaches the source instead of a buffer;
14
+ * and an idle stream still emits a comment per interval. A `setInterval` enqueuing comments regardless
15
+ * of demand would satisfy AC-5 and quietly break AC-6 — a stalled client would accumulate one comment
16
+ * per interval, forever.
17
+ */
18
+ import { asId } from "../index.js";
19
+ import { cursorFromLastEventId, openRunEventSse } from "../graphql/sse.js";
20
+ /** A comment frame. Intermediaries see bytes; clients ignore it. */
21
+ const KEEP_ALIVE = ": keep-alive\n\n";
22
+ const SSE_HEADERS = {
23
+ "content-type": "text/event-stream; charset=utf-8",
24
+ "cache-control": "no-cache, no-transform",
25
+ connection: "keep-alive",
26
+ // Without this an nginx in front buffers the stream and the client sees nothing until it ends,
27
+ // which for a live run is indistinguishable from the feature not working.
28
+ "x-accel-buffering": "no",
29
+ };
30
+ /**
31
+ * Read `runId` / `conversationId` / `after` out of a GraphQL operation body, tolerantly.
32
+ *
33
+ * Tolerant on purpose: a malformed or absent body is not an error here, because the query-parameter
34
+ * form is equally valid. A body that cannot be parsed simply yields no identifiers, and the caller
35
+ * then fails with the same 400 it would have for a missing parameter.
36
+ */
37
+ const readOperationVariables = async (request) => {
38
+ const empty = { runId: null, conversationId: null, after: null };
39
+ if (request.method !== "POST")
40
+ return empty;
41
+ try {
42
+ const body = (await request.clone().json());
43
+ const variables = body.variables ?? {};
44
+ const str = (key) => {
45
+ const value = variables[key];
46
+ return typeof value === "string" ? value : typeof value === "number" ? String(value) : null;
47
+ };
48
+ return { runId: str("runId"), conversationId: str("conversationId"), after: str("after") };
49
+ }
50
+ catch {
51
+ return empty;
52
+ }
53
+ };
54
+ export const createRunEventSseRoute = (options) => {
55
+ const keepAliveMs = options.keepAliveMs ?? 15_000;
56
+ const path = options.path ?? "/runs/events";
57
+ return {
58
+ path,
59
+ async handle(request) {
60
+ /**
61
+ * Identifiers from either shape, because two kinds of consumer reach this route.
62
+ *
63
+ * A `graphql-sse` client POSTs `{query, variables}` with `accept: text/event-stream` — that is
64
+ * what its distinct-connections mode does, and it never looks at query parameters. #109 accepted
65
+ * only query parameters, so #111's frame compliance was real while the *request* side still could
66
+ * not be reached by a real client. An `EventSource`, by contrast, can only issue a GET with a URL.
67
+ *
68
+ * The query text is deliberately not executed: this is a streaming route, not a GraphQL executor.
69
+ * See the open question on #112.
70
+ */
71
+ const url = new URL(request.url);
72
+ const fromBody = await readOperationVariables(request);
73
+ const runIdParam = url.searchParams.get("runId") ?? fromBody.runId;
74
+ const conversationIdParam = url.searchParams.get("conversationId") ?? fromBody.conversationId;
75
+ if (runIdParam === null || conversationIdParam === null) {
76
+ return new Response("runId and conversationId are required", { status: 400 });
77
+ }
78
+ const execution = await options.authenticate(request);
79
+ if (execution === null || execution === undefined) {
80
+ return new Response("Unauthenticated", { status: 401 });
81
+ }
82
+ const conversationId = asId(conversationIdParam);
83
+ const runId = asId(runIdParam);
84
+ /**
85
+ * Ownership from data, unconditionally.
86
+ *
87
+ * Every store read is tenant-scoped, so a conversation belonging to another tenant simply is not
88
+ * found — the caller cannot forget this check because the route performs it before anything else.
89
+ * A callback alone would have left the cross-tenant case, which is the dangerous one, to the
90
+ * caller's policy.
91
+ */
92
+ const conversation = await options.deps.conversations.findById({
93
+ tenantId: execution.tenantId,
94
+ id: conversationId,
95
+ });
96
+ // 404, not 403. A 403 confirms the conversation exists, which across tenants is itself the leak.
97
+ if (conversation === null)
98
+ return new Response("Not found", { status: 404 });
99
+ if (options.authorizeConversation) {
100
+ const allowed = await options.authorizeConversation(execution, conversationId);
101
+ // Also 404 rather than 403, for the same reason: an unentitled user learning a conversation
102
+ // exists is information they should not have.
103
+ if (!allowed)
104
+ return new Response("Not found", { status: 404 });
105
+ }
106
+ /**
107
+ * Resume cursor, from whichever source the consumer has.
108
+ *
109
+ * `Last-Event-ID` first, because a browser `EventSource` resends it automatically and that is the
110
+ * only mechanism it has. Then `after` from the operation variables — the graphql-sse client
111
+ * **never sends `Last-Event-ID`** (it is absent from its source entirely; it retries with backoff
112
+ * and re-subscribes from the start), so a consumer that wants resume has to pass a cursor itself.
113
+ * That is the one accommodation beyond the raw protocol, recorded for #112's AC-6.
114
+ */
115
+ const after = request.headers.get("last-event-id") !== null
116
+ ? cursorFromLastEventId(request.headers.get("last-event-id"))
117
+ : cursorFromLastEventId(fromBody.after);
118
+ // Polled by `openRunEventStream`, so a Web AbortSignal needs adapting rather than passing.
119
+ // Both directions matter: the request's signal (the client dropped) and the stream's `cancel`
120
+ // (the consumer stopped reading without closing) — the second is the case that leaks a
121
+ // generator.
122
+ let aborted = false;
123
+ const signal = {
124
+ get aborted() {
125
+ return aborted || request.signal.aborted;
126
+ },
127
+ };
128
+ /**
129
+ * A promise that settles when this stream is abandoned, and the reason it has to exist.
130
+ *
131
+ * `openRunEventStream` polls `signal.aborted`, which only helps *between* events. When it is
132
+ * parked awaiting the live source there is nothing to poll: an async generator suspended at an
133
+ * `await` cannot run its `finally` until that await settles, so calling `.return()` on it does
134
+ * not interrupt it — it queues. Awaiting that return in `cancel()` therefore hangs forever,
135
+ * which is exactly what the first version of this route did.
136
+ *
137
+ * So the live source is wrapped to race each read against this promise. Cancelling resolves it,
138
+ * the wrapper returns, and its `finally` releases the underlying subscription.
139
+ */
140
+ let abandon = () => { };
141
+ const abandoned = new Promise((resolve) => {
142
+ abandon = () => resolve("abandoned");
143
+ });
144
+ const live = {
145
+ subscribe(channel) {
146
+ const inner = options.deps.live.subscribe(channel)[Symbol.asyncIterator]();
147
+ return {
148
+ async *[Symbol.asyncIterator]() {
149
+ try {
150
+ for (;;) {
151
+ const next = await Promise.race([inner.next(), abandoned]);
152
+ if (next === "abandoned" || next.done === true)
153
+ return;
154
+ yield next.value;
155
+ }
156
+ }
157
+ finally {
158
+ // Not awaited: a parked in-memory subscriber cannot be interrupted mid-await, so
159
+ // awaiting here would reintroduce the hang. The subscription is released when the
160
+ // inner generator next wakes.
161
+ void inner.return?.(undefined);
162
+ }
163
+ },
164
+ };
165
+ },
166
+ };
167
+ const frames = openRunEventSse({
168
+ tenantId: execution.tenantId,
169
+ runId,
170
+ conversationId,
171
+ after,
172
+ log: options.deps.eventLog,
173
+ live,
174
+ ...(options.deps.channelFor ? { channelFor: options.deps.channelFor } : {}),
175
+ signal,
176
+ })[Symbol.asyncIterator]();
177
+ const encoder = new TextEncoder();
178
+ /**
179
+ * One reader owns the generator; `pull` takes from a **one-slot** handoff.
180
+ *
181
+ * The obvious implementation — race `frames.next()` against a keep-alive timer inside `pull` —
182
+ * has a subtle flaw that cost real debugging time. When the keep-alive wins, the outstanding
183
+ * `next()` must be retained, or the event it eventually yields is delivered to an abandoned
184
+ * promise and lost. Retaining it is not enough either: a generator that yields and then returns
185
+ * (which is exactly what a terminal event does) can deliver its value to one queued `next()` and
186
+ * `done` to another, so the frame disappears and the stream just closes. Observed: `yielding 1`
187
+ * followed immediately by `terminal`, with no frame ever reaching the client.
188
+ *
189
+ * A single reader removes the class of problem. It reads one frame, parks until `pull` takes it,
190
+ * then reads the next — so the generator has exactly one consumer and exactly one outstanding
191
+ * `next()`, and the one-slot capacity is what keeps AC-6 true: a client that stops reading stops
192
+ * the reader after one frame rather than draining the source into a buffer.
193
+ */
194
+ let slot = null;
195
+ let finished = false;
196
+ let failure = null;
197
+ let notifyPull = null;
198
+ let notifyReader = null;
199
+ const wake = (fn) => fn?.();
200
+ const readerLoop = (async () => {
201
+ try {
202
+ for (;;) {
203
+ if (signal.aborted)
204
+ return;
205
+ const next = await frames.next();
206
+ if (next.done === true)
207
+ return;
208
+ slot = next.value;
209
+ wake(notifyPull);
210
+ // Park until `pull` empties the slot. This is the backpressure: no further read happens
211
+ // while the consumer has not taken what is already there.
212
+ if (slot !== null) {
213
+ await new Promise((resolve) => {
214
+ notifyReader = resolve;
215
+ });
216
+ notifyReader = null;
217
+ }
218
+ }
219
+ }
220
+ catch (error) {
221
+ failure = error;
222
+ }
223
+ finally {
224
+ finished = true;
225
+ wake(notifyPull);
226
+ abandon();
227
+ void frames.return?.(undefined);
228
+ }
229
+ })();
230
+ const body = new ReadableStream({
231
+ async pull(controller) {
232
+ for (;;) {
233
+ if (failure !== null) {
234
+ controller.error(failure);
235
+ return;
236
+ }
237
+ if (slot !== null) {
238
+ const frame = slot;
239
+ slot = null;
240
+ wake(notifyReader);
241
+ controller.enqueue(encoder.encode(frame));
242
+ return;
243
+ }
244
+ if (finished || signal.aborted) {
245
+ controller.close();
246
+ return;
247
+ }
248
+ // Nothing waiting: emit a keep-alive if the interval elapses first. Only ever reached on
249
+ // demand, so an idle stream produces one comment per pull rather than one per interval.
250
+ let timer;
251
+ const armed = new Promise((resolve) => {
252
+ timer = setTimeout(() => resolve("tick"), keepAliveMs);
253
+ });
254
+ const arrival = new Promise((resolve) => {
255
+ notifyPull = () => resolve("frame");
256
+ });
257
+ const outcome = await Promise.race([arrival, armed]);
258
+ if (timer !== undefined)
259
+ clearTimeout(timer);
260
+ notifyPull = null;
261
+ if (outcome === "tick") {
262
+ controller.enqueue(encoder.encode(KEEP_ALIVE));
263
+ return;
264
+ }
265
+ // A frame (or the end) arrived; loop once to handle whichever it was.
266
+ }
267
+ },
268
+ cancel() {
269
+ // Flip the polled flag, settle the abandonment promise so the live wrapper unwinds, and let
270
+ // the reader loop finish on its own. Not awaited: a parked source cannot be interrupted
271
+ // mid-await, and awaiting here is what hangs.
272
+ aborted = true;
273
+ abandon();
274
+ wake(notifyReader);
275
+ void readerLoop;
276
+ },
277
+ });
278
+ return new Response(body, { status: 200, headers: SSE_HEADERS });
279
+ },
280
+ };
281
+ };
282
+ //# sourceMappingURL=sse-route.js.map
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Skills — `docs/03-intelligence-runtime.md`.
3
+ *
4
+ * A skill is a compact catalog entry plus a lazily loaded instruction body. Only the
5
+ * entry sits in context; the body arrives when the model calls `load_skill`.
6
+ *
7
+ * Two rules the type system helps enforce:
8
+ *
9
+ * 1. Arbitrary skill scripts are disabled by default — a skill is instructions and
10
+ * data, never executable code.
11
+ * 2. A tenant-authored body is untrusted text. It cannot grant a tool, lower an effect
12
+ * classification or bypass an approval; it only shapes how the model works.
13
+ */
14
+ import type { SkillId, TenantId } from "../core/ids.js";
15
+ export declare const SKILL_SOURCES: readonly ["built-in", "tenant", "plugin"];
16
+ export type SkillSource = (typeof SKILL_SOURCES)[number];
17
+ export type SkillStatus = "draft" | "active" | "archived";
18
+ /** What discovery puts in context. Deliberately excludes the body. */
19
+ export type SkillCatalogEntry = {
20
+ readonly id: SkillId;
21
+ /** Slug form, matching the existing workspace-skill constraint. */
22
+ readonly name: string;
23
+ readonly description: string;
24
+ readonly source: SkillSource;
25
+ readonly version: number;
26
+ };
27
+ export type SkillVersion = SkillCatalogEntry & {
28
+ readonly instructions: string;
29
+ readonly status: SkillStatus;
30
+ readonly tenantId?: TenantId;
31
+ readonly createdAt: string;
32
+ readonly createdBy?: string;
33
+ };
34
+ /**
35
+ * Limits mirroring the constraints already enforced on `workspace_agent_skills`, so a
36
+ * ported tenant skill cannot violate them on the way in.
37
+ */
38
+ export declare const SKILL_LIMITS: {
39
+ readonly namePattern: RegExp;
40
+ readonly nameMaxLength: 64;
41
+ readonly descriptionMinLength: 20;
42
+ readonly descriptionMaxLength: 1024;
43
+ readonly instructionsMaxLength: 20000;
44
+ /** Per tenant. */
45
+ readonly maxSkills: 25;
46
+ /** Per run, to bound what `load_skill` can pull into context. */
47
+ readonly maxLoadedPerRun: 5;
48
+ };
49
+ /**
50
+ * Resolution layers built-in skills first, then tenant skills, so a tenant skill of the
51
+ * same name shadows a built-in one — matching the current `build_skills_for` behaviour.
52
+ */
53
+ export interface SkillResolver {
54
+ listCatalog(input: {
55
+ tenantId: TenantId;
56
+ assigned: readonly string[];
57
+ allowTenantSkills: boolean;
58
+ }): Promise<readonly SkillCatalogEntry[]>;
59
+ /** Pins to an exact version so a mid-run edit cannot change behaviour. */
60
+ loadBody(input: {
61
+ tenantId: TenantId;
62
+ name: string;
63
+ version: number;
64
+ }): Promise<SkillVersion>;
65
+ }
66
+ export * from "./resolver.js";
67
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Skills — `docs/03-intelligence-runtime.md`.
3
+ *
4
+ * A skill is a compact catalog entry plus a lazily loaded instruction body. Only the
5
+ * entry sits in context; the body arrives when the model calls `load_skill`.
6
+ *
7
+ * Two rules the type system helps enforce:
8
+ *
9
+ * 1. Arbitrary skill scripts are disabled by default — a skill is instructions and
10
+ * data, never executable code.
11
+ * 2. A tenant-authored body is untrusted text. It cannot grant a tool, lower an effect
12
+ * classification or bypass an approval; it only shapes how the model works.
13
+ */
14
+ export const SKILL_SOURCES = ["built-in", "tenant", "plugin"];
15
+ /**
16
+ * Limits mirroring the constraints already enforced on `workspace_agent_skills`, so a
17
+ * ported tenant skill cannot violate them on the way in.
18
+ */
19
+ export const SKILL_LIMITS = {
20
+ namePattern: /^[a-z0-9]+(-[a-z0-9]+)*$/,
21
+ nameMaxLength: 64,
22
+ descriptionMinLength: 20,
23
+ descriptionMaxLength: 1024,
24
+ instructionsMaxLength: 20_000,
25
+ /** Per tenant. */
26
+ maxSkills: 25,
27
+ /** Per run, to bound what `load_skill` can pull into context. */
28
+ maxLoadedPerRun: 5,
29
+ };
30
+ export * from "./resolver.js";
31
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Skill resolution & per-run recording — `docs/03-intelligence-runtime.md` → Skills.
3
+ *
4
+ * A skill is a compact catalog entry plus a lazily loaded instruction body. Only the entry sits in
5
+ * context; the body arrives when the model calls `load_skill`. Resolution layers built-in skills
6
+ * first, then tenant skills, so a tenant skill of the same name shadows a built-in one. Two rules
7
+ * are enforced structurally: a skill is instructions and data — never executable code — and a
8
+ * tenant body is untrusted text that cannot grant a tool or lower an effect. And every load is
9
+ * recorded against the run, so skill versions are auditable per run.
10
+ */
11
+ import type { SkillStore } from "../persistence/index.js";
12
+ import { type SkillResolver, type SkillSource, type SkillVersion } from "./index.js";
13
+ /**
14
+ * Validate a tenant-authored skill against the same limits as `workspace_agent_skills`, so a ported
15
+ * skill cannot violate them on the way in. Returns the value; throws `invalid_input` on any breach.
16
+ * There is no executable field to validate — a skill body is always plain instructions.
17
+ */
18
+ export declare const validateSkillInput: (skill: SkillVersion) => SkillVersion;
19
+ /**
20
+ * Resolver over a static built-in set plus a tenant `SkillStore`. Tenant skills shadow built-ins of
21
+ * the same name. `listCatalog` returns compact entries only (never bodies); `loadBody` pins to an
22
+ * exact version so a mid-run edit cannot change behaviour.
23
+ */
24
+ export declare const createSkillResolver: (config: {
25
+ readonly builtIn: readonly SkillVersion[];
26
+ readonly store: SkillStore;
27
+ }) => SkillResolver;
28
+ /** What a run records for each skill it loaded — the audit trail of "skill versions per run". */
29
+ export type SkillLoadRecord = {
30
+ readonly name: string;
31
+ readonly version: number;
32
+ readonly source: SkillSource;
33
+ readonly loadedAt: string;
34
+ };
35
+ /**
36
+ * Per-run skill loader: loads a body on demand, enforces `maxLoadedPerRun`, and records every load
37
+ * so the run's manifest of skill versions is complete and auditable. Loading the same skill twice
38
+ * is idempotent and does not count against the limit again.
39
+ */
40
+ export declare const createRunSkillTracker: (config: {
41
+ readonly resolver: SkillResolver;
42
+ readonly maxLoadedPerRun?: number;
43
+ readonly clock?: () => string;
44
+ }) => {
45
+ load(input: {
46
+ readonly tenantId: string;
47
+ readonly runId: string;
48
+ readonly name: string;
49
+ readonly version: number;
50
+ }): Promise<SkillVersion>;
51
+ /** The skill versions loaded during a run — recorded on the run per the acceptance criteria. */
52
+ recorded(runId: string): readonly SkillLoadRecord[];
53
+ };
54
+ //# sourceMappingURL=resolver.d.ts.map
@@ -0,0 +1,121 @@
1
+ /**
2
+ * Skill resolution & per-run recording — `docs/03-intelligence-runtime.md` → Skills.
3
+ *
4
+ * A skill is a compact catalog entry plus a lazily loaded instruction body. Only the entry sits in
5
+ * context; the body arrives when the model calls `load_skill`. Resolution layers built-in skills
6
+ * first, then tenant skills, so a tenant skill of the same name shadows a built-in one. Two rules
7
+ * are enforced structurally: a skill is instructions and data — never executable code — and a
8
+ * tenant body is untrusted text that cannot grant a tool or lower an effect. And every load is
9
+ * recorded against the run, so skill versions are auditable per run.
10
+ */
11
+ import { AgentPlatformError } from "../core/errors.js";
12
+ import {} from "./index.js";
13
+ import { SKILL_LIMITS } from "./index.js";
14
+ const invalid = (message) => new AgentPlatformError({ code: "invalid_input", message, retryable: false });
15
+ /**
16
+ * Validate a tenant-authored skill against the same limits as `workspace_agent_skills`, so a ported
17
+ * skill cannot violate them on the way in. Returns the value; throws `invalid_input` on any breach.
18
+ * There is no executable field to validate — a skill body is always plain instructions.
19
+ */
20
+ export const validateSkillInput = (skill) => {
21
+ if (!SKILL_LIMITS.namePattern.test(skill.name) || skill.name.length > SKILL_LIMITS.nameMaxLength)
22
+ throw invalid(`Skill name "${skill.name}" is not a valid slug`);
23
+ if (skill.description.length < SKILL_LIMITS.descriptionMinLength ||
24
+ skill.description.length > SKILL_LIMITS.descriptionMaxLength)
25
+ throw invalid(`Skill "${skill.name}" description length is out of bounds`);
26
+ if (skill.instructions.length > SKILL_LIMITS.instructionsMaxLength)
27
+ throw invalid(`Skill "${skill.name}" instructions exceed ${SKILL_LIMITS.instructionsMaxLength} chars`);
28
+ return skill;
29
+ };
30
+ const toEntry = (s) => ({
31
+ id: s.id,
32
+ name: s.name,
33
+ description: s.description,
34
+ source: s.source,
35
+ version: s.version,
36
+ });
37
+ /**
38
+ * Resolver over a static built-in set plus a tenant `SkillStore`. Tenant skills shadow built-ins of
39
+ * the same name. `listCatalog` returns compact entries only (never bodies); `loadBody` pins to an
40
+ * exact version so a mid-run edit cannot change behaviour.
41
+ */
42
+ export const createSkillResolver = (config) => {
43
+ const builtInByName = new Map(config.builtIn.map((s) => [s.name, s]));
44
+ return {
45
+ async listCatalog({ tenantId, assigned, allowTenantSkills }) {
46
+ const assignedSet = new Set(assigned);
47
+ const byName = new Map();
48
+ // Built-ins first, and only the active ones.
49
+ //
50
+ // The store adapters already filter discovery to the latest *active* version per name —
51
+ // deliberate and tested: "a run pinned to an archived version keeps working and no new run picks
52
+ // it up." This layer did not, so `status` was load-bearing for a tenant skill and inert for a
53
+ // built-in. Same field, two meanings, which is an inconsistency rather than a decision (#122).
54
+ for (const s of config.builtIn)
55
+ if (s.status === "active" && assignedSet.has(s.name))
56
+ byName.set(s.name, toEntry(s));
57
+ // ...then tenant skills shadow them by name.
58
+ if (allowTenantSkills) {
59
+ for (const entry of await config.store.listCatalog({ tenantId })) {
60
+ if (assignedSet.has(entry.name))
61
+ byName.set(entry.name, entry);
62
+ }
63
+ }
64
+ return [...byName.values()];
65
+ },
66
+ async loadBody({ tenantId, name, version }) {
67
+ // Tenant skill of this name+version shadows the built-in.
68
+ const tenantSkill = await config.store.findVersion({ tenantId, name, version });
69
+ if (tenantSkill)
70
+ return tenantSkill;
71
+ // Resolved regardless of status, matching `findVersion`: a run pinned to a version that has since
72
+ // been archived must keep working. Only *discovery* hides it.
73
+ const builtIn = builtInByName.get(name);
74
+ if (builtIn && builtIn.version === version)
75
+ return builtIn;
76
+ throw new AgentPlatformError({
77
+ code: "not_found",
78
+ message: `Skill ${name}@${version} not found`,
79
+ retryable: false,
80
+ });
81
+ },
82
+ };
83
+ };
84
+ /**
85
+ * Per-run skill loader: loads a body on demand, enforces `maxLoadedPerRun`, and records every load
86
+ * so the run's manifest of skill versions is complete and auditable. Loading the same skill twice
87
+ * is idempotent and does not count against the limit again.
88
+ */
89
+ export const createRunSkillTracker = (config) => {
90
+ const max = config.maxLoadedPerRun ?? SKILL_LIMITS.maxLoadedPerRun;
91
+ const clock = config.clock ?? (() => new Date().toISOString());
92
+ const byRun = new Map();
93
+ const runLog = (runId) => {
94
+ let m = byRun.get(runId);
95
+ if (!m)
96
+ byRun.set(runId, (m = new Map()));
97
+ return m;
98
+ };
99
+ return {
100
+ async load(input) {
101
+ const log = runLog(input.runId);
102
+ const already = log.get(input.name);
103
+ const body = await config.resolver.loadBody({
104
+ tenantId: input.tenantId,
105
+ name: input.name,
106
+ version: input.version,
107
+ });
108
+ if (!already) {
109
+ if (log.size >= max)
110
+ throw invalid(`Run ${input.runId} has already loaded the maximum ${max} skills`);
111
+ log.set(input.name, { name: body.name, version: body.version, source: body.source, loadedAt: clock() });
112
+ }
113
+ return body;
114
+ },
115
+ /** The skill versions loaded during a run — recorded on the run per the acceptance criteria. */
116
+ recorded(runId) {
117
+ return [...runLog(runId).values()];
118
+ },
119
+ };
120
+ };
121
+ //# sourceMappingURL=resolver.js.map
@@ -0,0 +1,93 @@
1
+ /**
2
+ * Teams — REQ-037 (#186).
3
+ *
4
+ * ## A team compiles to a flow
5
+ *
6
+ * There is no team interpreter. `compileTeam` turns a `TeamDefinition` into a `FlowDefinition`, and the flow
7
+ * interpreter runs it. That is the whole design, and it is what makes #186's acceptance criteria properties rather
8
+ * than features to add:
9
+ *
10
+ * - **AC-2, "the difference is a property of the team rather than two code paths"** — both processes compile to a
11
+ * flow. `sequential` produces a chain of agent steps; `manager-led` produces one agent step whose tools include
12
+ * a delegation tool. The interpreter does not know which it is running.
13
+ * - **AC-4, budgets compose** — a team's budget *is* the compiled flow's budget, checked by the same code that
14
+ * checks a flow's. A member cannot exceed the team's remaining budget because the check is on the execution's
15
+ * spend, and there is one execution.
16
+ * - **AC-5, bounded recursion** — `maxDepth` on the compiled flow, enforced by the interpreter. A → B → A
17
+ * terminates for the same reason a nested subflow does.
18
+ * - **AC-6, one run identity** — one `FlowExecution`, so one `runId`. Each member's steps are attributable inside
19
+ * it through `StepRecord.member`.
20
+ * - **AC-7, HITL inside a team** — a member's question parks the execution exactly as a flow's checkpoint does,
21
+ * because it *is* the same mechanism.
22
+ * - **AC-8, a member failing is modelled** — `onFailure` per step, chosen by the team.
23
+ *
24
+ * Writing a second interpreter would have meant a second answer to each of those, and the second answer is the one
25
+ * that gets a fix late.
26
+ *
27
+ * ## Manager-led is one agent turn with a delegation tool
28
+ *
29
+ * The obvious design is a loop: ask the manager who is next, run them, ask again. The better one is to give the
30
+ * manager a *tool* that runs a member, and let the engine's existing turn loop do the iterating — because #186
31
+ * AC-3 asks that "delegation is a tool call, so it inherits authorization, approval, idempotency and accounting
32
+ * unchanged", and the way to inherit those unchanged is to be a tool call rather than to resemble one.
33
+ *
34
+ * So a delegation is a real entry in the registry. It is authorised like any tool, its result is recorded like any
35
+ * tool's, its cost lands on the run like any tool's, and a retry deduplicates like any tool's.
36
+ */
37
+ import type { FlowDefinition, TeamDefinition, TeamMember } from "../flows/index.js";
38
+ export declare const DEFAULT_DELEGATION_DEPTH = 3;
39
+ /**
40
+ * The tool a manager calls to hand work to a member.
41
+ *
42
+ * Named once, here, because three things have to agree on it: the compiled flow that puts it in the manager's
43
+ * tool set, the registry entry that implements it, and the guard that stops a member reaching it recursively.
44
+ */
45
+ export declare const DELEGATE_TOOL = "delegate_to_member";
46
+ export type TeamCompileProblem = {
47
+ readonly team: string;
48
+ readonly problem: string;
49
+ };
50
+ /**
51
+ * Is this team runnable at all?
52
+ *
53
+ * Checked before compiling rather than discovered while running, because every one of these produces a flow that
54
+ * fails at a step rather than a definition that fails to load — and a definition that only fails once someone
55
+ * triggers it is a definition that fails in front of a customer.
56
+ */
57
+ export declare const validateTeam: (team: TeamDefinition) => readonly TeamCompileProblem[];
58
+ /**
59
+ * Turn a team into the flow that runs it.
60
+ *
61
+ * Pure, so a team's shape can be asserted without executing anything — which matters more than usual here,
62
+ * because the interesting claims are about the *graph* ("a member cannot outspend the team", "delegation is a
63
+ * tool") rather than about behaviour at a step.
64
+ */
65
+ export declare const compileTeam: (team: TeamDefinition) => FlowDefinition;
66
+ /**
67
+ * What the manager is told about its team.
68
+ *
69
+ * Generated from the definition rather than written by hand, because a manager whose instructions list a member
70
+ * the team no longer has will delegate to it and get a refusal it cannot act on — and that is a definition and a
71
+ * prompt disagreeing, which nothing would catch.
72
+ */
73
+ export declare const managerInstructions: (team: TeamDefinition) => string;
74
+ /**
75
+ * The tools a member may use.
76
+ *
77
+ * An **intersection**, never a union — #186 AC-3's second half: "a delegated agent cannot reach a tool the
78
+ * delegating one could not." A member's `tools` narrows; it cannot widen. Enforced where the set is built rather
79
+ * than checked afterwards, because a check afterwards is a check somebody can forget to call.
80
+ *
81
+ * A member that names a tool the delegating context does not have gets it silently dropped rather than an error:
82
+ * the team is still runnable, and the alternative is a whole team refusing to start because one member's list
83
+ * mentions something a particular caller's role happens to exclude — which would make a team's usability depend
84
+ * on who triggered it.
85
+ */
86
+ export declare const memberTools: (input: {
87
+ readonly member: TeamMember;
88
+ /** What the delegating context can reach. The ceiling. */
89
+ readonly available: readonly string[];
90
+ }) => readonly string[];
91
+ /** The brief a team execution starts from, under the key the compiled prompts read. */
92
+ export declare const teamBrief: (brief: string) => Readonly<Record<string, unknown>>;
93
+ //# sourceMappingURL=index.d.ts.map