@oscharko-dev/keiko 0.1.0-beta.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 (450) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +7 -0
  3. package/README.md +621 -0
  4. package/TRADEMARKS.md +41 -0
  5. package/dist/audit/aggregate.d.ts +5 -0
  6. package/dist/audit/aggregate.js +25 -0
  7. package/dist/audit/build.d.ts +2 -0
  8. package/dist/audit/build.js +224 -0
  9. package/dist/audit/errors.d.ts +25 -0
  10. package/dist/audit/errors.js +39 -0
  11. package/dist/audit/index-api.d.ts +14 -0
  12. package/dist/audit/index-api.js +131 -0
  13. package/dist/audit/index.d.ts +12 -0
  14. package/dist/audit/index.js +17 -0
  15. package/dist/audit/persist.d.ts +8 -0
  16. package/dist/audit/persist.js +40 -0
  17. package/dist/audit/redaction.d.ts +3 -0
  18. package/dist/audit/redaction.js +61 -0
  19. package/dist/audit/report.d.ts +18 -0
  20. package/dist/audit/report.js +50 -0
  21. package/dist/audit/retention.d.ts +3 -0
  22. package/dist/audit/retention.js +95 -0
  23. package/dist/audit/runid.d.ts +1 -0
  24. package/dist/audit/runid.js +29 -0
  25. package/dist/audit/side-file.d.ts +12 -0
  26. package/dist/audit/side-file.js +82 -0
  27. package/dist/audit/store.d.ts +12 -0
  28. package/dist/audit/store.js +198 -0
  29. package/dist/audit/types.d.ts +188 -0
  30. package/dist/audit/types.js +8 -0
  31. package/dist/audit/workflow-evidence.d.ts +27 -0
  32. package/dist/audit/workflow-evidence.js +145 -0
  33. package/dist/cli/context.d.ts +2 -0
  34. package/dist/cli/context.js +102 -0
  35. package/dist/cli/evaluate.d.ts +7 -0
  36. package/dist/cli/evaluate.js +207 -0
  37. package/dist/cli/evidence.d.ts +8 -0
  38. package/dist/cli/evidence.js +88 -0
  39. package/dist/cli/gateway-config.d.ts +10 -0
  40. package/dist/cli/gateway-config.js +12 -0
  41. package/dist/cli/gen-tests.d.ts +7 -0
  42. package/dist/cli/gen-tests.js +208 -0
  43. package/dist/cli/index.d.ts +2 -0
  44. package/dist/cli/index.js +14 -0
  45. package/dist/cli/investigate.d.ts +8 -0
  46. package/dist/cli/investigate.js +242 -0
  47. package/dist/cli/models.d.ts +3 -0
  48. package/dist/cli/models.js +64 -0
  49. package/dist/cli/run.d.ts +7 -0
  50. package/dist/cli/run.js +187 -0
  51. package/dist/cli/runner.d.ts +6 -0
  52. package/dist/cli/runner.js +83 -0
  53. package/dist/cli/ui.d.ts +31 -0
  54. package/dist/cli/ui.js +240 -0
  55. package/dist/cli/verify.d.ts +2 -0
  56. package/dist/cli/verify.js +103 -0
  57. package/dist/evaluations/fixtures/bug-investigation/happy-path.d.ts +2 -0
  58. package/dist/evaluations/fixtures/bug-investigation/happy-path.js +66 -0
  59. package/dist/evaluations/fixtures/bug-investigation/investigation-only.d.ts +2 -0
  60. package/dist/evaluations/fixtures/bug-investigation/investigation-only.js +39 -0
  61. package/dist/evaluations/fixtures/bug-investigation/unsafe-action.d.ts +2 -0
  62. package/dist/evaluations/fixtures/bug-investigation/unsafe-action.js +37 -0
  63. package/dist/evaluations/fixtures/index.d.ts +7 -0
  64. package/dist/evaluations/fixtures/index.js +35 -0
  65. package/dist/evaluations/fixtures/support.d.ts +5 -0
  66. package/dist/evaluations/fixtures/support.js +42 -0
  67. package/dist/evaluations/fixtures/unit-tests/happy-path.d.ts +2 -0
  68. package/dist/evaluations/fixtures/unit-tests/happy-path.js +40 -0
  69. package/dist/evaluations/fixtures/unit-tests/retry-then-accept.d.ts +2 -0
  70. package/dist/evaluations/fixtures/unit-tests/retry-then-accept.js +39 -0
  71. package/dist/evaluations/fixtures/unit-tests/unsafe-action.d.ts +2 -0
  72. package/dist/evaluations/fixtures/unit-tests/unsafe-action.js +32 -0
  73. package/dist/evaluations/index.d.ts +12 -0
  74. package/dist/evaluations/index.js +12 -0
  75. package/dist/evaluations/manifest-check.d.ts +1 -0
  76. package/dist/evaluations/manifest-check.js +48 -0
  77. package/dist/evaluations/model-provider.d.ts +12 -0
  78. package/dist/evaluations/model-provider.js +26 -0
  79. package/dist/evaluations/render.d.ts +2 -0
  80. package/dist/evaluations/render.js +59 -0
  81. package/dist/evaluations/runner-support.d.ts +27 -0
  82. package/dist/evaluations/runner-support.js +163 -0
  83. package/dist/evaluations/runner.d.ts +20 -0
  84. package/dist/evaluations/runner.js +174 -0
  85. package/dist/evaluations/scorer.d.ts +14 -0
  86. package/dist/evaluations/scorer.js +131 -0
  87. package/dist/evaluations/scripted-model.d.ts +6 -0
  88. package/dist/evaluations/scripted-model.js +26 -0
  89. package/dist/evaluations/surface-parity.d.ts +2 -0
  90. package/dist/evaluations/surface-parity.js +184 -0
  91. package/dist/evaluations/types.d.ts +74 -0
  92. package/dist/evaluations/types.js +16 -0
  93. package/dist/gateway/capabilities.d.ts +11 -0
  94. package/dist/gateway/capabilities.data.d.ts +2 -0
  95. package/dist/gateway/capabilities.data.js +203 -0
  96. package/dist/gateway/capabilities.js +41 -0
  97. package/dist/gateway/config.d.ts +15 -0
  98. package/dist/gateway/config.js +154 -0
  99. package/dist/gateway/errors.d.ts +72 -0
  100. package/dist/gateway/errors.js +82 -0
  101. package/dist/gateway/gateway.d.ts +19 -0
  102. package/dist/gateway/gateway.js +94 -0
  103. package/dist/gateway/index.d.ts +10 -0
  104. package/dist/gateway/index.js +11 -0
  105. package/dist/gateway/model-selection.d.ts +9 -0
  106. package/dist/gateway/model-selection.js +36 -0
  107. package/dist/gateway/normalize.d.ts +7 -0
  108. package/dist/gateway/normalize.js +93 -0
  109. package/dist/gateway/openai-adapter.d.ts +20 -0
  110. package/dist/gateway/openai-adapter.js +263 -0
  111. package/dist/gateway/redaction.d.ts +1 -0
  112. package/dist/gateway/redaction.js +51 -0
  113. package/dist/gateway/resilience.d.ts +24 -0
  114. package/dist/gateway/resilience.js +166 -0
  115. package/dist/gateway/types.d.ts +108 -0
  116. package/dist/gateway/types.js +2 -0
  117. package/dist/harness/adapters.d.ts +23 -0
  118. package/dist/harness/adapters.js +38 -0
  119. package/dist/harness/context.d.ts +33 -0
  120. package/dist/harness/context.js +21 -0
  121. package/dist/harness/emitter.d.ts +15 -0
  122. package/dist/harness/emitter.js +72 -0
  123. package/dist/harness/errors.d.ts +21 -0
  124. package/dist/harness/errors.js +39 -0
  125. package/dist/harness/executor.d.ts +3 -0
  126. package/dist/harness/executor.js +211 -0
  127. package/dist/harness/fingerprint.d.ts +6 -0
  128. package/dist/harness/fingerprint.js +43 -0
  129. package/dist/harness/index.d.ts +9 -0
  130. package/dist/harness/index.js +13 -0
  131. package/dist/harness/loop.d.ts +3 -0
  132. package/dist/harness/loop.js +159 -0
  133. package/dist/harness/patcher.d.ts +4 -0
  134. package/dist/harness/patcher.js +49 -0
  135. package/dist/harness/planner.d.ts +3 -0
  136. package/dist/harness/planner.js +21 -0
  137. package/dist/harness/ports.d.ts +61 -0
  138. package/dist/harness/ports.js +4 -0
  139. package/dist/harness/session.d.ts +25 -0
  140. package/dist/harness/session.js +116 -0
  141. package/dist/harness/sinks.d.ts +30 -0
  142. package/dist/harness/sinks.js +72 -0
  143. package/dist/harness/tasks/explain-plan.d.ts +3 -0
  144. package/dist/harness/tasks/explain-plan.js +29 -0
  145. package/dist/harness/tasks/generate-unit-tests.d.ts +3 -0
  146. package/dist/harness/tasks/generate-unit-tests.js +28 -0
  147. package/dist/harness/tasks/investigate-bug.d.ts +3 -0
  148. package/dist/harness/tasks/investigate-bug.js +31 -0
  149. package/dist/harness/tasks/policy.d.ts +11 -0
  150. package/dist/harness/tasks/policy.js +22 -0
  151. package/dist/harness/tasks/verify.d.ts +3 -0
  152. package/dist/harness/tasks/verify.js +16 -0
  153. package/dist/harness/types.d.ts +270 -0
  154. package/dist/harness/types.js +33 -0
  155. package/dist/index.d.ts +11 -0
  156. package/dist/index.js +36 -0
  157. package/dist/sdk/index.d.ts +9 -0
  158. package/dist/sdk/index.js +37 -0
  159. package/dist/sdk/run-agent.d.ts +16 -0
  160. package/dist/sdk/run-agent.js +56 -0
  161. package/dist/tools/browser/cdp-client.d.ts +35 -0
  162. package/dist/tools/browser/cdp-client.js +218 -0
  163. package/dist/tools/browser/errors.d.ts +25 -0
  164. package/dist/tools/browser/errors.js +55 -0
  165. package/dist/tools/browser/index.d.ts +5 -0
  166. package/dist/tools/browser/index.js +6 -0
  167. package/dist/tools/browser/session.d.ts +44 -0
  168. package/dist/tools/browser/session.js +748 -0
  169. package/dist/tools/browser/types.d.ts +48 -0
  170. package/dist/tools/browser/types.js +2 -0
  171. package/dist/tools/browser/validators.d.ts +5 -0
  172. package/dist/tools/browser/validators.js +97 -0
  173. package/dist/tools/errors.d.ts +59 -0
  174. package/dist/tools/errors.js +94 -0
  175. package/dist/tools/exec.d.ts +42 -0
  176. package/dist/tools/exec.js +327 -0
  177. package/dist/tools/index.d.ts +11 -0
  178. package/dist/tools/index.js +14 -0
  179. package/dist/tools/patch-content.d.ts +10 -0
  180. package/dist/tools/patch-content.js +126 -0
  181. package/dist/tools/patch-normalize.d.ts +1 -0
  182. package/dist/tools/patch-normalize.js +80 -0
  183. package/dist/tools/patch-parse.d.ts +8 -0
  184. package/dist/tools/patch-parse.js +201 -0
  185. package/dist/tools/patch.d.ts +18 -0
  186. package/dist/tools/patch.js +403 -0
  187. package/dist/tools/registry.d.ts +36 -0
  188. package/dist/tools/registry.js +231 -0
  189. package/dist/tools/sandbox.d.ts +8 -0
  190. package/dist/tools/sandbox.js +121 -0
  191. package/dist/tools/schemas.d.ts +2 -0
  192. package/dist/tools/schemas.js +51 -0
  193. package/dist/tools/terminal-policy.d.ts +9 -0
  194. package/dist/tools/terminal-policy.js +313 -0
  195. package/dist/tools/types.d.ts +99 -0
  196. package/dist/tools/types.js +103 -0
  197. package/dist/tools/writer.d.ts +7 -0
  198. package/dist/tools/writer.js +20 -0
  199. package/dist/ui/browser.d.ts +10 -0
  200. package/dist/ui/browser.js +231 -0
  201. package/dist/ui/chat-handlers.d.ts +4 -0
  202. package/dist/ui/chat-handlers.js +281 -0
  203. package/dist/ui/csp-hashes.json +17 -0
  204. package/dist/ui/csp.d.ts +2 -0
  205. package/dist/ui/csp.js +66 -0
  206. package/dist/ui/deps.d.ts +34 -0
  207. package/dist/ui/deps.js +137 -0
  208. package/dist/ui/evidence.d.ts +27 -0
  209. package/dist/ui/evidence.js +142 -0
  210. package/dist/ui/files-deny.d.ts +2 -0
  211. package/dist/ui/files-deny.js +12 -0
  212. package/dist/ui/files.d.ts +65 -0
  213. package/dist/ui/files.js +492 -0
  214. package/dist/ui/headers.d.ts +2 -0
  215. package/dist/ui/headers.js +21 -0
  216. package/dist/ui/host-check.d.ts +2 -0
  217. package/dist/ui/host-check.js +58 -0
  218. package/dist/ui/index.d.ts +20 -0
  219. package/dist/ui/index.js +23 -0
  220. package/dist/ui/load-csp.d.ts +1 -0
  221. package/dist/ui/load-csp.js +28 -0
  222. package/dist/ui/read-handlers.d.ts +8 -0
  223. package/dist/ui/read-handlers.js +247 -0
  224. package/dist/ui/routes.d.ts +36 -0
  225. package/dist/ui/routes.js +129 -0
  226. package/dist/ui/run-engine.d.ts +20 -0
  227. package/dist/ui/run-engine.js +345 -0
  228. package/dist/ui/run-handlers.d.ts +8 -0
  229. package/dist/ui/run-handlers.js +431 -0
  230. package/dist/ui/run-request.d.ts +13 -0
  231. package/dist/ui/run-request.js +219 -0
  232. package/dist/ui/runs.d.ts +43 -0
  233. package/dist/ui/runs.js +92 -0
  234. package/dist/ui/server.d.ts +11 -0
  235. package/dist/ui/server.js +143 -0
  236. package/dist/ui/sink.d.ts +27 -0
  237. package/dist/ui/sink.js +80 -0
  238. package/dist/ui/sse.d.ts +7 -0
  239. package/dist/ui/sse.js +27 -0
  240. package/dist/ui/static/404.html +1 -0
  241. package/dist/ui/static/_next/static/ca-A01hy9W98aRvMZKdAw/_buildManifest.js +1 -0
  242. package/dist/ui/static/_next/static/ca-A01hy9W98aRvMZKdAw/_ssgManifest.js +1 -0
  243. package/dist/ui/static/_next/static/chunks/255-d47fd57964443afe.js +1 -0
  244. package/dist/ui/static/_next/static/chunks/4-be1fef693af8e088.js +1 -0
  245. package/dist/ui/static/_next/static/chunks/4bd1b696-c023c6e3521b1417.js +1 -0
  246. package/dist/ui/static/_next/static/chunks/app/_not-found/page-75825b09bcecad97.js +1 -0
  247. package/dist/ui/static/_next/static/chunks/app/launch/page-9c86a13c29884245.js +1 -0
  248. package/dist/ui/static/_next/static/chunks/app/layout-bdea63fe87947d50.js +1 -0
  249. package/dist/ui/static/_next/static/chunks/app/page-4168c12c68b7a853.js +1 -0
  250. package/dist/ui/static/_next/static/chunks/framework-a6e0b7e30f98059a.js +1 -0
  251. package/dist/ui/static/_next/static/chunks/main-778a50aebff02192.js +1 -0
  252. package/dist/ui/static/_next/static/chunks/main-app-30679af7240d63e9.js +1 -0
  253. package/dist/ui/static/_next/static/chunks/pages/_app-7d307437aca18ad4.js +1 -0
  254. package/dist/ui/static/_next/static/chunks/pages/_error-cb2a52f75f2162e2.js +1 -0
  255. package/dist/ui/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  256. package/dist/ui/static/_next/static/chunks/webpack-4a462cecab786e93.js +1 -0
  257. package/dist/ui/static/_next/static/css/be7cb54d5c5673b6.css +1 -0
  258. package/dist/ui/static/assets/editors/goland.svg +35 -0
  259. package/dist/ui/static/assets/editors/intellij.svg +39 -0
  260. package/dist/ui/static/assets/editors/pycharm.svg +58 -0
  261. package/dist/ui/static/assets/editors/rustrover.svg +19 -0
  262. package/dist/ui/static/assets/editors/vscode.svg +1 -0
  263. package/dist/ui/static/assets/editors/webstorm.svg +21 -0
  264. package/dist/ui/static/assets/icons/anthropic.svg +1 -0
  265. package/dist/ui/static/assets/icons/brave.svg +1 -0
  266. package/dist/ui/static/assets/icons/css3.svg +1 -0
  267. package/dist/ui/static/assets/icons/docker.svg +1 -0
  268. package/dist/ui/static/assets/icons/git.svg +1 -0
  269. package/dist/ui/static/assets/icons/github.svg +1 -0
  270. package/dist/ui/static/assets/icons/go.svg +1 -0
  271. package/dist/ui/static/assets/icons/gradle.svg +1 -0
  272. package/dist/ui/static/assets/icons/grafana.svg +1 -0
  273. package/dist/ui/static/assets/icons/graphql.svg +1 -0
  274. package/dist/ui/static/assets/icons/html5.svg +1 -0
  275. package/dist/ui/static/assets/icons/image.svg +1 -0
  276. package/dist/ui/static/assets/icons/java.svg +1 -0
  277. package/dist/ui/static/assets/icons/javascript.svg +1 -0
  278. package/dist/ui/static/assets/icons/json.svg +1 -0
  279. package/dist/ui/static/assets/icons/kafka.svg +1 -0
  280. package/dist/ui/static/assets/icons/kubernetes.svg +1 -0
  281. package/dist/ui/static/assets/icons/linear.svg +1 -0
  282. package/dist/ui/static/assets/icons/markdown.svg +1 -0
  283. package/dist/ui/static/assets/icons/nginx.svg +1 -0
  284. package/dist/ui/static/assets/icons/nodejs.svg +1 -0
  285. package/dist/ui/static/assets/icons/notion.svg +1 -0
  286. package/dist/ui/static/assets/icons/openai.svg +1 -0
  287. package/dist/ui/static/assets/icons/playwright.svg +1 -0
  288. package/dist/ui/static/assets/icons/postgresql.svg +1 -0
  289. package/dist/ui/static/assets/icons/prometheus.svg +1 -0
  290. package/dist/ui/static/assets/icons/properties.svg +1 -0
  291. package/dist/ui/static/assets/icons/puppeteer.svg +1 -0
  292. package/dist/ui/static/assets/icons/python.svg +1 -0
  293. package/dist/ui/static/assets/icons/react.svg +1 -0
  294. package/dist/ui/static/assets/icons/redis.svg +1 -0
  295. package/dist/ui/static/assets/icons/rust.svg +1 -0
  296. package/dist/ui/static/assets/icons/sentry.svg +1 -0
  297. package/dist/ui/static/assets/icons/slack.svg +1 -0
  298. package/dist/ui/static/assets/icons/spring.svg +1 -0
  299. package/dist/ui/static/assets/icons/typescript.svg +1 -0
  300. package/dist/ui/static/assets/icons/upstash.svg +1 -0
  301. package/dist/ui/static/assets/icons/yaml.svg +1 -0
  302. package/dist/ui/static/assets/keiko-logo.svg +10 -0
  303. package/dist/ui/static/index.html +1 -0
  304. package/dist/ui/static/index.txt +19 -0
  305. package/dist/ui/static/keiko-logo.svg +10 -0
  306. package/dist/ui/static/launch.html +1 -0
  307. package/dist/ui/static/launch.txt +19 -0
  308. package/dist/ui/static.d.ts +3 -0
  309. package/dist/ui/static.js +72 -0
  310. package/dist/ui/store/chats.d.ts +14 -0
  311. package/dist/ui/store/chats.js +110 -0
  312. package/dist/ui/store/db.d.ts +6 -0
  313. package/dist/ui/store/db.js +182 -0
  314. package/dist/ui/store/errors.d.ts +12 -0
  315. package/dist/ui/store/errors.js +30 -0
  316. package/dist/ui/store/index.d.ts +6 -0
  317. package/dist/ui/store/index.js +6 -0
  318. package/dist/ui/store/messages.d.ts +5 -0
  319. package/dist/ui/store/messages.js +137 -0
  320. package/dist/ui/store/paths.d.ts +4 -0
  321. package/dist/ui/store/paths.js +69 -0
  322. package/dist/ui/store/projects.d.ts +7 -0
  323. package/dist/ui/store/projects.js +61 -0
  324. package/dist/ui/store/schema.d.ts +3 -0
  325. package/dist/ui/store/schema.js +77 -0
  326. package/dist/ui/store/types.d.ts +80 -0
  327. package/dist/ui/store/types.js +3 -0
  328. package/dist/ui/store/validation.d.ts +4 -0
  329. package/dist/ui/store/validation.js +72 -0
  330. package/dist/ui/store-handlers.d.ts +16 -0
  331. package/dist/ui/store-handlers.js +465 -0
  332. package/dist/ui/terminal-errors.d.ts +21 -0
  333. package/dist/ui/terminal-errors.js +45 -0
  334. package/dist/ui/terminal-evidence.d.ts +20 -0
  335. package/dist/ui/terminal-evidence.js +65 -0
  336. package/dist/ui/terminal-routes.d.ts +9 -0
  337. package/dist/ui/terminal-routes.js +219 -0
  338. package/dist/ui/terminal.d.ts +67 -0
  339. package/dist/ui/terminal.js +835 -0
  340. package/dist/verification/classify.d.ts +10 -0
  341. package/dist/verification/classify.js +53 -0
  342. package/dist/verification/detect.d.ts +4 -0
  343. package/dist/verification/detect.js +81 -0
  344. package/dist/verification/errors.d.ts +11 -0
  345. package/dist/verification/errors.js +21 -0
  346. package/dist/verification/index.d.ts +17 -0
  347. package/dist/verification/index.js +13 -0
  348. package/dist/verification/limits.d.ts +3 -0
  349. package/dist/verification/limits.js +40 -0
  350. package/dist/verification/monitor.d.ts +4 -0
  351. package/dist/verification/monitor.js +58 -0
  352. package/dist/verification/orchestrator.d.ts +16 -0
  353. package/dist/verification/orchestrator.js +363 -0
  354. package/dist/verification/plan.d.ts +9 -0
  355. package/dist/verification/plan.js +125 -0
  356. package/dist/verification/summary.d.ts +40 -0
  357. package/dist/verification/summary.js +67 -0
  358. package/dist/verification/types.d.ts +63 -0
  359. package/dist/verification/types.js +13 -0
  360. package/dist/workflows/bug-investigation/context.d.ts +7 -0
  361. package/dist/workflows/bug-investigation/context.js +119 -0
  362. package/dist/workflows/bug-investigation/descriptor.d.ts +3 -0
  363. package/dist/workflows/bug-investigation/descriptor.js +46 -0
  364. package/dist/workflows/bug-investigation/emit.d.ts +12 -0
  365. package/dist/workflows/bug-investigation/emit.js +35 -0
  366. package/dist/workflows/bug-investigation/events.d.ts +81 -0
  367. package/dist/workflows/bug-investigation/events.js +9 -0
  368. package/dist/workflows/bug-investigation/failure-parse.d.ts +3 -0
  369. package/dist/workflows/bug-investigation/failure-parse.js +154 -0
  370. package/dist/workflows/bug-investigation/guard.d.ts +2 -0
  371. package/dist/workflows/bug-investigation/guard.js +69 -0
  372. package/dist/workflows/bug-investigation/index.d.ts +7 -0
  373. package/dist/workflows/bug-investigation/index.js +13 -0
  374. package/dist/workflows/bug-investigation/internal.d.ts +37 -0
  375. package/dist/workflows/bug-investigation/internal.js +64 -0
  376. package/dist/workflows/bug-investigation/model-loop.d.ts +4 -0
  377. package/dist/workflows/bug-investigation/model-loop.js +223 -0
  378. package/dist/workflows/bug-investigation/parse.d.ts +3 -0
  379. package/dist/workflows/bug-investigation/parse.js +123 -0
  380. package/dist/workflows/bug-investigation/prompt.d.ts +4 -0
  381. package/dist/workflows/bug-investigation/prompt.js +107 -0
  382. package/dist/workflows/bug-investigation/report.d.ts +23 -0
  383. package/dist/workflows/bug-investigation/report.js +151 -0
  384. package/dist/workflows/bug-investigation/stages.d.ts +13 -0
  385. package/dist/workflows/bug-investigation/stages.js +242 -0
  386. package/dist/workflows/bug-investigation/types.d.ts +91 -0
  387. package/dist/workflows/bug-investigation/types.js +14 -0
  388. package/dist/workflows/bug-investigation/verify-stage.d.ts +10 -0
  389. package/dist/workflows/bug-investigation/verify-stage.js +91 -0
  390. package/dist/workflows/bug-investigation/workflow.d.ts +2 -0
  391. package/dist/workflows/bug-investigation/workflow.js +74 -0
  392. package/dist/workflows/descriptor.d.ts +20 -0
  393. package/dist/workflows/descriptor.js +8 -0
  394. package/dist/workflows/index.d.ts +3 -0
  395. package/dist/workflows/index.js +2 -0
  396. package/dist/workflows/unit-tests/context.d.ts +7 -0
  397. package/dist/workflows/unit-tests/context.js +129 -0
  398. package/dist/workflows/unit-tests/conventions.d.ts +4 -0
  399. package/dist/workflows/unit-tests/conventions.js +87 -0
  400. package/dist/workflows/unit-tests/descriptor.d.ts +4 -0
  401. package/dist/workflows/unit-tests/descriptor.js +43 -0
  402. package/dist/workflows/unit-tests/emit.d.ts +12 -0
  403. package/dist/workflows/unit-tests/emit.js +35 -0
  404. package/dist/workflows/unit-tests/events.d.ts +78 -0
  405. package/dist/workflows/unit-tests/events.js +7 -0
  406. package/dist/workflows/unit-tests/index.d.ts +6 -0
  407. package/dist/workflows/unit-tests/index.js +10 -0
  408. package/dist/workflows/unit-tests/internal.d.ts +35 -0
  409. package/dist/workflows/unit-tests/internal.js +43 -0
  410. package/dist/workflows/unit-tests/model-loop.d.ts +4 -0
  411. package/dist/workflows/unit-tests/model-loop.js +95 -0
  412. package/dist/workflows/unit-tests/parse.d.ts +6 -0
  413. package/dist/workflows/unit-tests/parse.js +68 -0
  414. package/dist/workflows/unit-tests/prompt.d.ts +4 -0
  415. package/dist/workflows/unit-tests/prompt.js +71 -0
  416. package/dist/workflows/unit-tests/report.d.ts +21 -0
  417. package/dist/workflows/unit-tests/report.js +90 -0
  418. package/dist/workflows/unit-tests/stages.d.ts +9 -0
  419. package/dist/workflows/unit-tests/stages.js +155 -0
  420. package/dist/workflows/unit-tests/types.d.ts +70 -0
  421. package/dist/workflows/unit-tests/types.js +11 -0
  422. package/dist/workflows/unit-tests/verify-stage.d.ts +9 -0
  423. package/dist/workflows/unit-tests/verify-stage.js +56 -0
  424. package/dist/workflows/unit-tests/workflow.d.ts +2 -0
  425. package/dist/workflows/unit-tests/workflow.js +58 -0
  426. package/dist/workspace/contextPack.d.ts +9 -0
  427. package/dist/workspace/contextPack.js +94 -0
  428. package/dist/workspace/detect.d.ts +3 -0
  429. package/dist/workspace/detect.js +135 -0
  430. package/dist/workspace/discovery.d.ts +9 -0
  431. package/dist/workspace/discovery.js +167 -0
  432. package/dist/workspace/errors.d.ts +39 -0
  433. package/dist/workspace/errors.js +66 -0
  434. package/dist/workspace/fs.d.ts +21 -0
  435. package/dist/workspace/fs.js +36 -0
  436. package/dist/workspace/ignore.d.ts +14 -0
  437. package/dist/workspace/ignore.js +176 -0
  438. package/dist/workspace/index.d.ts +11 -0
  439. package/dist/workspace/index.js +13 -0
  440. package/dist/workspace/paths.d.ts +2 -0
  441. package/dist/workspace/paths.js +38 -0
  442. package/dist/workspace/realpath.d.ts +7 -0
  443. package/dist/workspace/realpath.js +72 -0
  444. package/dist/workspace/retrieval.d.ts +9 -0
  445. package/dist/workspace/retrieval.js +74 -0
  446. package/dist/workspace/summary.d.ts +3 -0
  447. package/dist/workspace/summary.js +54 -0
  448. package/dist/workspace/types.d.ts +103 -0
  449. package/dist/workspace/types.js +27 -0
  450. package/package.json +58 -0
