chore: rebuild CentOS7 release package

This commit is contained in:
shiyue
2026-06-25 21:52:09 +08:00
parent 04dd48deb2
commit c387c92e4b
11 changed files with 924 additions and 34 deletions

View File

@@ -89,6 +89,8 @@ function ensureThread(threadId, params = {}) {
activeTurnId: null,
timer: null,
steers: [],
capacityRetryAttempts: new Map(),
reconnectRetryAttempts: new Map(),
goal: null,
});
}
@@ -463,6 +465,60 @@ function completeMcpToolTurn(thread, turnId) {
completeTurn(thread, turnId, `mcp result: ${JSON.stringify(payload)}`);
}
function emitCapacityError(thread, turnId) {
send({
method: 'error',
params: {
threadId: thread.id,
turnId,
type: 'error',
error: {
type: 'service_unavailable_error',
code: 'server_is_overloaded',
message: 'Our servers are currently overloaded. Please try again later.',
param: null,
},
sequence_number: 2,
},
});
thread.activeTurnId = null;
}
function emitPartialCapacityOutput(thread, turnId) {
send({
method: 'item/agentMessage/delta',
params: {
threadId: thread.id,
turnId,
itemId: 'agent-msg',
delta: 'partial capacity output before retry',
},
});
send({
method: 'item/started',
params: {
threadId: thread.id,
turnId,
startedAtMs: Date.now(),
item: {
id: 'capacity-tool',
type: 'commandExecution',
command: '/bin/bash -lc echo capacity',
status: 'inProgress',
},
},
});
send({
method: 'item/commandExecution/outputDelta',
params: {
threadId: thread.id,
turnId,
itemId: 'capacity-tool',
delta: 'capacity tool output\n',
},
});
}
function completeGuidedInputTurn(thread, turnId) {
requestClient('item/tool/requestUserInput', {
threadId: thread.id,
@@ -566,6 +622,34 @@ function startTurn(params) {
}
}
if (/codexapp capacity retry/i.test(text)) {
const attempts = (thread.capacityRetryAttempts.get(text) || 0) + 1;
thread.capacityRetryAttempts.set(text, attempts);
if (attempts <= 2) {
if (attempts === 2) emitPartialCapacityOutput(thread, turnId);
emitCapacityError(thread, turnId);
return { turn: { id: turnId, status: 'running', items: [] } };
}
}
if (/codexapp reconnect retry/i.test(text)) {
const attempts = (thread.reconnectRetryAttempts.get(text) || 0) + 1;
thread.reconnectRetryAttempts.set(text, attempts);
if (attempts === 1) {
emitPartialCapacityOutput(thread, turnId);
send({
method: 'error',
params: {
threadId: thread.id,
turnId,
message: 'Reconnecting... 1/5',
},
});
thread.activeTurnId = null;
return { turn: { id: turnId, status: 'running', items: [] } };
}
}
if (/collaboration/i.test(text)) {
completeTurn(thread, turnId, `collaboration mode: ${collaborationSummary(params)}`);
return { turn: { id: turnId, status: 'running', items: [] } };

View File

@@ -87,6 +87,20 @@ function sleep(ms) {
process.exit(1);
}
if (input === 'trigger codex capacity retry' && !state.capacityRetried) {
state.capacityRetried = true;
fs.writeFileSync(statePath, JSON.stringify(state));
process.stdout.write(`${JSON.stringify({
type: 'turn.failed',
error: {
type: 'service_unavailable_error',
code: 'server_is_overloaded',
message: 'Our servers are currently overloaded. Please try again later.',
},
})}\n`);
process.exit(1);
}
if (input === 'slow cross-session prompt') {
await sleep(800);
}

View File

@@ -621,6 +621,7 @@ async function main() {
HOME: homeDir,
CLAUDE_PATH: MOCK_CLAUDE,
CODEX_PATH: MOCK_CODEX_APP_SERVER,
CC_WEB_CODEX_TRANSIENT_RETRY_BASE_DELAY_MS: '100',
}, async () => {
await assertWsUpgradeRejected(port, '/not-ws');
@@ -663,6 +664,7 @@ async function main() {
activeProfile: 'Regression Profile',
profiles: [{ name: 'Regression Profile', apiKey: 'sk-regression', apiBase: 'https://example.com/v1' }],
enableSearch: true,
retry: { mode: 'limited', intervalSeconds: 1, maxAttempts: 2 },
},
}));
const codexConfigMsg = await nextMessage(messages, ws, (msg) => msg.type === 'codex_config');
@@ -671,6 +673,9 @@ async function main() {
assert(Array.isArray(codexConfigMsg.config.profiles) && codexConfigMsg.config.profiles[0]?.apiKey.includes('****'), 'Codex profile API key should be masked');
assert(codexConfigMsg.config.supportsSearch === false, 'Codex config should expose unsupported search capability');
assert(codexConfigMsg.config.enableSearch === false, 'Codex config should ignore unsupported search toggle');
assert(codexConfigMsg.config.retry?.mode === 'limited', 'Codex retry mode should round-trip');
assert(codexConfigMsg.config.retry?.intervalSeconds === 1, 'Codex retry interval should round-trip');
assert(codexConfigMsg.config.retry?.maxAttempts === 2, 'Codex retry max attempts should round-trip');
const codexInitCwd = path.join(tempRoot, 'codex-space');
mkdirp(codexInitCwd);
@@ -1201,6 +1206,15 @@ async function main() {
assert(lastSpawn.includes('-s read-only'), 'Codex plan mode should set sandbox read-only');
assert(lastSpawn.includes('-s read-only resume'), 'Codex resume in plan mode must place -s before resume subcommand');
ws.send(JSON.stringify({ type: 'message', text: 'trigger codex capacity retry', sessionId: firstMessageSession.sessionId, mode: 'plan', agent: 'codex' }));
const capacityRetryNotice = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && /自动重试/.test(msg.message || '') && msg.sessionId === firstMessageSession.sessionId, 10000);
assert(/Codex 服务暂时繁忙/.test(capacityRetryNotice.message || ''), 'Codex transient capacity failure should announce automatic retry');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === firstMessageSession.sessionId, 20000);
const storedAfterCapacityRetry = JSON.parse(fs.readFileSync(codexSessionPath, 'utf8'));
const capacityRetryUsers = storedAfterCapacityRetry.messages.filter((message) => message.role === 'user' && message.content === 'trigger codex capacity retry');
assert(capacityRetryUsers.length === 1, 'Codex transient retry should not duplicate the user message');
assert(storedAfterCapacityRetry.messages.some((message) => message.role === 'assistant' && /trigger codex capacity retry/.test(String(message.content || ''))), 'Codex transient retry should persist the successful assistant response');
const runtimeToml = fs.readFileSync(path.join(configDir, 'codex-runtime-home', 'config.toml'), 'utf8');
assert(runtimeToml.includes('preferred_auth_method = "apikey"'), 'Codex custom profile should write isolated runtime auth mode');
assert(runtimeToml.includes('base_url = "https://example.com/v1"'), 'Codex custom profile should write isolated runtime base_url');
@@ -1265,6 +1279,64 @@ async function main() {
assert(/"hasTopLevelEffort":false/.test(codexAppDefaultCollab.text || ''), 'Codex App collaboration turn should not duplicate effort at top level');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === codexAppSession.sessionId);
ws.send(JSON.stringify({
type: 'save_codex_config',
config: {
mode: 'custom',
activeProfile: 'Regression Profile Updated',
profiles: [{ name: 'Regression Profile Updated', apiKey: 'sk-regression-updated', apiBase: 'https://updated.example.com/v1' }],
enableSearch: false,
retry: { mode: 'limited', intervalSeconds: 1, maxAttempts: 2 },
},
}));
const codexAppChangedConfig = await nextMessage(messages, ws, (msg) =>
msg.type === 'codex_config' && msg.config?.activeProfile === 'Regression Profile Updated'
);
assert(codexAppChangedConfig.config.mode === 'custom', 'Codex App config-change regression should save custom mode');
ws.send(JSON.stringify({ type: 'message', text: 'codexapp after config change prompt', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppAfterConfigChange = await nextMessage(messages, ws, (msg) => (
msg.type === 'text_delta' &&
msg.sessionId === codexAppSession.sessionId &&
/codexapp after config change prompt/.test(msg.text || '')
));
assert(/codexapp after config change prompt/.test(codexAppAfterConfigChange.text || ''), 'Codex App should not reject a new turn after config signature changes');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === codexAppSession.sessionId);
const codexAppRetryText = 'codexapp capacity retry prompt';
ws.send(JSON.stringify({ type: 'message', text: codexAppRetryText, sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppCapacityRetryNotice = await nextMessage(messages, ws, (msg) => (
msg.type === 'system_message' &&
msg.sessionId === codexAppSession.sessionId &&
/自动重试/.test(msg.message || '')
), 10000);
assert(/Codex 服务暂时繁忙/.test(codexAppCapacityRetryNotice.message || ''), 'Codex App transient capacity failure should announce automatic retry');
const codexAppPartialCapacityRetryNotice = await nextMessage(messages, ws, (msg) => (
msg.type === 'system_message' &&
msg.sessionId === codexAppSession.sessionId &&
/自动重试/.test(msg.message || '')
), 10000);
assert(/第 2\/2 次/.test(codexAppPartialCapacityRetryNotice.message || ''), 'Codex App transient retry should continue after partial output');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === codexAppSession.sessionId, 20000);
const storedCodexAppAfterCapacityRetry = JSON.parse(fs.readFileSync(path.join(sessionsDir, `${codexAppSession.sessionId}.json`), 'utf8'));
const codexAppCapacityRetryUsers = storedCodexAppAfterCapacityRetry.messages.filter((message) => message.role === 'user' && message.content === codexAppRetryText);
assert(codexAppCapacityRetryUsers.length === 1, 'Codex App transient retry should not duplicate the user message');
assert(storedCodexAppAfterCapacityRetry.messages.some((message) => message.role === 'assistant' && /codexapp capacity retry prompt/.test(String(message.content || ''))), 'Codex App transient retry should persist the successful assistant response');
const codexAppReconnectRetryText = 'codexapp reconnect retry prompt';
ws.send(JSON.stringify({ type: 'message', text: codexAppReconnectRetryText, sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppReconnectRetryNotice = await nextMessage(messages, ws, (msg) => (
msg.type === 'system_message' &&
msg.sessionId === codexAppSession.sessionId &&
/自动重试/.test(msg.message || '')
), 10000);
assert(/Codex 服务暂时繁忙/.test(codexAppReconnectRetryNotice.message || ''), 'Codex App reconnect failure should announce automatic retry');
await nextMessage(messages, ws, (msg) => msg.type === 'done' && msg.sessionId === codexAppSession.sessionId, 20000);
const storedCodexAppAfterReconnectRetry = JSON.parse(fs.readFileSync(path.join(sessionsDir, `${codexAppSession.sessionId}.json`), 'utf8'));
const codexAppReconnectRetryUsers = storedCodexAppAfterReconnectRetry.messages.filter((message) => message.role === 'user' && message.content === codexAppReconnectRetryText);
assert(codexAppReconnectRetryUsers.length === 1, 'Codex App reconnect retry should not duplicate the user message');
assert(storedCodexAppAfterReconnectRetry.messages.some((message) => message.role === 'assistant' && /codexapp reconnect retry prompt/.test(String(message.content || ''))), 'Codex App reconnect retry should persist the successful assistant response');
ws.send(JSON.stringify({ type: 'message', text: '/goal improve benchmark coverage', sessionId: codexAppSession.sessionId, mode: 'yolo', agent: 'codexapp' }));
const codexAppGoalSet = await nextMessage(messages, ws, (msg) => msg.type === 'system_message' && msg.sessionId === codexAppSession.sessionId && /Goal active/.test(msg.message || '') && /improve benchmark coverage/.test(msg.message || ''));
assert(/Goal active/.test(codexAppGoalSet.message || ''), 'Codex App /goal should set an active goal');