akm-cli 0.10.261012-beta → 0.10.261014-beta

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 (518) hide show
  1. package/CHANGELOG.md +710 -3
  2. package/README.md +15 -0
  3. package/SECURITY.md +11 -10
  4. package/STABILITY.md +47 -51
  5. package/dist/assets/hints/cli-hints-full.md +21 -19
  6. package/dist/assets/hints/cli-hints-short.md +3 -4
  7. package/dist/assets/opencode/akm-plugin.js +177 -0
  8. package/dist/assets/stash-skeleton/README.md +1 -1
  9. package/dist/assets/tasks/core/improve.yml +1 -1
  10. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
  11. package/dist/assets/ui/config.js +27 -10
  12. package/dist/assets/workflows/workflow-template.md +2 -2
  13. package/dist/cli/clack.js +3 -1
  14. package/dist/cli/selection.js +33 -0
  15. package/dist/cli/shared.js +14 -1
  16. package/dist/cli/unknown-flags.js +6 -37
  17. package/dist/cli.js +69 -48
  18. package/dist/commands/agent/agent-dispatch.js +17 -25
  19. package/dist/commands/agent/contribute-cli.js +9 -8
  20. package/dist/commands/command/command-cli.js +4 -8
  21. package/dist/commands/command/command-execution.js +25 -39
  22. package/dist/commands/command/execution-source-loader.js +10 -14
  23. package/dist/commands/completions.js +1 -1
  24. package/dist/commands/config-cli.js +14 -5
  25. package/dist/commands/env/child-env.js +12 -14
  26. package/dist/commands/env/env-binding.js +47 -58
  27. package/dist/commands/env/env-cli.js +22 -24
  28. package/dist/commands/env/env.js +10 -58
  29. package/dist/commands/env/secret-cli.js +11 -29
  30. package/dist/commands/env/secret.js +3 -10
  31. package/dist/commands/health/checks.js +10 -849
  32. package/dist/commands/health/connections-and-harnesses-check.js +109 -0
  33. package/dist/commands/health/egress.js +3 -3
  34. package/dist/commands/health/html-report.js +9 -10
  35. package/dist/commands/health/plugin-staleness.js +18 -11
  36. package/dist/commands/health/report-view-model.js +16 -12
  37. package/dist/commands/health/scheduler-binary.js +1 -1
  38. package/dist/commands/health/semantic-search-check.js +85 -0
  39. package/dist/commands/health/type-directory-check.js +0 -3
  40. package/dist/commands/health.js +30 -42
  41. package/dist/commands/improve/consolidate/pair-pass.js +10 -25
  42. package/dist/commands/improve/consolidate.js +10 -15
  43. package/dist/commands/improve/distill.js +5 -17
  44. package/dist/commands/improve/eligibility.js +1 -3
  45. package/dist/commands/improve/execution.js +37 -40
  46. package/dist/commands/improve/extract-cli.js +6 -11
  47. package/dist/commands/improve/extract-prompt.js +2 -2
  48. package/dist/commands/improve/extract.js +67 -97
  49. package/dist/commands/improve/improve-cli.js +22 -128
  50. package/dist/commands/improve/improve-report.js +1 -1
  51. package/dist/commands/improve/improve-strategies.js +25 -108
  52. package/dist/commands/improve/improve.js +10 -14
  53. package/dist/commands/improve/loop-stages.js +3 -0
  54. package/dist/commands/improve/memory/memory-improve.js +1 -1
  55. package/dist/commands/improve/preparation.js +8 -13
  56. package/dist/commands/improve/reflect.js +203 -332
  57. package/dist/commands/improve/retrieval-scope.js +1 -1
  58. package/dist/commands/improve/session-asset.js +3 -2
  59. package/dist/commands/improve/stage.js +87 -115
  60. package/dist/commands/lint/base-linter.js +3 -3
  61. package/dist/commands/lint/env-key-rules.js +7 -6
  62. package/dist/commands/lint/index.js +3 -3
  63. package/dist/commands/models-cli.js +103 -63
  64. package/dist/commands/proposal/drain.js +26 -39
  65. package/dist/commands/proposal/proposal-cli.js +14 -18
  66. package/dist/commands/proposal/propose-cli.js +4 -2
  67. package/dist/commands/proposal/propose.js +37 -64
  68. package/dist/commands/proposal/repository.js +17 -17
  69. package/dist/commands/proposal/validators/proposal-validators.js +3 -6
  70. package/dist/commands/read/curate.js +10 -6
  71. package/dist/commands/read/registry-search.js +2 -48
  72. package/dist/commands/read/search-cli.js +1 -8
  73. package/dist/commands/read/search.js +5 -6
  74. package/dist/commands/read/show.js +6 -29
  75. package/dist/commands/remember.js +25 -40
  76. package/dist/commands/sources/add-cli.js +8 -63
  77. package/dist/commands/sources/bundle-cli.js +8 -9
  78. package/dist/commands/sources/bundle-config-ops.js +2 -2
  79. package/dist/commands/sources/info.js +12 -1
  80. package/dist/commands/sources/init.js +1 -1
  81. package/dist/commands/sources/installed-stashes.js +119 -63
  82. package/dist/commands/sources/migration-help.js +1 -1
  83. package/dist/commands/sources/plugin-upgrade.js +8 -15
  84. package/dist/commands/sources/schema-repair.js +4 -10
  85. package/dist/commands/sources/source-add.js +2 -2
  86. package/dist/commands/sources/source-clone.js +31 -7
  87. package/dist/commands/sources/source-manage.js +4 -4
  88. package/dist/commands/targets.js +175 -0
  89. package/dist/commands/tasks/explain.js +104 -69
  90. package/dist/commands/tasks/tasks-cli.js +9 -11
  91. package/dist/commands/tasks/tasks.js +75 -97
  92. package/dist/commands/ui/api.js +11 -3
  93. package/dist/commands/ui/redact.js +5 -31
  94. package/dist/commands/ui/workspace-actions.js +1 -1
  95. package/dist/commands/workflow/plan.js +48 -9
  96. package/dist/commands/workflow-cli.js +40 -45
  97. package/dist/core/adapter/adapters/agent-skills-adapter.js +10 -11
  98. package/dist/core/adapter/adapters/akm-adapter.js +36 -41
  99. package/dist/core/adapter/adapters/akm-lint.js +10 -12
  100. package/dist/core/adapter/adapters/akm-metadata.js +2 -2
  101. package/dist/core/adapter/adapters/akm-task-adapter.js +8 -9
  102. package/dist/core/adapter/adapters/akm-workflow-adapter.js +5 -5
  103. package/dist/core/adapter/adapters/claude-adapter.js +1 -1
  104. package/dist/core/adapter/adapters/dotenv-adapter.js +7 -6
  105. package/dist/core/adapter/adapters/generic-files-adapter.js +5 -5
  106. package/dist/core/adapter/adapters/index.js +3 -4
  107. package/dist/core/adapter/adapters/llm-wiki-adapter.js +12 -14
  108. package/dist/core/adapter/adapters/okf-adapter.js +8 -10
  109. package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
  110. package/dist/core/adapter/adapters/shared.js +3 -3
  111. package/dist/core/adapter/adapters/tool-dir-shared.js +7 -25
  112. package/dist/core/adapter/adapters/website-snapshot-adapter.js +3 -3
  113. package/dist/core/adapter/detect-adapter.js +1 -1
  114. package/dist/core/adapter/execution-source.js +13 -35
  115. package/dist/core/adapter/registry.js +1 -1
  116. package/dist/core/adapter/validate-context.js +2 -4
  117. package/dist/core/asset/asset-placement.js +1 -1
  118. package/dist/core/asset/asset-ref.js +3 -3
  119. package/dist/core/asset/resolve-ref.js +5 -0
  120. package/dist/core/bundle-rename.js +12 -4
  121. package/dist/core/closest-match.js +37 -0
  122. package/dist/core/common.js +37 -57
  123. package/dist/core/config/config-io.js +26 -18
  124. package/dist/core/config/config-schema.js +19 -106
  125. package/dist/core/config/config-sources.js +3 -3
  126. package/dist/core/config/config-types.js +4 -4
  127. package/dist/core/config/config-walker.js +50 -77
  128. package/dist/core/config/config.js +438 -109
  129. package/dist/core/config/convert-engine-references.js +114 -0
  130. package/dist/core/config/convert-engines-shared.js +40 -0
  131. package/dist/core/config/convert-engines.js +300 -0
  132. package/dist/core/config/convert-models-overlay.js +137 -0
  133. package/dist/core/config/credentials.js +304 -0
  134. package/dist/core/config/engine-semantics.js +3 -3
  135. package/dist/core/config/migrate-keys.js +222 -0
  136. package/dist/core/config/model-aliases.js +37 -0
  137. package/dist/core/config/models-file.js +34 -0
  138. package/dist/core/config/retired-engines.js +53 -0
  139. package/dist/core/config/schema/connections.js +41 -0
  140. package/dist/core/config/schema/embedding.js +2 -2
  141. package/dist/core/config/schema/harnesses.js +41 -0
  142. package/dist/core/config/schema/improve-processes.js +9 -28
  143. package/dist/core/config/schema/improve.js +36 -1
  144. package/dist/core/config/schema/index-config.js +18 -20
  145. package/dist/core/config/schema/primitives.js +42 -17
  146. package/dist/core/config/schema/search.js +6 -11
  147. package/dist/core/config/schema/sources-bundles.js +9 -9
  148. package/dist/core/config/schema/workflow.js +2 -6
  149. package/dist/core/config/unusable-entries.js +66 -0
  150. package/dist/core/content-safety.js +3 -6
  151. package/dist/core/endpoint-url.js +47 -0
  152. package/dist/core/env-secret-ref.js +84 -73
  153. package/dist/core/errors.js +10 -16
  154. package/dist/core/extra-params.js +3 -3
  155. package/dist/core/improve-result.js +8 -9
  156. package/dist/core/json-schema.js +1 -1
  157. package/dist/core/lesson-lint.js +1 -1
  158. package/dist/core/llm-inference.js +80 -0
  159. package/dist/core/parse.js +2 -2
  160. package/dist/core/paths.js +33 -10
  161. package/dist/core/recognition-util.js +8 -10
  162. package/dist/core/redaction.js +94 -55
  163. package/dist/core/ref-token.js +82 -0
  164. package/dist/core/secret-value.js +14 -0
  165. package/dist/core/state/migrations.js +17 -22
  166. package/dist/core/structured.js +2 -68
  167. package/dist/core/subprocess.js +63 -22
  168. package/dist/core/type-presentation.js +10 -14
  169. package/dist/core/write-source.js +20 -4
  170. package/dist/execution/input-contract.js +3 -6
  171. package/dist/execution/notices.js +49 -0
  172. package/dist/execution/resolved-request.js +24 -40
  173. package/dist/execution/source.js +21 -45
  174. package/dist/execution/target-ref.js +2 -2
  175. package/dist/indexer/bundle-identity-guard.js +6 -5
  176. package/dist/indexer/ensure-index.js +1 -1
  177. package/dist/indexer/index-writer-lock.js +1 -1
  178. package/dist/indexer/indexer.js +46 -42
  179. package/dist/indexer/installations.js +12 -22
  180. package/dist/indexer/lookup/adapter-concept-owner.js +40 -14
  181. package/dist/indexer/materialize-embeddings.js +20 -16
  182. package/dist/indexer/passes/memory-inference.js +21 -50
  183. package/dist/indexer/passes/metadata.js +5 -5
  184. package/dist/indexer/scan/doc-to-entry.js +1 -1
  185. package/dist/indexer/scan/drain-dir.js +9 -11
  186. package/dist/indexer/search/db-search.js +9 -7
  187. package/dist/indexer/search/search-source.js +42 -22
  188. package/dist/indexer/usage/usage-events.js +2 -3
  189. package/dist/indexer/walk/index-context.js +2 -1
  190. package/dist/indexer/walk/matchers.js +3 -11
  191. package/dist/indexer/walk/path-resolver.js +13 -68
  192. package/dist/indexer/walk/walker.js +32 -26
  193. package/dist/integrations/agent/akm-read-tools.js +81 -0
  194. package/dist/integrations/agent/config.js +1 -1
  195. package/dist/integrations/agent/detect.js +32 -36
  196. package/dist/integrations/agent/execution.js +130 -428
  197. package/dist/integrations/agent/index.js +1 -1
  198. package/dist/integrations/agent/profiles.js +24 -28
  199. package/dist/integrations/agent/prompts.js +17 -30
  200. package/dist/integrations/agent/request-lowering.js +67 -101
  201. package/dist/integrations/agent/resolution.js +332 -0
  202. package/dist/integrations/agent/runner-dispatch.js +156 -181
  203. package/dist/integrations/agent/runner.js +20 -70
  204. package/dist/integrations/agent/runtime-port.js +4 -0
  205. package/dist/integrations/agent/runtime.js +10 -0
  206. package/dist/integrations/agent/spawn.js +65 -190
  207. package/dist/integrations/harnesses/aider/index.js +19 -39
  208. package/dist/integrations/harnesses/amazonq/index.js +17 -32
  209. package/dist/integrations/harnesses/claude/index.js +59 -28
  210. package/dist/integrations/harnesses/claude/session-log.js +7 -5
  211. package/dist/integrations/harnesses/codex/index.js +19 -31
  212. package/dist/integrations/harnesses/copilot/index.js +17 -35
  213. package/dist/integrations/harnesses/gemini/index.js +18 -34
  214. package/dist/integrations/harnesses/harness.js +36 -0
  215. package/dist/integrations/harnesses/index.js +20 -51
  216. package/dist/integrations/harnesses/opencode/agent-builder.js +132 -100
  217. package/dist/integrations/harnesses/opencode/index.js +11 -33
  218. package/dist/integrations/harnesses/opencode/roots.js +50 -0
  219. package/dist/integrations/harnesses/opencode/runtime/binary.js +206 -0
  220. package/dist/integrations/harnesses/opencode/runtime/command.js +152 -0
  221. package/dist/integrations/harnesses/opencode/runtime/index.js +177 -0
  222. package/dist/integrations/harnesses/opencode/runtime/tar.js +107 -0
  223. package/dist/integrations/harnesses/opencode/session-log-v1.js +15 -7
  224. package/dist/integrations/harnesses/opencode/session-log-v2.js +72 -48
  225. package/dist/integrations/harnesses/opencode/session-log.js +58 -137
  226. package/dist/integrations/harnesses/opencode/version.js +34 -53
  227. package/dist/integrations/harnesses/openhands/index.js +13 -37
  228. package/dist/integrations/harnesses/pi/index.js +21 -32
  229. package/dist/integrations/lockfile.js +1 -1
  230. package/dist/integrations/session-logs/index.js +11 -31
  231. package/dist/llm/client.js +93 -111
  232. package/dist/llm/embedder.js +19 -34
  233. package/dist/llm/embedders/connection.js +31 -0
  234. package/dist/llm/embedders/local-model-files.js +56 -0
  235. package/dist/llm/embedders/local.js +146 -115
  236. package/dist/llm/embedders/remote.js +26 -23
  237. package/dist/llm/embedders/types.js +1 -1
  238. package/dist/llm/index-passes.js +33 -39
  239. package/dist/llm/memory-infer.js +67 -77
  240. package/dist/llm/model-list.js +35 -0
  241. package/dist/llm/rerank-client.js +8 -14
  242. package/dist/llm/structured-call.js +45 -99
  243. package/dist/llm/structured.js +60 -0
  244. package/dist/output/renderers.js +2 -8
  245. package/dist/output/shapes/helpers.js +18 -44
  246. package/dist/output/shapes/passthrough.js +1 -0
  247. package/dist/output/shapes.js +1 -7
  248. package/dist/output/text/command-format.js +41 -39
  249. package/dist/output/text/health-format.js +8 -2
  250. package/dist/output/text/helpers.js +1 -1
  251. package/dist/output/text/migrate.js +12 -0
  252. package/dist/output/text/models.js +3 -2
  253. package/dist/output/text/registry-commands.js +1 -2
  254. package/dist/output/text/show-directives.js +16 -28
  255. package/dist/output/text/show-format.js +0 -2
  256. package/dist/output/text/targets-table.js +70 -0
  257. package/dist/output/text/workflow-format.js +44 -15
  258. package/dist/output/text.js +1 -1
  259. package/dist/registry/providers/skills-sh.js +1 -28
  260. package/dist/registry/providers/static-index.js +1 -71
  261. package/dist/runtime.js +6 -2
  262. package/dist/scripts/akm-migrate-node.js +47095 -44905
  263. package/dist/scripts/akm-migrate.js +46946 -44755
  264. package/dist/setup/detect.js +28 -273
  265. package/dist/setup/endpoint.js +36 -0
  266. package/dist/setup/semantic-assets.js +13 -19
  267. package/dist/setup/setup-flags.js +77 -0
  268. package/dist/setup/setup-plan.js +144 -0
  269. package/dist/setup/setup.js +134 -358
  270. package/dist/setup/steps/connection-shared.js +49 -101
  271. package/dist/setup/steps/connection.js +121 -524
  272. package/dist/setup/steps/embeddings.js +151 -0
  273. package/dist/setup/steps/harnesses.js +118 -0
  274. package/dist/setup/steps/platforms.js +2 -81
  275. package/dist/setup/steps/tasks.js +1 -2
  276. package/dist/setup/steps.js +10 -0
  277. package/dist/setup/summary.js +67 -0
  278. package/dist/sources/freshness.js +16 -21
  279. package/dist/sources/providers/git-provider.js +2 -9
  280. package/dist/sources/providers/provider-utils.js +13 -5
  281. package/dist/sources/resolve.js +12 -16
  282. package/dist/sources/snapshot-fetchers/robots.js +11 -12
  283. package/dist/sources/snapshot-fetchers/secret-seam.js +2 -4
  284. package/dist/sources/snapshot-fetchers/website-ingest.js +8 -15
  285. package/dist/sources/snapshot-fetchers/x.js +1 -1
  286. package/dist/standalone/onnxruntime-library.js +52 -0
  287. package/dist/storage/repositories/improve-ledger-repository.js +1 -1
  288. package/dist/storage/repositories/improve-runs-repository.js +0 -13
  289. package/dist/storage/repositories/index-entries-repository.js +2 -2
  290. package/dist/storage/repositories/proposals-repository.js +2 -2
  291. package/dist/storage/repositories/task-history-repository.js +2 -2
  292. package/dist/storage/repositories/workflow-runs-repository.js +44 -129
  293. package/dist/storage/sqlite-read-snapshot.js +33 -29
  294. package/dist/tasks/embedded.js +1 -1
  295. package/dist/tasks/log-redaction.js +7 -119
  296. package/dist/tasks/prepare/prepare-support.js +8 -7
  297. package/dist/tasks/prepare/prepare.js +8 -9
  298. package/dist/tasks/prepare/script-capture.js +9 -25
  299. package/dist/tasks/run/attempt-lifecycle.js +17 -35
  300. package/dist/tasks/run/load-task.js +54 -27
  301. package/dist/tasks/run/run-command-task.js +15 -10
  302. package/dist/tasks/run/run-native-task.js +8 -21
  303. package/dist/tasks/run/run-task.js +5 -8
  304. package/dist/tasks/run/run-workflow-task.js +14 -21
  305. package/dist/tasks/run/task-history.js +9 -17
  306. package/dist/tasks/run/task-log.js +1 -5
  307. package/dist/tasks/scheduler-invocation.js +13 -18
  308. package/dist/tasks/scheduler-sync.js +0 -1
  309. package/dist/tasks/source/bounded-document.js +31 -117
  310. package/dist/tasks/source/parse-task-source.js +0 -1
  311. package/dist/tasks/source/project-v4.js +5 -3
  312. package/dist/tasks/source/task-input-diagnostics.js +3 -4
  313. package/dist/tasks/source/task-source-v4.js +48 -72
  314. package/dist/tasks/source-v3.js +2 -5
  315. package/dist/tasks/task-run-reserved-flags.js +1 -2
  316. package/dist/workflows/authoring/authoring.js +2 -7
  317. package/dist/workflows/compile.js +1 -15
  318. package/dist/workflows/concurrency-policy.js +4 -4
  319. package/dist/workflows/exec/child-workflow.js +1 -4
  320. package/dist/workflows/exec/dispatch-redaction.js +35 -86
  321. package/dist/workflows/exec/environment.js +13 -77
  322. package/dist/workflows/exec/exec-unit.js +14 -55
  323. package/dist/workflows/exec/frozen-judge.js +26 -28
  324. package/dist/workflows/exec/native-executor.js +126 -71
  325. package/dist/workflows/exec/run-workflow.js +38 -42
  326. package/dist/workflows/exec/step-work.js +13 -17
  327. package/dist/workflows/exec/unit-dispatch.js +7 -21
  328. package/dist/workflows/freeze/environment.js +14 -119
  329. package/dist/workflows/freeze/freeze.js +14 -33
  330. package/dist/workflows/freeze/step-values.js +6 -13
  331. package/dist/workflows/freeze/targets/child-workflow.js +3 -5
  332. package/dist/workflows/freeze/targets/command.js +9 -15
  333. package/dist/workflows/freeze/targets/shell.js +0 -3
  334. package/dist/workflows/freeze/task-bindings.js +0 -1
  335. package/dist/workflows/parser.js +50 -59
  336. package/dist/workflows/plan.js +8 -2
  337. package/dist/workflows/renderer.js +83 -9
  338. package/dist/workflows/resource-limits.js +2 -2
  339. package/dist/workflows/runtime/run-plan.js +38 -23
  340. package/dist/workflows/runtime/runs.js +55 -93
  341. package/dist/workflows/runtime/workflow-asset-loader.js +55 -86
  342. package/dist/workflows/source-files.js +7 -19
  343. package/docs/README.md +10 -16
  344. package/docs/architecture/README.md +2 -37
  345. package/docs/architecture/adapters.md +2 -2
  346. package/docs/architecture/akm-core-principles.md +256 -118
  347. package/docs/architecture/architecture.md +283 -99
  348. package/docs/architecture/improvement.md +8 -2
  349. package/docs/architecture/internals/classification.md +1 -3
  350. package/docs/architecture/internals/fresh-host-rebuild-runbook.md +7 -6
  351. package/docs/architecture/internals/health-advisories.md +35 -74
  352. package/docs/architecture/internals/improve-workflow.md +27 -26
  353. package/docs/architecture/internals/indexing.md +3 -3
  354. package/docs/architecture/internals/storage-locations.md +48 -15
  355. package/docs/architecture/persisted-data-compat.md +10 -6
  356. package/docs/architecture/specs/okf-support.md +9 -11
  357. package/docs/architecture/specs/ref.md +7 -9
  358. package/docs/architecture/testing/testing-workflow.md +172 -52
  359. package/docs/architecture/workflow-engine.md +51 -34
  360. package/docs/guides/README.md +0 -1
  361. package/docs/guides/author-bundles.md +15 -20
  362. package/docs/guides/author-workflows.md +93 -71
  363. package/docs/guides/bundles.md +20 -16
  364. package/docs/guides/discover-and-load.md +1 -1
  365. package/docs/guides/getting-started.md +49 -3
  366. package/docs/guides/improve-the-library.md +10 -4
  367. package/docs/guides/recipes/headless-install.md +11 -16
  368. package/docs/guides/run-workflows.md +29 -20
  369. package/docs/guides/scheduling.md +2 -2
  370. package/docs/guides/use-with-any-agent.md +20 -22
  371. package/docs/integration/bundling-akm.md +19 -9
  372. package/docs/maintainers/README.md +2 -6
  373. package/docs/maintainers/release-checklist.md +73 -126
  374. package/docs/migration/README.md +10 -3
  375. package/docs/migration/release-notes/0.10.0.md +81 -16
  376. package/docs/migration/release-notes/0.6.0.md +1 -1
  377. package/docs/migration/release-notes/0.7.0.md +1 -1
  378. package/docs/migration/release-notes/0.9.0.md +1 -1
  379. package/docs/migration/release-notes/README.md +1 -1
  380. package/docs/migration/v0.9-to-v0.10.md +300 -60
  381. package/docs/migration/v0.9.1-to-v0.9.2.md +6 -5
  382. package/docs/posts/config-v2-lessons-16.md +1 -1
  383. package/docs/posts/llm-mode-reflect-13.md +1 -1
  384. package/docs/posts/release-0.6.0.md +11 -11
  385. package/docs/posts/release-0.8.0.md +4 -4
  386. package/docs/posts/workflows-vaults-09.md +1 -1
  387. package/docs/reference/README.md +1 -1
  388. package/docs/reference/asset-types.md +2 -2
  389. package/docs/reference/cli.md +477 -388
  390. package/docs/reference/configuration.md +569 -550
  391. package/docs/reference/data-and-telemetry.md +9 -6
  392. package/docs/reference/env-and-secrets.md +72 -15
  393. package/docs/reference/refs.md +3 -20
  394. package/docs/reference/registry.md +12 -38
  395. package/docs/reference/supported-formats.md +1 -1
  396. package/docs/reference/tasks.md +22 -11
  397. package/docs/reference/ui-api.md +14 -9
  398. package/docs/reference/workflow-schema.md +199 -154
  399. package/docs/reference/workflows.md +4 -6
  400. package/package.json +9 -11
  401. package/schemas/akm-config.json +1696 -2922
  402. package/schemas/akm-task.json +4 -4
  403. package/schemas/akm-workflow.json +36 -9
  404. package/ROADMAP.md +0 -112
  405. package/dist/assets/models.json +0 -35
  406. package/dist/commands/health/engine-usage.js +0 -45
  407. package/dist/commands/sources/dangerous-env-audit.js +0 -134
  408. package/dist/core/activation-policy.js +0 -67
  409. package/dist/core/config/schema/engines.js +0 -160
  410. package/dist/core/config/schema/execution.js +0 -23
  411. package/dist/core/spawn-env.js +0 -268
  412. package/dist/execution/directory-identity.js +0 -78
  413. package/dist/integrations/agent/builder-shared.js +0 -33
  414. package/dist/integrations/agent/builders.js +0 -43
  415. package/dist/integrations/agent/engine-fallback.js +0 -59
  416. package/dist/integrations/agent/engine-resolution.js +0 -333
  417. package/dist/integrations/agent/model-map.js +0 -475
  418. package/dist/integrations/harnesses/aider/agent-builder.js +0 -107
  419. package/dist/integrations/harnesses/aider/result-extractor.js +0 -53
  420. package/dist/integrations/harnesses/amazonq/agent-builder.js +0 -138
  421. package/dist/integrations/harnesses/amazonq/result-extractor.js +0 -48
  422. package/dist/integrations/harnesses/claude/agent-builder.js +0 -106
  423. package/dist/integrations/harnesses/claude/config-import.js +0 -67
  424. package/dist/integrations/harnesses/claude/result-extractor.js +0 -67
  425. package/dist/integrations/harnesses/codex/agent-builder.js +0 -150
  426. package/dist/integrations/harnesses/codex/result-extractor.js +0 -110
  427. package/dist/integrations/harnesses/copilot/agent-builder.js +0 -117
  428. package/dist/integrations/harnesses/copilot/result-extractor.js +0 -178
  429. package/dist/integrations/harnesses/gemini/agent-builder.js +0 -114
  430. package/dist/integrations/harnesses/gemini/result-extractor.js +0 -149
  431. package/dist/integrations/harnesses/opencode/config-import.js +0 -149
  432. package/dist/integrations/harnesses/opencode/model-config.js +0 -33
  433. package/dist/integrations/harnesses/opencode/model-work-agent.js +0 -115
  434. package/dist/integrations/harnesses/opencode/session-log-types.js +0 -12
  435. package/dist/integrations/harnesses/opencode-sdk/index.js +0 -44
  436. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -1052
  437. package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +0 -199
  438. package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +0 -254
  439. package/dist/integrations/harnesses/opencode-sdk/wire.js +0 -66
  440. package/dist/integrations/harnesses/openhands/agent-builder.js +0 -120
  441. package/dist/integrations/harnesses/openhands/result-extractor.js +0 -135
  442. package/dist/integrations/harnesses/pi/agent-builder.js +0 -89
  443. package/dist/integrations/harnesses/pi/result-extractor.js +0 -168
  444. package/dist/integrations/harnesses/shared.js +0 -18
  445. package/dist/integrations/harnesses/types.js +0 -55
  446. package/dist/llm/feature-gate.js +0 -115
  447. package/dist/output/shapes/models-list.js +0 -16
  448. package/dist/output/shapes/registry-search.js +0 -10
  449. package/dist/setup/detected-engines.js +0 -136
  450. package/dist/setup/engine-config.js +0 -97
  451. package/dist/setup/harness-config-import.js +0 -47
  452. package/dist/setup/providers.js +0 -14
  453. package/dist/setup/steps/semantic.js +0 -39
  454. package/dist/workflows/authoring/scope-key.js +0 -79
  455. package/dist/workflows/exec/lowering-notices.js +0 -23
  456. package/dist/workflows/source-semantics.js +0 -110
  457. package/docs/architecture/0.10-process-rules.md +0 -832
  458. package/docs/architecture/akm-architecture-decision-history.md +0 -2055
  459. package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +0 -550
  460. package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +0 -72
  461. package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +0 -142
  462. package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +0 -189
  463. package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +0 -97
  464. package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +0 -108
  465. package/docs/architecture/decisions/0006-task-source-version-routing.md +0 -124
  466. package/docs/architecture/decisions/0007-workflow-composition-bounds.md +0 -83
  467. package/docs/architecture/decisions/0008-task-binding-normalization.md +0 -88
  468. package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +0 -80
  469. package/docs/architecture/decisions/0010-driver-protocol-cut.md +0 -36
  470. package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +0 -125
  471. package/docs/architecture/decisions/README.md +0 -62
  472. package/docs/architecture/internals/functional-contract-patterns.md +0 -340
  473. package/docs/architecture/internals/registry-network-boundary.md +0 -57
  474. package/docs/architecture/internals/search.md +0 -248
  475. package/docs/architecture/reviews/env-secret-access.md +0 -319
  476. package/docs/architecture/runtime-boundary-design.md +0 -153
  477. package/docs/architecture/specs/0.9.0-close-out-plan.md +0 -361
  478. package/docs/architecture/specs/0.9.0-decisions.md +0 -532
  479. package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +0 -745
  480. package/docs/architecture/specs/0.9.0-open-items-register.md +0 -135
  481. package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +0 -740
  482. package/docs/architecture/specs/0.9.0-release-surface-review.md +0 -636
  483. package/docs/architecture/specs/agent-command-engine-model-design.md +0 -513
  484. package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +0 -501
  485. package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +0 -291
  486. package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +0 -2059
  487. package/docs/architecture/specs/di-seams-plan.md +0 -539
  488. package/docs/architecture/specs/driver-protocol-keep-or-cut.md +0 -275
  489. package/docs/architecture/specs/fact-asset-type.md +0 -142
  490. package/docs/architecture/specs/improve-collapse-churn-detector-design.md +0 -634
  491. package/docs/architecture/specs/reviews/task-workflow-unification/README.md +0 -72
  492. package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +0 -152
  493. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +0 -352
  494. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +0 -300
  495. package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +0 -402
  496. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +0 -758
  497. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +0 -645
  498. package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +0 -602
  499. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +0 -27
  500. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +0 -27
  501. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +0 -74
  502. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +0 -15
  503. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +0 -132
  504. package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +0 -147
  505. package/docs/architecture/specs/stash-conventions-code-spec.md +0 -275
  506. package/docs/architecture/specs/stash-organization-conventions.md +0 -377
  507. package/docs/architecture/specs/task-workflow-format-unification.md +0 -721
  508. package/docs/architecture/specs/workflow-engine-buy-vs-build.md +0 -231
  509. package/docs/architecture/specs/workflow-format-unification.md +0 -432
  510. package/docs/architecture/testing/manual-testing-checklist.md +0 -3411
  511. package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +0 -924
  512. package/docs/architecture/testing/task-workflow-manual-tests.md +0 -1720
  513. package/docs/guides/claude-code-vs-akm-workflows.md +0 -29
  514. package/docs/guides/knowledge-management.md +0 -18
  515. package/docs/maintainers/curate-workmap.md +0 -335
  516. package/docs/migration/v0.5-to-v0.6.md +0 -759
  517. package/docs/migration/v0.7-to-v0.8.md +0 -1378
  518. package/docs/plans/0.9.2-agent-command-workflow-plan.md +0 -423
