mirror of
https://github.com/wu736139669/hapi.git
synced 2026-08-05 06:24:37 +00:00
feat(codex): support proactive /agent mode (#1172)
This commit is contained in:
@@ -15,6 +15,7 @@ export interface EnhancedMode {
|
||||
permissionMode: PermissionMode;
|
||||
model?: string;
|
||||
collaborationMode: CodexCollaborationMode;
|
||||
proactiveMultiAgent?: boolean;
|
||||
modelReasoningEffort?: ReasoningEffort;
|
||||
/**
|
||||
* Service tier override. `undefined` leaves it untouched (account default),
|
||||
|
||||
@@ -73,6 +73,7 @@ export async function runCodex(opts: {
|
||||
model: mode.model,
|
||||
modelReasoningEffort: mode.modelReasoningEffort,
|
||||
collaborationMode: mode.collaborationMode,
|
||||
proactiveMultiAgent: mode.proactiveMultiAgent,
|
||||
serviceTier: mode.serviceTier
|
||||
}));
|
||||
|
||||
@@ -89,6 +90,7 @@ export async function runCodex(opts: {
|
||||
let currentModel = opts.model;
|
||||
let currentModelReasoningEffort: ReasoningEffort | undefined = opts.modelReasoningEffort;
|
||||
let currentCollaborationMode: EnhancedMode['collaborationMode'] = opts.collaborationMode ?? 'default';
|
||||
let currentProactiveMultiAgent: boolean | undefined;
|
||||
// Service tier (Fast mode), stored representation: `'fast'` and
|
||||
// `'standard'` are explicit user choices, `undefined`/`null` mean untouched
|
||||
// (use the account default). Prefer the spawn-time override (set by the hub
|
||||
@@ -137,6 +139,7 @@ export async function runCodex(opts: {
|
||||
modelReasoningEffort?: ReasoningEffort | null;
|
||||
collaborationMode?: EnhancedMode['collaborationMode'];
|
||||
serviceTier?: string | null;
|
||||
proactiveMultiAgent?: boolean;
|
||||
} | undefined): void => {
|
||||
if (!updates) return;
|
||||
if (updates.permissionMode !== undefined) {
|
||||
@@ -154,6 +157,9 @@ export async function runCodex(opts: {
|
||||
if (updates.serviceTier !== undefined) {
|
||||
currentServiceTier = updates.serviceTier;
|
||||
}
|
||||
if (updates.proactiveMultiAgent !== undefined) {
|
||||
currentProactiveMultiAgent = updates.proactiveMultiAgent;
|
||||
}
|
||||
applyCurrentConfigToSession();
|
||||
};
|
||||
|
||||
@@ -194,7 +200,8 @@ export async function runCodex(opts: {
|
||||
collaborationMode: currentCollaborationMode,
|
||||
model: currentModel,
|
||||
modelReasoningEffort: currentModelReasoningEffort,
|
||||
serviceTier: currentServiceTier
|
||||
serviceTier: currentServiceTier,
|
||||
proactiveMultiAgent: currentProactiveMultiAgent
|
||||
});
|
||||
if (slash.kind === 'goal') {
|
||||
if (slash.message) {
|
||||
@@ -253,6 +260,7 @@ export async function runCodex(opts: {
|
||||
model: currentModel,
|
||||
modelReasoningEffort: currentModelReasoningEffort,
|
||||
collaborationMode: currentCollaborationMode,
|
||||
proactiveMultiAgent: currentProactiveMultiAgent,
|
||||
serviceTier: currentServiceTier
|
||||
};
|
||||
if (isolatedCommandText) {
|
||||
@@ -267,6 +275,7 @@ export async function runCodex(opts: {
|
||||
model: currentModel,
|
||||
modelReasoningEffort: currentModelReasoningEffort,
|
||||
collaborationMode: currentCollaborationMode,
|
||||
proactiveMultiAgent: currentProactiveMultiAgent,
|
||||
serviceTier: currentServiceTier
|
||||
};
|
||||
messageQueue.push(formatMessageWithAttachments(message.content.text, message.content.attachments), enhancedMode, localId);
|
||||
|
||||
@@ -422,6 +422,23 @@ describe('appServerConfig', () => {
|
||||
expect(instructions).toContain('Do not rely on parent turn reasoning settings for spawned agents');
|
||||
});
|
||||
|
||||
it('injects proactive multi-agent instructions when /agent mode is enabled', () => {
|
||||
const params = buildTurnStartParams({
|
||||
threadId: 'thread-1',
|
||||
message: 'work',
|
||||
cwd: '/repo',
|
||||
mode: {
|
||||
permissionMode: 'default',
|
||||
model: 'o3',
|
||||
collaborationMode: 'default',
|
||||
proactiveMultiAgent: true
|
||||
}
|
||||
});
|
||||
|
||||
expect(params.collaborationMode?.settings.developer_instructions)
|
||||
.toContain('Proactive multi-agent delegation is active.');
|
||||
});
|
||||
|
||||
it('rejects collaboration mode payloads without a resolved model', () => {
|
||||
expect(() => buildTurnStartParams({
|
||||
threadId: 'thread-1',
|
||||
|
||||
@@ -124,8 +124,14 @@ function resolveInstructions(args: {
|
||||
};
|
||||
}
|
||||
|
||||
function appendCollaborationInstructions(developerInstructions: string): string {
|
||||
return `${developerInstructions}\n\n${codexCollaborationSpawnAgentInstructions}`;
|
||||
function appendCollaborationInstructions(developerInstructions: string, proactiveMultiAgent?: boolean): string {
|
||||
if (proactiveMultiAgent === undefined) {
|
||||
return `${developerInstructions}\n\n${codexCollaborationSpawnAgentInstructions}`;
|
||||
}
|
||||
const multiAgentMode = proactiveMultiAgent
|
||||
? 'Proactive multi-agent delegation is active. Any earlier instruction requiring an explicit user request before spawning sub-agents no longer applies. Use sub-agents when parallel work would materially improve speed or quality. This mode remains active until a later multi-agent mode developer message changes it.'
|
||||
: 'Any earlier instruction enabling proactive multi-agent delegation no longer applies. Do not spawn sub-agents unless the user or applicable AGENTS.md/skill instructions explicitly ask for sub-agents, delegation, or parallel agent work.';
|
||||
return `${developerInstructions}\n\n${codexCollaborationSpawnAgentInstructions}\n\n<multi_agent_mode>${multiAgentMode}</multi_agent_mode>`;
|
||||
}
|
||||
|
||||
function mentionNameFromPath(path: string): string {
|
||||
@@ -275,7 +281,7 @@ export function buildTurnStartParams(args: {
|
||||
settings: {
|
||||
model,
|
||||
reasoning_effort: modelReasoningEffort ?? null,
|
||||
developer_instructions: appendCollaborationInstructions(developerInstructions)
|
||||
developer_instructions: appendCollaborationInstructions(developerInstructions, args.mode?.proactiveMultiAgent)
|
||||
}
|
||||
};
|
||||
} else if (model) {
|
||||
|
||||
@@ -9,6 +9,19 @@ const state = {
|
||||
};
|
||||
|
||||
describe('resolveCodexSlashCommand', () => {
|
||||
it('toggles proactive multi-agent mode', () => {
|
||||
expect(resolveCodexSlashCommand('/agent', state)).toMatchObject({
|
||||
updates: { proactiveMultiAgent: true }
|
||||
});
|
||||
expect(resolveCodexSlashCommand('/agent off', { ...state, proactiveMultiAgent: true })).toMatchObject({
|
||||
updates: { proactiveMultiAgent: false }
|
||||
});
|
||||
expect(resolveCodexSlashCommand('/agent status', { ...state, proactiveMultiAgent: true })).toEqual({
|
||||
kind: 'handled',
|
||||
message: 'Codex proactive multi-agent mode: on'
|
||||
});
|
||||
});
|
||||
|
||||
it('enables plan mode without sending a turn', () => {
|
||||
expect(resolveCodexSlashCommand('/plan', state)).toEqual({
|
||||
kind: 'handled',
|
||||
|
||||
@@ -33,6 +33,7 @@ export type CodexSlashResolution =
|
||||
model?: string | null;
|
||||
modelReasoningEffort?: ReasoningEffort | null;
|
||||
serviceTier?: string | null;
|
||||
proactiveMultiAgent?: boolean;
|
||||
};
|
||||
}
|
||||
| {
|
||||
@@ -45,6 +46,7 @@ export type CodexSlashResolution =
|
||||
model?: string | null;
|
||||
modelReasoningEffort?: ReasoningEffort | null;
|
||||
serviceTier?: string | null;
|
||||
proactiveMultiAgent?: boolean;
|
||||
};
|
||||
}
|
||||
| {
|
||||
@@ -63,6 +65,7 @@ export function resolveCodexSlashCommand(
|
||||
model?: string;
|
||||
modelReasoningEffort?: ReasoningEffort;
|
||||
serviceTier?: string | null;
|
||||
proactiveMultiAgent?: boolean;
|
||||
}
|
||||
): CodexSlashResolution {
|
||||
const match = /^\s*\/([a-z0-9:_-]+)(?:\s+([\s\S]*))?$/i.exec(text);
|
||||
@@ -107,6 +110,30 @@ export function resolveCodexSlashCommand(
|
||||
};
|
||||
}
|
||||
|
||||
if (command === 'agent') {
|
||||
const value = rest.toLowerCase();
|
||||
if (value === 'status') {
|
||||
return {
|
||||
kind: 'handled',
|
||||
message: `Codex proactive multi-agent mode: ${state.proactiveMultiAgent ? 'on' : 'off'}`
|
||||
};
|
||||
}
|
||||
if (value && !['on', 'enable', 'enabled', 'off', 'disable', 'disabled'].includes(value)) {
|
||||
return {
|
||||
kind: 'handled',
|
||||
message: 'Usage: /agent [on|off|status]'
|
||||
};
|
||||
}
|
||||
const enabled = value
|
||||
? ['on', 'enable', 'enabled'].includes(value)
|
||||
: !state.proactiveMultiAgent;
|
||||
return {
|
||||
kind: 'handled',
|
||||
message: `Codex proactive multi-agent mode ${enabled ? 'enabled' : 'disabled'}`,
|
||||
updates: { proactiveMultiAgent: enabled }
|
||||
};
|
||||
}
|
||||
|
||||
if (command === 'goal') {
|
||||
const lowerRest = rest.toLowerCase();
|
||||
if (!rest) {
|
||||
|
||||
Reference in New Issue
Block a user