mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-07 06:52:28 +00:00
[codex] improve Codex plan mode compatibility (#538)
* fix: improve codex plan mode compatibility * fix: tighten codex collaboration retry detection --------- Co-authored-by: weishu <twsxtd@gmail.com>
This commit is contained in:
@@ -53,7 +53,10 @@ export interface CollaborationModeListItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface CollaborationModeListResponse {
|
export interface CollaborationModeListResponse {
|
||||||
data?: CollaborationModeListItem[];
|
data?: Array<CollaborationModeListItem | string>;
|
||||||
|
modes?: Array<CollaborationModeListItem | string>;
|
||||||
|
collaborationModes?: Array<CollaborationModeListItem | string>;
|
||||||
|
items?: Array<CollaborationModeListItem | string>;
|
||||||
[key: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -969,6 +969,23 @@ describe('codexRemoteLauncher', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('recognizes alternate collaboration mode list envelopes', async () => {
|
||||||
|
harness.collaborationModeResponse = { collaborationModes: [{ id: 'plan' }] };
|
||||||
|
const { session } = createSessionStub(['plan this'], {
|
||||||
|
permissionMode: 'default',
|
||||||
|
collaborationMode: 'plan',
|
||||||
|
model: 'gpt-5.4'
|
||||||
|
});
|
||||||
|
|
||||||
|
const exitReason = await codexRemoteLauncher(session as never);
|
||||||
|
|
||||||
|
expect(exitReason).toBe('exit');
|
||||||
|
expect(harness.startTurnParams).toHaveLength(1);
|
||||||
|
expect(harness.startTurnParams[0]?.collaborationMode).toMatchObject({
|
||||||
|
mode: 'plan'
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('retries plan turns without collaborationMode when the runtime rejects the field', async () => {
|
it('retries plan turns without collaborationMode when the runtime rejects the field', async () => {
|
||||||
harness.startTurnErrors.push(new Error('unknown field collaborationMode'));
|
harness.startTurnErrors.push(new Error('unknown field collaborationMode'));
|
||||||
const { session, sessionEvents } = createSessionStub(['plan this'], {
|
const { session, sessionEvents } = createSessionStub(['plan this'], {
|
||||||
@@ -1036,7 +1053,7 @@ describe('codexRemoteLauncher', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('falls back to a normal turn when collaborationMode/list omits plan', async () => {
|
it('still attempts plan mode when collaborationMode/list omits plan', async () => {
|
||||||
harness.collaborationModeResponse = { data: [{ mode: 'default' }] };
|
harness.collaborationModeResponse = { data: [{ mode: 'default' }] };
|
||||||
const { session, sessionEvents } = createSessionStub(['plan this'], {
|
const { session, sessionEvents } = createSessionStub(['plan this'], {
|
||||||
permissionMode: 'default',
|
permissionMode: 'default',
|
||||||
@@ -1048,9 +1065,10 @@ describe('codexRemoteLauncher', () => {
|
|||||||
|
|
||||||
expect(exitReason).toBe('exit');
|
expect(exitReason).toBe('exit');
|
||||||
expect(harness.startTurnParams).toHaveLength(1);
|
expect(harness.startTurnParams).toHaveLength(1);
|
||||||
expect(harness.startTurnParams[0]?.collaborationMode).toBeUndefined();
|
expect(harness.startTurnParams[0]?.collaborationMode).toMatchObject({
|
||||||
expect(harness.startTurnParams[0]?.model).toBe('gpt-5.4');
|
mode: 'plan'
|
||||||
expect(sessionEvents).toContainEqual({
|
});
|
||||||
|
expect(sessionEvents).not.toContainEqual({
|
||||||
type: 'message',
|
type: 'message',
|
||||||
message: 'Plan mode is not supported by this Codex runtime. Sent as a normal turn instead.'
|
message: 'Plan mode is not supported by this Codex runtime. Sent as a normal turn instead.'
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -266,9 +266,9 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return message.includes('requires experimentalapi')
|
return message.includes('experimentalapi')
|
||||||
|| message.includes('unknown field')
|
|
||||||
|| message.includes('unsupported')
|
|| message.includes('unsupported')
|
||||||
|
|| message.includes('unknown')
|
||||||
|| message.includes('unrecognized')
|
|| message.includes('unrecognized')
|
||||||
|| message.includes('unexpected')
|
|| message.includes('unexpected')
|
||||||
|| message.includes('invalid field');
|
|| message.includes('invalid field');
|
||||||
@@ -278,7 +278,10 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
const record = asRecord(response);
|
const record = asRecord(response);
|
||||||
const candidates = [
|
const candidates = [
|
||||||
Array.isArray(response) ? response : undefined,
|
Array.isArray(response) ? response : undefined,
|
||||||
Array.isArray(record?.data) ? record.data : undefined
|
Array.isArray(record?.data) ? record.data : undefined,
|
||||||
|
Array.isArray(record?.modes) ? record.modes : undefined,
|
||||||
|
Array.isArray(record?.collaborationModes) ? record.collaborationModes : undefined,
|
||||||
|
Array.isArray(record?.items) ? record.items : undefined
|
||||||
];
|
];
|
||||||
|
|
||||||
for (const candidate of candidates) {
|
for (const candidate of candidates) {
|
||||||
@@ -288,7 +291,9 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
const entryRecord = asRecord(entry);
|
const entryRecord = asRecord(entry);
|
||||||
const mode = asString(entryRecord?.mode) ?? asString(entryRecord?.name);
|
const mode = asString(entryRecord?.mode)
|
||||||
|
?? asString(entryRecord?.name)
|
||||||
|
?? asString(entryRecord?.id);
|
||||||
if (mode === 'plan') {
|
if (mode === 'plan') {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2275,7 +2280,6 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let supportsTurnCollaborationMode = true;
|
let supportsTurnCollaborationMode = true;
|
||||||
let supportsPlanCollaborationMode = true;
|
|
||||||
let supportsGoals = true;
|
let supportsGoals = true;
|
||||||
try {
|
try {
|
||||||
await appServerClient.setExperimentalFeatureEnablement({ enablement: { goals: true } });
|
await appServerClient.setExperimentalFeatureEnablement({ enablement: { goals: true } });
|
||||||
@@ -2289,7 +2293,7 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
const hasPlanMode = responseContainsPlanCollaborationMode(response);
|
const hasPlanMode = responseContainsPlanCollaborationMode(response);
|
||||||
logger.debug(`[Codex] collaborationMode/list plan=${hasPlanMode}`);
|
logger.debug(`[Codex] collaborationMode/list plan=${hasPlanMode}`);
|
||||||
if (!hasPlanMode) {
|
if (!hasPlanMode) {
|
||||||
supportsPlanCollaborationMode = false;
|
logger.debug('[Codex] collaborationMode/list did not report plan; will still attempt collaborationMode until rejected');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.debug(`[Codex] collaborationMode/list failed: ${errorMessage(error)}`);
|
logger.debug(`[Codex] collaborationMode/list failed: ${errorMessage(error)}`);
|
||||||
@@ -2735,8 +2739,7 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
model: session.getModel() ?? message.mode.model
|
model: session.getModel() ?? message.mode.model
|
||||||
};
|
};
|
||||||
const shouldSendCollaborationMode = supportsTurnCollaborationMode
|
const shouldSendCollaborationMode = supportsTurnCollaborationMode
|
||||||
&& Boolean(mode.collaborationMode)
|
&& Boolean(mode.collaborationMode);
|
||||||
&& (mode.collaborationMode !== 'plan' || supportsPlanCollaborationMode);
|
|
||||||
const buildParams = (suppressCollaborationMode: boolean) => buildTurnStartParams({
|
const buildParams = (suppressCollaborationMode: boolean) => buildTurnStartParams({
|
||||||
threadId: this.currentThreadId!,
|
threadId: this.currentThreadId!,
|
||||||
message: message.message,
|
message: message.message,
|
||||||
@@ -2749,7 +2752,7 @@ class CodexRemoteLauncher extends RemoteLauncherBase {
|
|||||||
});
|
});
|
||||||
if (
|
if (
|
||||||
mode.collaborationMode === 'plan'
|
mode.collaborationMode === 'plan'
|
||||||
&& (!supportsTurnCollaborationMode || !supportsPlanCollaborationMode)
|
&& !supportsTurnCollaborationMode
|
||||||
) {
|
) {
|
||||||
session.sendSessionEvent({
|
session.sendSessionEvent({
|
||||||
type: 'message',
|
type: 'message',
|
||||||
|
|||||||
Reference in New Issue
Block a user