@@ -8,13 +8,11 @@
8
8
  * probing, and availability checks) separate from higher-level workflows.
9
9
  */
10
10
  import { fetchWithTimeout, readBodyWithByteCap } from "../core/common.js";
11
- import { resolveSecret } from "../core/config/config.js";
12
- import { isApiKeyReference } from "../core/config/schema/primitives.js";
11
+ import { openAiBaseUrl, openAiOperationUrl } from "../core/endpoint-url.js";
13
12
  import { formatExtraParamsIssue, validateExtraParams } from "../core/extra-params.js";
14
- import { redactErrorBody, redactSensitiveText } from "../core/redaction.js";
13
+ import { effectiveRequestFields } from "../core/llm-inference.js";
14
+ import { redactErrorBody, redactSensitiveText, redactUrlCredentials } from "../core/redaction.js";
15
15
  import { warn, warnVerbose } from "../core/warn.js";
16
- import { DEFAULT_LLM_TIMEOUT_MS } from "../integrations/agent/config.js";
17
- import { resolveSecretFromStore } from "../sources/snapshot-fetchers/secret-seam.js";
18
16
  import { emitLlmUsage, extractUsageTokens, } from "./usage-telemetry.js";
19
17
  /** Maximum length of an upstream response excerpt included in thrown errors. */
