mirror of
https://github.com/aaif-goose/goose.git
synced 2026-07-03 14:10:03 +02:00
fix: sync local message ID to backend via acpSendMessage
Pass userMessage.id from the local Zustand store through to acpSendMessage so the backend stores the same UUID. Without this, the frontend and backend have different IDs for the same user message, causing truncate_before_message_id lookups to find nothing — edit/retry truncation silently fails and messages zombie back on session reload. Signed-off-by: Taylor Ho <taylorkmho@gmail.com>
This commit is contained in:
@@ -95,12 +95,12 @@ describe("useChat attachments", () => {
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith(
|
||||
"session-1",
|
||||
"Attached items:\n- [file] /tmp/report.pdf\n- [directory] /tmp/screenshots\nPlease review these",
|
||||
{
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: undefined,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -146,12 +146,12 @@ describe("useChat attachments", () => {
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith(
|
||||
"session-1",
|
||||
"Attached items:\n- [image] diagram.png (image attached)\n ",
|
||||
{
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: [["abc123", "image/png"]],
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -193,12 +193,12 @@ describe("useChat attachments", () => {
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith(
|
||||
"session-1",
|
||||
"Attached items:\n- [file] /tmp/mobile-confirmation.html\n- [directory] /tmp/neighborhood block\n- [image] Screenshot 2026-04-09 at 1.25.32 PM.png (image attached)\ncan you see the attachments i attached?",
|
||||
{
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: [["abc123", "image/png"]],
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -233,12 +233,12 @@ describe("useChat attachments", () => {
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith(
|
||||
"session-1",
|
||||
"Attached items:\n- [file] report.pdf\nPlease review this",
|
||||
{
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: undefined,
|
||||
},
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -127,12 +127,14 @@ describe("useChat", () => {
|
||||
result.current.stopGeneration();
|
||||
});
|
||||
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith("session-1", "Hello", {
|
||||
systemPrompt: undefined,
|
||||
personaId: "persona-b",
|
||||
personaName: "Persona B",
|
||||
images: undefined,
|
||||
});
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith("session-1", "Hello",
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: "persona-b",
|
||||
personaName: "Persona B",
|
||||
images: undefined,
|
||||
}),
|
||||
);
|
||||
expect(mockAcpCancelSession).toHaveBeenCalledWith("session-1", "persona-b");
|
||||
|
||||
deferred.resolve();
|
||||
@@ -313,23 +315,23 @@ describe("useChat", () => {
|
||||
1,
|
||||
"session-1",
|
||||
"First",
|
||||
{
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: undefined,
|
||||
},
|
||||
}),
|
||||
);
|
||||
expect(mockAcpSendMessage).toHaveBeenNthCalledWith(
|
||||
2,
|
||||
"session-2",
|
||||
"Second",
|
||||
{
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: undefined,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
deferred.resolve();
|
||||
@@ -366,12 +368,14 @@ describe("useChat", () => {
|
||||
personaId: undefined,
|
||||
});
|
||||
expect(mockAcpSetModel).toHaveBeenCalledWith("session-1", "gpt-4.1");
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith("session-1", "Hello", {
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: undefined,
|
||||
});
|
||||
expect(mockAcpSendMessage).toHaveBeenCalledWith("session-1", "Hello",
|
||||
expect.objectContaining({
|
||||
systemPrompt: undefined,
|
||||
personaId: undefined,
|
||||
personaName: undefined,
|
||||
images: undefined,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("appends an error message and removes the empty assistant placeholder when send fails", async () => {
|
||||
|
||||
@@ -244,6 +244,7 @@ export function useChat(
|
||||
(img) => [img.base64, img.mimeType] as [string, string],
|
||||
),
|
||||
truncateBeforeMessageId,
|
||||
messageId: userMessage.id,
|
||||
});
|
||||
|
||||
store.setChatState(sessionId, "idle");
|
||||
|
||||
@@ -22,6 +22,10 @@ export interface AcpSendMessageOptions {
|
||||
* from both the display log and LLM context before appending the new prompt.
|
||||
* Used by edit and retry to rewind the conversation. */
|
||||
truncateBeforeMessageId?: string;
|
||||
/** Pre-generated message ID to use for this user message. When provided the
|
||||
* same ID is registered with the notification handler and sent to the
|
||||
* backend so the frontend store and backend thread_messages stay in sync. */
|
||||
messageId?: string;
|
||||
}
|
||||
|
||||
export interface AcpPrepareSessionOptions {
|
||||
@@ -63,7 +67,7 @@ export async function acpSendMessage(
|
||||
? { truncate_before_message_id: truncateBeforeMessageId }
|
||||
: undefined;
|
||||
|
||||
const messageId = crypto.randomUUID();
|
||||
const messageId = options.messageId ?? crypto.randomUUID();
|
||||
setActiveMessageId(gooseSessionId, messageId);
|
||||
|
||||
await directAcp.prompt(gooseSessionId, content, messageId, meta);
|
||||
|
||||
Reference in New Issue
Block a user