akm-cli 0.9.24 → 0.9.25-alpha.2

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 (84) hide show
  1. package/CHANGELOG.md +173 -0
  2. package/dist/cli.js +1 -1
  3. package/dist/commands/health/checks.js +10 -11
  4. package/dist/commands/improve/consolidate/pair-pass.js +4 -2
  5. package/dist/commands/improve/consolidate.js +10 -4
  6. package/dist/commands/improve/execution.js +4 -11
  7. package/dist/commands/improve/extract-prompt.js +4 -4
  8. package/dist/commands/improve/extract.js +11 -13
  9. package/dist/commands/improve/improve-cli.js +65 -34
  10. package/dist/commands/improve/improve-strategies.js +49 -43
  11. package/dist/commands/improve/improve-usage-report.js +8 -17
  12. package/dist/commands/improve/loop-stages.js +3 -0
  13. package/dist/commands/improve/preparation.js +3 -1
  14. package/dist/commands/improve/reflect-noise.js +125 -0
  15. package/dist/commands/improve/reflect.js +105 -172
  16. package/dist/commands/improve/retrieval-gate.js +7 -2
  17. package/dist/commands/improve/stage.js +67 -24
  18. package/dist/commands/proposal/drain.js +11 -2
  19. package/dist/commands/proposal/proposal-cli.js +1 -5
  20. package/dist/commands/proposal/propose-cli.js +2 -2
  21. package/dist/commands/proposal/propose.js +72 -84
  22. package/dist/commands/proposal/validators/proposal-quality-validators.js +4 -2
  23. package/dist/commands/read/search-cli.js +0 -38
  24. package/dist/commands/remember.js +3 -3
  25. package/dist/commands/sources/schema-repair.js +1 -1
  26. package/dist/core/config/config-schema.js +37 -60
  27. package/dist/core/config/engine-semantics.js +15 -11
  28. package/dist/core/config/schema/improve-processes.js +18 -2
  29. package/dist/core/improve-result.js +3 -3
  30. package/dist/core/redaction.js +4 -0
  31. package/dist/core/spawn-env.js +25 -0
  32. package/dist/core/structured.js +11 -1
  33. package/dist/execution/source.js +10 -0
  34. package/dist/indexer/passes/memory-inference.js +2 -1
  35. package/dist/integrations/agent/builder-shared.js +15 -0
  36. package/dist/integrations/agent/config.js +1 -1
  37. package/dist/integrations/agent/engine-resolution.js +13 -31
  38. package/dist/integrations/agent/execution.js +48 -22
  39. package/dist/integrations/agent/index.js +1 -1
  40. package/dist/integrations/agent/profiles.js +2 -2
  41. package/dist/integrations/agent/prompts.js +55 -114
  42. package/dist/integrations/agent/request-lowering.js +21 -8
  43. package/dist/integrations/agent/runner-dispatch.js +96 -3
  44. package/dist/integrations/agent/runner.js +8 -2
  45. package/dist/integrations/harnesses/aider/agent-builder.js +10 -23
  46. package/dist/integrations/harnesses/aider/index.js +0 -5
  47. package/dist/integrations/harnesses/amazonq/agent-builder.js +9 -21
  48. package/dist/integrations/harnesses/amazonq/index.js +0 -5
  49. package/dist/integrations/harnesses/claude/agent-builder.js +47 -36
  50. package/dist/integrations/harnesses/claude/index.js +0 -14
  51. package/dist/integrations/harnesses/codex/agent-builder.js +3 -4
  52. package/dist/integrations/harnesses/codex/index.js +0 -4
  53. package/dist/integrations/harnesses/copilot/agent-builder.js +4 -13
  54. package/dist/integrations/harnesses/copilot/index.js +2 -7
  55. package/dist/integrations/harnesses/gemini/agent-builder.js +4 -13
  56. package/dist/integrations/harnesses/gemini/index.js +0 -5
  57. package/dist/integrations/harnesses/ids.js +12 -10
  58. package/dist/integrations/harnesses/opencode/agent-builder.js +41 -9
  59. package/dist/integrations/harnesses/opencode/index.js +0 -8
  60. package/dist/integrations/harnesses/opencode/model-config.js +33 -0
  61. package/dist/integrations/harnesses/opencode/model-work-agent.js +115 -0
  62. package/dist/integrations/harnesses/opencode-sdk/harness.js +2 -7
  63. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +114 -28
  64. package/dist/integrations/harnesses/openhands/agent-builder.js +7 -21
  65. package/dist/integrations/harnesses/openhands/index.js +0 -5
  66. package/dist/integrations/harnesses/pi/agent-builder.js +7 -21
  67. package/dist/integrations/harnesses/pi/index.js +0 -5
  68. package/dist/llm/client.js +5 -0
  69. package/dist/llm/feature-gate.js +12 -9
  70. package/dist/llm/index-passes.js +2 -5
  71. package/dist/llm/memory-infer.js +6 -5
  72. package/dist/llm/structured-call.js +33 -11
  73. package/dist/output/shapes/passthrough.js +1 -0
  74. package/dist/scripts/akm-migrate-node.js +298 -228
  75. package/dist/scripts/akm-migrate.js +298 -228
  76. package/dist/workflows/exec/step-work.js +6 -5
  77. package/dist/workflows/exec/unit-dispatch.js +4 -13
  78. package/dist/workflows/freeze/step-values.js +1 -1
  79. package/docs/reference/cli.md +41 -18
  80. package/docs/reference/configuration.md +165 -12
  81. package/docs/reference/data-and-telemetry.md +2 -3
  82. package/docs/reference/workflow-schema.md +10 -9
  83. package/package.json +1 -1
  84. package/schemas/akm-config.json +108 -0
