chore: update codex pool git rules
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import { renderCodexLocalConsumerToml } from "./src/platform-infra-sub2api-codex";
|
||||
|
||||
function assertCondition(condition: unknown, message: string, detail: unknown = {}): void {
|
||||
if (!condition) throw new Error(`${message}: ${JSON.stringify(detail)}`);
|
||||
}
|
||||
|
||||
const baseOptions = {
|
||||
providerName: "OpenAI",
|
||||
baseUrl: "http://127.0.0.1:21880",
|
||||
wireApi: "responses",
|
||||
supportsWebSockets: true,
|
||||
responsesWebSocketsV2: true,
|
||||
};
|
||||
|
||||
const existing = [
|
||||
'model_provider = "Legacy"',
|
||||
"",
|
||||
"[model_providers.OpenAI]",
|
||||
'name = "OpenAI"',
|
||||
'base_url = "https://old.example"',
|
||||
'wire_api = "responses"',
|
||||
"requires_openai_auth = false",
|
||||
"supports_websockets = false",
|
||||
'env_key = "OLD_OPENAI_API_KEY"',
|
||||
'extra_setting = "kept"',
|
||||
"",
|
||||
"[features]",
|
||||
"goals = true",
|
||||
"responses_websockets_v2 = false",
|
||||
"",
|
||||
].join("\n");
|
||||
|
||||
const updated = renderCodexLocalConsumerToml(existing, baseOptions);
|
||||
|
||||
assertCondition(updated.includes('model_provider = "OpenAI"'), "model_provider must point at the configured provider", updated);
|
||||
assertCondition(updated.includes('base_url = "http://127.0.0.1:21880"'), "provider base_url must use the Sub2API consumer endpoint", updated);
|
||||
assertCondition(updated.includes("requires_openai_auth = true"), "provider must require OpenAI auth", updated);
|
||||
assertCondition(updated.includes("supports_websockets = true"), "provider must enable WebSocket transport", updated);
|
||||
assertCondition(updated.includes("responses_websockets_v2 = true"), "features must enable Responses WebSocket v2", updated);
|
||||
assertCondition(updated.includes("goals = true"), "existing feature flags must be preserved", updated);
|
||||
assertCondition(updated.includes('extra_setting = "kept"'), "unknown provider settings must be preserved", updated);
|
||||
assertCondition(!updated.includes("env_key"), "stale provider env_key must be removed", updated);
|
||||
assertCondition(updated.endsWith("\n"), "rendered TOML must end with newline", updated);
|
||||
|
||||
const fresh = renderCodexLocalConsumerToml("", baseOptions);
|
||||
|
||||
assertCondition(fresh.includes("[model_providers.OpenAI]"), "fresh TOML must create the provider section", fresh);
|
||||
assertCondition(fresh.includes("[features]"), "fresh TOML must create the features section", fresh);
|
||||
assertCondition(fresh.includes("supports_websockets = true"), "fresh TOML must enable WebSocket transport", fresh);
|
||||
assertCondition(fresh.includes("responses_websockets_v2 = true"), "fresh TOML must enable Responses WebSocket v2", fresh);
|
||||
|
||||
console.log(JSON.stringify({
|
||||
ok: true,
|
||||
checks: [
|
||||
"existing Codex TOML is upgraded to the Sub2API WSv2 consumer settings",
|
||||
"fresh Codex TOML creates provider and feature sections with WSv2 enabled",
|
||||
],
|
||||
}));
|
||||
@@ -15,6 +15,7 @@ const syntaxFiles = [
|
||||
"scripts/cli.ts",
|
||||
"scripts/playwright-cli.ts",
|
||||
"scripts/playwright-cli-contract-test.ts",
|
||||
"scripts/platform-infra-sub2api-codex-local-config-contract-test.ts",
|
||||
"scripts/src/playwright-cli.ts",
|
||||
"scripts/src/check.ts",
|
||||
"scripts/src/artifact-registry.ts",
|
||||
@@ -382,6 +383,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
|
||||
fileItem("scripts/gh-cli-pr-files-contract-test.ts"),
|
||||
fileItem("scripts/gh-cli-pr-contract-test.ts"),
|
||||
fileItem("scripts/playwright-cli-contract-test.ts"),
|
||||
fileItem("scripts/platform-infra-sub2api-codex-local-config-contract-test.ts"),
|
||||
fileItem("scripts/code-queue-pr-preflight-example.ts"),
|
||||
fileItem("scripts/schedule-cli-contract-test.ts"),
|
||||
fileItem("scripts/server-cleanup-plan-contract-test.ts"),
|
||||
@@ -446,6 +448,7 @@ export function runChecks(config: UniDeskConfig, options: CheckOptions = default
|
||||
items.push(commandItem("gh:pr-files-contract", ["bun", "scripts/gh-cli-pr-files-contract-test.ts"], 30_000));
|
||||
items.push(commandItem("gh:pr-contract", ["bun", "scripts/gh-cli-pr-contract-test.ts"], 30_000));
|
||||
items.push(commandItem("playwright:cli-wrapper-contract", ["bun", "scripts/playwright-cli-contract-test.ts"], 30_000));
|
||||
items.push(commandItem("platform-infra:sub2api-codex-local-config-contract", ["bun", "scripts/platform-infra-sub2api-codex-local-config-contract-test.ts"], 30_000));
|
||||
items.push(commandItem("auth-broker:p0-contract", ["bun", "scripts/auth-broker-contract-test.ts"], 30_000));
|
||||
items.push(commandItem("d601:recovery-guardrails-contract", ["bun", "scripts/d601-recovery-guardrails-contract-test.ts"], 30_000));
|
||||
items.push(commandItem("hwlab:cd-wrapper-contract", ["bun", "scripts/hwlab-cd-wrapper-contract-test.ts"], 30_000));
|
||||
|
||||
@@ -103,6 +103,16 @@ interface CodexPoolLocalCodexConfig {
|
||||
backupSuffix: string;
|
||||
providerName: string;
|
||||
wireApi: string;
|
||||
supportsWebSockets: boolean;
|
||||
responsesWebSocketsV2: boolean;
|
||||
}
|
||||
|
||||
interface CodexLocalConsumerTomlOptions {
|
||||
providerName: string;
|
||||
baseUrl: string;
|
||||
wireApi: string;
|
||||
supportsWebSockets: boolean;
|
||||
responsesWebSocketsV2: boolean;
|
||||
}
|
||||
|
||||
export function codexPoolHelp(): unknown {
|
||||
@@ -367,6 +377,8 @@ async function codexPoolConfigureLocal(config: UniDeskConfig, options: ConfirmOp
|
||||
baseUrl: pool.publicExposure.masterBaseUrl,
|
||||
providerName: pool.localCodex.providerName,
|
||||
wireApi: pool.localCodex.wireApi,
|
||||
supportsWebSockets: pool.localCodex.supportsWebSockets,
|
||||
responsesWebSocketsV2: pool.localCodex.responsesWebSocketsV2,
|
||||
valuesPrinted: false,
|
||||
},
|
||||
next: {
|
||||
@@ -570,6 +582,8 @@ function defaultCodexPoolConfig(): CodexPoolConfig {
|
||||
backupSuffix: "pre-sub2api",
|
||||
providerName: "OpenAI",
|
||||
wireApi: "responses",
|
||||
supportsWebSockets: true,
|
||||
responsesWebSocketsV2: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -647,6 +661,13 @@ function readAccountCapacity(value: unknown, key: string): number {
|
||||
return capacity;
|
||||
}
|
||||
|
||||
function readBooleanConfig(value: unknown, key: string, fallback: boolean): boolean {
|
||||
if (value === undefined || value === null) return fallback;
|
||||
const parsed = booleanValue(value);
|
||||
if (parsed === null) throw new Error(`${codexPoolConfigPath}.${key} must be a boolean`);
|
||||
return parsed;
|
||||
}
|
||||
|
||||
function readPublicExposureConfig(value: unknown, defaults: CodexPoolPublicExposureConfig): CodexPoolPublicExposureConfig {
|
||||
if (!isRecord(value)) return defaults;
|
||||
const masterFrpsValue = isRecord(value.masterFrps) ? value.masterFrps : {};
|
||||
@@ -688,6 +709,8 @@ function readLocalCodexConfig(value: unknown, defaults: CodexPoolLocalCodexConfi
|
||||
backupSuffix: stringValue(value.backupSuffix) ?? defaults.backupSuffix,
|
||||
providerName: stringValue(value.providerName) ?? defaults.providerName,
|
||||
wireApi: stringValue(value.wireApi) ?? defaults.wireApi,
|
||||
supportsWebSockets: readBooleanConfig(value.supportsWebSockets, "localCodex.supportsWebSockets", defaults.supportsWebSockets),
|
||||
responsesWebSocketsV2: readBooleanConfig(value.responsesWebSocketsV2, "localCodex.responsesWebSocketsV2", defaults.responsesWebSocketsV2),
|
||||
};
|
||||
if (!/^[A-Za-z0-9._-]+$/u.test(config.backupSuffix)) throw new Error(`${codexPoolConfigPath}.localCodex.backupSuffix has an unsupported format`);
|
||||
validateProxyName(config.providerName, "localCodex.providerName");
|
||||
@@ -1093,6 +1116,8 @@ function writeLocalCodexConfig(pool: CodexPoolConfig, apiKey: string): Record<st
|
||||
name: pool.localCodex.providerName,
|
||||
baseUrl: pool.publicExposure.masterBaseUrl,
|
||||
wireApi: pool.localCodex.wireApi,
|
||||
supportsWebSockets: pool.localCodex.supportsWebSockets,
|
||||
responsesWebSocketsV2: pool.localCodex.responsesWebSocketsV2,
|
||||
},
|
||||
valuesPrinted: false,
|
||||
};
|
||||
@@ -1106,8 +1131,19 @@ function copyIfMissing(source: string, target: string): "created" | "kept-existi
|
||||
}
|
||||
|
||||
function updateCodexConfigToml(current: string, pool: CodexPoolConfig): string {
|
||||
let next = upsertTopLevelTomlString(current, "model_provider", pool.localCodex.providerName);
|
||||
next = upsertProviderSection(next, pool.localCodex.providerName, pool.publicExposure.masterBaseUrl, pool.localCodex.wireApi);
|
||||
return renderCodexLocalConsumerToml(current, {
|
||||
providerName: pool.localCodex.providerName,
|
||||
baseUrl: pool.publicExposure.masterBaseUrl,
|
||||
wireApi: pool.localCodex.wireApi,
|
||||
supportsWebSockets: pool.localCodex.supportsWebSockets,
|
||||
responsesWebSocketsV2: pool.localCodex.responsesWebSocketsV2,
|
||||
});
|
||||
}
|
||||
|
||||
export function renderCodexLocalConsumerToml(current: string, options: CodexLocalConsumerTomlOptions): string {
|
||||
let next = upsertTopLevelTomlString(current, "model_provider", options.providerName);
|
||||
next = upsertProviderSection(next, options);
|
||||
next = upsertTomlSectionBoolean(next, "features", "responses_websockets_v2", options.responsesWebSocketsV2);
|
||||
return next.endsWith("\n") ? next : `${next}\n`;
|
||||
}
|
||||
|
||||
@@ -1125,7 +1161,8 @@ function upsertTopLevelTomlString(text: string, key: string, value: string): str
|
||||
return lines.join("\n");
|
||||
}
|
||||
|
||||
function upsertProviderSection(text: string, providerName: string, baseUrl: string, wireApi: string): string {
|
||||
function upsertProviderSection(text: string, options: CodexLocalConsumerTomlOptions): string {
|
||||
const { providerName, baseUrl, wireApi, supportsWebSockets } = options;
|
||||
const header = `[model_providers.${providerName}]`;
|
||||
const lines = text.split(/\r?\n/u);
|
||||
const start = lines.findIndex((line) => line.trim() === header);
|
||||
@@ -1134,6 +1171,7 @@ function upsertProviderSection(text: string, providerName: string, baseUrl: stri
|
||||
`base_url = ${tomlString(baseUrl)}`,
|
||||
`wire_api = ${tomlString(wireApi)}`,
|
||||
"requires_openai_auth = true",
|
||||
`supports_websockets = ${tomlBoolean(supportsWebSockets)}`,
|
||||
];
|
||||
if (start === -1) {
|
||||
const needsBlank = lines.length > 0 && lines[lines.length - 1].trim() !== "";
|
||||
@@ -1147,12 +1185,37 @@ function upsertProviderSection(text: string, providerName: string, baseUrl: stri
|
||||
}
|
||||
}
|
||||
const preserved = lines.slice(start + 1, end).filter((line) => {
|
||||
return !/^\s*(name|base_url|wire_api|requires_openai_auth|env_key)\s*=/u.test(line);
|
||||
return !/^\s*(name|base_url|wire_api|requires_openai_auth|supports_websockets|env_key)\s*=/u.test(line);
|
||||
});
|
||||
const replacement = [header, ...canonical, ...preserved.filter((line) => line.trim() !== "")];
|
||||
return [...lines.slice(0, start), ...replacement, ...lines.slice(end)].join("\n");
|
||||
}
|
||||
|
||||
function upsertTomlSectionBoolean(text: string, sectionName: string, key: string, value: boolean): string {
|
||||
const header = `[${sectionName}]`;
|
||||
const lines = text.split(/\r?\n/u);
|
||||
const start = lines.findIndex((line) => line.trim() === header);
|
||||
const assignment = `${key} = ${tomlBoolean(value)}`;
|
||||
if (start === -1) {
|
||||
const needsBlank = lines.length > 0 && lines[lines.length - 1].trim() !== "";
|
||||
return [...lines, ...(needsBlank ? [""] : []), header, assignment].join("\n");
|
||||
}
|
||||
let end = lines.length;
|
||||
for (let index = start + 1; index < lines.length; index += 1) {
|
||||
if (/^\s*\[/.test(lines[index])) {
|
||||
end = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let index = start + 1; index < end; index += 1) {
|
||||
if (new RegExp(`^\\s*${escapeRegExp(key)}\\s*=`).test(lines[index])) {
|
||||
lines[index] = assignment;
|
||||
return lines.join("\n");
|
||||
}
|
||||
}
|
||||
return [...lines.slice(0, start + 1), assignment, ...lines.slice(start + 1)].join("\n");
|
||||
}
|
||||
|
||||
async function validatePublicGatewayWithKey(pool: CodexPoolConfig, apiKey: string): Promise<Record<string, unknown>> {
|
||||
const probe = await probePublicModels(pool, "with-api-key", apiKey);
|
||||
return {
|
||||
@@ -1216,6 +1279,10 @@ function tomlString(value: string): string {
|
||||
return JSON.stringify(value);
|
||||
}
|
||||
|
||||
function tomlBoolean(value: boolean): string {
|
||||
return value ? "true" : "false";
|
||||
}
|
||||
|
||||
function escapeRegExp(value: string): string {
|
||||
return value.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user