akm-cli 0.9.0-rc.0 → 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 +339 -2
- 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/prompts/workflow-unit-preamble.md +26 -0
- 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/env-binding.js +95 -0
- package/dist/commands/env/env-cli.js +8 -65
- 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/migration-help.js +7 -4
- 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/commands/workflow-cli.js +276 -12
- package/dist/core/asset/asset-spec.js +58 -1
- 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 +379 -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/json-schema.js +142 -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 +118 -2
- 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/indexer/walk/matchers.js +39 -0
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -50
- 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 +16 -2
- package/dist/integrations/agent/profiles.js +36 -62
- package/dist/integrations/agent/runner-dispatch.js +91 -4
- package/dist/integrations/agent/runner.js +76 -207
- package/dist/integrations/agent/spawn.js +141 -20
- package/dist/integrations/harnesses/aider/agent-builder.js +112 -0
- package/dist/integrations/harnesses/aider/index.js +57 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +152 -0
- package/dist/integrations/harnesses/amazonq/index.js +58 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
- package/dist/integrations/harnesses/claude/index.js +25 -25
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/codex/agent-builder.js +136 -0
- package/dist/integrations/harnesses/codex/index.js +62 -0
- package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
- package/dist/integrations/harnesses/copilot/agent-builder.js +121 -0
- package/dist/integrations/harnesses/copilot/index.js +59 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
- package/dist/integrations/harnesses/gemini/index.js +59 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/index.js +27 -28
- package/dist/integrations/harnesses/opencode/agent-builder.js +2 -3
- package/dist/integrations/harnesses/opencode/index.js +15 -22
- package/dist/integrations/harnesses/opencode-sdk/harness.js +60 -0
- package/dist/integrations/harnesses/opencode-sdk/index.js +8 -32
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
- package/dist/integrations/harnesses/openhands/agent-builder.js +125 -0
- package/dist/integrations/harnesses/openhands/index.js +57 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +103 -0
- package/dist/integrations/harnesses/pi/index.js +57 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/types.js +8 -32
- package/dist/integrations/lockfile.js +32 -21
- package/dist/integrations/session-logs/index.js +24 -11
- 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/renderers.js +3 -2
- package/dist/output/shapes/helpers.js +2 -1
- package/dist/output/shapes/passthrough.js +6 -0
- package/dist/output/text/helpers.js +215 -2
- package/dist/output/text/workflow.js +3 -1
- package/dist/schemas/akm-config.json +16638 -0
- package/dist/schemas/akm-task.json +87 -0
- package/dist/schemas/akm-workflow.json +372 -0
- package/dist/scripts/migrate-storage.js +10944 -8801
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +9247 -350
- 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 +190 -1
- 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/text-import-hook.mjs +1 -1
- package/dist/wiki/wiki.js +9 -8
- package/dist/workflows/authoring/authoring.js +123 -10
- package/dist/workflows/authoring/workflow-program-template.yaml +31 -0
- package/dist/workflows/cli.js +4 -0
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/db.js +200 -13
- package/dist/workflows/exec/brief.js +478 -0
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +1034 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1355 -0
- package/dist/workflows/exec/run-workflow.js +609 -0
- package/dist/workflows/exec/scheduler.js +71 -0
- package/dist/workflows/exec/step-work.js +1212 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/watch.js +116 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +375 -0
- package/dist/workflows/ir/freeze.js +243 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +68 -0
- package/dist/workflows/ir/schema.js +545 -0
- package/dist/workflows/parser.js +10 -1
- package/dist/workflows/program/expressions.js +369 -0
- package/dist/workflows/program/parser.js +869 -0
- package/dist/workflows/program/project.js +104 -0
- package/dist/workflows/program/schema.js +54 -0
- package/dist/workflows/renderer.js +82 -5
- package/dist/workflows/resource-limits.js +20 -0
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/plan-classifier.js +187 -0
- package/dist/workflows/runtime/runs.js +246 -69
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +42 -1
- package/dist/workflows/validate-summary.js +24 -3
- package/dist/workflows/validator.js +26 -1
- package/docs/data-and-telemetry.md +4 -3
- 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/release-notes/0.9.0-beta.60.md +19 -0
- 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
|
@@ -0,0 +1,142 @@
|
|
|
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 { createHash } from "node:crypto";
|
|
5
|
+
import { ConfigError } from "../core/errors.js";
|
|
6
|
+
const CHAT_SUFFIX = "/chat/completions";
|
|
7
|
+
export function normalizeChatCompletionsEndpoint(input) {
|
|
8
|
+
const url = new URL(input);
|
|
9
|
+
if (url.protocol !== "http:" && url.protocol !== "https:")
|
|
10
|
+
throw new Error("endpoint must use http or https");
|
|
11
|
+
if (url.username || url.password || url.search || url.hash)
|
|
12
|
+
throw new Error("endpoint cannot contain credentials, query, or fragment");
|
|
13
|
+
let pathname = url.pathname.replace(/\/+$/, "");
|
|
14
|
+
if (!pathname.endsWith(CHAT_SUFFIX)) {
|
|
15
|
+
if (!pathname.endsWith("/v1") && !pathname.includes("/openai"))
|
|
16
|
+
pathname += "/v1";
|
|
17
|
+
pathname += CHAT_SUFFIX;
|
|
18
|
+
}
|
|
19
|
+
url.pathname = pathname;
|
|
20
|
+
return url.toString().replace(/\/$/, "");
|
|
21
|
+
}
|
|
22
|
+
export function engineFingerprint(engine) {
|
|
23
|
+
return engine.kind === "llm"
|
|
24
|
+
? `llm:${normalizeChatCompletionsEndpoint(engine.endpoint)}`
|
|
25
|
+
: `agent:${engine.platform}`;
|
|
26
|
+
}
|
|
27
|
+
export async function verifyOpenAiCompatibleEndpoint(candidate, fetchFn = fetch) {
|
|
28
|
+
let endpoint;
|
|
29
|
+
try {
|
|
30
|
+
endpoint = normalizeChatCompletionsEndpoint(candidate.endpoint);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
34
|
+
}
|
|
35
|
+
if (!candidate.model.trim())
|
|
36
|
+
return { ok: false, reason: "no detected model" };
|
|
37
|
+
const credential = candidate.apiKeyEnvVar ? process.env[candidate.apiKeyEnvVar] : undefined;
|
|
38
|
+
if (candidate.apiKeyEnvVar && !credential) {
|
|
39
|
+
return { ok: false, reason: `required credential ${candidate.apiKeyEnvVar} is unavailable` };
|
|
40
|
+
}
|
|
41
|
+
const controller = new AbortController();
|
|
42
|
+
const timer = setTimeout(() => controller.abort(), 10_000);
|
|
43
|
+
timer.unref?.();
|
|
44
|
+
try {
|
|
45
|
+
const response = await fetchFn(endpoint, {
|
|
46
|
+
method: "POST",
|
|
47
|
+
headers: {
|
|
48
|
+
"content-type": "application/json",
|
|
49
|
+
...(credential ? { authorization: `Bearer ${credential}` } : {}),
|
|
50
|
+
},
|
|
51
|
+
body: JSON.stringify({
|
|
52
|
+
model: candidate.model,
|
|
53
|
+
messages: [{ role: "user", content: "Reply OK" }],
|
|
54
|
+
max_tokens: 1,
|
|
55
|
+
stream: false,
|
|
56
|
+
}),
|
|
57
|
+
signal: controller.signal,
|
|
58
|
+
});
|
|
59
|
+
if (!response.ok)
|
|
60
|
+
return { ok: false, reason: `HTTP ${response.status}` };
|
|
61
|
+
const body = (await response.json());
|
|
62
|
+
if (typeof body.choices?.[0]?.message?.content !== "string") {
|
|
63
|
+
return { ok: false, reason: "response did not contain choices[0].message.content" };
|
|
64
|
+
}
|
|
65
|
+
return { ok: true, endpoint };
|
|
66
|
+
}
|
|
67
|
+
catch (error) {
|
|
68
|
+
return { ok: false, reason: error instanceof Error ? error.message : String(error) };
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
clearTimeout(timer);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function slug(value) {
|
|
75
|
+
const normalized = value
|
|
76
|
+
.toLowerCase()
|
|
77
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
78
|
+
.replace(/^-|-$/g, "");
|
|
79
|
+
return normalized && /^[a-z]/.test(normalized) ? normalized : "local";
|
|
80
|
+
}
|
|
81
|
+
function availableName(config, preferred, fingerprint) {
|
|
82
|
+
for (const [name, engine] of Object.entries(config.engines ?? {}).sort(([left], [right]) => left.localeCompare(right))) {
|
|
83
|
+
if (engineFingerprint(engine) === fingerprint)
|
|
84
|
+
return name;
|
|
85
|
+
}
|
|
86
|
+
const base = slug(preferred);
|
|
87
|
+
const expectedKind = fingerprint.startsWith("llm:") ? "llm" : "agent";
|
|
88
|
+
const baseEngine = config.engines?.[base];
|
|
89
|
+
if (baseEngine && baseEngine.kind !== expectedKind) {
|
|
90
|
+
throw new ConfigError(`Detected ${expectedKind} engine name ${JSON.stringify(base)} conflicts with configured ${baseEngine.kind} engine of the same name. Rename one engine before rerunning setup.`, "INVALID_CONFIG_FILE");
|
|
91
|
+
}
|
|
92
|
+
if (!config.engines?.[base])
|
|
93
|
+
return base;
|
|
94
|
+
const suffix = createHash("sha256").update(fingerprint).digest("hex").slice(0, 8);
|
|
95
|
+
const candidate = `${base}-${suffix}`;
|
|
96
|
+
const collision = config.engines?.[candidate];
|
|
97
|
+
if (!collision || engineFingerprint(collision) === fingerprint)
|
|
98
|
+
return candidate;
|
|
99
|
+
throw new ConfigError(`Detected engine identity collision at ${JSON.stringify(candidate)}. Choose an explicit engine name before rerunning setup.`, "INVALID_CONFIG_FILE");
|
|
100
|
+
}
|
|
101
|
+
/** Insert or reuse an LLM engine by canonical endpoint without modifying a match. */
|
|
102
|
+
export function upsertDetectedLlmEngine(config, candidate) {
|
|
103
|
+
const endpoint = normalizeChatCompletionsEndpoint(candidate.endpoint);
|
|
104
|
+
const fingerprint = `llm:${endpoint}`;
|
|
105
|
+
const name = availableName(config, candidate.provider, fingerprint);
|
|
106
|
+
const existing = config.engines?.[name];
|
|
107
|
+
const reused = existing !== undefined && engineFingerprint(existing) === fingerprint;
|
|
108
|
+
const engines = reused
|
|
109
|
+
? config.engines
|
|
110
|
+
: {
|
|
111
|
+
...(config.engines ?? {}),
|
|
112
|
+
[name]: {
|
|
113
|
+
kind: "llm",
|
|
114
|
+
provider: candidate.provider,
|
|
115
|
+
endpoint,
|
|
116
|
+
model: candidate.model,
|
|
117
|
+
...(candidate.apiKeyEnvVar ? { apiKey: `\${${candidate.apiKeyEnvVar}}` } : {}),
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
const defaults = { ...(config.defaults ?? {}) };
|
|
121
|
+
const currentDefault = defaults.llmEngine;
|
|
122
|
+
if (!currentDefault ||
|
|
123
|
+
(config.engines?.[currentDefault] && engineFingerprint(config.engines[currentDefault]) === fingerprint)) {
|
|
124
|
+
defaults.llmEngine = name;
|
|
125
|
+
}
|
|
126
|
+
return { config: { ...config, engines, defaults }, name, reused };
|
|
127
|
+
}
|
|
128
|
+
/** Insert or reuse an agent engine by canonical platform without modifying a match. */
|
|
129
|
+
export function upsertDetectedAgentEngine(config, platform) {
|
|
130
|
+
const fingerprint = `agent:${platform}`;
|
|
131
|
+
const name = availableName(config, platform, fingerprint);
|
|
132
|
+
const existing = config.engines?.[name];
|
|
133
|
+
const reused = existing !== undefined && engineFingerprint(existing) === fingerprint;
|
|
134
|
+
const engines = reused ? config.engines : { ...(config.engines ?? {}), [name]: { kind: "agent", platform } };
|
|
135
|
+
const defaults = { ...(config.defaults ?? {}) };
|
|
136
|
+
const currentDefault = defaults.engine;
|
|
137
|
+
if (!currentDefault ||
|
|
138
|
+
(config.engines?.[currentDefault] && engineFingerprint(config.engines[currentDefault]) === fingerprint)) {
|
|
139
|
+
defaults.engine = name;
|
|
140
|
+
}
|
|
141
|
+
return { config: { ...config, engines, defaults }, name, reused };
|
|
142
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
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 { ConfigError } from "../core/errors.js";
|
|
5
|
+
export function readCurrentLlmEngine(config) {
|
|
6
|
+
const name = config.defaults?.llmEngine;
|
|
7
|
+
const engine = name ? config.engines?.[name] : undefined;
|
|
8
|
+
if (!engine || engine.kind !== "llm")
|
|
9
|
+
return undefined;
|
|
10
|
+
const { kind: _kind, supportsJsonSchema, timeoutMs, ...connection } = engine;
|
|
11
|
+
return {
|
|
12
|
+
...connection,
|
|
13
|
+
...(timeoutMs !== undefined ? { timeoutMs } : {}),
|
|
14
|
+
...(supportsJsonSchema !== undefined ? { capabilities: { structuredOutput: supportsJsonSchema } } : {}),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function readAgentEngineSelection(config) {
|
|
18
|
+
const engines = {};
|
|
19
|
+
for (const [name, engine] of Object.entries(config.engines ?? {})) {
|
|
20
|
+
if (engine.kind === "agent")
|
|
21
|
+
engines[name] = { ...engine };
|
|
22
|
+
}
|
|
23
|
+
const defaultName = config.defaults?.engine;
|
|
24
|
+
const defaultIsAgent = defaultName && config.engines?.[defaultName]?.kind === "agent";
|
|
25
|
+
if (Object.keys(engines).length === 0 && !defaultIsAgent)
|
|
26
|
+
return undefined;
|
|
27
|
+
return { ...(defaultIsAgent ? { default: defaultName } : {}), engines };
|
|
28
|
+
}
|
|
29
|
+
/** Write an OpenAI-compatible connection as a named LLM engine. */
|
|
30
|
+
export function writeLlmEngine(config, llm) {
|
|
31
|
+
const name = config.defaults?.llmEngine ?? "default";
|
|
32
|
+
if (!llm) {
|
|
33
|
+
const engines = { ...(config.engines ?? {}) };
|
|
34
|
+
if (engines[name]?.kind === "llm")
|
|
35
|
+
delete engines[name];
|
|
36
|
+
const defaults = { ...(config.defaults ?? {}) };
|
|
37
|
+
delete defaults.llmEngine;
|
|
38
|
+
return { engines, defaults };
|
|
39
|
+
}
|
|
40
|
+
if (config.engines?.[name] && config.engines[name].kind !== "llm") {
|
|
41
|
+
throw new ConfigError(`Cannot configure LLM engine ${JSON.stringify(name)} because that name belongs to an agent engine.`, "INVALID_CONFIG_FILE");
|
|
42
|
+
}
|
|
43
|
+
const endpoint = llm.endpoint.endsWith("/chat/completions")
|
|
44
|
+
? llm.endpoint
|
|
45
|
+
: `${llm.endpoint.replace(/\/$/, "")}/chat/completions`;
|
|
46
|
+
const { capabilities, ...connection } = llm;
|
|
47
|
+
return {
|
|
48
|
+
engines: {
|
|
49
|
+
...(config.engines ?? {}),
|
|
50
|
+
[name]: {
|
|
51
|
+
...connection,
|
|
52
|
+
kind: "llm",
|
|
53
|
+
endpoint,
|
|
54
|
+
...(capabilities?.structuredOutput !== undefined ? { supportsJsonSchema: capabilities.structuredOutput } : {}),
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
defaults: { ...(config.defaults ?? {}), llmEngine: name },
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** Merge setup-selected agent engines without translating profile-shaped data. */
|
|
61
|
+
export function writeAgentEngines(config, selection) {
|
|
62
|
+
for (const [name, engine] of Object.entries(selection?.engines ?? {})) {
|
|
63
|
+
const existing = config.engines?.[name];
|
|
64
|
+
if (existing && existing.kind !== engine.kind) {
|
|
65
|
+
throw new ConfigError(`Cannot configure ${engine.kind} engine ${JSON.stringify(name)} because that name belongs to an ${existing.kind} engine.`, "INVALID_CONFIG_FILE");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const defaults = { ...(config.defaults ?? {}) };
|
|
69
|
+
if (!selection?.default)
|
|
70
|
+
delete defaults.engine;
|
|
71
|
+
else
|
|
72
|
+
defaults.engine = selection.default;
|
|
73
|
+
const engines = { ...(config.engines ?? {}), ...(selection?.engines ?? {}) };
|
|
74
|
+
if (selection?.default && engines[selection.default] && engines[selection.default].kind !== "agent") {
|
|
75
|
+
throw new ConfigError(`Cannot select agent engine ${JSON.stringify(selection.default)} because that name belongs to an LLM engine.`, "INVALID_CONFIG_FILE");
|
|
76
|
+
}
|
|
77
|
+
if (selection?.default && !engines[selection.default]) {
|
|
78
|
+
engines[selection.default] = {
|
|
79
|
+
kind: "agent",
|
|
80
|
+
platform: selection.default,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
return { engines, defaults };
|
|
84
|
+
}
|
|
85
|
+
export function cloneLlmConnection(llm) {
|
|
86
|
+
if (!llm)
|
|
87
|
+
return undefined;
|
|
88
|
+
return JSON.parse(JSON.stringify(llm));
|
|
89
|
+
}
|