mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-10-26 01:34:51 +08:00
revert(forms): drop the Codex main reasoning effort picker
The picker for the top-level model_reasoning_effort duplicated what Codex users already pick in /model, and the line stays visible and editable in the TOML editor at the bottom of the form. It also did nothing for the Aggregation case, where the key is written regardless and the picker was hidden. Removes the field, its state and TOML helpers, tests and locale keys. The subagent effort select keeps the shared effort select.
This commit is contained in:
1 parent
28ee933ccf
commit
ac2eebc004
10 files changed
+11
-297
No files matched your search
@@ -179,11 +179,6 @@ interface CodexFormFieldsProps {
|
||||
codexModel?: string;
|
||||
onModelChange?: (model: string) => void;
|
||||
|
||||
// Main agent reasoning effort (config.toml top-level `model_reasoning_effort`).
|
||||
// Codex only; the Stack layout omits it.
|
||||
reasoningEffort?: string;
|
||||
onReasoningEffortChange?: (effort: string) => void;
|
||||
|
||||
// Subagent defaults (config.toml `[agents]`). Codex only: Grok Build has no
|
||||
// such keys, and the Stack layout omits them (subagents follow the main model).
|
||||
subagentModel?: string;
|
||||
@@ -561,8 +556,6 @@ export function CodexFormFields({
|
||||
onAutoSelectChange,
|
||||
codexModel = "",
|
||||
onModelChange,
|
||||
reasoningEffort = "",
|
||||
onReasoningEffortChange,
|
||||
subagentModel = "",
|
||||
onSubagentModelChange,
|
||||
subagentReasoningEffort = "",
|
||||
@@ -1777,7 +1770,7 @@ export function CodexFormFields({
|
||||
</p>
|
||||
);
|
||||
|
||||
// 推理强度下拉(主代理和子代理共用):第一项是不写这个键;值不在已知档位里时原样列出,
|
||||
// 子代理推理强度下拉:第一项是不写这个键;值不在已知档位里时原样列出,
|
||||
// 免得手写的值被下拉吞掉。
|
||||
const renderEffortSelect = (
|
||||
value: string,
|
||||
@@ -1785,13 +1778,12 @@ export function CodexFormFields({
|
||||
ariaLabel: string,
|
||||
inheritLabel: string,
|
||||
className: string,
|
||||
id?: string,
|
||||
) => (
|
||||
<Select
|
||||
value={value || EFFORT_INHERIT}
|
||||
onValueChange={(next) => onChange(next === EFFORT_INHERIT ? "" : next)}
|
||||
>
|
||||
<SelectTrigger id={id} aria-label={ariaLabel} className={className}>
|
||||
<SelectTrigger aria-label={ariaLabel} className={className}>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -1809,36 +1801,6 @@ export function CodexFormFields({
|
||||
</Select>
|
||||
);
|
||||
|
||||
// 推理强度 —— config.toml 顶层 model_reasoning_effort,主代理默认用的强度。只在完整表单显示
|
||||
// (Codex 才传);留空删键,各模型用目录行里自己的默认等级。
|
||||
const reasoningEffortField = category !== "official" &&
|
||||
onReasoningEffortChange && (
|
||||
<div className="space-y-1.5">
|
||||
{labelWithHelp(
|
||||
t("codexConfig.mainReasoningEffortLabel", {
|
||||
defaultValue: "推理强度",
|
||||
}),
|
||||
t("codexConfig.mainReasoningEffortHelp", {
|
||||
defaultValue:
|
||||
"Codex 主代理默认用的推理强度,会盖过模型列表里每行的默认等级。选「按模型默认」就删掉这一项,各模型用自己的默认等级。",
|
||||
}),
|
||||
"codexReasoningEffort",
|
||||
)}
|
||||
{renderEffortSelect(
|
||||
reasoningEffort,
|
||||
onReasoningEffortChange,
|
||||
t("codexConfig.mainReasoningEffortLabel", {
|
||||
defaultValue: "推理强度",
|
||||
}),
|
||||
t("codexConfig.mainReasoningEffortDefault", {
|
||||
defaultValue: "按模型默认",
|
||||
}),
|
||||
"w-full",
|
||||
"codexReasoningEffort",
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
||||
// 默认模型 —— config.toml 顶层 model,Codex 启动时默认请求的模型。实时写回 TOML;留空则删行。
|
||||
// 有模型列表时第一行就是它,不显示这个框(Grok Build 没有列表,一直显示);列表为空时
|
||||
// 两种布局都显示,聚合模式下发布的就是它。
|
||||
@@ -2102,8 +2064,6 @@ export function CodexFormFields({
|
||||
{/* 默认模型:列表为空(或没有列表)时才显示 */}
|
||||
{defaultModelField}
|
||||
|
||||
{reasoningEffortField}
|
||||
|
||||
{/* 子代理 —— config.toml 的 [agents] default_subagent_model / default_subagent_reasoning_effort。
|
||||
留空删键,子代理跟随主模型;聚合模式下不写进 live。 */}
|
||||
{category !== "official" && onSubagentModelChange && (
|
||||
|
||||
@@ -712,7 +712,6 @@ function ProviderFormFull({
|
||||
codexApiKey,
|
||||
codexBaseUrl,
|
||||
codexModel,
|
||||
codexReasoningEffort,
|
||||
codexSubagentModel,
|
||||
codexSubagentReasoningEffort,
|
||||
codexCatalogModels,
|
||||
@@ -723,7 +722,6 @@ function ProviderFormFull({
|
||||
handleCodexApiKeyChange,
|
||||
handleCodexBaseUrlChange,
|
||||
handleCodexModelChange,
|
||||
handleCodexReasoningEffortChange,
|
||||
handleCodexSubagentModelChange,
|
||||
handleCodexSubagentReasoningEffortChange,
|
||||
handleCodexConfigChange: originalHandleCodexConfigChange,
|
||||
@@ -2684,8 +2682,6 @@ function ProviderFormFull({
|
||||
onAutoSelectChange={setEndpointAutoSelect}
|
||||
codexModel={codexModel}
|
||||
onModelChange={handleCodexModelChange}
|
||||
reasoningEffort={codexReasoningEffort}
|
||||
onReasoningEffortChange={handleCodexReasoningEffortChange}
|
||||
subagentModel={codexSubagentModel}
|
||||
onSubagentModelChange={handleCodexSubagentModelChange}
|
||||
subagentReasoningEffort={codexSubagentReasoningEffort}
|
||||
|
||||
@@ -4,11 +4,9 @@ import {
|
||||
extractCodexBaseUrl,
|
||||
extractCodexExperimentalBearerToken,
|
||||
extractCodexModelName,
|
||||
extractCodexTopLevelString,
|
||||
setCodexBaseUrl as setCodexBaseUrlInConfig,
|
||||
setCodexAgentsString,
|
||||
setCodexModelName as setCodexModelNameInConfig,
|
||||
setCodexTopLevelString,
|
||||
updateCodexExperimentalBearerToken,
|
||||
} from "@/utils/providerConfigUtils";
|
||||
import { normalizeTomlText } from "@/utils/textNormalization";
|
||||
@@ -280,22 +278,6 @@ export function useCodexConfigState({ initialData }: UseCodexConfigStateProps) {
|
||||
[setCodexConfig],
|
||||
);
|
||||
|
||||
// 主代理的推理强度(顶层 `model_reasoning_effort`):直接从 TOML 读,改动实时写回,清空则删键
|
||||
const codexReasoningEffort = useMemo(
|
||||
() =>
|
||||
extractCodexTopLevelString(codexConfig, "model_reasoning_effort") || "",
|
||||
[codexConfig],
|
||||
);
|
||||
|
||||
const handleCodexReasoningEffortChange = useCallback(
|
||||
(effort: string) => {
|
||||
setCodexConfig((prev) =>
|
||||
setCodexTopLevelString(prev, "model_reasoning_effort", effort),
|
||||
);
|
||||
},
|
||||
[setCodexConfig],
|
||||
);
|
||||
|
||||
// 子代理的默认模型和推理强度(`[agents]` 表):直接从 TOML 读,改动实时写回,清空则删键
|
||||
const codexSubagentModel = useMemo(
|
||||
() => extractCodexAgentsString(codexConfig, "default_subagent_model") || "",
|
||||
@@ -372,7 +354,6 @@ export function useCodexConfigState({ initialData }: UseCodexConfigStateProps) {
|
||||
codexApiKey,
|
||||
codexBaseUrl,
|
||||
codexModel,
|
||||
codexReasoningEffort,
|
||||
codexSubagentModel,
|
||||
codexSubagentReasoningEffort,
|
||||
codexCatalogModels,
|
||||
@@ -383,7 +364,6 @@ export function useCodexConfigState({ initialData }: UseCodexConfigStateProps) {
|
||||
handleCodexApiKeyChange,
|
||||
handleCodexBaseUrlChange,
|
||||
handleCodexModelChange,
|
||||
handleCodexReasoningEffortChange,
|
||||
handleCodexSubagentModelChange,
|
||||
handleCodexSubagentReasoningEffortChange,
|
||||
handleCodexConfigChange,
|
||||
|
||||
@@ -1938,10 +1938,7 @@
|
||||
"inactiveFieldCopied": "Copied",
|
||||
"upstreamFormatCopilotRouteHint": "Every mode requires routing, which injects the Copilot account credentials. A protocol you pick explicitly fails for models that don't support it.",
|
||||
"maxOutputTokensWarning": "Don't exceed the real output limit of the model or gateway, or requests return 400.",
|
||||
"routeOnlySettingsHint": "The two settings below only apply in routing and Aggregation modes.",
|
||||
"mainReasoningEffortLabel": "Reasoning effort",
|
||||
"mainReasoningEffortHelp": "The reasoning effort Codex's main agent uses by default; it overrides each model list row's default level. Pick \"Model default\" to remove it so each model uses its own default.",
|
||||
"mainReasoningEffortDefault": "Model default"
|
||||
"routeOnlySettingsHint": "The two settings below only apply in routing and Aggregation modes."
|
||||
},
|
||||
"geminiConfig": {
|
||||
"envFile": "Environment Variables (.env)",
|
||||
|
||||
@@ -1938,10 +1938,7 @@
|
||||
"inactiveFieldCopied": "コピーしました",
|
||||
"upstreamFormatCopilotRouteHint": "どのモードでもルーティングが必要で、ルーティングが Copilot アカウントの認証情報を注入します。手動指定したプロトコルにモデルが対応していないとエラーになります。",
|
||||
"maxOutputTokensWarning": "モデルやゲートウェイの実際の出力上限を超えないでください。超えると 400 が返ります。",
|
||||
"routeOnlySettingsHint": "以下の二つはルーティングモードと集約モードでのみ有効です。",
|
||||
"mainReasoningEffortLabel": "推論の強さ",
|
||||
"mainReasoningEffortHelp": "Codex のメインエージェントが既定で使う推論の強さです。モデル一覧の各行の既定レベルより優先されます。「モデルの既定」を選ぶとこの項目を削除し、各モデル自身の既定レベルを使います。",
|
||||
"mainReasoningEffortDefault": "モデルの既定"
|
||||
"routeOnlySettingsHint": "以下の二つはルーティングモードと集約モードでのみ有効です。"
|
||||
},
|
||||
"geminiConfig": {
|
||||
"envFile": "環境変数 (.env)",
|
||||
|
||||
@@ -1939,10 +1939,7 @@
|
||||
"inactiveFieldCopied": "已複製",
|
||||
"upstreamFormatCopilotRouteHint": "所有模式都需要開啟路由,由路由注入 Copilot 帳號憑證;手動指定的協定模型不支援時會報錯。",
|
||||
"maxOutputTokensWarning": "不要超過模型或閘道的真實輸出上限,否則會回傳 400。",
|
||||
"routeOnlySettingsHint": "以下兩項只在路由、聚合模式下生效。",
|
||||
"mainReasoningEffortLabel": "推理強度",
|
||||
"mainReasoningEffortHelp": "Codex 主代理預設使用的推理強度,會蓋過模型列表裡每行的預設等級。選「依模型預設」就刪掉這一項,各模型用自己的預設等級。",
|
||||
"mainReasoningEffortDefault": "依模型預設"
|
||||
"routeOnlySettingsHint": "以下兩項只在路由、聚合模式下生效。"
|
||||
},
|
||||
"geminiConfig": {
|
||||
"envFile": "環境變數 (.env)",
|
||||
|
||||
@@ -1938,10 +1938,7 @@
|
||||
"inactiveFieldCopied": "已复制",
|
||||
"upstreamFormatCopilotRouteHint": "所有模式都需要开启路由,由路由注入 Copilot 账号凭据;手动指定的协议模型不支持时会报错。",
|
||||
"maxOutputTokensWarning": "不要超过模型或网关的真实输出上限,否则会返回 400。",
|
||||
"routeOnlySettingsHint": "以下两项只在路由、聚合模式下生效。",
|
||||
"mainReasoningEffortLabel": "推理强度",
|
||||
"mainReasoningEffortHelp": "Codex 主代理默认用的推理强度,会盖过模型列表里每行的默认等级。选「按模型默认」就删掉这一项,各模型用自己的默认等级。",
|
||||
"mainReasoningEffortDefault": "按模型默认"
|
||||
"routeOnlySettingsHint": "以下两项只在路由、聚合模式下生效。"
|
||||
},
|
||||
"geminiConfig": {
|
||||
"envFile": "环境变量 (.env)",
|
||||
|
||||
@@ -1500,86 +1500,6 @@ export const setCodexAgentsString = (
|
||||
}
|
||||
};
|
||||
|
||||
// ========== Codex top-level string fields ==========
|
||||
|
||||
// 主代理的推理强度(顶层 `model_reasoning_effort`)。后端把它当关键字段,随供应商切换。
|
||||
export type CodexTopLevelStringKey = "model_reasoning_effort";
|
||||
|
||||
export const extractCodexTopLevelString = (
|
||||
configText: string | undefined | null,
|
||||
key: CodexTopLevelStringKey,
|
||||
): string | undefined => {
|
||||
const text = normalizeTomlText(
|
||||
typeof configText === "string" ? configText : "",
|
||||
);
|
||||
if (!text) return undefined;
|
||||
try {
|
||||
const value = (parseToml(text) as Record<string, unknown>)[key];
|
||||
return typeof value === "string" ? value : undefined;
|
||||
} catch {
|
||||
// 编辑中的 TOML 解析不了时按行在顶层找。
|
||||
}
|
||||
const lines = text.split("\n");
|
||||
const patterns = tomlStringAssignmentPatterns(key);
|
||||
const topLevelEndIndex = getTopLevelEndIndex(lines);
|
||||
for (let i = 0; i < topLevelEndIndex; i += 1) {
|
||||
const doubleQuoted = lines[i].match(patterns.doubleQuoted);
|
||||
if (doubleQuoted) return unescapeTomlBasicString(doubleQuoted[1]);
|
||||
const singleQuoted = lines[i].match(patterns.singleQuoted);
|
||||
if (singleQuoted) return singleQuoted[1];
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
// 写入或删除顶层的一个字符串键;空值删除。新键放在 `model` 行后面(没有就放在
|
||||
// `model_provider` 后面,再没有就放在第一个表之前)。改完解析失败就原样返回。
|
||||
export const setCodexTopLevelString = (
|
||||
configText: string,
|
||||
key: CodexTopLevelStringKey,
|
||||
value: string,
|
||||
): string => {
|
||||
const trimmed = value.trim();
|
||||
const normalizedText = normalizeTomlText(configText);
|
||||
const lines = normalizedText ? normalizedText.split("\n") : [];
|
||||
const topLevelEndIndex = getTopLevelEndIndex(lines);
|
||||
const lineIndex = findTomlLineInRange(
|
||||
lines,
|
||||
tomlStringAssignmentPatterns(key).anyValue,
|
||||
0,
|
||||
topLevelEndIndex,
|
||||
);
|
||||
const replacementLine = `${key} = ${tomlBasicString(trimmed)}`;
|
||||
|
||||
if (!trimmed) {
|
||||
if (lineIndex === -1) return normalizedText;
|
||||
lines.splice(lineIndex, 1);
|
||||
} else if (lineIndex !== -1) {
|
||||
lines[lineIndex] = replacementLine;
|
||||
} else {
|
||||
const modelIndex = findTopLevelModelLineIndex(lines, topLevelEndIndex);
|
||||
const anchor =
|
||||
modelIndex !== -1 ? modelIndex : getTopLevelModelProviderLineIndex(lines);
|
||||
lines.splice(
|
||||
anchor !== -1 ? anchor + 1 : topLevelEndIndex,
|
||||
0,
|
||||
replacementLine,
|
||||
);
|
||||
}
|
||||
|
||||
const candidate = finalizeTomlText(lines);
|
||||
try {
|
||||
parseToml(normalizedText);
|
||||
} catch {
|
||||
return candidate;
|
||||
}
|
||||
try {
|
||||
parseToml(candidate);
|
||||
return candidate;
|
||||
} catch {
|
||||
return normalizedText;
|
||||
}
|
||||
};
|
||||
|
||||
// ========== Codex top-level integer field utils ==========
|
||||
|
||||
const tomlTopLevelIntPattern = (field: string) =>
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
ProviderForm,
|
||||
type ProviderFormValues,
|
||||
} from "@/components/providers/forms/ProviderForm";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { ProviderForm } from "@/components/providers/forms/ProviderForm";
|
||||
import type { ProviderMeta } from "@/types";
|
||||
import type { AppMode } from "@/types/proxy";
|
||||
import { createTestQueryClient } from "../utils/testQueryClient";
|
||||
@@ -102,18 +99,14 @@ function expandClaudeAdvanced() {
|
||||
expect(toggle).toHaveAttribute("aria-expanded", "true");
|
||||
}
|
||||
|
||||
function renderCodex(
|
||||
meta?: ProviderMeta,
|
||||
onSubmit: (values: ProviderFormValues) => void = vi.fn(),
|
||||
topLevel = "",
|
||||
) {
|
||||
function renderCodex(meta?: ProviderMeta) {
|
||||
return render(
|
||||
<QueryClientProvider client={createTestQueryClient()}>
|
||||
<ProviderForm
|
||||
appId="codex"
|
||||
providerId="relay"
|
||||
submitLabel="save-provider"
|
||||
onSubmit={onSubmit}
|
||||
onSubmit={vi.fn()}
|
||||
onCancel={vi.fn()}
|
||||
initialData={{
|
||||
name: "Relay",
|
||||
@@ -122,7 +115,6 @@ function renderCodex(
|
||||
auth: {},
|
||||
config:
|
||||
'model_provider = "custom"\nmodel = "m-1"\n' +
|
||||
topLevel +
|
||||
'\n[model_providers.custom]\nname = "custom"\nbase_url = "https://relay.example/v1"\nexperimental_bearer_token = "sk-test"\n',
|
||||
},
|
||||
meta,
|
||||
@@ -272,61 +264,6 @@ describe("完整表单按实际模式提示(Codex)", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("Codex 主代理推理强度", () => {
|
||||
beforeAll(() => {
|
||||
// jsdom 没有 scrollIntoView,Radix Select 打开已选中值的列表时会调用。
|
||||
Object.defineProperty(HTMLElement.prototype, "scrollIntoView", {
|
||||
configurable: true,
|
||||
value: () => {},
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
modeState.mode = "route";
|
||||
modeState.directProviderId = null;
|
||||
});
|
||||
|
||||
it("读出 model_reasoning_effort,选「按模型默认」后保存时删掉这一项", async () => {
|
||||
const onSubmit = vi.fn();
|
||||
renderCodex(undefined, onSubmit, 'model_reasoning_effort = "high"\n');
|
||||
|
||||
const control = screen.getByRole("combobox", { name: "推理强度" });
|
||||
expect(control).toHaveTextContent("high");
|
||||
fireEvent.keyDown(control, { key: "ArrowDown" });
|
||||
fireEvent.click(await screen.findByRole("option", { name: "按模型默认" }));
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "save-provider" }));
|
||||
await waitFor(() => expect(onSubmit).toHaveBeenCalledTimes(1));
|
||||
const values = onSubmit.mock.calls[0][0] as ProviderFormValues;
|
||||
const settings = JSON.parse(values.settingsConfig);
|
||||
expect(settings.config).not.toContain("model_reasoning_effort");
|
||||
expect(settings.config).toContain('model = "m-1"');
|
||||
});
|
||||
|
||||
it("选一个档位后保存写进顶层", async () => {
|
||||
const onSubmit = vi.fn();
|
||||
renderCodex(undefined, onSubmit);
|
||||
|
||||
const control = screen.getByRole("combobox", { name: "推理强度" });
|
||||
fireEvent.keyDown(control, { key: "ArrowDown" });
|
||||
fireEvent.click(await screen.findByRole("option", { name: "low" }));
|
||||
|
||||
fireEvent.click(screen.getByRole("button", { name: "save-provider" }));
|
||||
await waitFor(() => expect(onSubmit).toHaveBeenCalledTimes(1));
|
||||
const values = onSubmit.mock.calls[0][0] as ProviderFormValues;
|
||||
const settings = JSON.parse(values.settingsConfig);
|
||||
expect(settings.config).toContain('model_reasoning_effort = "low"');
|
||||
});
|
||||
|
||||
it("聚合布局不显示", () => {
|
||||
modeState.mode = "stack";
|
||||
renderCodex();
|
||||
|
||||
expect(screen.queryByRole("combobox", { name: "推理强度" })).toBeNull();
|
||||
expect(screen.getByText("模型列表")).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("完整 URL 开关在高级选项里", () => {
|
||||
beforeEach(() => {
|
||||
modeState.mode = "route";
|
||||
|
||||
@@ -6,13 +6,11 @@ import {
|
||||
extractCodexExperimentalBearerToken,
|
||||
extractCodexModelName,
|
||||
extractCodexTopLevelInt,
|
||||
extractCodexTopLevelString,
|
||||
removeCodexTopLevelField,
|
||||
setCodexAgentsString,
|
||||
setCodexBaseUrl,
|
||||
setCodexModelName,
|
||||
setCodexTopLevelInt,
|
||||
setCodexTopLevelString,
|
||||
updateCodexExperimentalBearerToken,
|
||||
} from "@/utils/providerConfigUtils";
|
||||
|
||||
@@ -547,68 +545,3 @@ describe("Codex [agents] subagent defaults", () => {
|
||||
expect((parseToml(updated) as any).agents).toEqual({ max_threads: 4 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("Codex top-level model_reasoning_effort", () => {
|
||||
const base = [
|
||||
'model_provider = "custom"',
|
||||
'model = "gpt-a"',
|
||||
"",
|
||||
"[model_providers.custom]",
|
||||
'base_url = "https://a.example/v1"',
|
||||
].join("\n");
|
||||
|
||||
it("inserts after model, replaces in place, and removes on empty", () => {
|
||||
const added = setCodexTopLevelString(
|
||||
base,
|
||||
"model_reasoning_effort",
|
||||
"high",
|
||||
);
|
||||
expect(added.split("\n").slice(0, 3)).toEqual([
|
||||
'model_provider = "custom"',
|
||||
'model = "gpt-a"',
|
||||
'model_reasoning_effort = "high"',
|
||||
]);
|
||||
expect(extractCodexTopLevelString(added, "model_reasoning_effort")).toBe(
|
||||
"high",
|
||||
);
|
||||
|
||||
const replaced = setCodexTopLevelString(
|
||||
added,
|
||||
"model_reasoning_effort",
|
||||
"low",
|
||||
);
|
||||
expect((parseToml(replaced) as any).model_reasoning_effort).toBe("low");
|
||||
expect(replaced.match(/model_reasoning_effort/g)).toHaveLength(1);
|
||||
|
||||
const removed = setCodexTopLevelString(
|
||||
replaced,
|
||||
"model_reasoning_effort",
|
||||
"",
|
||||
);
|
||||
expect(removed.trimEnd()).toBe(base);
|
||||
expect(
|
||||
extractCodexTopLevelString(removed, "model_reasoning_effort"),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not touch a same-named key inside a table", () => {
|
||||
const input = [
|
||||
'model = "gpt-a"',
|
||||
"",
|
||||
"[profiles.fast]",
|
||||
'model_reasoning_effort = "low"',
|
||||
].join("\n");
|
||||
|
||||
expect(
|
||||
extractCodexTopLevelString(input, "model_reasoning_effort"),
|
||||
).toBeUndefined();
|
||||
const updated = setCodexTopLevelString(
|
||||
input,
|
||||
"model_reasoning_effort",
|
||||
"high",
|
||||
);
|
||||
const parsed = parseToml(updated) as any;
|
||||
expect(parsed.model_reasoning_effort).toBe("high");
|
||||
expect(parsed.profiles.fast.model_reasoning_effort).toBe("low");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user