@@ -0,0 +1,154 @@
1
+ // Gateway config loading, hand-rolled validation, and redaction-aware serialisation.
2
+ // No schema library: validation is explicit if/throw with actionable messages.
3
+ // API keys are sourced only from environment or the config file, never CLI flags,
4
+ // and are excluded from every serialisation path.
5
+ import { readFileSync } from "node:fs";
6
+ import { findCapability } from "./capabilities.js";
7
+ import { ConfigInvalidError } from "./errors.js";
8
+ const DEFAULT_TIMEOUT_MS = 30_000;
9
+ const DEFAULT_MAX_RETRIES = 3;
10
+ const DEFAULT_RETRY_BASE_DELAY_MS = 500;
11
+ const DEFAULT_FAILURE_THRESHOLD = 5;
12
+ const DEFAULT_COOLDOWN_MS = 30_000;
13
+ const DEFAULT_HALF_OPEN_PROBES = 2;
14
+ function isRecord(value) {
15
+ return typeof value === "object" && value !== null && !Array.isArray(value);
16
+ }
17
+ function requirePositiveInt(value, path) {
18
+ if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
19
+ throw new ConfigInvalidError(`${path} must be a positive integer`);
20
+ }
21
+ return value;
22
+ }
23
+ function requireNonEmptyString(value, path) {
24
+ if (typeof value !== "string" || value.length === 0) {
25
+ throw new ConfigInvalidError(`${path} must be a non-empty string`);
26
+ }
27
+ return value;
28
+ }
29
+ // Model id → KEIKO_MODEL_<UPPER>_ form: non-alphanumerics become "_", uppercased.
30
+ function envModelToken(modelId) {
31
+ return modelId.replace(/[^A-Za-z0-9]/g, "_").toUpperCase();
32
+ }
33
+ function resolveSecret(modelId, fileValue, env, suffix) {
34
+ const perModel = env[`KEIKO_MODEL_${envModelToken(modelId)}_${suffix}`];
35
+ if (perModel !== undefined && perModel.length > 0) {
36
+ return perModel;
37
+ }
38
+ if (fileValue.length > 0) {
39
+ return fileValue;
40
+ }
41
+ const fallback = env[`KEIKO_DEFAULT_${suffix}`];
42
+ return fallback ?? "";
43
+ }
44
+ // Validates a resolved baseUrl for scheme and credential hygiene. Host/IP is
45
+ // intentionally NOT restricted: Keiko addresses customer-internally-hosted endpoints
46
+ // (private IPs are a valid, first-class target); this guard is scheme/credential
47
+ // hygiene + defence-in-depth, not host filtering.
48
+ function isLoopbackHost(hostname) {
49
+ return (hostname === "localhost" ||
50
+ hostname === "::1" ||
51
+ hostname === "[::1]" ||
52
+ hostname.startsWith("127."));
53
+ }
54
+ function validateBaseUrl(baseUrl, path) {
55
+ let url;
56
+ try {
57
+ url = new URL(baseUrl);
58
+ }
59
+ catch {
60
+ throw new ConfigInvalidError(`${path}.baseUrl must be a valid absolute URL`);
61
+ }
62
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
63
+ throw new ConfigInvalidError(`${path}.baseUrl must use the http or https scheme`);
64
+ }
65
+ if (url.protocol === "http:" && !isLoopbackHost(url.hostname)) {
66
+ throw new ConfigInvalidError(`${path}.baseUrl must use https unless it targets localhost or loopback`);
67
+ }
68
+ if (url.username !== "" || url.password !== "") {
69
+ throw new ConfigInvalidError(`${path}.baseUrl must not embed credentials in the URL; provide the key via apiKey`);
70
+ }
71
+ }
72
+ function parseProvider(raw, index, env) {
73
+ const path = `providers[${String(index)}]`;
74
+ if (!isRecord(raw)) {
75
+ throw new ConfigInvalidError(`${path} must be an object`);
76
+ }
77
+ const modelId = requireNonEmptyString(raw.modelId, `${path}.modelId`);
78
+ if (findCapability(modelId) === undefined) {
79
+ throw new ConfigInvalidError(`${path}.modelId must be registered in the capability registry`);
80
+ }
81
+ const fileBaseUrl = typeof raw.baseUrl === "string" ? raw.baseUrl : "";
82
+ const fileApiKey = typeof raw.apiKey === "string" ? raw.apiKey : "";
83
+ const baseUrl = resolveSecret(modelId, fileBaseUrl, env, "BASE_URL");
84
+ const apiKey = resolveSecret(modelId, fileApiKey, env, "API_KEY");
85
+ if (baseUrl.length === 0) {
86
+ throw new ConfigInvalidError(`${path}.baseUrl must be set via config or environment`);
87
+ }
88
+ if (apiKey.length === 0) {
89
+ throw new ConfigInvalidError(`${path}.apiKey must be set via config or environment`);
90
+ }
91
+ validateBaseUrl(baseUrl, path);
92
+ return {
93
+ modelId,
94
+ baseUrl,
95
+ apiKey,
96
+ timeoutMs: requirePositiveInt(raw.timeoutMs ?? DEFAULT_TIMEOUT_MS, `${path}.timeoutMs`),
97
+ maxRetries: requireNonNegativeInt(raw.maxRetries ?? DEFAULT_MAX_RETRIES, `${path}.maxRetries`),
98
+ retryBaseDelayMs: requirePositiveInt(raw.retryBaseDelayMs ?? DEFAULT_RETRY_BASE_DELAY_MS, `${path}.retryBaseDelayMs`),
99
+ };
100
+ }
101
+ function requireNonNegativeInt(value, path) {
102
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
103
+ throw new ConfigInvalidError(`${path} must be a non-negative integer`);
104
+ }
105
+ return value;
106
+ }
107
+ function parseCircuitBreaker(raw) {
108
+ const source = isRecord(raw) ? raw : {};
109
+ return {
110
+ failureThreshold: requirePositiveInt(source.failureThreshold ?? DEFAULT_FAILURE_THRESHOLD, "circuitBreaker.failureThreshold"),
111
+ cooldownMs: requirePositiveInt(source.cooldownMs ?? DEFAULT_COOLDOWN_MS, "circuitBreaker.cooldownMs"),
112
+ halfOpenProbes: requirePositiveInt(source.halfOpenProbes ?? DEFAULT_HALF_OPEN_PROBES, "circuitBreaker.halfOpenProbes"),
113
+ };
114
+ }
115
+ export function parseGatewayConfig(raw, env = {}) {
116
+ if (!isRecord(raw)) {
117
+ throw new ConfigInvalidError("config root must be a JSON object");
118
+ }
119
+ const providersRaw = raw.providers;
120
+ if (!Array.isArray(providersRaw) || providersRaw.length === 0) {
121
+ throw new ConfigInvalidError("providers must be a non-empty array");
122
+ }
123
+ const providers = providersRaw.map((item, index) => parseProvider(item, index, env));
124
+ return { providers, circuitBreaker: parseCircuitBreaker(raw.circuitBreaker) };
125
+ }
126
+ export function loadConfigFromFile(path, env = {}) {
127
+ let text;
128
+ try {
129
+ text = readFileSync(path, "utf8");
130
+ }
131
+ catch {
132
+ throw new ConfigInvalidError(`config file could not be read: ${path}`);
133
+ }
134
+ let parsed;
135
+ try {
136
+ parsed = JSON.parse(text);
137
+ }
138
+ catch {
139
+ throw new ConfigInvalidError(`config file is not valid JSON: ${path}`);
140
+ }
141
+ return parseGatewayConfig(parsed, env);
142
+ }
143
+ // Credential- and endpoint-free projection for logging, CLI output, and serialisation.
144
+ export function toSafeObject(config) {
145
+ return {
146
+ providers: config.providers.map((provider) => ({
147
+ modelId: provider.modelId,
148
+ timeoutMs: provider.timeoutMs,
149
+ maxRetries: provider.maxRetries,
150
+ retryBaseDelayMs: provider.retryBaseDelayMs,
151
+ })),
152
+ circuitBreaker: config.circuitBreaker,
153
+ };
154
+ }
@@ -0,0 +1,72 @@
1
+ export declare const ERROR_CODES: {
2
+ readonly AUTHENTICATION: "GATEWAY_AUTHENTICATION";
3
+ readonly TRANSPORT: "GATEWAY_TRANSPORT";
4
+ readonly MODEL_REFUSAL: "GATEWAY_MODEL_REFUSAL";
5
+ readonly MALFORMED_TOOL_CALL: "GATEWAY_MALFORMED_TOOL_CALL";
6
+ readonly CONTEXT_OVERFLOW: "GATEWAY_CONTEXT_OVERFLOW";
7
+ readonly RATE_LIMIT: "GATEWAY_RATE_LIMIT";
8
+ readonly TIMEOUT: "GATEWAY_TIMEOUT";
9
+ readonly CANCELLED: "GATEWAY_CANCELLED";
10
+ readonly CIRCUIT_OPEN: "GATEWAY_CIRCUIT_OPEN";
11
+ readonly PROVIDER_ERROR: "GATEWAY_PROVIDER_ERROR";
12
+ readonly CONFIG_INVALID: "GATEWAY_CONFIG_INVALID";
13
+ readonly UNKNOWN_MODEL: "GATEWAY_UNKNOWN_MODEL";
14
+ };
15
+ export type ErrorCode = (typeof ERROR_CODES)[keyof typeof ERROR_CODES];
16
+ export declare abstract class GatewayError extends Error {
17
+ abstract readonly code: ErrorCode;
18
+ abstract readonly retryable: boolean;
19
+ constructor(message: string, secrets?: readonly string[]);
20
+ }
21
+ export declare class AuthenticationError extends GatewayError {
22
+ readonly code: "GATEWAY_AUTHENTICATION";
23
+ readonly retryable = false;
24
+ }
25
+ export declare class TransportError extends GatewayError {
26
+ readonly code: "GATEWAY_TRANSPORT";
27
+ readonly retryable = true;
28
+ }
29
+ export declare class ModelRefusalError extends GatewayError {
30
+ readonly code: "GATEWAY_MODEL_REFUSAL";
31
+ readonly retryable = false;
32
+ }
33
+ export declare class MalformedToolCallError extends GatewayError {
34
+ readonly code: "GATEWAY_MALFORMED_TOOL_CALL";
35
+ readonly retryable = false;
36
+ }
37
+ export declare class ContextOverflowError extends GatewayError {
38
+ readonly code: "GATEWAY_CONTEXT_OVERFLOW";
39
+ readonly retryable = false;
40
+ }
41
+ export declare class RateLimitError extends GatewayError {
42
+ readonly code: "GATEWAY_RATE_LIMIT";
43
+ readonly retryable = true;
44
+ readonly retryAfterMs: number | null;
45
+ constructor(message: string, retryAfterMs?: number | null, secrets?: readonly string[]);
46
+ }
47
+ export declare class TimeoutError extends GatewayError {
48
+ readonly code: "GATEWAY_TIMEOUT";
49
+ readonly retryable = true;
50
+ }
51
+ export declare class CancelledError extends GatewayError {
52
+ readonly code: "GATEWAY_CANCELLED";
53
+ readonly retryable = false;
54
+ }
55
+ export declare class CircuitOpenError extends GatewayError {
56
+ readonly code: "GATEWAY_CIRCUIT_OPEN";
57
+ readonly retryable = false;
58
+ }
59
+ export declare class ProviderError extends GatewayError {
60
+ readonly code: "GATEWAY_PROVIDER_ERROR";
61
+ readonly retryable = false;
62
+ readonly httpStatus: number;
63
+ constructor(message: string, httpStatus: number, secrets?: readonly string[]);
64
+ }
65
+ export declare class ConfigInvalidError extends GatewayError {
66
+ readonly code: "GATEWAY_CONFIG_INVALID";
67
+ readonly retryable = false;
68
+ }
69
+ export declare class UnknownModelError extends GatewayError {
70
+ readonly code: "GATEWAY_UNKNOWN_MODEL";
71
+ readonly retryable = false;
72
+ }
@@ -0,0 +1,82 @@
1
+ // Typed error taxonomy with stable string `code` discriminants. Callers switch on
2
+ // `error.code`; they never parse `error.message`. Every message is redacted at
3
+ // construction so errors are always safe to log.
4
+ import { redact } from "./redaction.js";
5
+ export const ERROR_CODES = {
6
+ AUTHENTICATION: "GATEWAY_AUTHENTICATION",
7
+ TRANSPORT: "GATEWAY_TRANSPORT",
8
+ MODEL_REFUSAL: "GATEWAY_MODEL_REFUSAL",
9
+ MALFORMED_TOOL_CALL: "GATEWAY_MALFORMED_TOOL_CALL",
10
+ CONTEXT_OVERFLOW: "GATEWAY_CONTEXT_OVERFLOW",
11
+ RATE_LIMIT: "GATEWAY_RATE_LIMIT",
12
+ TIMEOUT: "GATEWAY_TIMEOUT",
13
+ CANCELLED: "GATEWAY_CANCELLED",
14
+ CIRCUIT_OPEN: "GATEWAY_CIRCUIT_OPEN",
15
+ PROVIDER_ERROR: "GATEWAY_PROVIDER_ERROR",
16
+ CONFIG_INVALID: "GATEWAY_CONFIG_INVALID",
17
+ UNKNOWN_MODEL: "GATEWAY_UNKNOWN_MODEL",
18
+ };
19
+ export class GatewayError extends Error {
20
+ constructor(message, secrets = []) {
21
+ super(redact(message, secrets));
22
+ this.name = new.target.name;
23
+ }
24
+ }
25
+ export class AuthenticationError extends GatewayError {
26
+ code = ERROR_CODES.AUTHENTICATION;
27
+ retryable = false;
28
+ }
29
+ export class TransportError extends GatewayError {
30
+ code = ERROR_CODES.TRANSPORT;
31
+ retryable = true;
32
+ }
33
+ export class ModelRefusalError extends GatewayError {
34
+ code = ERROR_CODES.MODEL_REFUSAL;
35
+ retryable = false;
36
+ }
37
+ export class MalformedToolCallError extends GatewayError {
38
+ code = ERROR_CODES.MALFORMED_TOOL_CALL;
39
+ retryable = false;
40
+ }
41
+ export class ContextOverflowError extends GatewayError {
42
+ code = ERROR_CODES.CONTEXT_OVERFLOW;
43
+ retryable = false;
44
+ }
45
+ export class RateLimitError extends GatewayError {
46
+ code = ERROR_CODES.RATE_LIMIT;
47
+ retryable = true;
48
+ retryAfterMs;
49
+ constructor(message, retryAfterMs = null, secrets = []) {
50
+ super(message, secrets);
51
+ this.retryAfterMs = retryAfterMs;
52
+ }
53
+ }
54
+ export class TimeoutError extends GatewayError {
55
+ code = ERROR_CODES.TIMEOUT;
56
+ retryable = true;
57
+ }
58
+ export class CancelledError extends GatewayError {
59
+ code = ERROR_CODES.CANCELLED;
60
+ retryable = false;
61
+ }
62
+ export class CircuitOpenError extends GatewayError {
63
+ code = ERROR_CODES.CIRCUIT_OPEN;
64
+ retryable = false;
65
+ }
66
+ export class ProviderError extends GatewayError {
67
+ code = ERROR_CODES.PROVIDER_ERROR;
68
+ retryable = false;
69
+ httpStatus;
70
+ constructor(message, httpStatus, secrets = []) {
71
+ super(message, secrets);
72
+ this.httpStatus = httpStatus;
73
+ }
74
+ }
75
+ export class ConfigInvalidError extends GatewayError {
76
+ code = ERROR_CODES.CONFIG_INVALID;
77
+ retryable = false;
78
+ }
79
+ export class UnknownModelError extends GatewayError {
80
+ code = ERROR_CODES.UNKNOWN_MODEL;
81
+ retryable = false;
82
+ }
@@ -0,0 +1,19 @@
1
+ import type { Clock, CircuitBreakerStatus, GatewayConfig, GatewayRequest, NormalizedResponse, ProviderAdapter } from "./types.js";
2
+ export interface GatewayDeps {
3
+ readonly adapter?: ProviderAdapter | undefined;
4
+ readonly clock?: Clock | undefined;
5
+ }
6
+ export declare class Gateway {
7
+ private readonly config;
8
+ private readonly clock;
9
+ private readonly adapter;
10
+ private readonly providers;
11
+ private readonly breakers;
12
+ constructor(config: GatewayConfig, deps?: GatewayDeps);
13
+ chat(request: GatewayRequest): Promise<NormalizedResponse>;
14
+ circuitStatus(modelId: string): CircuitBreakerStatus;
15
+ private invoke;
16
+ private route;
17
+ private breakerFor;
18
+ private adapterFor;
19
+ }
@@ -0,0 +1,94 @@
1
+ // Orchestrator: routes a request through the capability registry, then through the
2
+ // circuit breaker, bounded retry, and the provider adapter. Usage metadata
3
+ // (request id, latency, cost class) is owned by the gateway, not the provider, so
4
+ // the audit ledger (issue #10) has a reliable typed target on every response.
5
+ import { randomUUID } from "node:crypto";
6
+ import { findCapability } from "./capabilities.js";
7
+ import { UnknownModelError } from "./errors.js";
8
+ import { OpenAiAdapter } from "./openai-adapter.js";
9
+ import { CircuitBreaker, executeWithRetry, systemClock } from "./resilience.js";
10
+ export class Gateway {
11
+ config;
12
+ clock;
13
+ adapter;
14
+ providers;
15
+ breakers = new Map();
16
+ constructor(config, deps = {}) {
17
+ this.config = config;
18
+ this.clock = deps.clock ?? systemClock;
19
+ this.adapter = deps.adapter;
20
+ this.providers = new Map(config.providers.map((p) => [p.modelId, p]));
21
+ }
22
+ async chat(request) {
23
+ const route = this.route(request.modelId);
24
+ const breaker = this.breakerFor(route.provider);
25
+ const requestId = randomUUID();
26
+ const start = this.clock.now();
27
+ const adapter = this.adapterFor(requestId, route.capability);
28
+ const result = await executeWithRetry((attemptTimeoutMs) => this.invoke(breaker, adapter, request, {
29
+ ...route.provider,
30
+ ...(attemptTimeoutMs === undefined ? {} : { timeoutMs: attemptTimeoutMs }),
31
+ }), route.provider, this.clock, request.cancellationSignal);
32
+ return {
33
+ ...result,
34
+ usage: {
35
+ ...result.usage,
36
+ requestId,
37
+ latencyMs: Math.max(1, this.clock.now() - start),
38
+ costClass: route.capability.costClass,
39
+ },
40
+ };
41
+ }
42
+ circuitStatus(modelId) {
43
+ const breaker = this.breakers.get(modelId);
44
+ return (breaker?.status(modelId) ?? {
45
+ modelId,
46
+ state: "closed",
47
+ consecutiveFailures: 0,
48
+ openedAt: null,
49
+ });
50
+ }
51
+ async invoke(breaker, adapter, request, provider) {
52
+ breaker.assertAllowed();
53
+ try {
54
+ const response = await adapter.call(request, provider);
55
+ breaker.recordSuccess();
56
+ return response;
57
+ }
58
+ catch (error) {
59
+ breaker.recordFailure();
60
+ throw error;
61
+ }
62
+ }
63
+ route(modelId) {
64
+ const provider = this.providers.get(modelId);
65
+ if (provider === undefined) {
66
+ throw new UnknownModelError(`no provider configured for model '${modelId}'`);
67
+ }
68
+ const capability = findCapability(modelId);
69
+ if (capability === undefined) {
70
+ throw new UnknownModelError(`model '${modelId}' is not in the capability registry`);
71
+ }
72
+ if (capability.kind !== "chat") {
73
+ throw new UnknownModelError(`model '${modelId}' has kind '${capability.kind}'; the chat path requires a chat model`);
74
+ }
75
+ return { provider, capability };
76
+ }
77
+ breakerFor(provider) {
78
+ const existing = this.breakers.get(provider.modelId);
79
+ if (existing !== undefined) {
80
+ return existing;
81
+ }
82
+ const breaker = new CircuitBreaker(provider.modelId, this.config.circuitBreaker, this.clock);
83
+ this.breakers.set(provider.modelId, breaker);
84
+ return breaker;
85
+ }
86
+ adapterFor(requestId, capability) {
87
+ return (this.adapter ??
88
+ new OpenAiAdapter({
89
+ requestId,
90
+ costClass: capability.costClass,
91
+ now: this.clock.now,
92
+ }));
93
+ }
94
+ }
@@ -0,0 +1,10 @@
1
+ export type { CircuitBreakerConfig, CircuitBreakerStatus, CircuitState, ChatMessage, Clock, CostClass, FinishReason, GatewayConfig, GatewayRequest, LatencyClass, ModelCapability, ModelKind, ModelProviderConfig, NormalizedResponse, NormalizedToolCall, ProviderAdapter, ResponseFormat, StreamDelta, StreamEvent, ToolDefinition, UsageMetadata, } from "./types.js";
2
+ export { CAPABILITY_REGISTRY, findCapability, listCapabilities, selectCheapest, type CapabilityQuery, } from "./capabilities.js";
3
+ export { loadConfigFromFile, parseGatewayConfig, toSafeObject, type EnvSource, type SafeGatewayConfig, type SafeProviderConfig, } from "./config.js";
4
+ export { Gateway, type GatewayDeps } from "./gateway.js";
5
+ export { OpenAiAdapter, type AdapterDeps } from "./openai-adapter.js";
6
+ export { assertConfiguredModel, selectConfiguredModel, type ModelSelectionQuery, } from "./model-selection.js";
7
+ export { CircuitBreaker, executeWithRetry, systemClock, type RetryConfig } from "./resilience.js";
8
+ export { normalizeChatResponse, type UsageSeed } from "./normalize.js";
9
+ export { redact } from "./redaction.js";
10
+ export { AuthenticationError, CancelledError, CircuitOpenError, ConfigInvalidError, ContextOverflowError, ERROR_CODES, GatewayError, MalformedToolCallError, ModelRefusalError, ProviderError, RateLimitError, TimeoutError, TransportError, UnknownModelError, type ErrorCode, } from "./errors.js";
@@ -0,0 +1,11 @@
1
+ // Public barrel for the model gateway: all types, the Gateway orchestrator, the
2
+ // capability registry helpers, config loaders, and the typed error taxonomy.
3
+ export { CAPABILITY_REGISTRY, findCapability, listCapabilities, selectCheapest, } from "./capabilities.js";
4
+ export { loadConfigFromFile, parseGatewayConfig, toSafeObject, } from "./config.js";
5
+ export { Gateway } from "./gateway.js";
6
+ export { OpenAiAdapter } from "./openai-adapter.js";
7
+ export { assertConfiguredModel, selectConfiguredModel, } from "./model-selection.js";
8
+ export { CircuitBreaker, executeWithRetry, systemClock } from "./resilience.js";
9
+ export { normalizeChatResponse } from "./normalize.js";
10
+ export { redact } from "./redaction.js";
11
+ export { AuthenticationError, CancelledError, CircuitOpenError, ConfigInvalidError, ContextOverflowError, ERROR_CODES, GatewayError, MalformedToolCallError, ModelRefusalError, ProviderError, RateLimitError, TimeoutError, TransportError, UnknownModelError, } from "./errors.js";
@@ -0,0 +1,9 @@
1
+ import type { GatewayConfig, ModelKind } from "./types.js";
2
+ export interface ModelSelectionQuery {
3
+ readonly kind: ModelKind;
4
+ readonly toolCalling?: boolean | undefined;
5
+ readonly structuredOutput?: boolean | undefined;
6
+ readonly minContextWindow?: number | undefined;
7
+ }
8
+ export declare function assertConfiguredModel(config: GatewayConfig, modelId: string): void;
9
+ export declare function selectConfiguredModel(config: GatewayConfig, query: ModelSelectionQuery): string | undefined;
@@ -0,0 +1,36 @@
1
+ import { listCapabilities } from "./capabilities.js";
2
+ import { ConfigInvalidError } from "./errors.js";
3
+ const COST_RANK = { low: 0, medium: 1, high: 2 };
4
+ function matches(capability, query) {
5
+ if (capability.kind !== query.kind) {
6
+ return false;
7
+ }
8
+ if (query.toolCalling === true && !capability.toolCalling) {
9
+ return false;
10
+ }
11
+ if (query.structuredOutput === true && !capability.structuredOutput) {
12
+ return false;
13
+ }
14
+ if (query.minContextWindow !== undefined && capability.contextWindow < query.minContextWindow) {
15
+ return false;
16
+ }
17
+ return true;
18
+ }
19
+ export function assertConfiguredModel(config, modelId) {
20
+ if (!config.providers.some((provider) => provider.modelId === modelId)) {
21
+ throw new ConfigInvalidError(`model '${modelId}' is not configured as a provider`);
22
+ }
23
+ }
24
+ export function selectConfiguredModel(config, query) {
25
+ const configured = new Set(config.providers.map((provider) => provider.modelId));
26
+ let best;
27
+ for (const capability of listCapabilities()) {
28
+ if (!configured.has(capability.id) || !matches(capability, query)) {
29
+ continue;
30
+ }
31
+ if (best === undefined || COST_RANK[capability.costClass] < COST_RANK[best.costClass]) {
32
+ best = capability;
33
+ }
34
+ }
35
+ return best?.id;
36
+ }
@@ -0,0 +1,7 @@
1
+ import type { CostClass, NormalizedResponse } from "./types.js";
2
+ export interface UsageSeed {
3
+ readonly requestId: string;
4
+ readonly latencyMs: number;
5
+ readonly costClass: CostClass;
6
+ }
7
+ export declare function normalizeChatResponse(rawPayload: unknown, modelId: string, seed: UsageSeed, expectStructured?: boolean): NormalizedResponse;
@@ -0,0 +1,93 @@
1
+ // Provider payload → NormalizedResponse. The internal contract is strict and small
2
+ // so workflows fail closed when a provider response is unsafe or malformed.
3
+ import { MalformedToolCallError, ModelRefusalError } from "./errors.js";
4
+ const FINISH_REASONS = new Set([
5
+ "stop",
6
+ "tool_calls",
7
+ "length",
8
+ "content_filter",
9
+ "error",
10
+ "cancelled",
11
+ ]);
12
+ function isRecord(value) {
13
+ return typeof value === "object" && value !== null && !Array.isArray(value);
14
+ }
15
+ function asCount(value) {
16
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : 0;
17
+ }
18
+ function mapFinishReason(value) {
19
+ return typeof value === "string" && FINISH_REASONS.has(value)
20
+ ? value
21
+ : "stop";
22
+ }
23
+ function buildUsage(payload, seed) {
24
+ const usage = isRecord(payload.usage) ? payload.usage : {};
25
+ return {
26
+ requestId: seed.requestId,
27
+ promptTokens: asCount(usage.prompt_tokens),
28
+ completionTokens: asCount(usage.completion_tokens),
29
+ latencyMs: seed.latencyMs,
30
+ costClass: seed.costClass,
31
+ };
32
+ }
33
+ function parseToolCall(raw) {
34
+ if (!isRecord(raw) || !isRecord(raw.function)) {
35
+ throw new MalformedToolCallError("tool call is missing a function descriptor");
36
+ }
37
+ const fn = raw.function;
38
+ const name = typeof fn.name === "string" ? fn.name : "";
39
+ const id = typeof raw.id === "string" ? raw.id : "";
40
+ const argsText = typeof fn.arguments === "string" ? fn.arguments : "{}";
41
+ let parsed;
42
+ try {
43
+ parsed = JSON.parse(argsText);
44
+ }
45
+ catch {
46
+ throw new MalformedToolCallError(`tool call '${name}' has non-JSON arguments`);
47
+ }
48
+ if (!isRecord(parsed)) {
49
+ throw new MalformedToolCallError(`tool call '${name}' arguments are not an object`);
50
+ }
51
+ return { id, name, arguments: parsed };
52
+ }
53
+ function parseToolCalls(message) {
54
+ const raw = message.tool_calls;
55
+ return Array.isArray(raw) ? raw.map(parseToolCall) : [];
56
+ }
57
+ function parseStructuredOutput(content) {
58
+ try {
59
+ const parsed = JSON.parse(content);
60
+ return isRecord(parsed) ? parsed : null;
61
+ }
62
+ catch {
63
+ return null;
64
+ }
65
+ }
66
+ function assertNotRefusal(message, finishReason) {
67
+ if (finishReason === "content_filter") {
68
+ throw new ModelRefusalError("provider filtered the model response");
69
+ }
70
+ const refusal = message.refusal;
71
+ if (typeof refusal === "string" && refusal.length > 0) {
72
+ throw new ModelRefusalError("provider refused the model request");
73
+ }
74
+ }
75
+ function firstChoice(payload) {
76
+ const choices = payload.choices;
77
+ if (!Array.isArray(choices) || choices.length === 0) {
78
+ return undefined;
79
+ }
80
+ return isRecord(choices[0]) ? choices[0] : undefined;
81
+ }
82
+ export function normalizeChatResponse(rawPayload, modelId, seed, expectStructured = false) {
83
+ const payload = isRecord(rawPayload) ? rawPayload : {};
84
+ const usage = buildUsage(payload, seed);
85
+ const choice = firstChoice(payload);
86
+ const message = choice !== undefined && isRecord(choice.message) ? choice.message : {};
87
+ const finishReason = mapFinishReason(choice?.finish_reason);
88
+ assertNotRefusal(message, finishReason);
89
+ const toolCalls = parseToolCalls(message);
90
+ const content = typeof message.content === "string" ? message.content : "";
91
+ const structuredOutput = expectStructured && content.length > 0 ? parseStructuredOutput(content) : null;
92
+ return { modelId, content, finishReason, toolCalls, structuredOutput, usage };
93
+ }
@@ -0,0 +1,20 @@
1
+ import type { CostClass, GatewayRequest, ModelProviderConfig, NormalizedResponse, ProviderAdapter } from "./types.js";
2
+ export interface AdapterDeps {
3
+ readonly fetchImpl?: typeof fetch | undefined;
4
+ readonly requestId: string;
5
+ readonly costClass: CostClass;
6
+ readonly now?: (() => number) | undefined;
7
+ }
8
+ export declare class OpenAiAdapter implements ProviderAdapter {
9
+ private readonly deps;
10
+ private readonly fetchImpl;
11
+ private readonly now;
12
+ private readonly useBundledCaFallback;
13
+ constructor(deps: AdapterDeps);
14
+ call: (request: GatewayRequest, config: ModelProviderConfig) => Promise<NormalizedResponse>;
15
+ private dispatch;
16
+ private dispatchWithBundledCa;
17
+ private mapDispatchError;
18
+ private readBody;
19
+ private readErrorBody;
20
+ }