@@ -1,6 +1,7 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ import { DEFAULT_LLM_TIMEOUT_MS } from "../integrations/agent/config.js";
4
5
  /**
5
6
  * For each feature key, return the effective enabled state by reading the
6
7
  * 0.9.0 config shape.
@@ -37,14 +38,11 @@ export function isLlmFeatureEnabled(config, feature, improveEnabled) {
37
38
  return false;
38
39
  return resolver(config);
39
40
  }
40
- /**
41
- * Default hard timeout for every bounded in-tree LLM call.
42
- */
43
- const DEFAULT_TIMEOUT_MS = 600_000;
44
41
  /**
45
42
  * Run `fn()` only if `isLlmFeatureEnabled(config, feature)` is `true`. On
46
43
  * disablement, throw, or timeout, return `fallback` (or — if it is a
47
- * thunk — the value produced by calling it).
44
+ * thunk — the value produced by calling it). The timeout aborts the signal
45
+ * `fn` receives, so the work it started stops too.
48
46
  */
49
47
  export async function tryLlmFeature(feature, config, fn, fallback, opts) {
50
48
  const resolveFallback = async () => typeof fallback === "function" ? await fallback() : fallback;
@@ -52,10 +50,10 @@ export async function tryLlmFeature(feature, config, fn, fallback, opts) {
52
50
  opts?.onFallback?.({ feature, reason: "disabled" });
53
51
  return resolveFallback();
54
52
  }
55
- const timeoutMs = opts && Object.hasOwn(opts, "timeoutMs") ? (opts.timeoutMs ?? null) : DEFAULT_TIMEOUT_MS;
53
+ const timeoutMs = opts && Object.hasOwn(opts, "timeoutMs") ? (opts.timeoutMs ?? null) : DEFAULT_LLM_TIMEOUT_MS;
56
54
  try {
57
55
  if (timeoutMs === null || timeoutMs <= 0) {
58
- return await fn();
56
+ return await fn(new AbortController().signal);
59
57
  }
60
58
  return await runWithTimeout(fn, timeoutMs, feature);
61
59
  }
@@ -97,11 +95,16 @@ export class LlmFeatureTimeoutError extends Error {
97
95
  }
98
96
  async function runWithTimeout(fn, timeoutMs, feature) {
99
97
  let timer;
98
+ const controller = new AbortController();
100
99
  try {
101
100
  return await new Promise((resolve, reject) => {
102
- timer = setTimeout(() => reject(new LlmFeatureTimeoutError(feature, timeoutMs)), timeoutMs);
101
+ timer = setTimeout(() => {
102
+ const timedOut = new LlmFeatureTimeoutError(feature, timeoutMs);
103
+ controller.abort(timedOut);
104
+ reject(timedOut);
105
+ }, timeoutMs);
103
106
  Promise.resolve()
104
- .then(() => fn())
107
+ .then(() => fn(controller.signal))
105
108
  .then(resolve, reject);
106
109
  });
107
110
  }
@@ -1,7 +1,6 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { warn } from "../core/warn.js";
5
4
  import { cloneExecutionJsonObject } from "../execution/json.js";
6
5
  import { buildExecution, resolveExecution } from "../integrations/agent/execution.js";
7
6
  const NO_LOWERING_NOTICES = Object.freeze([]);
@@ -38,16 +37,14 @@ export function resolveIndexPassExecution(passName, config) {
38
37
  ...indexExecutionDefaults(defaults),
39
38
  ...(!own(defaults, "engine") && fallbackLlmEngine ? { engine: fallbackLlmEngine } : {}),
40
39
  };
40
+ // Under the model-work tool policy, so an engine that cannot confine it is refused here.
41
41
  const prepared = resolveExecution({
42
42
  content: "",
43
43
  config,
44
44
  invocationDefaults,
45
45
  current: indexExecutionDefaults(pass),
46
+ modelWork: true,
46
47
  });
47
48
  const lowered = buildExecution(prepared.request, prepared.runner);
48
- if (lowered.runner.kind !== "llm") {
49
- warn("[akm] Index pass %s requires an LLM engine; %s is not one. Skipping this pass.", passName, selectedEngine);
50
- return Object.freeze({ runner: undefined, notices: NO_LOWERING_NOTICES });
51
- }
52
49
  return Object.freeze({ runner: lowered.runner, notices: lowered.notices });
53
50
  }
@@ -21,6 +21,7 @@ import memoryInferUserPrompt from "../assets/prompts/memory-infer-user.md" with
21
21
  import { toErrorMessage } from "../core/common.js";
22
22
  import { parseEmbeddedJsonResponse } from "../core/parse.js";
23
23
  import { warn } from "../core/warn.js";
24
+ import { runnerLlmConnection } from "../integrations/agent/runner.js";
24
25
  import { callStructured } from "./structured-call.js";
25
26
  const SYSTEM_PROMPT = memoryInferSystemPrompt;
26
27
  const USER_PROMPT_PREFIX = memoryInferUserPrompt;
@@ -34,9 +35,9 @@ const PROMPT_PLACEHOLDERS = new Set([
34
35
  "2-3 sentence compressed body preserving key facts verbatim",
35
36
  ]);
36
37
  /**
37
- * Strict JSON Schema for the derived-memory payload. Sent to providers that
38
- * opt in via `runner.connection.supportsJsonSchema = true`; the client
39
- * silently drops the schema for providers that don't.
38
+ * Strict JSON Schema for the derived-memory payload. Sent as `response_format`
39
+ * unless the engine sets `supportsJsonSchema: false`; the client drops it once
40
+ * for a provider that rejects it.
40
41
  *
41
42
  * Extends the responseSchema lift (PR 1, asset-writers-investigation §5) to
42
43
  * the memory-inference path. Mirrors the validation gate below
@@ -89,8 +90,8 @@ export async function compressMemoryToDerivedMemory(llmRunner, body, signal, akm
89
90
  ],
90
91
  request: {
91
92
  // The engine's or the process's configured temperature; 0.1 only when neither sets one.
92
- temperature: llmRunner.connection.temperature ?? 0.1,
93
- timeoutMs: llmRunner.timeoutMs,
93
+ temperature: runnerLlmConnection(llmRunner)?.temperature ?? 0.1,
94
+ ...(Object.hasOwn(llmRunner, "timeoutMs") ? { timeoutMs: llmRunner.timeoutMs } : {}),
94
95
  signal,
95
96
  responseSchema: DERIVED_MEMORY_JSON_SCHEMA,
96
97
  onRetryAttempt,
@@ -2,6 +2,7 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { ConfigError } from "../core/errors.js";
5
+ import { DEFAULT_LLM_TIMEOUT_MS } from "../integrations/agent/config.js";
5
6
  import { buildExecution, resolveExecution } from "../integrations/agent/execution.js";
6
7
  import { runExecution } from "../integrations/agent/runner-dispatch.js";
7
8
  import { isContextSizeError, LlmCallError } from "./client.js";
@@ -22,8 +23,12 @@ export function classifyLlmError(err) {
22
23
  function own(value, key) {
23
24
  return value !== undefined && Object.hasOwn(value, key);
24
25
  }
25
- /** @internal Exact request-to-cascade projection, exported for presence-semantics contracts. */
26
- export function resolveStructuredCurrent(current, request) {
26
+ /**
27
+ * @internal Exact request-to-cascade projection, exported for presence-semantics contracts.
28
+ * Model work is bounded: with no timeout from the request or the runner, it
29
+ * gets {@link DEFAULT_LLM_TIMEOUT_MS} on every runner kind.
30
+ */
31
+ export function resolveStructuredCurrent(current, request, runner) {
27
32
  const out = current ? { ...current } : {};
28
33
  const requestHasInference = own(request, "temperature") || own(request, "maxTokens") || own(request, "enableThinking");
29
34
  const baseInference = current?.inference && typeof current.inference === "object" && !Array.isArray(current.inference)
@@ -46,6 +51,9 @@ export function resolveStructuredCurrent(current, request) {
46
51
  }
47
52
  if (own(request, "timeoutMs"))
48
53
  out.timeout = request?.timeoutMs ?? null;
54
+ else if (runner && !Object.hasOwn(runner, "timeoutMs") && !own(current, "timeout")) {
55
+ out.timeout = DEFAULT_LLM_TIMEOUT_MS;
56
+ }
49
57
  return Object.keys(out).length > 0 ? out : undefined;
50
58
  }
51
59
  function requireTerminalUserMessage(messages) {
@@ -59,8 +67,17 @@ function requireTerminalUserMessage(messages) {
59
67
  };
60
68
  }
61
69
  function dispatchFailure(result) {
62
- const message = result.error ?? result.stderr ?? result.reason ?? "LLM dispatch failed";
63
- return result.llmErrorCode ? new LlmCallError(message, result.llmErrorCode) : new Error(message);
70
+ const message = result.error ?? result.stderr ?? result.reason ?? "dispatch failed";
71
+ const error = result.llmErrorCode ? new LlmCallError(message, result.llmErrorCode) : new Error(message);
72
+ return Object.assign(error, { reason: result.reason, result });
73
+ }
74
+ /** The runner's failure reason (`timeout`, `aborted`, …) a failed dispatch threw with, whatever its kind. */
75
+ export function dispatchFailureReason(err) {
76
+ return err instanceof Error ? err.reason : undefined;
77
+ }
78
+ /** The failed dispatch's own result (an agent's exit code and stderr, say), whatever its kind. */
79
+ export function dispatchFailureResult(err) {
80
+ return err instanceof Error ? err.result : undefined;
64
81
  }
65
82
  export async function callStructured(opts) {
66
83
  const { feature, akmConfig, enabled, messages, request, parse, onError, fallback, onFallback } = opts;
@@ -77,23 +94,28 @@ export async function callStructured(opts) {
77
94
  }
78
95
  const runner = opts.runner;
79
96
  if (!runner)
80
- throw new TypeError("callStructured requires a resolved LLM runner");
97
+ throw new TypeError("callStructured requires a resolved runner");
81
98
  const terminal = requireTerminalUserMessage(messages);
99
+ // `gateSignal` aborts when the feature gate's timeout fires, so the dispatch stops with it.
100
+ // Every structured call is unattended model work, so it runs under the model-work tool policy.
82
101
  const prepareInvocation = () => {
83
- const current = resolveStructuredCurrent(opts.current, request);
84
102
  const prepared = resolveExecution({
85
103
  content: terminal.content,
86
104
  conversation: terminal.conversation,
87
105
  runner,
88
- ...(current ? { current } : {}),
106
+ current: resolveStructuredCurrent(opts.current, request, runner),
107
+ modelWork: true,
89
108
  });
90
109
  const lowered = buildExecution(prepared.request, prepared.runner);
91
110
  opts.onNotices?.(lowered.notices);
92
- return async () => {
111
+ return async (gateSignal) => {
112
+ const signal = request?.signal && gateSignal ? AbortSignal.any([request.signal, gateSignal]) : (request?.signal ?? gateSignal);
113
+ const runOptions = { ...request?.runOptions, ...(signal ? { signal } : {}) };
93
114
  const result = await runExecution(lowered, {
94
115
  ...(request?.chat ? { chat: request.chat } : {}),
116
+ ...(request?.runSdk ? { runSdk: request.runSdk } : {}),
95
117
  ...(request?.onRetryAttempt ? { onRetryAttempt: request.onRetryAttempt } : {}),
96
- ...(own(request, "signal") ? { runOptions: { signal: request?.signal } } : {}),
118
+ ...(Object.keys(runOptions).length > 0 ? { runOptions } : {}),
97
119
  });
98
120
  if (!result.ok)
99
121
  throw dispatchFailure(result);
@@ -111,9 +133,9 @@ export async function callStructured(opts) {
111
133
  const invoke = prepareInvocation();
112
134
  // GATED: run through `tryLlmFeature`. A throw inside is classified ONCE and
113
135
  // routed to `onError`; `tryLlmFeature` returns `fallback` on disablement/timeout.
114
- const outcome = await tryLlmFeature(feature, akmConfig, async () => {
136
+ const outcome = await tryLlmFeature(feature, akmConfig, async (gateSignal) => {
115
137
  try {
116
- return { kind: "value", value: await invoke() };
138
+ return { kind: "value", value: await invoke(gateSignal) };
117
139
  }
118
140
  catch (err) {
119
141
  // Credential materialization remains dispatch-owned, so a missing
@@ -43,6 +43,7 @@ const PASSTHROUGH_COMMANDS = [
43
43
  "extract",
44
44
  "health",
45
45
  "improve",
46
+ "improve-judge",
46
47
  "improve-report",
47
48
  "import",
48
49
  "index",