chore: rebuild CentOS7 release package
This commit is contained in:
@@ -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: [] } };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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');
|
||||
|
||||
Reference in New Issue
Block a user