mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-08-26 09:02:11 +03:00
Adds a Grok Build card to the CLI Code dashboard: configures the main model and per-subagent model overrides, surgically upserts only the [model.omniroute] section of config.toml (preserving unrelated user sections), resolves config.toml via GROK_HOME or the CLI config home, and omits API keys from settings responses. Closes #10829. Validated in an isolated worktree boarded onto origin/release/v3.8.50 (0 conflicts, 14 files): - 6/48 focused node:test cases in tests/integration/cli-settings-grok-build.test.ts initially failed with 422 instead of 200/409 — traced to this route being the first CLI-tool settings route to actually pass a targetPath into the shared guardCliConfigWrite/ensureCliConfigWriteAllowed container-ephemeral-write guard (every other cli-tools/*-settings route calls it with no path, which always no-ops). This devbox genuinely runs inside Docker with no bind mount for the test's tmpdir fixtures, so the guard correctly refused — a real environment-dependent gap in the PR's own test setup (missing OMNIROUTE_ALLOW_CONTAINER_CONFIG_WRITE=1, the pattern already used by tests/unit/cli-tools-apply-container-422.test.ts for this exact guard). Fixed by setting that flag in the test file's setup, pushed fix-in-place. - 61/61 tests pass after the fix (grok-build-config, check-tool-config-status, all-statuses-route, cli-settings-grok-build, plus 13/13 UI tests via vitest for GrokBuildToolCard/ToolDetailClient). - Verified the "omit API keys from settings responses" claim: GET applies omitApiKeys() to both config/settings before responding. - check-file-size, check-changelog-integrity: OK. - typecheck:core: clean. - check-complexity / check-cognitive-complexity: OK, both under baseline. Co-authored-by: tuandinh0801 <tuandinh0801@users.noreply.github.com>
166 lines
5.6 KiB
TypeScript
166 lines
5.6 KiB
TypeScript
import assert from "node:assert/strict";
|
|
import test from "node:test";
|
|
|
|
import {
|
|
applyGrokBuildConfig,
|
|
GrokBuildConfigConflictError,
|
|
parseGrokBuildConfig,
|
|
resetGrokBuildConfig,
|
|
} from "../../src/shared/services/grokBuildConfig.ts";
|
|
|
|
const main = {
|
|
baseUrl: "http://localhost:20128/v1",
|
|
apiKey: "sk-test",
|
|
model: "openai/gpt-5.5",
|
|
contextWindow: 400000,
|
|
};
|
|
|
|
test("apply adds the main slot and preserves unrelated TOML", () => {
|
|
const source = [
|
|
"# user comment",
|
|
"[models]",
|
|
'default = "custom"',
|
|
'theme = "dark"',
|
|
"",
|
|
"[model.custom]",
|
|
'model = "custom-model"',
|
|
'base_url = "https://example.test/v1"',
|
|
"",
|
|
].join("\n");
|
|
|
|
const result = applyGrokBuildConfig(source, main);
|
|
const parsed = parseGrokBuildConfig(result);
|
|
|
|
assert.equal(parsed.default, "omniroute");
|
|
assert.equal(parsed.model?.model, main.model);
|
|
assert.equal(parsed.model?.context_window, main.contextWindow);
|
|
assert.match(result, /# omniroute-prev-default = "custom"/);
|
|
assert.match(result, /# user comment/);
|
|
assert.match(result, /theme = "dark"/);
|
|
assert.match(result, /\[model\.custom\]/);
|
|
});
|
|
|
|
test("apply records an absent default once and reset removes it", () => {
|
|
const appliedTwice = applyGrokBuildConfig(applyGrokBuildConfig("[ui]\ncompact = true\n", main), {
|
|
...main,
|
|
model: "anthropic/claude-opus-4-1",
|
|
});
|
|
|
|
assert.equal(appliedTwice.match(/omniroute-prev-default/g)?.length, 1);
|
|
const reset = resetGrokBuildConfig(appliedTwice);
|
|
assert.doesNotMatch(reset, /^default\s*=/m);
|
|
assert.doesNotMatch(reset, /\[model\.omniroute\]/);
|
|
assert.match(reset, /\[ui\]\ncompact = true/);
|
|
});
|
|
|
|
test("reset never restores the obsolete grok-build default", () => {
|
|
const source = [
|
|
"[models]",
|
|
'default = "omniroute"',
|
|
"",
|
|
'# omniroute-prev-default = "grok-build"',
|
|
"[model.omniroute]",
|
|
'# omniroute-managed = "true"',
|
|
'model = "openai/gpt-5.5"',
|
|
'base_url = "http://localhost:20128/v1"',
|
|
'name = "OmniRoute"',
|
|
'description = "Routed via OmniRoute gateway"',
|
|
'api_backend = "chat_completions"',
|
|
"",
|
|
].join("\n");
|
|
|
|
const result = resetGrokBuildConfig(source);
|
|
assert.doesNotMatch(result, /^default\s*=/m);
|
|
assert.doesNotMatch(result, /grok-build/);
|
|
});
|
|
|
|
test("apply manages all subagent slots and keeps context windows", () => {
|
|
const result = applyGrokBuildConfig(
|
|
["[subagents.models]", 'general-purpose = "old-general"', 'explore = "old-explore"', ""].join(
|
|
"\n"
|
|
),
|
|
{
|
|
...main,
|
|
subagentModels: {
|
|
"general-purpose": { model: "google/gemini-2.5-pro", contextWindow: 1048576 },
|
|
plan: { model: "anthropic/claude-sonnet-4", contextWindow: 200000 },
|
|
},
|
|
}
|
|
);
|
|
const parsed = parseGrokBuildConfig(result);
|
|
|
|
assert.equal(parsed.subagentMappings["general-purpose"], "omniroute-general-purpose");
|
|
assert.equal(parsed.subagentMappings.explore, "old-explore");
|
|
assert.equal(parsed.subagentMappings.plan, "omniroute-plan");
|
|
assert.equal(parsed.subagentModels["general-purpose"]?.context_window, 1048576);
|
|
assert.equal(parsed.subagentModels.plan?.context_window, 200000);
|
|
assert.match(result, /omniroute-prev-subagent-general-purpose = "old-general"/);
|
|
assert.match(result, /omniroute-prev-subagent-plan = "__omniroute_unset__"/);
|
|
});
|
|
|
|
test("an absent subagentModels property preserves current subagent values", () => {
|
|
const source = applyGrokBuildConfig("", {
|
|
...main,
|
|
subagentModels: { explore: { model: "xai/grok-4", contextWindow: 256000 } },
|
|
});
|
|
const result = applyGrokBuildConfig(source, { ...main, model: "openai/gpt-5.5-codex" });
|
|
|
|
assert.equal(parseGrokBuildConfig(result).subagentModels.explore?.model, "xai/grok-4");
|
|
});
|
|
|
|
test("an empty subagentModels object removes all managed overrides", () => {
|
|
const source = applyGrokBuildConfig('[subagents.models]\nexplore = "user-explore"\n', {
|
|
...main,
|
|
subagentModels: {
|
|
explore: { model: "xai/grok-4", contextWindow: 256000 },
|
|
plan: { model: "openai/gpt-5.5", contextWindow: 400000 },
|
|
},
|
|
});
|
|
const result = applyGrokBuildConfig(source, { ...main, subagentModels: {} });
|
|
const parsed = parseGrokBuildConfig(result);
|
|
|
|
assert.equal(parsed.subagentMappings.explore, "user-explore");
|
|
assert.equal(parsed.subagentMappings.plan, null);
|
|
assert.doesNotMatch(result, /\[model\.omniroute-(?:explore|plan)\]/);
|
|
});
|
|
|
|
test("reset restores only mappings that still reference managed slots", () => {
|
|
let source = applyGrokBuildConfig('[subagents.models]\nexplore = "old-explore"\n', {
|
|
...main,
|
|
subagentModels: { explore: { model: "xai/grok-4", contextWindow: 256000 } },
|
|
});
|
|
source = source.replace('explore = "omniroute-explore"', 'explore = "user-changed-explore"');
|
|
|
|
const result = resetGrokBuildConfig(source);
|
|
assert.match(result, /explore = "user-changed-explore"/);
|
|
assert.doesNotMatch(result, /omniroute-prev-subagent/);
|
|
});
|
|
|
|
test("apply accepts the exact legacy OmniRoute table", () => {
|
|
const legacy = [
|
|
"[model.omniroute]",
|
|
'model = "grok-4.5"',
|
|
'base_url = "http://localhost:20128/v1"',
|
|
'name = "OmniRoute"',
|
|
'description = "Routed via OmniRoute gateway"',
|
|
'api_backend = "chat_completions"',
|
|
'api_key = "sk-old"',
|
|
"",
|
|
].join("\n");
|
|
|
|
assert.doesNotThrow(() => applyGrokBuildConfig(legacy, main));
|
|
});
|
|
|
|
test("apply rejects an unowned model.omniroute table", () => {
|
|
const source = [
|
|
"[model.omniroute]",
|
|
'model = "private-model"',
|
|
'base_url = "https://example.test/v1"',
|
|
'name = "User model"',
|
|
'api_backend = "chat_completions"',
|
|
"",
|
|
].join("\n");
|
|
|
|
assert.throws(() => applyGrokBuildConfig(source, main), GrokBuildConfigConflictError);
|
|
});
|