mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-03 19:12:04 +08:00
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>
This commit is contained in:
@@ -410,6 +410,9 @@ const TOML_WIRE_API_PATTERN =
|
||||
/^\s*wire_api\s*=\s*(["'])([^"'\r\n]+)\1\s*(?:#.*)?$/;
|
||||
const TOML_MODEL_PROVIDER_LINE_PATTERN =
|
||||
/^\s*model_provider\s*=\s*(["'])([^"'\r\n]+)\1\s*(?:#.*)?$/;
|
||||
const TOML_GOALS_FEATURE_PATTERN = /^\s*goals\s*=\s*(true|false)\s*(?:#.*)?$/;
|
||||
const TOML_GOALS_FEATURE_REPLACE_PATTERN =
|
||||
/^(\s*goals\s*=\s*)(true|false)(\s*(?:#.*)?)$/;
|
||||
const CODEX_RESERVED_MODEL_PROVIDER_IDS = new Set([
|
||||
"amazon-bedrock",
|
||||
"openai",
|
||||
@@ -422,6 +425,7 @@ const CODEX_RESERVED_MODEL_PROVIDER_IDS = new Set([
|
||||
interface TomlSectionRange {
|
||||
bodyEndIndex: number;
|
||||
bodyStartIndex: number;
|
||||
headerLineIndex: number;
|
||||
}
|
||||
|
||||
interface TomlAssignmentMatch {
|
||||
@@ -458,6 +462,7 @@ const getTomlSectionRange = (
|
||||
return {
|
||||
bodyStartIndex: headerLineIndex + 1,
|
||||
bodyEndIndex: index,
|
||||
headerLineIndex,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -468,6 +473,7 @@ const getTomlSectionRange = (
|
||||
return {
|
||||
bodyStartIndex: headerLineIndex + 1,
|
||||
bodyEndIndex: lines.length,
|
||||
headerLineIndex,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -639,6 +645,14 @@ const getTopLevelModelProviderLineIndex = (lines: string[]): number => {
|
||||
return -1;
|
||||
};
|
||||
|
||||
const hasTomlSectionBodyContent = (
|
||||
lines: string[],
|
||||
sectionRange: TomlSectionRange,
|
||||
): boolean =>
|
||||
lines
|
||||
.slice(sectionRange.bodyStartIndex, sectionRange.bodyEndIndex)
|
||||
.some((line) => line.trim() !== "");
|
||||
|
||||
const TOML_BASIC_STRING_ESCAPES: Record<string, string> = {
|
||||
'"': '\\"',
|
||||
"\\": "\\\\",
|
||||
@@ -797,6 +811,103 @@ export const setCodexWireApi = (
|
||||
return finalizeTomlText(lines);
|
||||
};
|
||||
|
||||
export const isCodexGoalModeEnabled = (
|
||||
configText: string | undefined | null,
|
||||
): boolean => {
|
||||
try {
|
||||
const raw = typeof configText === "string" ? configText : "";
|
||||
const text = normalizeTomlText(raw);
|
||||
if (!text) return false;
|
||||
|
||||
try {
|
||||
const parsed = parseToml(text) as Record<string, any>;
|
||||
return parsed.features?.goals === true;
|
||||
} catch {
|
||||
// Fall back to line scanning while the user is editing invalid TOML.
|
||||
}
|
||||
|
||||
const lines = text.split("\n");
|
||||
const featureRange = getTomlSectionRange(lines, "features");
|
||||
if (!featureRange) return false;
|
||||
|
||||
const index = findTomlLineInRange(
|
||||
lines,
|
||||
TOML_GOALS_FEATURE_PATTERN,
|
||||
featureRange.bodyStartIndex,
|
||||
featureRange.bodyEndIndex,
|
||||
);
|
||||
if (index === -1) return false;
|
||||
|
||||
return lines[index].match(TOML_GOALS_FEATURE_PATTERN)?.[1] === "true";
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
export const setCodexGoalMode = (
|
||||
configText: string,
|
||||
enabled: boolean,
|
||||
): string => {
|
||||
const normalizedText = normalizeTomlText(configText);
|
||||
const lines = normalizedText ? normalizedText.split("\n") : [];
|
||||
let featureRange = getTomlSectionRange(lines, "features");
|
||||
|
||||
if (featureRange) {
|
||||
const goalLineIndex = findTomlLineInRange(
|
||||
lines,
|
||||
TOML_GOALS_FEATURE_REPLACE_PATTERN,
|
||||
featureRange.bodyStartIndex,
|
||||
featureRange.bodyEndIndex,
|
||||
);
|
||||
|
||||
if (enabled) {
|
||||
if (goalLineIndex !== -1) {
|
||||
lines[goalLineIndex] = lines[goalLineIndex].replace(
|
||||
TOML_GOALS_FEATURE_REPLACE_PATTERN,
|
||||
"$1true$3",
|
||||
);
|
||||
} else {
|
||||
lines.splice(
|
||||
getTomlSectionInsertIndex(lines, featureRange),
|
||||
0,
|
||||
"goals = true",
|
||||
);
|
||||
}
|
||||
return finalizeTomlText(lines);
|
||||
}
|
||||
|
||||
if (goalLineIndex !== -1) {
|
||||
lines.splice(goalLineIndex, 1);
|
||||
featureRange = getTomlSectionRange(lines, "features");
|
||||
if (featureRange && !hasTomlSectionBodyContent(lines, featureRange)) {
|
||||
lines.splice(
|
||||
featureRange.headerLineIndex,
|
||||
featureRange.bodyEndIndex - featureRange.headerLineIndex,
|
||||
);
|
||||
}
|
||||
}
|
||||
return finalizeTomlText(lines);
|
||||
}
|
||||
|
||||
if (!enabled) return normalizedText;
|
||||
|
||||
const topLevelEndIndex = getTopLevelEndIndex(lines);
|
||||
const sectionLines: string[] = [];
|
||||
if (topLevelEndIndex > 0 && lines[topLevelEndIndex - 1].trim() !== "") {
|
||||
sectionLines.push("");
|
||||
}
|
||||
sectionLines.push("[features]", "goals = true");
|
||||
if (
|
||||
topLevelEndIndex < lines.length &&
|
||||
lines[topLevelEndIndex]?.trim() !== ""
|
||||
) {
|
||||
sectionLines.push("");
|
||||
}
|
||||
|
||||
lines.splice(topLevelEndIndex, 0, ...sectionLines);
|
||||
return finalizeTomlText(lines);
|
||||
};
|
||||
|
||||
// 从 Codex 的 TOML 配置文本中提取 base_url(支持单/双引号)
|
||||
export const extractCodexBaseUrl = (
|
||||
configText: string | undefined | null,
|
||||
|
||||
Reference in New Issue
Block a user