From 922bcf76602f729cc96dc832628515223c8e05e9 Mon Sep 17 00:00:00 2001 From: DoSun Date: Mon, 11 May 2026 15:30:37 +0800 Subject: [PATCH] fix(server): accept client messageID to enable optimistic message dedup --- src/server/routes/session.ts | 10 +++++++--- src/server/sessionHandle.ts | 7 +++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/server/routes/session.ts b/src/server/routes/session.ts index ff7a231fa..5577281bf 100644 --- a/src/server/routes/session.ts +++ b/src/server/routes/session.ts @@ -27,6 +27,7 @@ function ssePrompt( content: string, c: import('hono').Context, parts?: Array>, + messageID?: string, ) { return streamSSE(c, async stream => { const startTime = Date.now() @@ -82,7 +83,7 @@ function ssePrompt( }) try { - await handle.prompt(content, { parts }) + await handle.prompt(content, { parts, messageID }) } catch { if (!resultWritten) { pendingWrite = pendingWrite.then(() => @@ -374,6 +375,7 @@ export function createSessionRoutes( images?: unknown[] model?: { providerID?: string; modelID?: string } agent?: string + messageID?: string }>() const textContent = body.content ?? body.parts @@ -396,7 +398,7 @@ export function createSessionRoutes( try { await handle.setAgent(effectiveAgent) } catch {} } - return ssePrompt(handle, id, content, c, body.parts) + return ssePrompt(handle, id, content, c, body.parts, body.messageID) }) .post('/session/:sessionID/prompt_async', async c => { const id = c.req.param('sessionID') @@ -427,6 +429,7 @@ export function createSessionRoutes( images?: unknown[] model?: { providerID?: string; modelID?: string } agent?: string + messageID?: string }>() const textContent = body.content ?? body.parts @@ -457,7 +460,8 @@ export function createSessionRoutes( if (effectiveAgent && effectiveAgent !== handle.agent) { try { await handle.setAgent(effectiveAgent) } catch {} } - handle.prompt(content, { parts: body.parts }).catch(() => {}) + handle.prompt(content, { parts: body.parts, messageID: body.messageID }).catch(() => {}) + } catch {} })() diff --git a/src/server/sessionHandle.ts b/src/server/sessionHandle.ts index f49d62759..bb30301a3 100644 --- a/src/server/sessionHandle.ts +++ b/src/server/sessionHandle.ts @@ -468,7 +468,7 @@ export class SessionHandle { return (response.mcpServers as unknown[]) ?? [] } - async prompt(content: string, _opts?: { parts?: Array> }): Promise<{ done: boolean; error?: string }> { + async prompt(content: string, opts?: { parts?: Array>; messageID?: string }): Promise<{ done: boolean; error?: string }> { if (this._status === 'stopped') { throw new Error( `Session ${this.sessionId} is stopped`, @@ -487,10 +487,12 @@ export class SessionHandle { this.emitBusyStatus() this.lastActiveAt = Date.now() + const uuid = opts?.messageID ?? crypto.randomUUID() + const userMsg = jsonStringify({ type: 'user', content, - uuid: crypto.randomUUID(), + uuid, session_id: this.sessionId, message: { role: 'user', content }, parent_tool_use_id: null, @@ -499,6 +501,7 @@ export class SessionHandle { this.emitEvent('message', { type: 'user', content, + uuid, session_id: this.sessionId, model: this._model ?? '', provider_id: this._providerId ?? '',