Files
cc-switch/tests/utils/providerConfigUtils.codex.test.ts
Kairos Duan 3c3d417457 Enable Codex goals in provider templates (#3089)
* Enable Codex goals in provider templates

* feat: add Codex goal mode toggle

- Remove forced goals=true from Codex provider presets and custom templates.
- Add a Codex provider editor switch that updates [features].goals on demand.
- Update docs, i18n, and regression coverage for the optional Goal mode flow.

---------

Co-authored-by: Jason <farion1231@gmail.com>
2026-05-27 11:31:31 +08:00

408 lines
12 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
extractCodexBaseUrl,
extractCodexExperimentalBearerToken,
extractCodexModelName,
extractCodexTopLevelInt,
isCodexGoalModeEnabled,
removeCodexTopLevelField,
setCodexBaseUrl,
setCodexGoalMode,
setCodexModelName,
setCodexTopLevelInt,
updateCodexExperimentalBearerToken,
} from "@/utils/providerConfigUtils";
describe("Codex TOML utils", () => {
it("removes base_url line when set to empty", () => {
const input = [
'model_provider = "openai"',
'base_url = "https://api.example.com/v1"',
'model = "gpt-5-codex"',
"",
].join("\n");
const output = setCodexBaseUrl(input, "");
expect(output).not.toMatch(/^\s*base_url\s*=/m);
expect(extractCodexBaseUrl(output)).toBeUndefined();
expect(extractCodexModelName(output)).toBe("gpt-5-codex");
});
it("removes only the top-level model line when set to empty", () => {
const input = [
'model_provider = "openai"',
'base_url = "https://api.example.com/v1"',
'model = "gpt-5-codex"',
"",
"[profiles.default]",
'model = "profile-model"',
"",
].join("\n");
const output = setCodexModelName(input, "");
expect(output).not.toMatch(/^model\s*=\s*"gpt-5-codex"$/m);
expect(output).toMatch(/^\[profiles\.default\]\nmodel = "profile-model"$/m);
expect(extractCodexModelName(output)).toBeUndefined();
expect(extractCodexBaseUrl(output)).toBe("https://api.example.com/v1");
});
it("updates existing values when non-empty", () => {
const input = [
'model_provider = "openai"',
"base_url = 'https://old.example/v1'",
'model = "old-model"',
"",
].join("\n");
const output1 = setCodexBaseUrl(input, " https://new.example/v1 \n");
expect(extractCodexBaseUrl(output1)).toBe("https://new.example/v1");
const output2 = setCodexModelName(output1, " new-model \n");
expect(extractCodexModelName(output2)).toBe("new-model");
});
it("reads and writes base_url in the active provider section", () => {
const input = [
'model_provider = "custom"',
'model = "gpt-5.4"',
"",
"[model_providers.custom]",
'name = "custom"',
'wire_api = "responses"',
"",
"[profiles.default]",
'approval_policy = "never"',
"",
].join("\n");
const output = setCodexBaseUrl(input, "https://api.example.com/v1");
expect(output).toContain(
'[model_providers.custom]\nname = "custom"\nwire_api = "responses"\nbase_url = "https://api.example.com/v1"',
);
expect(extractCodexBaseUrl(output)).toBe("https://api.example.com/v1");
});
it("recovers a single misplaced base_url from another section", () => {
const input = [
'model_provider = "custom"',
'model = "gpt-5.4"',
"",
"[model_providers.custom]",
'name = "custom"',
'wire_api = "responses"',
"",
"[profiles.default]",
'approval_policy = "never"',
'base_url = "https://wrong.example/v1"',
"",
].join("\n");
expect(extractCodexBaseUrl(input)).toBe("https://wrong.example/v1");
const output = setCodexBaseUrl(input, "https://fixed.example/v1");
expect(output).toContain(
'[model_providers.custom]\nname = "custom"\nwire_api = "responses"\nbase_url = "https://fixed.example/v1"',
);
expect(output).not.toContain("https://wrong.example/v1");
expect(output.match(/base_url\s*=/g)).toHaveLength(1);
});
it("does not treat mcp_servers base_url as provider base_url", () => {
const input = [
'model_provider = "azure"',
'model = "gpt-4"',
"",
"[model_providers.azure]",
'name = "Azure OpenAI"',
'wire_api = "responses"',
"",
"[mcp_servers.my_server]",
'base_url = "http://localhost:8080"',
"",
].join("\n");
expect(extractCodexBaseUrl(input)).toBeUndefined();
const output = setCodexBaseUrl(input, "https://new.azure/v1");
expect(output).toContain(
'[model_providers.azure]\nname = "Azure OpenAI"\nwire_api = "responses"\nbase_url = "https://new.azure/v1"',
);
expect(output).toContain(
'[mcp_servers.my_server]\nbase_url = "http://localhost:8080"',
);
});
it("reads model only from the top-level config", () => {
const input = [
'model_provider = "custom"',
"",
"[profiles.default]",
'model = "profile-model"',
"",
].join("\n");
expect(extractCodexModelName(input)).toBeUndefined();
});
it("handles single-quoted values", () => {
const input = "base_url = 'https://api.example.com/v1'\nmodel = 'gpt-5'\n";
expect(extractCodexBaseUrl(input)).toBe("https://api.example.com/v1");
expect(extractCodexModelName(input)).toBe("gpt-5");
});
it("reads, writes, and removes top-level integer metadata fields", () => {
const input = [
'model_provider = "custom"',
'model = "deepseek-v4-flash"',
"",
"[model_providers.custom]",
'name = "DeepSeek"',
"",
].join("\n");
const withContext = setCodexTopLevelInt(
input,
"model_context_window",
128000,
);
const withCompact = setCodexTopLevelInt(
withContext,
"model_auto_compact_token_limit",
90000,
);
expect(extractCodexTopLevelInt(withCompact, "model_context_window")).toBe(
128000,
);
expect(
extractCodexTopLevelInt(withCompact, "model_auto_compact_token_limit"),
).toBe(90000);
expect(withCompact).toMatch(/^model_context_window = 128000$/m);
expect(withCompact).toMatch(/^model_auto_compact_token_limit = 90000$/m);
const removed = removeCodexTopLevelField(
withCompact,
"model_context_window",
);
expect(
extractCodexTopLevelInt(removed, "model_context_window"),
).toBeUndefined();
expect(removed).toContain("[model_providers.custom]");
});
it("adds Goal mode under the top-level features table", () => {
const input = [
'model_provider = "custom"',
'model = "gpt-5.4"',
"",
"[model_providers.custom]",
'name = "custom"',
"",
].join("\n");
const output = setCodexGoalMode(input, true);
expect(isCodexGoalModeEnabled(output)).toBe(true);
expect(output).toContain(
'model = "gpt-5.4"\n\n[features]\ngoals = true\n\n[model_providers.custom]',
);
});
it("removes Goal mode without deleting other feature flags", () => {
const input = [
'model_provider = "custom"',
"",
"[features]",
"goals = true",
"experimental_resume = true",
"",
"[model_providers.custom]",
'name = "custom"',
"",
].join("\n");
const output = setCodexGoalMode(input, false);
expect(isCodexGoalModeEnabled(output)).toBe(false);
expect(output).toContain("[features]\nexperimental_resume = true");
expect(output).not.toMatch(/^\s*goals\s*=/m);
});
it("removes the features table when disabling the only Goal mode flag", () => {
const input = [
'model_provider = "custom"',
"",
"[features]",
"goals = true",
"",
"[model_providers.custom]",
'name = "custom"',
"",
].join("\n");
const output = setCodexGoalMode(input, false);
expect(isCodexGoalModeEnabled(output)).toBe(false);
expect(output).not.toContain("[features]");
expect(output).toContain("[model_providers.custom]");
});
it("preserves feature-section comments when disabling Goal mode", () => {
const input = [
'model_provider = "custom"',
"",
"[features]",
"# Keep this note",
"goals = true",
"",
"[model_providers.custom]",
'name = "custom"',
"",
].join("\n");
const output = setCodexGoalMode(input, false);
expect(isCodexGoalModeEnabled(output)).toBe(false);
expect(output).toContain("[features]\n# Keep this note");
expect(output).not.toMatch(/^\s*goals\s*=/m);
});
// P3 回归: 不能在 config 没用 bearer token 模式时, 误为它新增一行
it("updateCodexExperimentalBearerToken leaves config without the token alone", () => {
const input = [
'model_provider = "openai"',
'base_url = "https://api.example.com/v1"',
"",
].join("\n");
expect(updateCodexExperimentalBearerToken(input, "new-key")).toBe(input);
expect(updateCodexExperimentalBearerToken(input, "")).toBe(input);
});
// P3 回归: bearer 模式下清空 API key 必须真正擦掉 token, 让 pickCodexApiKey 的 fallback 找不到
it("updateCodexExperimentalBearerToken removes the token line when set to empty", () => {
const input = [
'model_provider = "thirdparty"',
"",
"[model_providers.thirdparty]",
'name = "Thirdparty"',
'base_url = "https://thirdparty.example/v1"',
'experimental_bearer_token = "old-key"',
"requires_openai_auth = true",
"",
].join("\n");
const cleared = updateCodexExperimentalBearerToken(input, "");
expect(extractCodexExperimentalBearerToken(cleared)).toBeUndefined();
expect(cleared).toMatch(/requires_openai_auth = true/);
expect(cleared).toMatch(/base_url = "https:\/\/thirdparty\.example\/v1"/);
});
it("updateCodexExperimentalBearerToken replaces the token inside the active model_providers section", () => {
const input = [
'model_provider = "thirdparty"',
"",
"[model_providers.thirdparty]",
'experimental_bearer_token = "old-key"',
"",
].join("\n");
const updated = updateCodexExperimentalBearerToken(input, "new-key");
expect(extractCodexExperimentalBearerToken(updated)).toBe("new-key");
expect(updated).not.toMatch(/old-key/);
});
it("updateCodexExperimentalBearerToken escapes basic TOML strings and keeps comments", () => {
const input = [
'model_provider = "thirdparty"',
"",
"[model_providers.thirdparty]",
'experimental_bearer_token = "old-key" # vendor token',
"",
].join("\n");
const updated = updateCodexExperimentalBearerToken(input, 'abc"def\\ghi');
expect(updated).toContain(
'experimental_bearer_token = "abc\\"def\\\\ghi" # vendor token',
);
expect(extractCodexExperimentalBearerToken(updated)).toBe('abc"def\\ghi');
});
it("updateCodexExperimentalBearerToken escapes all TOML control characters", () => {
const input = [
'model_provider = "thirdparty"',
"",
"[model_providers.thirdparty]",
'experimental_bearer_token = "old-key"',
"",
].join("\n");
const updated = updateCodexExperimentalBearerToken(
input,
"a\u0000b\u0001c\u001fd",
);
expect(updated).toContain(
'experimental_bearer_token = "a\\u0000b\\u0001c\\u001fd"',
);
expect(extractCodexExperimentalBearerToken(updated)).toBe(
"a\u0000b\u0001c\u001fd",
);
});
it("updateCodexExperimentalBearerToken can replace an already escaped basic string", () => {
const input = [
'model_provider = "thirdparty"',
"",
"[model_providers.thirdparty]",
'experimental_bearer_token = "old\\"key" # vendor token',
"",
].join("\n");
const updated = updateCodexExperimentalBearerToken(input, "new-key");
expect(updated).toContain(
'experimental_bearer_token = "new-key" # vendor token',
);
expect(extractCodexExperimentalBearerToken(updated)).toBe("new-key");
});
it("extractCodexExperimentalBearerToken ignores reserved provider tables", () => {
const input = [
'model_provider = "openai"',
'experimental_bearer_token = "top-level-key"',
"",
"[model_providers.openai]",
'experimental_bearer_token = "stale-table-key"',
"",
].join("\n");
expect(extractCodexExperimentalBearerToken(input)).toBe("top-level-key");
});
it("extractCodexExperimentalBearerToken reads only top-level model_provider", () => {
const input = [
'experimental_bearer_token = "top-level-key"',
"",
"[profiles.work]",
'model_provider = "fake"',
"",
"[model_providers.fake]",
'experimental_bearer_token = "wrong-key"',
"",
].join("\n");
expect(extractCodexExperimentalBearerToken(input)).toBe("top-level-key");
});
});