diff --git a/cli/src/api/apiSession.ts b/cli/src/api/apiSession.ts index d308eb92..4df03246 100644 --- a/cli/src/api/apiSession.ts +++ b/cli/src/api/apiSession.ts @@ -6,7 +6,7 @@ import { backoff } from '@/utils/time' import { AsyncLock } from '@/utils/lock' import type { RawJSONLines } from '@/claude/types' import { configuration } from '@/configuration' -import type { AgentState, ClientToServerEvents, MessageContent, Metadata, ServerToClientEvents, Session, Update, UserMessage } from './types' +import type { AgentState, ClientToServerEvents, MessageContent, MessageMeta, Metadata, ServerToClientEvents, Session, Update, UserMessage } from './types' import { AgentStateSchema, MetadataSchema, UserMessageSchema } from './types' import { RpcHandlerManager } from './rpc/RpcHandlerManager' import { registerCommonHandlers } from '../modules/common/registerCommonHandlers' @@ -184,6 +184,29 @@ export class ApiSessionClient extends EventEmitter { } } + sendUserMessage(text: string, meta?: MessageMeta): void { + if (!text) { + return + } + + const content: MessageContent = { + role: 'user', + content: { + type: 'text', + text + }, + meta: { + sentFrom: 'cli', + ...(meta ?? {}) + } + } + + this.socket.emit('message', { + sid: this.sessionId, + message: content + }) + } + sendCodexMessage(body: unknown): void { const content = { role: 'agent', diff --git a/cli/src/codex/codexLocalLauncher.ts b/cli/src/codex/codexLocalLauncher.ts index 8363653e..d9a8ce05 100644 --- a/cli/src/codex/codexLocalLauncher.ts +++ b/cli/src/codex/codexLocalLauncher.ts @@ -17,6 +17,9 @@ export async function codexLocalLauncher(session: CodexSession): Promise<'switch session.onSessionFound(converted.sessionId); scanner.onNewSession(converted.sessionId); } + if (converted?.userMessage) { + session.sendUserMessage(converted.userMessage); + } if (converted?.message) { session.sendCodexMessage(converted.message); } diff --git a/cli/src/codex/session.ts b/cli/src/codex/session.ts index e1dd4106..ef05f03f 100644 --- a/cli/src/codex/session.ts +++ b/cli/src/codex/session.ts @@ -45,6 +45,10 @@ export class CodexSession extends AgentSessionBase { this.client.sendCodexMessage(message); }; + sendUserMessage = (text: string): void => { + this.client.sendUserMessage(text); + }; + sendSessionEvent = (event: Parameters[0]): void => { this.client.sendSessionEvent(event); }; diff --git a/cli/src/codex/utils/codexEventConverter.test.ts b/cli/src/codex/utils/codexEventConverter.test.ts index 446d2e13..3abf7776 100644 --- a/cli/src/codex/utils/codexEventConverter.test.ts +++ b/cli/src/codex/utils/codexEventConverter.test.ts @@ -23,6 +23,15 @@ describe('convertCodexEvent', () => { }); }); + it('converts user_message events', () => { + const result = convertCodexEvent({ + type: 'event_msg', + payload: { type: 'user_message', message: 'hello user' } + }); + + expect(result?.userMessage).toBe('hello user'); + }); + it('converts reasoning events', () => { const result = convertCodexEvent({ type: 'event_msg', diff --git a/cli/src/codex/utils/codexEventConverter.ts b/cli/src/codex/utils/codexEventConverter.ts index e783d92a..76dbf478 100644 --- a/cli/src/codex/utils/codexEventConverter.ts +++ b/cli/src/codex/utils/codexEventConverter.ts @@ -41,6 +41,7 @@ export type CodexMessage = { export type CodexConversionResult = { sessionId?: string; message?: CodexMessage; + userMessage?: string; }; function asRecord(value: unknown): Record | null { @@ -118,7 +119,15 @@ export function convertCodexEvent(rawEvent: unknown): CodexConversionResult | nu } if (eventType === 'user_message') { - return null; + const message = asString(payloadRecord.message) + ?? asString(payloadRecord.text) + ?? asString(payloadRecord.content); + if (!message) { + return null; + } + return { + userMessage: message + }; } if (eventType === 'agent_message') {