akm-cli 0.9.0-rc.1 → 0.9.0-rc.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.
- package/CHANGELOG.md +223 -9
- package/SECURITY.md +23 -24
- package/dist/assets/help/help-improve.md +10 -10
- package/dist/assets/hints/cli-hints-full.md +44 -10
- package/dist/assets/hints/cli-hints-short.md +6 -2
- package/dist/assets/{profiles → improve-strategies}/default.json +1 -0
- package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +1 -1
- package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +2 -3
- package/dist/assets/{profiles → improve-strategies}/reflect-distill.json +3 -4
- package/dist/assets/stash-skeleton/README.md +28 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +12 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +11 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +7 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +7 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +6 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +98 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +63 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +127 -0
- package/dist/assets/tasks/core/backup.yml +1 -0
- package/dist/assets/tasks/core/extract.yml +1 -0
- package/dist/assets/tasks/core/improve.yml +1 -0
- package/dist/assets/tasks/core/index-refresh.yml +1 -0
- package/dist/assets/tasks/core/sync.yml +1 -0
- package/dist/assets/tasks/core/version-check.yml +1 -0
- package/dist/assets/tasks/graph-refresh-weekly.yml +4 -4
- package/dist/assets/templates/html/health.html +5 -1
- package/dist/cli/config-migrate.js +31 -138
- package/dist/cli/config-validate.js +10 -8
- package/dist/cli.js +48 -14
- package/dist/commands/agent/agent-dispatch.js +17 -16
- package/dist/commands/agent/agent-support.js +0 -24
- package/dist/commands/agent/contribute-cli.js +5 -15
- package/dist/commands/backup-cli.js +54 -0
- package/dist/commands/config-cli.js +45 -159
- package/dist/commands/env/secret.js +8 -5
- package/dist/commands/health/checks.js +130 -83
- package/dist/commands/health/html-report.js +4 -0
- package/dist/commands/health/improve-metrics.js +30 -32
- package/dist/commands/health/llm-usage.js +19 -19
- package/dist/commands/health/md-report.js +4 -0
- package/dist/commands/health/metrics.js +2 -1
- package/dist/commands/health/surfaces.js +5 -4
- package/dist/commands/health.js +1 -1
- package/dist/commands/improve/consolidate/chunking.js +2 -2
- package/dist/commands/improve/consolidate.js +28 -25
- package/dist/commands/improve/distill/promote-memory.js +5 -12
- package/dist/commands/improve/distill/quality-gate.js +5 -7
- package/dist/commands/improve/distill.js +16 -5
- package/dist/commands/improve/eligibility.js +22 -12
- package/dist/commands/improve/extract-cli.js +47 -19
- package/dist/commands/improve/extract.js +110 -62
- package/dist/commands/improve/improve-cli.js +38 -16
- package/dist/commands/improve/improve-result-file.js +30 -24
- package/dist/commands/improve/improve-strategies.js +137 -0
- package/dist/commands/improve/improve.js +60 -30
- package/dist/commands/improve/locks.js +66 -45
- package/dist/commands/improve/loop-stages.js +75 -33
- package/dist/commands/improve/memory/memory-belief.js +79 -7
- package/dist/commands/improve/memory/memory-contradiction-detect.js +12 -4
- package/dist/commands/improve/preparation.js +71 -73
- package/dist/commands/improve/procedural.js +3 -2
- package/dist/commands/improve/recombine.js +2 -1
- package/dist/commands/improve/reflect.js +119 -214
- package/dist/commands/improve/shared.js +11 -5
- package/dist/commands/lint/base-linter.js +152 -42
- package/dist/commands/mv-cli.js +809 -0
- package/dist/commands/proposal/proposal-cli.js +18 -8
- package/dist/commands/proposal/propose.js +64 -69
- package/dist/commands/read/knowledge.js +436 -4
- package/dist/commands/read/remember-cli.js +39 -2
- package/dist/commands/read/search-cli.js +6 -1
- package/dist/commands/registry-cli.js +29 -14
- package/dist/commands/remember.js +2 -0
- package/dist/commands/sources/init.js +13 -14
- package/dist/commands/sources/schema-repair.js +2 -4
- package/dist/commands/sources/source-add.js +62 -73
- package/dist/commands/sources/source-manage.js +50 -46
- package/dist/commands/sources/stash-cli.js +41 -4
- package/dist/commands/tasks/default-tasks.js +12 -12
- package/dist/commands/tasks/tasks-cli.js +7 -3
- package/dist/commands/tasks/tasks.js +113 -18
- package/dist/commands/wiki-cli.js +9 -10
- package/dist/core/asset/frontmatter.js +12 -2
- package/dist/core/common.js +5 -3
- package/dist/core/config/config-io.js +28 -17
- package/dist/core/config/config-schema.js +358 -66
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config-version.js +29 -0
- package/dist/core/config/config-walker.js +98 -27
- package/dist/core/config/config.js +132 -266
- package/dist/core/config/deep-merge.js +41 -0
- package/dist/core/config/engine-semantics.js +32 -0
- package/dist/core/errors.js +2 -2
- package/dist/core/extra-params.js +61 -0
- package/dist/core/file-lock.js +201 -56
- package/dist/core/improve-result.js +178 -0
- package/dist/core/maintenance-barrier.js +119 -0
- package/dist/core/migration-backup.js +416 -0
- package/dist/core/paths.js +3 -0
- package/dist/core/redaction.js +358 -0
- package/dist/core/state/migrations.js +17 -2
- package/dist/core/state-db.js +44 -1
- package/dist/indexer/db/db.js +116 -1
- package/dist/indexer/graph/graph-extraction.js +28 -16
- package/dist/indexer/index-writer-lock.js +31 -24
- package/dist/indexer/index-written-assets.js +15 -6
- package/dist/indexer/indexer.js +47 -2
- package/dist/indexer/passes/memory-inference.js +10 -6
- package/dist/indexer/passes/metadata.js +250 -0
- package/dist/indexer/search/db-search.js +111 -44
- package/dist/indexer/search/fts-query.js +41 -0
- package/dist/indexer/search/ranking-contributors.js +48 -0
- package/dist/indexer/search/ranking.js +36 -23
- package/dist/indexer/search/search-fields.js +11 -1
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -52
- package/dist/integrations/agent/config.js +3 -143
- package/dist/integrations/agent/detect.js +17 -2
- package/dist/integrations/agent/engine-resolution.js +202 -0
- package/dist/integrations/agent/index.js +1 -2
- package/dist/integrations/agent/model-aliases.js +7 -2
- package/dist/integrations/agent/profiles.js +6 -99
- package/dist/integrations/agent/runner-dispatch.js +76 -13
- package/dist/integrations/agent/runner.js +76 -207
- package/dist/integrations/agent/spawn.js +4 -6
- package/dist/integrations/harnesses/aider/agent-builder.js +2 -3
- package/dist/integrations/harnesses/aider/index.js +0 -1
- package/dist/integrations/harnesses/amazonq/agent-builder.js +2 -3
- package/dist/integrations/harnesses/amazonq/index.js +0 -1
- package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
- package/dist/integrations/harnesses/claude/index.js +0 -2
- package/dist/integrations/harnesses/codex/agent-builder.js +2 -3
- package/dist/integrations/harnesses/codex/index.js +0 -1
- package/dist/integrations/harnesses/copilot/agent-builder.js +2 -3
- package/dist/integrations/harnesses/copilot/index.js +0 -1
- package/dist/integrations/harnesses/gemini/agent-builder.js +2 -3
- package/dist/integrations/harnesses/gemini/index.js +0 -1
- package/dist/integrations/harnesses/index.js +1 -24
- package/dist/integrations/harnesses/opencode/agent-builder.js +2 -3
- package/dist/integrations/harnesses/opencode/index.js +0 -6
- package/dist/integrations/harnesses/opencode-sdk/harness.js +1 -6
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
- package/dist/integrations/harnesses/openhands/agent-builder.js +2 -3
- package/dist/integrations/harnesses/openhands/index.js +0 -1
- package/dist/integrations/harnesses/pi/agent-builder.js +2 -3
- package/dist/integrations/harnesses/pi/index.js +0 -1
- package/dist/integrations/harnesses/types.js +1 -32
- package/dist/integrations/lockfile.js +32 -21
- package/dist/llm/client.js +48 -14
- package/dist/llm/feature-gate.js +15 -47
- package/dist/llm/graph-extract.js +1 -1
- package/dist/llm/index-passes.js +8 -42
- package/dist/llm/memory-infer-impl.js +1 -1
- package/dist/llm/usage-persist.js +4 -0
- package/dist/llm/usage-telemetry.js +35 -5
- package/dist/output/shapes/helpers.js +2 -1
- package/dist/output/shapes/passthrough.js +2 -0
- package/dist/output/text/helpers.js +3 -1
- package/dist/schemas/akm-config.json +11013 -8600
- package/dist/schemas/akm-task.json +87 -0
- package/dist/schemas/akm-workflow.json +57 -13
- package/dist/scripts/migrate-storage.js +8591 -509
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8623 -484
- package/dist/setup/detected-engines.js +142 -0
- package/dist/setup/engine-config.js +89 -0
- package/dist/setup/setup.js +236 -132
- package/dist/setup/steps/connection.js +61 -32
- package/dist/setup/steps/platforms.js +4 -4
- package/dist/setup/steps.js +3 -2
- package/dist/storage/database.js +13 -1
- package/dist/storage/engines/sqlite-migrations.js +1 -0
- package/dist/storage/repositories/improve-runs-repository.js +5 -5
- package/dist/storage/repositories/task-history-repository.js +78 -0
- package/dist/storage/repositories/workflow-runs-repository.js +9 -8
- package/dist/tasks/parser.js +138 -52
- package/dist/tasks/runner.js +71 -75
- package/dist/tasks/schema.js +1 -1
- package/dist/tasks/validator.js +11 -6
- package/dist/wiki/wiki.js +9 -8
- package/dist/workflows/authoring/workflow-program-template.yaml +3 -3
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/db.js +65 -13
- package/dist/workflows/exec/brief.js +18 -24
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +124 -65
- package/dist/workflows/exec/report.js +93 -33
- package/dist/workflows/exec/run-workflow.js +38 -25
- package/dist/workflows/exec/scheduler.js +12 -41
- package/dist/workflows/exec/step-work.js +91 -35
- package/dist/workflows/ir/compile.js +13 -26
- package/dist/workflows/ir/freeze.js +243 -0
- package/dist/workflows/ir/plan-hash.js +40 -5
- package/dist/workflows/ir/schema.js +542 -1
- package/dist/workflows/parser.js +7 -0
- package/dist/workflows/program/parser.js +132 -23
- package/dist/workflows/program/project.js +3 -4
- package/dist/workflows/program/schema.js +2 -2
- package/dist/workflows/resource-limits.js +20 -0
- package/dist/workflows/runtime/plan-classifier.js +187 -0
- package/dist/workflows/runtime/runs.js +54 -47
- package/dist/workflows/runtime/workflow-asset-loader.js +0 -22
- package/dist/workflows/validator.js +25 -0
- package/docs/data-and-telemetry.md +2 -2
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +5 -4
- package/docs/migration/v0.8-to-v0.9.md +401 -0
- package/package.json +4 -2
- package/schemas/akm-config.json +16638 -0
- package/schemas/akm-task.json +87 -0
- package/schemas/akm-workflow.json +372 -0
- package/dist/commands/improve/improve-profiles.js +0 -168
- package/dist/core/config/config-migration.js +0 -602
- package/dist/core/deep-merge.js +0 -38
- package/dist/llm/call-ai.js +0 -62
- package/dist/setup/legacy-config.js +0 -106
- package/docs/README.md +0 -104
- /package/dist/assets/{profiles → improve-strategies}/catchup.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/consolidate.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/frequent.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/memory-focus.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/quick.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/recombine-only.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/synthesize.json +0 -0
- /package/dist/assets/{profiles → improve-strategies}/thorough.json +0 -0
|
@@ -34,7 +34,11 @@
|
|
|
34
34
|
* enforced at save time via `superRefine` on the top-level schema.
|
|
35
35
|
*/
|
|
36
36
|
import { z } from "zod";
|
|
37
|
-
import {
|
|
37
|
+
import { validateExtraParams } from "../extra-params.js";
|
|
38
|
+
import { HARNESS_BY_ID, VALID_HARNESS_IDS } from "./config-types.js";
|
|
39
|
+
import { BUILTIN_IMPROVE_STRATEGY_NAMES, ENGINE_NAME_PATTERN_SOURCE, IMPROVE_PROCESS_ENGINE_CAPABILITIES, } from "./engine-semantics.js";
|
|
40
|
+
/** Persisted config schema version. Package prerelease/patch versions do not change this value. */
|
|
41
|
+
export const CURRENT_CONFIG_VERSION = "0.9.0";
|
|
38
42
|
// ── Reusable atomic schemas ─────────────────────────────────────────────────
|
|
39
43
|
/** Positive integer (used for tokens, timeouts, batch sizes). */
|
|
40
44
|
const positiveInt = z.number().int().positive();
|
|
@@ -49,6 +53,57 @@ const nonEmptyString = z
|
|
|
49
53
|
const httpUrl = z.string().refine((v) => v.startsWith("http://") || v.startsWith("https://"), {
|
|
50
54
|
message: "endpoint must start with http:// or https://",
|
|
51
55
|
});
|
|
56
|
+
const ENGINE_NAME_PATTERN = new RegExp(ENGINE_NAME_PATTERN_SOURCE);
|
|
57
|
+
const ENV_REFERENCE_PATTERN = /^\$[A-Za-z_][A-Za-z0-9_]*$|^\$\{[A-Za-z_][A-Za-z0-9_]*\}$/;
|
|
58
|
+
const engineName = z
|
|
59
|
+
.string()
|
|
60
|
+
.max(63)
|
|
61
|
+
.regex(ENGINE_NAME_PATTERN, "names must be lowercase kebab-case and must not begin with reserved akm-");
|
|
62
|
+
const chatCompletionsEndpoint = z.string().superRefine((value, ctx) => {
|
|
63
|
+
try {
|
|
64
|
+
const url = new URL(value);
|
|
65
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
66
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "endpoint must use http:// or https://" });
|
|
67
|
+
}
|
|
68
|
+
if (url.username || url.password || url.search || url.hash || !url.pathname.endsWith("/chat/completions")) {
|
|
69
|
+
ctx.addIssue({
|
|
70
|
+
code: z.ZodIssueCode.custom,
|
|
71
|
+
message: "endpoint must be a credential-free OpenAI chat-completions URL without query or fragment",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "endpoint must be a complete URL" });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
const ExtraParamsSchema = z.record(z.unknown()).superRefine((value, ctx) => {
|
|
80
|
+
for (const issue of validateExtraParams(value)) {
|
|
81
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: issue.path, message: issue.message });
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
function normalizeAliasKeys(raw, ctx) {
|
|
85
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
86
|
+
return raw;
|
|
87
|
+
const normalized = {};
|
|
88
|
+
const originalByKey = new Map();
|
|
89
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
90
|
+
const lower = key.toLowerCase();
|
|
91
|
+
const previous = originalByKey.get(lower);
|
|
92
|
+
if (previous !== undefined) {
|
|
93
|
+
ctx.addIssue({
|
|
94
|
+
code: z.ZodIssueCode.custom,
|
|
95
|
+
path: [key],
|
|
96
|
+
message: `alias collides case-insensitively with ${previous}`,
|
|
97
|
+
});
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
originalByKey.set(lower, key);
|
|
101
|
+
normalized[lower] = value;
|
|
102
|
+
}
|
|
103
|
+
return normalized;
|
|
104
|
+
}
|
|
105
|
+
const ModelAliasMapSchema = z.preprocess((raw, ctx) => normalizeAliasKeys(raw, ctx), z.record(z.string().min(1), z.string().min(1)));
|
|
106
|
+
const GlobalModelAliasesSchema = z.preprocess((raw, ctx) => normalizeAliasKeys(raw, ctx), z.record(z.string().min(1), z.record(z.string().min(1), z.string().min(1))));
|
|
52
107
|
// ── Feedback failure modes (F-3 / #384) ─────────────────────────────────────
|
|
53
108
|
/**
|
|
54
109
|
* Curated taxonomy of failure modes for negative feedback.
|
|
@@ -71,8 +126,8 @@ const LlmCapabilitiesSchema = z
|
|
|
71
126
|
})
|
|
72
127
|
.passthrough();
|
|
73
128
|
/**
|
|
74
|
-
*
|
|
75
|
-
*
|
|
129
|
+
* OpenAI-compatible connection fields shared by named LLM engines and bounded
|
|
130
|
+
* internal call helpers. `model` is required at schema level — partial entries
|
|
76
131
|
* created by `akm config set llm.endpoint <url>` (where model is left absent)
|
|
77
132
|
* are normalized to `model: ""` *before* Zod sees them by the load-time
|
|
78
133
|
* pre-Zod migrator hook, so this strict shape gates CLI writes without
|
|
@@ -86,12 +141,11 @@ export const LlmConnectionConfigSchema = z
|
|
|
86
141
|
apiKey: z.string().optional(),
|
|
87
142
|
temperature: z.number().finite().optional(),
|
|
88
143
|
maxTokens: positiveInt.optional(),
|
|
89
|
-
timeoutMs: positiveInt.optional(),
|
|
144
|
+
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
90
145
|
concurrency: positiveInt.optional(),
|
|
91
146
|
capabilities: LlmCapabilitiesSchema.optional(),
|
|
92
|
-
extraParams:
|
|
147
|
+
extraParams: ExtraParamsSchema.optional(),
|
|
93
148
|
contextLength: positiveInt.optional(),
|
|
94
|
-
judgeModel: z.string().min(1).optional(),
|
|
95
149
|
enableThinking: z.boolean().optional(),
|
|
96
150
|
})
|
|
97
151
|
.passthrough();
|
|
@@ -117,7 +171,7 @@ export const EmbeddingConnectionConfigSchema = z
|
|
|
117
171
|
provider: z.string().optional(),
|
|
118
172
|
endpoint: z.string().optional(),
|
|
119
173
|
model: z.string().optional(),
|
|
120
|
-
apiKey: z.string().optional(),
|
|
174
|
+
apiKey: z.string().regex(ENV_REFERENCE_PATTERN, `apiKey must be $VAR or \${VAR}`).optional(),
|
|
121
175
|
dimension: positiveInt.optional(),
|
|
122
176
|
localModel: z.string().min(1).optional(),
|
|
123
177
|
maxTokens: positiveInt.optional(),
|
|
@@ -127,34 +181,94 @@ export const EmbeddingConnectionConfigSchema = z
|
|
|
127
181
|
ollamaOptions: EmbeddingOllamaOptionsSchema.optional(),
|
|
128
182
|
})
|
|
129
183
|
.passthrough();
|
|
130
|
-
// ── Agent
|
|
184
|
+
// ── Agent engines ───────────────────────────────────────────────────────────
|
|
131
185
|
// Derives from the canonical VALID_HARNESS_IDS (#565) so the Zod gate cannot
|
|
132
186
|
// drift from the TS union / parse check / setup detection.
|
|
133
187
|
const AgentPlatformSchema = z.enum(VALID_HARNESS_IDS);
|
|
134
|
-
export const
|
|
188
|
+
export const LlmInvocationOverridesSchema = z
|
|
189
|
+
.object({
|
|
190
|
+
temperature: z.number().finite().optional(),
|
|
191
|
+
maxTokens: positiveInt.optional(),
|
|
192
|
+
supportsJsonSchema: z.boolean().optional(),
|
|
193
|
+
extraParams: ExtraParamsSchema.optional(),
|
|
194
|
+
contextLength: positiveInt.optional(),
|
|
195
|
+
enableThinking: z.boolean().optional(),
|
|
196
|
+
})
|
|
197
|
+
.passthrough();
|
|
198
|
+
const LlmEngineSchema = z
|
|
199
|
+
.object({
|
|
200
|
+
kind: z.literal("llm"),
|
|
201
|
+
provider: z.string().optional(),
|
|
202
|
+
endpoint: chatCompletionsEndpoint,
|
|
203
|
+
model: nonEmptyString,
|
|
204
|
+
apiKey: z.string().regex(ENV_REFERENCE_PATTERN, `apiKey must be $VAR or \${VAR}`).optional(),
|
|
205
|
+
temperature: z.number().finite().optional(),
|
|
206
|
+
maxTokens: positiveInt.optional(),
|
|
207
|
+
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
208
|
+
concurrency: positiveInt.optional(),
|
|
209
|
+
supportsJsonSchema: z.boolean().optional(),
|
|
210
|
+
extraParams: ExtraParamsSchema.optional(),
|
|
211
|
+
contextLength: positiveInt.optional(),
|
|
212
|
+
enableThinking: z.boolean().optional(),
|
|
213
|
+
})
|
|
214
|
+
.passthrough()
|
|
215
|
+
.superRefine((value, ctx) => {
|
|
216
|
+
for (const key of ["platform", "bin", "args", "workspace", "modelAliases", "llmEngine"]) {
|
|
217
|
+
if (key in value)
|
|
218
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an LLM engine` });
|
|
219
|
+
}
|
|
220
|
+
});
|
|
221
|
+
const AgentEngineSchema = z
|
|
135
222
|
.object({
|
|
136
|
-
|
|
137
|
-
|
|
223
|
+
kind: z.literal("agent"),
|
|
224
|
+
platform: AgentPlatformSchema.refine((platform) => HARNESS_BY_ID.get(platform)?.capabilities.agentDispatch === true, {
|
|
225
|
+
message: "platform does not support agent dispatch",
|
|
226
|
+
}),
|
|
227
|
+
bin: nonEmptyString.optional(),
|
|
138
228
|
args: z.array(z.string()).optional(),
|
|
139
|
-
workspace:
|
|
140
|
-
model:
|
|
141
|
-
// Per-call timeout (ms) used when a command does not pass an explicit
|
|
142
|
-
// timeout (e.g. `akm wiki ingest` without `--timeout-ms`). null = no
|
|
143
|
-
// timeout. Honored by resolveAgentProfile (integrations/agent/config.ts).
|
|
229
|
+
workspace: nonEmptyString.optional(),
|
|
230
|
+
model: nonEmptyString.optional(),
|
|
144
231
|
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
// (integrations/agent/model-aliases.ts) — beats the config-root
|
|
148
|
-
// `modelAliases` table and the built-in opus/sonnet/haiku entries.
|
|
149
|
-
modelAliases: z.record(z.string().min(1), z.string().min(1)).optional(),
|
|
232
|
+
modelAliases: ModelAliasMapSchema.optional(),
|
|
233
|
+
llmEngine: engineName.optional(),
|
|
150
234
|
})
|
|
151
|
-
.passthrough()
|
|
235
|
+
.passthrough()
|
|
236
|
+
.superRefine((value, ctx) => {
|
|
237
|
+
for (const key of [
|
|
238
|
+
"provider",
|
|
239
|
+
"endpoint",
|
|
240
|
+
"apiKey",
|
|
241
|
+
"temperature",
|
|
242
|
+
"maxTokens",
|
|
243
|
+
"concurrency",
|
|
244
|
+
"supportsJsonSchema",
|
|
245
|
+
"extraParams",
|
|
246
|
+
"contextLength",
|
|
247
|
+
"enableThinking",
|
|
248
|
+
]) {
|
|
249
|
+
if (key in value)
|
|
250
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: [key], message: `${key} is not valid on an agent engine` });
|
|
251
|
+
}
|
|
252
|
+
if (value.platform !== "opencode-sdk" && value.llmEngine !== undefined) {
|
|
253
|
+
ctx.addIssue({
|
|
254
|
+
code: z.ZodIssueCode.custom,
|
|
255
|
+
path: ["llmEngine"],
|
|
256
|
+
message: "llmEngine is only valid on opencode-sdk",
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
if (value.platform === "opencode-sdk" && value.args !== undefined) {
|
|
260
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: ["args"], message: "args is not valid on opencode-sdk" });
|
|
261
|
+
}
|
|
262
|
+
});
|
|
263
|
+
export const EngineConfigSchema = z.union([LlmEngineSchema, AgentEngineSchema]);
|
|
264
|
+
export const EnginesSchema = z.record(engineName, EngineConfigSchema);
|
|
152
265
|
// ── Improve profile / process ──────────────────────────────────────────────
|
|
153
266
|
export const ImproveProcessConfigSchema = z
|
|
154
267
|
.object({
|
|
268
|
+
engine: engineName.optional(),
|
|
269
|
+
model: nonEmptyString.optional(),
|
|
270
|
+
llm: LlmInvocationOverridesSchema.optional(),
|
|
155
271
|
enabled: z.boolean().optional(),
|
|
156
|
-
mode: z.enum(["llm", "agent", "sdk"]).optional(),
|
|
157
|
-
profile: z.string().min(1).optional(),
|
|
158
272
|
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
159
273
|
allowedTypes: z.array(z.string().min(1)).optional(),
|
|
160
274
|
// Consolidate process: minimum eligible-memory pool size below which the
|
|
@@ -226,6 +340,10 @@ export const ImproveProcessConfigSchema = z
|
|
|
226
340
|
// high-signal-first sweep). Unset = process all eligible (current
|
|
227
341
|
// behavior). Only meaningful on `graphExtraction`.
|
|
228
342
|
topN: positiveInt.optional(),
|
|
343
|
+
// Improve-owned graph extraction scope and batching. These are passed to
|
|
344
|
+
// the invocation directly and never inherited from standalone index.graph.
|
|
345
|
+
includeTypes: z.array(z.string().min(1)).min(1).optional(),
|
|
346
|
+
batchSize: positiveInt.optional(),
|
|
229
347
|
// graphExtraction process: full-corpus scan. When true, graph extraction
|
|
230
348
|
// runs on ALL stash files instead of only files touched by actionable refs
|
|
231
349
|
// in the current run. Used by the `graph-refresh` built-in profile / a
|
|
@@ -399,14 +517,34 @@ export const ImproveProcessConfigSchema = z
|
|
|
399
517
|
rejectEmpty: z.boolean().optional(),
|
|
400
518
|
judgment: z
|
|
401
519
|
.object({
|
|
402
|
-
|
|
403
|
-
|
|
520
|
+
engine: engineName.optional(),
|
|
521
|
+
model: nonEmptyString.optional(),
|
|
404
522
|
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
523
|
+
llm: LlmInvocationOverridesSchema.optional(),
|
|
405
524
|
})
|
|
406
525
|
.passthrough()
|
|
407
526
|
.optional(),
|
|
408
527
|
})
|
|
409
|
-
.passthrough()
|
|
528
|
+
.passthrough()
|
|
529
|
+
.superRefine((value, ctx) => {
|
|
530
|
+
for (const key of ["mode", "profile"]) {
|
|
531
|
+
if (key in value) {
|
|
532
|
+
ctx.addIssue({ code: z.ZodIssueCode.custom, path: [key], message: `${key} is retired; use engine` });
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
const judgment = value.judgment;
|
|
536
|
+
if (judgment) {
|
|
537
|
+
for (const key of ["mode", "profile"]) {
|
|
538
|
+
if (key in judgment) {
|
|
539
|
+
ctx.addIssue({
|
|
540
|
+
code: z.ZodIssueCode.custom,
|
|
541
|
+
path: ["judgment", key],
|
|
542
|
+
message: `${key} is retired; use engine`,
|
|
543
|
+
});
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
});
|
|
410
548
|
const ImproveProfileProcessesSchema = z
|
|
411
549
|
.object({
|
|
412
550
|
reflect: ImproveProcessConfigSchema.optional(),
|
|
@@ -439,6 +577,10 @@ const ImproveProfileProcessesSchema = z
|
|
|
439
577
|
});
|
|
440
578
|
export const ImproveProfileConfigSchema = z
|
|
441
579
|
.object({
|
|
580
|
+
engine: engineName.optional(),
|
|
581
|
+
model: nonEmptyString.optional(),
|
|
582
|
+
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
583
|
+
llm: LlmInvocationOverridesSchema.optional(),
|
|
442
584
|
description: z.string().min(1).optional(),
|
|
443
585
|
processes: ImproveProfileProcessesSchema.optional(),
|
|
444
586
|
autoAccept: nonNegativeNumber.optional(),
|
|
@@ -463,19 +605,12 @@ export const ImproveProfileConfigSchema = z
|
|
|
463
605
|
.optional(),
|
|
464
606
|
})
|
|
465
607
|
.passthrough();
|
|
466
|
-
// ──
|
|
467
|
-
export const ProfilesSchema = z
|
|
468
|
-
.object({
|
|
469
|
-
llm: z.record(z.string(), LlmProfileConfigSchema).optional(),
|
|
470
|
-
agent: z.record(z.string(), AgentProfileConfigSchema).optional(),
|
|
471
|
-
improve: z.record(z.string(), ImproveProfileConfigSchema).optional(),
|
|
472
|
-
})
|
|
473
|
-
.passthrough();
|
|
608
|
+
// ── Defaults ───────────────────────────────────────────────────────────────
|
|
474
609
|
export const DefaultsSchema = z
|
|
475
610
|
.object({
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
611
|
+
engine: engineName.optional(),
|
|
612
|
+
llmEngine: engineName.optional(),
|
|
613
|
+
improveStrategy: engineName.optional(),
|
|
479
614
|
})
|
|
480
615
|
.passthrough();
|
|
481
616
|
// ── Sources / registries / installed ────────────────────────────────────────
|
|
@@ -503,6 +638,13 @@ export const SourceConfigEntrySchema = z
|
|
|
503
638
|
})
|
|
504
639
|
.passthrough()
|
|
505
640
|
.superRefine((entry, ctx) => {
|
|
641
|
+
if (!["filesystem", "git", "website", "npm"].includes(entry.type)) {
|
|
642
|
+
ctx.addIssue({
|
|
643
|
+
code: z.ZodIssueCode.custom,
|
|
644
|
+
path: ["type"],
|
|
645
|
+
message: `unsupported source type "${entry.type}"; expected filesystem, git, website, or npm`,
|
|
646
|
+
});
|
|
647
|
+
}
|
|
506
648
|
if (entry.writable === true && (entry.type === "website" || entry.type === "npm")) {
|
|
507
649
|
ctx.addIssue({
|
|
508
650
|
code: z.ZodIssueCode.custom,
|
|
@@ -673,6 +815,7 @@ const ImproveCollapseDetectorSchema = z
|
|
|
673
815
|
.passthrough();
|
|
674
816
|
export const ImproveConfigSchema = z
|
|
675
817
|
.object({
|
|
818
|
+
strategies: z.record(engineName, ImproveProfileConfigSchema).optional(),
|
|
676
819
|
utilityDecay: ImproveUtilityDecaySchema.optional(),
|
|
677
820
|
eventRetentionDays: nonNegativeNumber.optional(),
|
|
678
821
|
calibration: ImproveCalibrationSchema.optional(),
|
|
@@ -694,9 +837,8 @@ const GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED = [
|
|
|
694
837
|
"wiki",
|
|
695
838
|
"fact",
|
|
696
839
|
];
|
|
697
|
-
const
|
|
840
|
+
const INDEX_PASS_RETIRED_KEYS = new Set([
|
|
698
841
|
"endpoint",
|
|
699
|
-
"model",
|
|
700
842
|
"provider",
|
|
701
843
|
"apiKey",
|
|
702
844
|
"baseUrl",
|
|
@@ -705,16 +847,19 @@ const INDEX_PASS_PROVIDER_KEYS = new Set([
|
|
|
705
847
|
"capabilities",
|
|
706
848
|
]);
|
|
707
849
|
const INDEX_PASS_KNOWN_KEYS = new Set([
|
|
850
|
+
"engine",
|
|
851
|
+
"model",
|
|
852
|
+
"timeoutMs",
|
|
853
|
+
"enabled",
|
|
708
854
|
"llm",
|
|
709
855
|
"graphExtractionBatchSize",
|
|
710
856
|
"graphExtractionIncludeTypes",
|
|
711
|
-
"memoryInferenceBatchSize",
|
|
712
857
|
"lazyGraphExtraction",
|
|
713
858
|
]);
|
|
714
859
|
/**
|
|
715
860
|
* Per-pass `index.<pass>` entry. Uses preprocess + manual validation so we can
|
|
716
|
-
* emit
|
|
717
|
-
*
|
|
861
|
+
* emit targeted error messages ("Retired or misplaced engine setting",
|
|
862
|
+
* "Unknown key `index.<pass>.<key>`")
|
|
718
863
|
* instead of Zod's generic `Unrecognized key` / `Expected boolean, received
|
|
719
864
|
* string` strings — keeps `akm` startup errors actionable.
|
|
720
865
|
*/
|
|
@@ -724,38 +869,34 @@ export const IndexPassConfigSchema = z.preprocess((raw, ctx) => {
|
|
|
724
869
|
}
|
|
725
870
|
const obj = raw;
|
|
726
871
|
for (const key of Object.keys(obj)) {
|
|
727
|
-
if (
|
|
872
|
+
if (INDEX_PASS_RETIRED_KEYS.has(key)) {
|
|
728
873
|
ctx.addIssue({
|
|
729
874
|
code: z.ZodIssueCode.custom,
|
|
730
|
-
message: `
|
|
731
|
-
"
|
|
875
|
+
message: `Retired or misplaced engine setting: \`${[...(ctx.path ?? []), key].join(".")}\` is not allowed. ` +
|
|
876
|
+
"Select a named engine and use typed invocation fields instead.",
|
|
732
877
|
});
|
|
733
878
|
return raw;
|
|
734
879
|
}
|
|
735
880
|
if (!INDEX_PASS_KNOWN_KEYS.has(key)) {
|
|
736
881
|
ctx.addIssue({
|
|
737
882
|
code: z.ZodIssueCode.custom,
|
|
738
|
-
message: `Unknown key \`${[...(ctx.path ?? []), key].join(".")}\`. Per-pass entries support
|
|
739
|
-
"
|
|
740
|
-
"`
|
|
883
|
+
message: `Unknown key \`${[...(ctx.path ?? []), key].join(".")}\`. Per-pass entries support ` +
|
|
884
|
+
"`engine`, `model`, `timeoutMs`, `enabled`, `llm`, `graphExtractionBatchSize`, " +
|
|
885
|
+
"`graphExtractionIncludeTypes`, and `lazyGraphExtraction`.",
|
|
741
886
|
});
|
|
742
887
|
return raw;
|
|
743
888
|
}
|
|
744
889
|
}
|
|
745
|
-
if ("llm" in obj && typeof obj.llm !== "boolean") {
|
|
746
|
-
ctx.addIssue({
|
|
747
|
-
code: z.ZodIssueCode.custom,
|
|
748
|
-
message: `Invalid \`${[...(ctx.path ?? []), "llm"].join(".")}\`: expected a boolean (true to use the default LLM profile, false to opt out). Got ${typeof obj.llm}.`,
|
|
749
|
-
});
|
|
750
|
-
return raw;
|
|
751
|
-
}
|
|
752
890
|
return raw;
|
|
753
891
|
}, z
|
|
754
892
|
.object({
|
|
755
|
-
|
|
893
|
+
engine: engineName.optional(),
|
|
894
|
+
model: nonEmptyString.optional(),
|
|
895
|
+
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
896
|
+
enabled: z.boolean().optional(),
|
|
897
|
+
llm: LlmInvocationOverridesSchema.optional(),
|
|
756
898
|
graphExtractionBatchSize: positiveInt.optional(),
|
|
757
899
|
graphExtractionIncludeTypes: z.array(z.enum(GRAPH_EXTRACTION_INCLUDE_TYPES_ALLOWED)).nonempty().optional(),
|
|
758
|
-
memoryInferenceBatchSize: positiveInt.optional(),
|
|
759
900
|
lazyGraphExtraction: z.boolean().optional(),
|
|
760
901
|
})
|
|
761
902
|
.passthrough());
|
|
@@ -773,35 +914,61 @@ const StalenessDetectionSchema = z
|
|
|
773
914
|
thresholdDays: positiveInt.optional(),
|
|
774
915
|
})
|
|
775
916
|
.passthrough();
|
|
917
|
+
const IndexDefaultsSchema = z
|
|
918
|
+
.object({
|
|
919
|
+
engine: engineName.optional(),
|
|
920
|
+
model: nonEmptyString.optional(),
|
|
921
|
+
timeoutMs: z.union([positiveInt, z.null()]).optional(),
|
|
922
|
+
llm: LlmInvocationOverridesSchema.optional(),
|
|
923
|
+
})
|
|
924
|
+
.passthrough();
|
|
776
925
|
/**
|
|
777
926
|
* Index config is a union of reserved feature sections and per-pass entries.
|
|
778
927
|
* Passthrough so per-pass entries (keyed by arbitrary pass names like `graph`,
|
|
779
928
|
* `enrichment`) can live next to the reserved keys.
|
|
780
929
|
*
|
|
930
|
+
* Reserved scalar key `indexBodyOpening` (stash-conventions SPEC-8, default
|
|
931
|
+
* false): when true, the metadata pass captures the first prose paragraph of
|
|
932
|
+
* each markdown asset body into `entry.bodyOpening`, which folds into the
|
|
933
|
+
* lowest-weight `content` FTS column and the embedding text. It is a boolean,
|
|
934
|
+
* not a per-pass object — the preprocess below exempts it from the
|
|
935
|
+
* object-shape check so it never routes into the per-pass catchall.
|
|
936
|
+
*
|
|
781
937
|
* The outer preprocess emits the legacy parser's actionable error messages
|
|
782
938
|
* for the two most common type-shape mistakes:
|
|
783
939
|
* - An array at the `index` block.
|
|
784
940
|
* - A non-object at `index.<passName>`.
|
|
785
|
-
* Inner field validation (graphExtractionIncludeTypes enum,
|
|
786
|
-
* provider-key rejection) is delegated to {@link IndexPassConfigSchema}.
|
|
941
|
+
* Inner field validation (graphExtractionIncludeTypes enum, invocation
|
|
942
|
+
* overrides, provider-key rejection) is delegated to {@link IndexPassConfigSchema}.
|
|
787
943
|
*/
|
|
788
|
-
|
|
944
|
+
const IndexConfigRuntimeSchema = z.preprocess((raw, ctx) => {
|
|
789
945
|
if (raw === undefined || raw === null)
|
|
790
946
|
return raw;
|
|
791
947
|
if (Array.isArray(raw)) {
|
|
792
948
|
ctx.addIssue({
|
|
793
949
|
code: z.ZodIssueCode.custom,
|
|
794
|
-
message: 'Invalid `index` config: expected an object keyed by pass name (e.g. `{ "enrichment": { "
|
|
950
|
+
message: 'Invalid `index` config: expected an object keyed by pass name (e.g. `{ "enrichment": { "enabled": false } }`).',
|
|
795
951
|
});
|
|
796
952
|
return raw;
|
|
797
953
|
}
|
|
798
954
|
if (typeof raw !== "object")
|
|
799
955
|
return raw;
|
|
800
956
|
for (const [passName, value] of Object.entries(raw)) {
|
|
957
|
+
if (passName === "indexBodyOpening") {
|
|
958
|
+
if (typeof value !== "boolean") {
|
|
959
|
+
ctx.addIssue({
|
|
960
|
+
code: z.ZodIssueCode.custom,
|
|
961
|
+
message: "Invalid `index.indexBodyOpening`: expected a boolean (true to index the first body paragraph " +
|
|
962
|
+
`of markdown assets into search). Got ${Array.isArray(value) ? "array" : typeof value}.`,
|
|
963
|
+
});
|
|
964
|
+
return raw;
|
|
965
|
+
}
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
801
968
|
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
802
969
|
ctx.addIssue({
|
|
803
970
|
code: z.ZodIssueCode.custom,
|
|
804
|
-
message: `Invalid \`index.${passName}\` config: expected an object like \`{ "
|
|
971
|
+
message: `Invalid \`index.${passName}\` config: expected an object like \`{ "enabled": false }\`.`,
|
|
805
972
|
});
|
|
806
973
|
return raw;
|
|
807
974
|
}
|
|
@@ -828,10 +995,23 @@ export const IndexConfigSchema = z.preprocess((raw, ctx) => {
|
|
|
828
995
|
return raw;
|
|
829
996
|
}, z
|
|
830
997
|
.object({
|
|
998
|
+
defaults: IndexDefaultsSchema.optional(),
|
|
831
999
|
metadataEnhance: MetadataEnhanceSchema.optional(),
|
|
832
1000
|
stalenessDetection: StalenessDetectionSchema.optional(),
|
|
1001
|
+
indexBodyOpening: z
|
|
1002
|
+
.boolean()
|
|
1003
|
+
.optional()
|
|
1004
|
+
.describe("Index the first prose paragraph of each markdown asset body (capped at 280 chars) into the " +
|
|
1005
|
+
"lowest-weight `content` search column and the embedding text (default false). Secret/env files " +
|
|
1006
|
+
"and session-kind memories are never captured. Toggling the flag changes indexed text: run " +
|
|
1007
|
+
"`akm index --full` afterwards to re-extract every entry and regenerate embeddings, and re-mint " +
|
|
1008
|
+
"collapse-detector canary baselines via `akm improve canary --refresh`."),
|
|
833
1009
|
})
|
|
834
1010
|
.catchall(IndexPassConfigSchema));
|
|
1011
|
+
// The runtime catchall correctly validates arbitrary pass objects, but its
|
|
1012
|
+
// inferred string index signature also covers reserved scalar keys. Publish a
|
|
1013
|
+
// precise output type while retaining the stricter runtime and JSON schemas.
|
|
1014
|
+
export const IndexConfigSchema = IndexConfigRuntimeSchema;
|
|
835
1015
|
// ── Workflow engine ─────────────────────────────────────────────────────────
|
|
836
1016
|
/**
|
|
837
1017
|
* Workflow-engine settings (`workflow`).
|
|
@@ -883,8 +1063,8 @@ export const SetupConfigSchema = z
|
|
|
883
1063
|
* one-time 0.7→0.8 input transforms before the schema sees the value.
|
|
884
1064
|
*/
|
|
885
1065
|
export const AkmConfigShape = {
|
|
886
|
-
configVersion: z.
|
|
887
|
-
|
|
1066
|
+
configVersion: z.literal(CURRENT_CONFIG_VERSION),
|
|
1067
|
+
engines: EnginesSchema.optional(),
|
|
888
1068
|
defaults: DefaultsSchema.optional(),
|
|
889
1069
|
// Global model-alias tiers: alias → platform → exact model string, with a
|
|
890
1070
|
// reserved `"*"` platform key as fallback. Lets workflows/callers name a
|
|
@@ -894,7 +1074,7 @@ export const AkmConfigShape = {
|
|
|
894
1074
|
// builder resolves against ("claude", "opencode", "opencode-sdk", or a
|
|
895
1075
|
// custom profile's name for the default builder) — unknown keys are inert.
|
|
896
1076
|
// Precedence: profile modelAliases > this table > built-in aliases.
|
|
897
|
-
modelAliases:
|
|
1077
|
+
modelAliases: GlobalModelAliasesSchema.optional(),
|
|
898
1078
|
stashDir: nonEmptyString.optional(),
|
|
899
1079
|
semanticSearchMode: z.enum(["off", "auto"]).default("auto"),
|
|
900
1080
|
embedding: EmbeddingConnectionConfigSchema.optional(),
|
|
@@ -920,6 +1100,118 @@ export const AkmConfigShape = {
|
|
|
920
1100
|
};
|
|
921
1101
|
export const AkmConfigBaseSchema = z.object(AkmConfigShape).passthrough();
|
|
922
1102
|
export const AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
|
|
1103
|
+
const raw = config;
|
|
1104
|
+
for (const key of ["profiles", "llm", "agent", "features", "stashes"]) {
|
|
1105
|
+
if (key in raw) {
|
|
1106
|
+
ctx.addIssue({
|
|
1107
|
+
code: z.ZodIssueCode.custom,
|
|
1108
|
+
path: [key],
|
|
1109
|
+
message: `${key} is retired in 0.9; configure engines and improve.strategies instead`,
|
|
1110
|
+
});
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
for (const key of ["llm", "agent", "improve"]) {
|
|
1114
|
+
if (config.defaults && key in config.defaults) {
|
|
1115
|
+
ctx.addIssue({
|
|
1116
|
+
code: z.ZodIssueCode.custom,
|
|
1117
|
+
path: ["defaults", key],
|
|
1118
|
+
message: `defaults.${key} is retired in 0.9`,
|
|
1119
|
+
});
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
for (const [name, engine] of Object.entries(config.engines ?? {})) {
|
|
1123
|
+
if (engine.kind === "agent" && engine.llmEngine) {
|
|
1124
|
+
const fallback = config.engines?.[engine.llmEngine];
|
|
1125
|
+
if (!fallback || fallback.kind !== "llm") {
|
|
1126
|
+
ctx.addIssue({
|
|
1127
|
+
code: z.ZodIssueCode.custom,
|
|
1128
|
+
path: ["engines", name, "llmEngine"],
|
|
1129
|
+
message: "llmEngine must name an LLM engine",
|
|
1130
|
+
});
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
const defaultEngine = config.defaults?.engine;
|
|
1135
|
+
if (defaultEngine && !config.engines?.[defaultEngine]) {
|
|
1136
|
+
ctx.addIssue({
|
|
1137
|
+
code: z.ZodIssueCode.custom,
|
|
1138
|
+
path: ["defaults", "engine"],
|
|
1139
|
+
message: "engine does not name a configured engine",
|
|
1140
|
+
});
|
|
1141
|
+
}
|
|
1142
|
+
const defaultLlm = config.defaults?.llmEngine;
|
|
1143
|
+
if (defaultLlm && config.engines?.[defaultLlm]?.kind !== "llm") {
|
|
1144
|
+
ctx.addIssue({
|
|
1145
|
+
code: z.ZodIssueCode.custom,
|
|
1146
|
+
path: ["defaults", "llmEngine"],
|
|
1147
|
+
message: "llmEngine must name an LLM engine",
|
|
1148
|
+
});
|
|
1149
|
+
}
|
|
1150
|
+
const defaultStrategy = config.defaults?.improveStrategy;
|
|
1151
|
+
if (defaultStrategy &&
|
|
1152
|
+
!BUILTIN_IMPROVE_STRATEGY_NAMES.includes(defaultStrategy) &&
|
|
1153
|
+
!config.improve?.strategies?.[defaultStrategy]) {
|
|
1154
|
+
ctx.addIssue({
|
|
1155
|
+
code: z.ZodIssueCode.custom,
|
|
1156
|
+
path: ["defaults", "improveStrategy"],
|
|
1157
|
+
message: "improveStrategy does not name a built-in or configured strategy",
|
|
1158
|
+
});
|
|
1159
|
+
}
|
|
1160
|
+
for (const [strategyName, strategy] of Object.entries(config.improve?.strategies ?? {})) {
|
|
1161
|
+
const strategyEngine = strategy.engine;
|
|
1162
|
+
if (strategyEngine) {
|
|
1163
|
+
const engine = config.engines?.[strategyEngine];
|
|
1164
|
+
if (!engine || engine.kind !== "llm") {
|
|
1165
|
+
ctx.addIssue({
|
|
1166
|
+
code: z.ZodIssueCode.custom,
|
|
1167
|
+
path: ["improve", "strategies", strategyName, "engine"],
|
|
1168
|
+
message: engine ? "strategy engine must be an LLM engine" : "engine does not name a configured engine",
|
|
1169
|
+
});
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
for (const [processName, process] of Object.entries(strategy.processes ?? {})) {
|
|
1173
|
+
const processConfig = process;
|
|
1174
|
+
const capability = IMPROVE_PROCESS_ENGINE_CAPABILITIES[processName];
|
|
1175
|
+
if (processConfig.engine && capability === null) {
|
|
1176
|
+
ctx.addIssue({
|
|
1177
|
+
code: z.ZodIssueCode.custom,
|
|
1178
|
+
path: ["improve", "strategies", strategyName, "processes", processName, "engine"],
|
|
1179
|
+
message: `${processName} does not dispatch an engine`,
|
|
1180
|
+
});
|
|
1181
|
+
}
|
|
1182
|
+
else {
|
|
1183
|
+
const processEngine = processConfig.engine ?? strategyEngine;
|
|
1184
|
+
if (processEngine && capability === "llm") {
|
|
1185
|
+
const engine = config.engines?.[processEngine];
|
|
1186
|
+
if (!engine || engine.kind !== "llm") {
|
|
1187
|
+
ctx.addIssue({
|
|
1188
|
+
code: z.ZodIssueCode.custom,
|
|
1189
|
+
path: ["improve", "strategies", strategyName, "processes", processName, "engine"],
|
|
1190
|
+
message: engine ? `${processName} requires an LLM engine` : "engine does not name a configured engine",
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
else if (processConfig.engine && capability === "runner" && !config.engines?.[processConfig.engine]) {
|
|
1195
|
+
ctx.addIssue({
|
|
1196
|
+
code: z.ZodIssueCode.custom,
|
|
1197
|
+
path: ["improve", "strategies", strategyName, "processes", processName, "engine"],
|
|
1198
|
+
message: "engine does not name a configured engine",
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
const judgmentEngine = processConfig.judgment?.engine;
|
|
1203
|
+
if (judgmentEngine) {
|
|
1204
|
+
const engine = config.engines?.[judgmentEngine];
|
|
1205
|
+
if (!engine) {
|
|
1206
|
+
ctx.addIssue({
|
|
1207
|
+
code: z.ZodIssueCode.custom,
|
|
1208
|
+
path: ["improve", "strategies", strategyName, "processes", processName, "judgment", "engine"],
|
|
1209
|
+
message: "engine does not name a configured engine",
|
|
1210
|
+
});
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
923
1215
|
// #464.a: defaultWriteTarget must name a configured source when sources
|
|
924
1216
|
// are present. With no sources configured, error out instead of silently
|
|
925
1217
|
// accepting (no implicit "first writable" fallback — see locked decision 3).
|
|
@@ -5,12 +5,12 @@
|
|
|
5
5
|
// is the single source of truth replacing the previously-disconnected
|
|
6
6
|
// registries. config ← harnesses is the only import direction (harnesses/ is a
|
|
7
7
|
// dependency-graph leaf), so there is no cycle.
|
|
8
|
-
import { VALID_HARNESS_IDS } from "../../integrations/harnesses/index.js";
|
|
8
|
+
import { HARNESS_BY_ID, VALID_HARNESS_IDS } from "../../integrations/harnesses/index.js";
|
|
9
9
|
/**
|
|
10
10
|
* Canonical list of valid agent harness / platform ids. Re-exported from the
|
|
11
11
|
* unified harness registry (#562) so the Zod `AgentPlatformSchema` enum, the
|
|
12
|
-
*
|
|
12
|
+
* agent-engine platform union, and setup's `DetectedHarness` union all
|
|
13
13
|
* derive from one place and cannot drift. Add a harness in
|
|
14
14
|
* `src/integrations/harnesses/index.ts`.
|
|
15
15
|
*/
|
|
16
|
-
export { VALID_HARNESS_IDS };
|
|
16
|
+
export { HARNESS_BY_ID, VALID_HARNESS_IDS };
|