fix(codex): dedupe repeated goal updates (#649)

This commit is contained in:
SmallSpider
2026-05-20 10:00:51 +08:00
committed by GitHub
parent 197f327590
commit 2aaae25d0a
2 changed files with 162 additions and 4 deletions
+88
View File
@@ -41,6 +41,7 @@ const harness = vi.hoisted(() => ({
emitSecondChildMessage: false,
emitLateChildCommandAfterParentTool: false,
emitParentUsageEvents: false,
emitParentGoalDuplicateEvents: false,
emitChildNestedAgentTool: false,
emitParentTitleChange: false,
emitParentSpawnFailureWithoutAgentId: false,
@@ -223,6 +224,41 @@ vi.mock('./codexAppServerClient', () => {
}
if (params?.threadId === 'thread-1') {
if (harness.emitParentGoalDuplicateEvents) {
const goalBase = {
threadId,
objective: 'keep benchmark work moving',
status: 'active',
tokenBudget: null,
tokensUsed: 0,
timeUsedSeconds: 0,
createdAt: 1
};
for (let index = 0; index < 4; index += 1) {
const notification = {
threadId,
goal: {
...goalBase,
timeUsedSeconds: index,
updatedAt: 2 + index
}
};
harness.notifications.push({ method: 'thread/goal/updated', params: notification });
this.notificationHandler?.('thread/goal/updated', notification);
}
const pausedNotification = {
threadId,
goal: {
...goalBase,
status: 'paused',
timeUsedSeconds: 4,
updatedAt: 6
}
};
harness.notifications.push({ method: 'thread/goal/updated', params: pausedNotification });
this.notificationHandler?.('thread/goal/updated', pausedNotification);
}
if (harness.emitParentTitleChange) {
const titleStart = {
item: {
@@ -928,6 +964,7 @@ describe('codexRemoteLauncher', () => {
harness.emitSecondChildMessage = false;
harness.emitLateChildCommandAfterParentTool = false;
harness.emitParentUsageEvents = false;
harness.emitParentGoalDuplicateEvents = false;
harness.emitChildNestedAgentTool = false;
harness.emitParentTitleChange = false;
harness.emitParentSpawnFailureWithoutAgentId = false;
@@ -1700,6 +1737,57 @@ describe('codexRemoteLauncher', () => {
}));
});
it('suppresses duplicate parent goal updates that only change runtime counters', async () => {
harness.emitParentGoalDuplicateEvents = true;
const { session, codexMessages } = createSessionStub();
await codexRemoteLauncher(session as never);
const goalMessages = codexMessages.filter((message): message is Record<string, unknown> => {
return Boolean(message && typeof message === 'object' && (message as Record<string, unknown>).type === 'thread_goal_updated');
});
expect(goalMessages).toHaveLength(2);
expect(goalMessages).toEqual([
expect.objectContaining({
thread_id: 'thread-1',
goal: expect.objectContaining({
status: 'active',
updatedAt: 2
})
}),
expect.objectContaining({
thread_id: 'thread-1',
goal: expect.objectContaining({
status: 'paused',
updatedAt: 6
})
})
]);
});
it('suppresses duplicate goal events from repeated show commands', async () => {
const { session, codexMessages } = createSessionStub([
'/goal keep benchmark work moving',
'/goal'
]);
await codexRemoteLauncher(session as never);
expect(harness.goalSetCalls).toHaveLength(1);
expect(harness.goalGetCalls).toEqual([{ threadId: 'thread-1' }]);
const goalMessages = codexMessages.filter((message): message is Record<string, unknown> => {
return Boolean(message && typeof message === 'object' && (message as Record<string, unknown>).type === 'thread_goal_updated');
});
expect(goalMessages).toHaveLength(1);
expect(goalMessages[0]).toEqual(expect.objectContaining({
thread_id: 'thread-1',
goal: expect.objectContaining({
objective: 'keep benchmark work moving',
status: 'active'
})
}));
});
it('marks parent usage and compact events with parent scope', async () => {
harness.emitParentUsageEvents = true;
const { session, codexMessages } = createSessionStub();
+74 -4
View File
@@ -65,6 +65,40 @@ const SAME_THREAD_COMPACT_TIMEOUT_MS = 10 * 60 * 1000;
const CODEX_GOALS_UNSUPPORTED_MESSAGE = 'Codex goals are not supported by this Codex runtime. Upgrade Codex or enable features.goals.';
const MAX_CODEX_GOAL_OBJECTIVE_CHARS = 4_000;
type GoalForwardSignature = {
objective: string | null;
status: string | null;
tokenBudget: number | null;
tokenBucket: number | null;
};
function goalNumber(value: unknown): number | null {
return typeof value === 'number' && Number.isFinite(value) ? value : null;
}
function goalString(value: unknown): string | null {
return typeof value === 'string' ? value : null;
}
function buildGoalForwardSignature(goal: Record<string, unknown>): GoalForwardSignature {
const tokenBudget = goalNumber(goal.tokenBudget ?? goal.token_budget);
const tokensUsed = goalNumber(goal.tokensUsed ?? goal.tokens_used) ?? 0;
const tokenBucket = tokenBudget !== null && tokenBudget > 0
? Math.floor(Math.min(tokensUsed, tokenBudget) / Math.max(1, tokenBudget * 0.05))
: null;
return {
objective: goalString(goal.objective),
status: goalString(goal.status),
tokenBudget,
tokenBucket
};
}
function goalForwardSignatureKey(signature: GoalForwardSignature): string {
return JSON.stringify(signature);
}
function isSameThreadRetryableCodexError(error: string | null): boolean {
if (!error) {
return false;
@@ -1820,6 +1854,33 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
});
};
const forwardedGoalSignaturesByThreadId = new Map<string, string>();
const shouldForwardGoalUpdate = (msg: Record<string, unknown>, threadId: string | null): boolean => {
const goal = asRecord(msg.goal);
const scopedThreadId = threadId
?? asString(goal?.threadId ?? goal?.thread_id)
?? this.currentThreadId;
if (!goal || !scopedThreadId) {
return true;
}
const signature = goalForwardSignatureKey(buildGoalForwardSignature(goal));
if (forwardedGoalSignaturesByThreadId.get(scopedThreadId) === signature) {
logger.debug(`[Codex] Suppressing duplicate thread goal update; threadId=${scopedThreadId}`);
return false;
}
forwardedGoalSignaturesByThreadId.set(scopedThreadId, signature);
return true;
};
const noteGoalCleared = (threadId: string | null) => {
if (threadId) {
forwardedGoalSignaturesByThreadId.delete(threadId);
}
};
const handleCodexEvent = (msg: Record<string, unknown>) => {
const msgType = asString(msg.type);
if (!msgType) return;
@@ -1876,14 +1937,17 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
}
if (msgType === 'thread_goal_updated') {
session.sendAgentMessage({
...addCodexEventScope(msg, 'parent', eventThreadId ?? this.currentThreadId),
id: randomUUID()
});
if (shouldForwardGoalUpdate(msg, eventThreadId)) {
session.sendAgentMessage({
...addCodexEventScope(msg, 'parent', eventThreadId ?? this.currentThreadId),
id: randomUUID()
});
}
return;
}
if (msgType === 'thread_goal_cleared') {
noteGoalCleared(eventThreadId ?? this.currentThreadId);
session.sendAgentMessage({
...addCodexEventScope(msg, 'parent', eventThreadId ?? this.currentThreadId),
id: randomUUID()
@@ -2461,6 +2525,12 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
};
const sendGoalEvent = (event: Record<string, unknown>) => {
const threadId = asString(event.thread_id ?? event.threadId) ?? this.currentThreadId;
if (event.type === 'thread_goal_cleared') {
noteGoalCleared(threadId);
} else if (event.type === 'thread_goal_updated' && !shouldForwardGoalUpdate(event, threadId)) {
return;
}
session.sendAgentMessage({
...addCodexEventScope(event, 'parent', this.currentThreadId),
id: randomUUID()