feat: support codex app goal command

This commit is contained in:
shiyue
2026-06-17 14:08:32 +08:00
parent 7e01f24e61
commit b4bcd170d2
8 changed files with 3129 additions and 23 deletions

View File

@@ -88,6 +88,7 @@ function ensureThread(threadId, params = {}) {
activeTurnId: null,
timer: null,
steers: [],
goal: null,
});
}
const thread = threads.get(id);
@@ -481,6 +482,20 @@ function completeGuidedInputTurn(thread, turnId) {
});
}
function completeApprovalTurn(thread, turnId) {
requestClient('item/commandExecution/requestApproval', {
threadId: thread.id,
turnId,
itemId: 'approval-command-call',
reason: 'Need to run an approval-gated command',
command: 'echo approved',
cwd: thread.cwd,
}, (message) => {
const decision = message.result?.decision || 'missing';
completeTurn(thread, turnId, `approval decision: ${decision}`);
});
}
function completeEmptyReasoningTurn(thread, turnId, text) {
send({
method: 'item/started',
@@ -572,6 +587,11 @@ function startTurn(params) {
return { turn: { id: turnId, status: 'running', items: [] } };
}
if (/approval/i.test(text)) {
completeApprovalTurn(thread, turnId);
return { turn: { id: turnId, status: 'running', items: [] } };
}
const delay = /recover/i.test(text) ? 5000 : /slow/i.test(text) ? 900 : 80;
if (/recover/i.test(text)) {
send({
@@ -684,6 +704,44 @@ function handleRequest(message) {
send({ id, result: { thread: threadPayload(thread), model: params.model || 'gpt-5.5', cwd: thread.cwd, modelProvider: 'mock', approvalPolicy: params.approvalPolicy || 'never', approvalsReviewer: 'user', sandbox: params.sandbox || 'danger-full-access' } });
return;
}
if (method === 'thread/goal/get') {
const thread = ensureThread(params.threadId, params);
send({ id, result: { goal: thread.goal } });
return;
}
if (method === 'thread/goal/set') {
const thread = ensureThread(params.threadId, params);
const now = Date.now();
const previous = thread.goal || {};
const objective = String(params.objective || previous.objective || 'mock goal').trim();
thread.goal = {
threadId: thread.id,
objective,
status: String(params.status || previous.status || 'active'),
tokenBudget: previous.tokenBudget ?? null,
tokensUsed: previous.tokensUsed ?? 3,
timeUsedSeconds: previous.timeUsedSeconds ?? 0,
createdAt: previous.createdAt || now,
updatedAt: now,
};
send({
method: 'thread/goal/updated',
params: { threadId: thread.id, goal: thread.goal },
});
send({ id, result: { goal: thread.goal } });
return;
}
if (method === 'thread/goal/clear') {
const thread = ensureThread(params.threadId, params);
const cleared = !!thread.goal;
thread.goal = null;
send({
method: 'thread/goal/cleared',
params: { threadId: thread.id },
});
send({ id, result: { cleared } });
return;
}
if (method === 'turn/start') {
send({ id, result: startTurn(params) });
return;