20
18
  const ERROR_BODY_MAX_LEN = 200;
@@ -183,25 +181,37 @@ export async function chatCompletion(config, messages, options) {
183
181
  return chatCompletionOverride(config, messages, options);
184
182
  return chatCompletionReal(config, messages, options);
185
183
  }
184
+ /**
185
+ * One call's time budget: the first attempt is given all of it and a retry
186
+ * only what is left, so a call and its retries never outlast its timeout.
187
+ */
188
+ function timeBudget(totalMs) {
189
+ if (totalMs === null)
190
+ return () => null;
191
+ let deadlineAt;
192
+ return () => {
193
+ const now = Date.now();
194
+ deadlineAt ??= now + totalMs;
195
+ return Math.max(0, deadlineAt - now);
196
+ };
197
+ }
186
198
  async function chatCompletionReal(config, messages, options) {
187
199
  const effectiveTimeoutMs = options && Object.hasOwn(options, "timeoutMs")
188
200
  ? (options.timeoutMs ?? null)
189
201
  : Object.hasOwn(config, "timeoutMs")
190
202
  ? (config.timeoutMs ?? null)
191
- : DEFAULT_LLM_TIMEOUT_MS;
203
+ : null;
192
204
  const started = Date.now();
205
+ const budget = timeBudget(effectiveTimeoutMs);
193
206
  try {
194
- return await chatCompletionAttempt(config, messages, options, effectiveTimeoutMs);
207
+ return await chatCompletionAttempt(config, messages, options, budget);
195
208
  }
196
209
  catch (err) {
197
210
  if (!(err instanceof LlmCallError) || !isRetryable(err))
198
211
  throw err;
199
212
  // Timeout-budget guard: if the first attempt already burned most of the
200
213
  // budget, a second attempt cannot complete — skip the retry.
201
- const elapsed = Date.now() - started;
202
- const remaining = effectiveTimeoutMs === null ? null : effectiveTimeoutMs - elapsed;
203
- if (effectiveTimeoutMs !== null &&
204
- (elapsed >= effectiveTimeoutMs * RETRY_BUDGET_FRACTION || (remaining !== null && remaining <= 0))) {
214
+ if (effectiveTimeoutMs !== null && Date.now() - started >= effectiveTimeoutMs * RETRY_BUDGET_FRACTION) {
205
215
  throw err;
206
216
  }
207
217
  // Signal the caller so it can bump `retryAttempts` (NOT `failureCount`).
@@ -211,8 +221,8 @@ async function chatCompletionReal(config, messages, options) {
211
221
  warnVerbose(`[akm] LLM transient failure (${err.code}); retrying once: ${err.message}`);
212
222
  const wait = retryBackoffMs();
213
223
  await waitForRetry(wait, options?.sleep ?? sleep, options?.signal);
214
- // The retry must not exceed the original budget.
215
- return await chatCompletionAttempt(config, messages, options, remaining);
224
+ // The retry spends what is left of the original budget.
225
+ return await chatCompletionAttempt(config, messages, options, budget);
216
226
  }
217
227
  }
218
228
  // ── Structured-output attempt-then-fallback ─────────────────────────────────
@@ -286,10 +296,8 @@ const RESPONSE_FORMAT_NAMED = /format_ignored|response_format|json_schema/;
286
296
  * inline fallback-once when a schema was requested and the provider 4xx's
287
297
  * (never retried by the transient-failure policy below, by design — 4xx is
288
298
  * a same-request-will-always-fail signal EXCEPT for this one specific,
289
- * request-shape-dependent case). No cached verdict gates the first attempt:
290
- * `config.supportsJsonSchema === false` is the only thing that skips it,
291
- * and that is a value a human (or workflow author) set explicitly, not one
292
- * a probe wrote automatically.
299
+ * request-shape-dependent case). Only what a real call this process made has
300
+ * shown (`isJsonSchemaKnownUnsupported`) skips the first attempt.
293
301
  *
294
302
  * The thinking-control fields get the same treatment (#1045): a 4xx that
295
303
  * names `chat_template_kwargs` or `enable_thinking` is answered by one retry
@@ -298,9 +306,8 @@ const RESPONSE_FORMAT_NAMED = /format_ignored|response_format|json_schema/;
298
306
  * same way: the connection stops sending `temperature`, or sends the token cap
299
307
  * as `max_completion_tokens`, for the rest of the process.
300
308
  */
301
- async function chatCompletionAttempt(config, messages, options, timeoutMs, includeThinking = (options?.enableThinking ?? config.enableThinking) !== undefined &&
302
- !isThinkingControlKnownRejected(config)) {
303
- const wantsSchema = Boolean(options?.responseSchema) && config.supportsJsonSchema !== false && !isJsonSchemaKnownUnsupported(config);
309
+ async function chatCompletionAttempt(config, messages, options, budget, includeThinking = sendsThinkingFields(config, options) && !isThinkingControlKnownRejected(config)) {
310
+ const wantsSchema = Boolean(options?.responseSchema) && !isJsonSchemaKnownUnsupported(config);
304
311
  // The schema attempt's error record is held, not emitted: when the retry without the schema
305
312
  // recovers the call, that call is ONE success, not a failure plus a success. Every other exit
306
313
  // flushes the held record, so a failed call is still recorded once.
@@ -310,12 +317,12 @@ async function chatCompletionAttempt(config, messages, options, timeoutMs, inclu
310
317
  emitLlmUsage(held.record);
311
318
  };
312
319
  try {
313
- return await chatCompletionAttemptOnce(config, messages, options, timeoutMs, wantsSchema, includeThinking, held);
320
+ return await chatCompletionAttemptOnce(config, messages, options, budget(), wantsSchema, includeThinking, held);
314
321
  }
315
322
  catch (err) {
316
323
  // A 5xx that names the response format is answered like the 4xx rejection below (#1150).
317
324
  if (wantsSchema && err instanceof LlmCallError && err.namesResponseFormat) {
318
- return retryWithoutSchema(config, messages, options, timeoutMs, includeThinking, err);
325
+ return retryWithoutSchema(config, messages, options, budget, includeThinking, err);
319
326
  }
320
327
  if (!isRejectedRequest(err)) {
321
328
  flushHeld();
@@ -326,56 +333,76 @@ async function chatCompletionAttempt(config, messages, options, timeoutMs, inclu
326
333
  flushHeld();
327
334
  warnVerbose(`[akm] LLM rejected temperature (${err.statusCode}); retrying once without it: ${err.message}`);
328
335
  temperatureRejectedConnections.add(key);
329
- return chatCompletionAttempt(config, messages, options, timeoutMs, includeThinking);
336
+ return chatCompletionAttempt(config, messages, options, budget, includeThinking);
330
337
  }
331
338
  if (MAX_TOKENS_REPLACED.test(err.message) && !maxCompletionTokensConnections.has(key)) {
332
339
  flushHeld();
333
340
  warnVerbose(`[akm] LLM rejected max_tokens (${err.statusCode}); retrying once with max_completion_tokens: ${err.message}`);
334
341
  maxCompletionTokensConnections.add(key);
335
- return chatCompletionAttempt(config, messages, options, timeoutMs, includeThinking);
342
+ return chatCompletionAttempt(config, messages, options, budget, includeThinking);
336
343
  }
337
344
  if (includeThinking && THINKING_FIELD_NAMED.test(err.message)) {
338
345
  flushHeld();
339
346
  warnVerbose(`[akm] LLM rejected chat_template_kwargs/enable_thinking (${err.statusCode}); retrying once without them: ${err.message}`);
340
- const fallback = await chatCompletionAttempt(config, messages, options, timeoutMs, false);
347
+ const fallback = await chatCompletionAttempt(config, messages, options, budget, false);
341
348
  thinkingControlRejectedConnections.add(connectionKey(config));
342
349
  return fallback;
343
350
  }
344
351
  if (!wantsSchema)
345
352
  throw err;
346
- return retryWithoutSchema(config, messages, options, timeoutMs, includeThinking, err);
353
+ return retryWithoutSchema(config, messages, options, budget, includeThinking, err);
347
354
  }
348
355
  }
349
- async function retryWithoutSchema(config, messages, options, timeoutMs, includeThinking, err) {
356
+ async function retryWithoutSchema(config, messages, options, budget, includeThinking, err) {
350
357
  warnVerbose(`[akm] LLM rejected response_format:json_schema (${err.statusCode}); retrying once without it: ${err.message}`);
351
- const fallback = await chatCompletionAttemptOnce(config, messages, options, timeoutMs, false, includeThinking);
358
+ const fallback = await chatCompletionAttemptOnce(config, messages, options, budget(), false, includeThinking);
352
359
  jsonSchemaUnsupportedConnections.add(connectionKey(config));
353
360
  return fallback;
354
361
  }
362
+ /** Whether this request carries the two thinking-control fields, from a setting or as written. */
363
+ function sendsThinkingFields(config, options) {
364
+ return ((options?.enableThinking ?? config.inference?.enableThinking) !== undefined ||
365
+ config.request?.chat_template_kwargs !== undefined ||
366
+ config.request?.enable_thinking !== undefined);
367
+ }
368
+ /**
369
+ * The fields of one request: akm's default temperature, the connection's request
370
+ * fields as written, and the portable settings (the call's own over the
371
+ * connection's) translated, nearest last. A field the endpoint has rejected on an
372
+ * earlier call is left out, and the token cap goes by the name it asked for.
373
+ */
374
+ function requestFields(config, options, includeThinking) {
375
+ const settings = {
376
+ ...config.inference,
377
+ ...(options?.temperature !== undefined ? { temperature: options.temperature } : {}),
378
+ ...(options?.maxTokens !== undefined ? { maxTokens: options.maxTokens } : {}),
379
+ ...(options?.enableThinking !== undefined ? { enableThinking: options.enableThinking } : {}),
380
+ };
381
+ const fields = effectiveRequestFields({ temperature: 0.3, ...config.request }, settings);
382
+ const key = connectionKey(config);
383
+ if (temperatureRejectedConnections.has(key))
384
+ delete fields.temperature;
385
+ if (!includeThinking) {
386
+ delete fields.chat_template_kwargs;
387
+ delete fields.enable_thinking;
388
+ }
389
+ if (maxCompletionTokensConnections.has(key) && fields.max_tokens !== undefined) {
390
+ fields.max_completion_tokens = fields.max_tokens;
391
+ delete fields.max_tokens;
392
+ }
393
+ return fields;
394
+ }
355
395
  async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, includeSchema, includeThinking, held) {
356
- if (config.extraParams !== undefined) {
357
- const issue = validateExtraParams(config.extraParams)[0];
396
+ if (config.inference?.extraParams !== undefined) {
397
+ const issue = validateExtraParams(config.inference.extraParams)[0];
358
398
  if (issue)
359
399
  throw new Error(formatExtraParamsIssue("LLM extraParams", issue));
360
400
  }
361
401
  const headers = { "Content-Type": "application/json" };
362
- // Resolve ONLY a whole-string reference ($VAR/${VAR} or secret://<name>).
363
- // The execution boundary normally hands us a materialized credential after
364
- // resolving the reference upstream, so re-running the substitution over a
365
- // literal key mangled any credential containing `$` — `sk-live$ecret` lost
366
- // everything from the `$` onward, and the request failed with an opaque
367
- // 401. The narrow check keeps the symbolic form working for any direct
368
- // caller that still passes one.
369
- const resolvedKey = isApiKeyReference(config.apiKey ?? "")
370
- ? resolveSecret(config.apiKey, resolveSecretFromStore)
371
- : config.apiKey;
402
+ const resolvedKey = config.apiKey;
372
403
  if (resolvedKey) {
373
404
  headers.Authorization = `Bearer ${resolvedKey}`;
374
405
  }
375
- // Only include max_tokens when explicitly set. The model/API knows its own
376
- // limits; a hardcoded default creates silent truncation failures when the
377
- // guess is wrong. Users who need a cap can set llm.maxTokens in config.
378
- const resolvedMaxTokens = options?.maxTokens ?? config.maxTokens;
379
406
  const responseFormat = includeSchema && options?.responseSchema
380
407
  ? {
381
408
  response_format: {
@@ -384,32 +411,11 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
384
411
  },
385
412
  }
386
413
  : {};
387
- // #949: which of these two wire forms a backend honors is a fact about the
388
- // backend (and any gateway in front of it), not about akm's own `provider`
389
- // label — a llama.cpp build honors chat_template_kwargs, a bare
390
- // `enable_thinking` is honored by nothing observed, and a gateway
391
- // (freellmapi, Bifrost) can drop either one depending on how it was built.
392
- // Send both whenever thinking is explicitly resolved so the same engine
393
- // block keeps working across a direct vhost or any gateway in front of it.
394
- const resolvedEnableThinking = includeThinking ? (options?.enableThinking ?? config.enableThinking) : undefined;
395
- const thinkingParams = resolvedEnableThinking === undefined
396
- ? {}
397
- : { chat_template_kwargs: { enable_thinking: resolvedEnableThinking }, enable_thinking: resolvedEnableThinking };
398
- const reasoningEffortParams = config.reasoningEffort === undefined ? {} : { reasoning_effort: config.reasoningEffort };
399
- const key = connectionKey(config);
400
- const maxTokensField = maxCompletionTokensConnections.has(key) ? "max_completion_tokens" : "max_tokens";
401
- const requestBody = JSON.stringify({
402
- model: config.model,
403
- messages,
404
- ...(temperatureRejectedConnections.has(key)
405
- ? {}
406
- : { temperature: options?.temperature ?? config.temperature ?? 0.3 }),
407
- ...(resolvedMaxTokens !== undefined ? { [maxTokensField]: resolvedMaxTokens } : {}),
408
- ...config.extraParams,
409
- ...responseFormat,
410
- ...thinkingParams,
411
- ...reasoningEffortParams,
412
- });
414
+ const fields = requestFields(config, options, includeThinking);
415
+ const requestBody = JSON.stringify({ ...fields, model: config.model, messages, ...responseFormat });
416
+ const endpointUrl = openAiOperationUrl(config.endpoint, "chat/completions");
417
+ // What a message says about the endpoint: never a username or password the URL carries.
418
+ const shownEndpoint = redactUrlCredentials(config.endpoint);
413
419
  // Wall-clock start for per-attempt usage telemetry (#576). Captured here so the
414
420
  // emitted duration covers the full request/response/parse cycle of a single
415
421
  // attempt, not the retry-wrapping `chatCompletion`.
@@ -423,7 +429,7 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
423
429
  try {
424
430
  let response;
425
431
  try {
426
- response = await fetchWithTimeout(config.endpoint, {
432
+ response = await fetchWithTimeout(endpointUrl, {
427
433
  method: "POST",
428
434
  headers,
429
435
  body: requestBody,
@@ -460,15 +466,15 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
460
466
  const safeBody = redactSensitiveText(redactErrorBody(rawBody), resolvedKey ? [resolvedKey] : []);
461
467
  const status = response.status;
462
468
  if (status === 429) {
463
- throw new LlmCallError(`LLM request rate limited (429) ${config.endpoint}: ${safeBody}`, "rate_limited", status);
469
+ throw new LlmCallError(`LLM request rate limited (429) ${shownEndpoint}: ${safeBody}`, "rate_limited", status);
464
470
  }
465
471
  if (status >= 500 && isHtmlResponse(rawBody)) {
466
- throw new LlmCallError(`LLM provider returned HTML instead of JSON (${status}) ${config.endpoint}: ${redactSensitiveText(htmlExcerpt(rawBody), resolvedKey ? [resolvedKey] : [])}`, "provider_html_error", status);
472
+ throw new LlmCallError(`LLM provider returned HTML instead of JSON (${status}) ${shownEndpoint}: ${redactSensitiveText(htmlExcerpt(rawBody), resolvedKey ? [resolvedKey] : [])}`, "provider_html_error", status);
467
473
  }
468
474
  if (status >= 500) {
469
- throw new LlmCallError(`LLM provider error (${status}) ${config.endpoint}: ${safeBody}`, "provider_error", status, RESPONSE_FORMAT_NAMED.test(rawBody));
475
+ throw new LlmCallError(`LLM provider error (${status}) ${shownEndpoint}: ${safeBody}`, "provider_error", status, RESPONSE_FORMAT_NAMED.test(rawBody));
470
476
  }
471
- throw new LlmCallError(`LLM request failed (${status}) ${config.endpoint}: ${safeBody}`, "provider_error", status);
477
+ throw new LlmCallError(`LLM request failed (${status}) ${shownEndpoint}: ${safeBody}`, "provider_error", status);
472
478
  }
473
479
  // A 2xx response is still an error if the body is HTML where JSON was
474
480
  // expected (e.g. a provider serving its web UI). Read the raw body first so
@@ -489,19 +495,19 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
489
495
  throw err;
490
496
  }
491
497
  if (isHtmlResponse(rawOkBody)) {
492
- throw new LlmCallError(`LLM provider returned HTML instead of JSON (${response.status}) ${config.endpoint}: ${redactSensitiveText(htmlExcerpt(rawOkBody), resolvedKey ? [resolvedKey] : [])}`, "provider_html_error", response.status);
498
+ throw new LlmCallError(`LLM provider returned HTML instead of JSON (${response.status}) ${shownEndpoint}: ${redactSensitiveText(htmlExcerpt(rawOkBody), resolvedKey ? [resolvedKey] : [])}`, "provider_html_error", response.status);
493
499
  }
494
500
  let json;
495
501
  try {
496
502
  json = JSON.parse(rawOkBody);
497
503
  }
498
504
  catch {
499
- throw new LlmCallError(`LLM response was not valid JSON ${config.endpoint}: ${redactSensitiveText(redactErrorBody(rawOkBody), resolvedKey ? [resolvedKey] : [])}`, "parse_error", response.status);
505
+ throw new LlmCallError(`LLM response was not valid JSON ${shownEndpoint}: ${redactSensitiveText(redactErrorBody(rawOkBody), resolvedKey ? [resolvedKey] : [])}`, "parse_error", response.status);
500
506
  }
501
507
  // A 2xx can still carry a provider failure. OpenRouter answers a provider
502
508
  // that fails after the headers with a body holding only `error`.
503
509
  if (json.error !== undefined && json.error !== null && !json.choices?.length) {
504
- throw new LlmCallError(`LLM provider error (${response.status}) ${config.endpoint}: ${redactSensitiveText(redactErrorBody(rawOkBody), resolvedKey ? [resolvedKey] : [])}`, "provider_error", response.status);
510
+ throw new LlmCallError(`LLM provider error (${response.status}) ${shownEndpoint}: ${redactSensitiveText(redactErrorBody(rawOkBody), resolvedKey ? [resolvedKey] : [])}`, "provider_error", response.status);
505
511
  }
506
512
  const responseModel = typeof json.model === "string" && json.model.trim().length > 0 ? json.model : undefined;
507
513
  terminalFields = {
@@ -510,8 +516,8 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
510
516
  finishReason: typeof json.choices?.[0]?.finish_reason === "string" ? json.choices[0].finish_reason : undefined,
511
517
  ...extractUsageTokens(json.usage),
512
518
  };
513
- if (resolvedEnableThinking === false && (terminalFields.reasoningTokens ?? 0) > 0) {
514
- warn(`[akm] LLM returned ${terminalFields.reasoningTokens} reasoning tokens despite enableThinking: false; ` +
519
+ if (fields.enable_thinking === false && (terminalFields.reasoningTokens ?? 0) > 0) {
520
+ warn(`[akm] LLM returned ${terminalFields.reasoningTokens} reasoning tokens despite thinking being off; ` +
515
521
  'the provider may not honor that control. Configure reasoningEffort: "none" when the provider supports it.');
516
522
  }
517
523
  const content = (json.choices?.[0]?.message?.content ?? "").trim();
@@ -540,30 +546,6 @@ async function chatCompletionAttemptOnce(config, messages, options, timeoutMs, i
540
546
  }
541
547
  // ── Availability check ──────────────────────────────────────────────────────
542
548
  // ── Reachability probe ──────────────────────────────────────────────────────
543
- /**
544
- * Best-effort reachability check with an error message, for setup's optional
545
- * `--probe` connectivity verification. Deliberately does NOT probe or cache
546
- * `response_format: json_schema` support: that used to be persisted as
547
- * `capabilities.structuredOutput` and consulted on every later call, so a
548
- * config edit that changed the endpoint/model left a stale verdict in place
549
- * with no invalidation, and a stale `true` sent an unsupported request that
550
- * the retry policy explicitly does not retry (4xx). `chatCompletion` now
551
- * attempts the schema request fresh every time and falls back once per call
552
- * on a 4xx — see the in-memory tracker below.
553
- */
554
- export async function probeLlmReachable(config, timeoutMs) {
555
- try {
556
- const raw = await chatCompletion(config, [{ role: "user", content: "Respond with just the word: ok" }], {
557
- maxTokens: 16,
558
- temperature: 0,
559
- ...(timeoutMs !== undefined ? { timeoutMs } : {}),
560
- });
561
- return raw.length > 0 ? { reachable: true } : { reachable: false, error: "empty response" };
562
- }
563
- catch (err) {
564
- return { reachable: false, error: err instanceof Error ? err.message : String(err) };
565
- }
566
- }
567
549
  /**
568
550
  * Reachability probe for `akm health` (#914): one GET against the
569
551
  * OpenAI-compatible `/models` route, bounded by `timeoutMs`. Any HTTP
@@ -573,7 +555,7 @@ export async function probeLlmReachable(config, timeoutMs) {
573
555
  */
574
556
  export async function probeLlmEndpoint(config, timeoutMs = 3_000) {
575
557
  try {
576
- await fetch(`${config.endpoint.replace(/\/+$/, "")}/models`, { signal: AbortSignal.timeout(timeoutMs) });
558
+ await fetch(openAiOperationUrl(config.endpoint, "models"), { signal: AbortSignal.timeout(timeoutMs) });
577
559
  return { reachable: true };
578
560
  }
579
561
  catch (err) {
@@ -581,16 +563,16 @@ export async function probeLlmEndpoint(config, timeoutMs = 3_000) {
581
563
  }
582
564
  }
583
565
  /**
584
- * Endpoint-keyed probe memoization (#957): every caller that probes several
585
- * engine connections in one pass (`akm health`'s engine checks, `akm
586
- * improve --require-engines`) shares one in-flight probe per distinct
587
- * endpoint (trailing slashes normalized) instead of firing a duplicate probe
588
- * when two engines point at the same server. `cache` must be scoped to one
566
+ * Endpoint-keyed probe memoization (#957): a caller that probes several
567
+ * connections in one pass (`akm health`'s connections-and-harnesses check)
568
+ * shares one in-flight probe per distinct endpoint (trailing slashes
569
+ * normalized) instead of firing a duplicate probe when two connections point
570
+ * at the same server. `cache` must be scoped to one
589
571
  * invocation and never shared across calls — a stale "reachable" surviving
590
572
  * past the run that produced it is the failure mode this exists to avoid.
591
573
  */
592
574
  export function probeEndpointOnce(connection, cache, probe) {
593
- const key = connection.endpoint.replace(/\/+$/, "");
575
+ const key = openAiBaseUrl(connection.endpoint);
594
576
  let pending = cache.get(key);
595
577
  if (!pending) {
596
578
  pending = probe(connection);
@@ -3,31 +3,21 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { embedCacheKey, getCachedEmbedding, setCachedEmbedding } from "./embedders/cache.js";
5
5
  import { DETERMINISTIC_EMBED_MODEL_ID, deterministicEmbed, isDeterministicEmbedEnabled, } from "./embedders/deterministic.js";
6
- import { DEFAULT_LOCAL_MODEL, isTransformersAvailable as isTransformersAvailableReal, LocalEmbedder, } from "./embedders/local.js";
6
+ import { DEFAULT_LOCAL_MODEL, LocalEmbedder, LocalRuntimeUnavailableError } from "./embedders/local.js";
7
7
  import { hasRemoteEndpoint, RemoteEmbedder } from "./embedders/remote.js";
8
8
  // ── Shared exports ──────────────────────────────────────────────────────────
9
9
  export { clearEmbeddingCache } from "./embedders/cache.js";
10
- export { _setTransformersLoaderForTests, DEFAULT_LOCAL_MODEL } from "./embedders/local.js";
10
+ export { _setLocalPipelineLoaderForTests, DEFAULT_LOCAL_MODEL } from "./embedders/local.js";
11
11
  let embedderOverrides;
12
12
  /** TEST-ONLY. Swap embedder implementations; pass undefined to restore. */
13
13
  export function _setEmbedderForTests(fakes) {
14
14
  embedderOverrides = fakes;
15
15
  }
16
- /**
17
- * Check whether the external Transformers dependency is available.
18
- * Delegating wrapper around `./embedders/local`'s probe so tests can swap it
19
- * via {@link _setEmbedderForTests}.
20
- */
21
- export function isTransformersAvailable() {
22
- if (embedderOverrides?.isTransformersAvailable)
23
- return embedderOverrides.isTransformersAvailable();
24
- return isTransformersAvailableReal();
25
- }
26
16
  // ── Singleton local embedder ────────────────────────────────────────────────
27
17
  // `_localEmbedder` is an intentional module-level singleton but constructed
28
- // lazily on first use. The underlying Transformers.js pipeline is
29
- // expensive to initialise (model download + WASM compilation) and is safe to
30
- // share across calls because it is stateless once created. Deferring
18
+ // lazily on first use. The loaded model is expensive to initialise (model
19
+ // download, runtime and session load) and is safe to share across calls
20
+ // because it is stateless once created. Deferring
31
21
  // construction to first call keeps the module side-effect-free at import time,
32
22
  // which matters for the test suite (single Bun process, ~120 test files).
33
23
  let _localEmbedder;
@@ -44,11 +34,18 @@ function getLocalEmbedder() {
44
34
  export function resetLocalEmbedder() {
45
35
  getLocalEmbedder().reset();
46
36
  }
37
+ /**
38
+ * The runtime the local embedder has embedded with in this process, or
39
+ * `undefined` when it has not loaded a model (nothing was embedded locally).
40
+ */
41
+ export function localEmbeddingRuntime() {
42
+ return _localEmbedder?.runtime;
43
+ }
47
44
  // ── Public API ──────────────────────────────────────────────────────────────
48
45
  /**
49
46
  * Generate an embedding for the given text.
50
47
  * If embeddingConfig has a remote endpoint, uses the configured OpenAI-compatible endpoint.
51
- * Otherwise falls back to local Transformers.js using the model from
48
+ * Otherwise falls back to the local embedder using the model from
52
49
  * `embeddingConfig.localModel` or `DEFAULT_LOCAL_MODEL`.
53
50
  *
54
51
  * Results are cached in an LRU cache (max ~100 entries) keyed by query text
@@ -98,8 +95,8 @@ async function embedOnce(text, embeddingConfig, signal) {
98
95
  * sub-batch or oversized document that fails is skipped rather than
99
96
  * aborting the whole call — pass `onSkip` to learn which indices were
100
97
  * skipped and why; the result array holds `undefined` at those indices.
101
- * Uses the LocalEmbedder.embedBatch path for the local transformer pipeline,
102
- * which processes texts in chunks of 32 for genuine batched inference.
98
+ * Uses the LocalEmbedder.embedBatch path for the local model, which processes
99
+ * texts in chunks of 32 for genuine batched inference.
103
100
  *
104
101
  * `onBatch`, when given, fires once per provider/local batch as it completes
105
102
  * (#954) so a caller can commit each batch's rows durably as they land
@@ -123,7 +120,7 @@ export async function embedBatch(texts, embeddingConfig, signal, onSkip, onBatch
123
120
  if (embeddingConfig && hasRemoteEndpoint(embeddingConfig)) {
124
121
  return new RemoteEmbedder(embeddingConfig).embedBatch(texts, signal, onSkip, onBatch);
125
122
  }
126
- // Local transformer: use the batched path (chunks of 32 via LocalEmbedder).
123
+ // Local model: use the batched path (chunks of 32 via LocalEmbedder).
127
124
  // When a localModel override is set we cannot share the singleton (which uses
128
125
  // the default model), so fall back to per-text embedWithModel in that case.
129
126
  const localModel = embeddingConfig?.localModel;
@@ -144,7 +141,7 @@ export async function embedBatch(texts, embeddingConfig, signal, onSkip, onBatch
144
141
  // ── Similarity ──────────────────────────────────────────────────────────────
145
142
  // `cosineSimilarity` was moved to `./embedders/types.ts` so importers
146
143
  // (notably `db.ts`) can pull the math function without dragging in this
147
- // module and its Transformers.js import chain.
144
+ // module and the local embedder's import chain.
148
145
  export { cosineSimilarity } from "./embedders/types.js";
149
146
  // ── Model ID resolution ─────────────────────────────────────────────────────
150
147
  /**
@@ -154,7 +151,7 @@ export { cosineSimilarity } from "./embedders/types.js";
154
151
  *
155
152
  * Rules:
156
153
  * - Remote endpoint: use `config.model` (the API-level model name).
157
- * - Local transformers: use `config.localModel ?? DEFAULT_LOCAL_MODEL`.
154
+ * - Local model: use `config.localModel ?? DEFAULT_LOCAL_MODEL`.
158
155
  * - No config: use `DEFAULT_LOCAL_MODEL` (the shared singleton model).
159
156
  */
160
157
  export function resolveEmbeddingModelId(embeddingConfig) {
@@ -193,14 +190,6 @@ export async function checkEmbeddingAvailability(embeddingConfig) {
193
190
  };
194
191
  }
195
192
  }
196
- // Check if the package is importable before attempting the model download.
197
- if (!isTransformersAvailable()) {
198
- return {
199
- available: false,
200
- reason: "missing-package",
201
- message: "The @huggingface/transformers dependency is unavailable.",
202
- };
203
- }
204
193
  try {
205
194
  await getLocalEmbedder().getPipeline(embeddingConfig?.localModel);
206
195
  return { available: true };
@@ -208,12 +197,8 @@ export async function checkEmbeddingAvailability(embeddingConfig) {
208
197
  catch (err) {
209
198
  return {
210
199
  available: false,
211
- reason: "model-download-failed",
200
+ reason: err instanceof LocalRuntimeUnavailableError ? "runtime-unavailable" : "model-download-failed",
212
201
  message: err instanceof Error ? err.message : String(err),
213
202
  };
214
203
  }
215
204
  }
216
- export async function isEmbeddingAvailable(embeddingConfig) {
217
- const result = await checkEmbeddingAvailability(embeddingConfig);
218
- return result.available;
219
- }
@@ -0,0 +1,31 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import { defaultConnection } from "../../core/config/config.js";
5
+ import { apiKeyReference } from "../../core/config/credentials.js";
6
+ import { openAiBaseUrl } from "../../core/endpoint-url.js";
7
+ import { warnOnce } from "../../core/warn.js";
8
+ /**
9
+ * The embedding block as the embedder uses it. `embedding.model` without an
10
+ * `embedding.endpoint` means the model is served by the default connection: its
11
+ * endpoint, and its key (its `$VAR`, else `credentials.json` under its name).
12
+ * With no default connection there is nothing to serve it, so the built-in local
13
+ * embedder runs, with one warning. Computed where the embedder is used and never
14
+ * stored, so a config write cannot persist it.
15
+ */
16
+ export function effectiveEmbedding(config) {
17
+ const embedding = config.embedding;
18
+ if (!embedding || embedding.endpoint !== undefined || !embedding.model)
19
+ return embedding;
20
+ const found = defaultConnection(config);
21
+ if (!found) {
22
+ warnOnce("embedding:no-default-connection", "embedding.model is set, but there is no embedding.endpoint and no default connection to serve it; using the built-in local embedder. Add a connection with `akm setup`.");
23
+ return embedding;
24
+ }
25
+ return {
26
+ ...embedding,
27
+ endpoint: openAiBaseUrl(found.connection.endpoint),
28
+ ...(apiKeyReference(found.connection.apiKey) !== undefined ? { apiKey: found.connection.apiKey } : {}),
29
+ credentialName: found.name,
30
+ };
31
+ }
@@ -0,0 +1,56 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * The files of a local embedding model, fetched from the Hugging Face Hub into
6
+ * akm's model cache on first use. The layout is `<HF_HOME>/<repo>/<file>` (HF_HOME
7
+ * defaults to `<akm cache>/models`), the one earlier releases wrote through
8
+ * Transformers.js, so a cache they filled is reused as it is.
9
+ */
10
+ import fs from "node:fs";
11
+ import path from "node:path";
12
+ import { fetchWithRetry } from "../../core/common.js";
13
+ import { getCacheDir } from "../../core/paths.js";
14
+ import { writeResponseToFileCapped } from "../../runtime.js";
15
+ /** `config.json` is not read here; releases that ran the model through Transformers.js require it, so it stays in the cache. */
16
+ const MODEL_FILES = ["tokenizer.json", "tokenizer_config.json", "config.json", "onnx/model.onnx"];
17
+ function isEnabledEnvironmentFlag(value) {
18
+ return /^(?:1|true|yes|on)$/i.test(value?.trim() ?? "");
19
+ }
20
+ async function downloadFile(url, target) {
21
+ const response = await fetchWithRetry(url, undefined, { timeout: 60_000 });
22
+ if (!response.ok) {
23
+ await response.body?.cancel().catch(() => undefined);
24
+ throw new Error(`Could not download ${url}: HTTP ${response.status}`);
25
+ }
26
+ fs.mkdirSync(path.dirname(target), { recursive: true });
27
+ const partial = `${target}.${process.pid}.tmp`;
28
+ try {
29
+ // No overall deadline for a 127 MB file on a slow link (Transformers.js had none): only 60 s without bytes fails it.
30
+ await writeResponseToFileCapped(partial, response, { stallTimeoutMs: 60_000 });
31
+ fs.renameSync(partial, target);
32
+ }
33
+ catch (error) {
34
+ fs.rmSync(partial, { force: true });
35
+ throw error;
36
+ }
37
+ }
38
+ /**
39
+ * Make sure every file of `modelName` (a Hub repo id) is cached and return the
40
+ * directory holding them. With `HF_HUB_OFFLINE` set nothing is fetched and a
41
+ * missing file is an error.
42
+ */
43
+ export async function ensureLocalModelFiles(modelName) {
44
+ const modelDir = path.join(process.env.HF_HOME || path.join(getCacheDir(), "models"), ...modelName.split("/"));
45
+ const offline = isEnabledEnvironmentFlag(process.env.HF_HUB_OFFLINE);
46
+ for (const file of MODEL_FILES) {
47
+ const target = path.join(modelDir, ...file.split("/"));
48
+ if (fs.existsSync(target))
49
+ continue;
50
+ if (offline) {
51
+ throw new Error(`The local embedding model file ${target} is not cached and HF_HUB_OFFLINE is set.`);
52
+ }
53
+ await downloadFile(`https://huggingface.co/${modelName}/resolve/main/${file}`, target);
54
+ }
55
+ return modelDir;
56
+ }