feat: migrate session metadata storage from frontend overlay to backend (#8769)

Signed-off-by: Matt Toohey <contact@matttoohey.com>
Co-authored-by: Bradley Axen <baxen@squareup.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Matt Toohey
2026-04-24 15:28:48 +12:00
committed by GitHub
parent 97671f30b0
commit 86afdeab6a
19 changed files with 287 additions and 411 deletions
+7 -1
View File
@@ -95,7 +95,13 @@ export async function acpSendMessage(
`[perf:send] ${sid} acpSendMessage → prompt(len=${prompt.length}, imgs=${images?.length ?? 0})`,
);
const tPrompt = performance.now();
await directAcp.prompt(gooseSessionId, content);
const meta: Record<string, unknown> = {};
if (personaId) meta.personaId = personaId;
await directAcp.prompt(
gooseSessionId,
content,
Object.keys(meta).length > 0 ? meta : undefined,
);
const tDone = performance.now();
perfLog(
`[perf:send] ${sid} prompt() resolved in ${(tDone - tPrompt).toFixed(1)}ms (total acpSendMessage ${(tDone - tStart).toFixed(1)}ms)`,
+41 -1
View File
@@ -17,8 +17,14 @@ export interface AcpSessionInfo {
sessionId: string;
title: string | null;
updatedAt: string | null;
createdAt: string | null;
archivedAt: string | null;
userSetName: boolean;
messageCount: number;
projectId?: string | null;
providerId: string | null;
modelId: string | null;
personaId: string | null;
}
const DEPRECATED_PROVIDER_IDS = new Set(["claude-code", "codex", "gemini-cli"]);
@@ -50,8 +56,14 @@ export async function listSessions(): Promise<AcpSessionInfo[]> {
sessionId: info.sessionId,
title: info.title ?? null,
updatedAt: info.updatedAt ?? null,
createdAt: (info._meta?.createdAt as string) ?? null,
archivedAt: (info._meta?.archivedAt as string) ?? null,
userSetName: info._meta?.userSetName === true,
messageCount: (info._meta?.messageCount as number) ?? 0,
projectId: (info._meta?.projectId as string) ?? null,
providerId: (info._meta?.providerId as string) ?? null,
modelId: (info._meta?.modelId as string) ?? null,
personaId: (info._meta?.personaId as string) ?? null,
}));
}
@@ -78,7 +90,14 @@ export async function forkSession(sessionId: string): Promise<AcpSessionInfo> {
sessionId: response.sessionId,
title: (response._meta?.title as string) ?? null,
updatedAt: null,
createdAt: (response._meta?.createdAt as string) ?? null,
archivedAt: (response._meta?.archivedAt as string) ?? null,
userSetName: response._meta?.userSetName === true,
messageCount: (response._meta?.messageCount as number) ?? 0,
projectId: (response._meta?.projectId as string) ?? null,
providerId: (response._meta?.providerId as string) ?? null,
modelId: (response._meta?.modelId as string) ?? null,
personaId: (response._meta?.personaId as string) ?? null,
};
}
@@ -137,6 +156,24 @@ export async function updateSessionProject(
});
}
export async function archiveSession(sessionId: string): Promise<void> {
const client = await getClient();
await client.extMethod("_goose/session/archive", { sessionId });
}
export async function unarchiveSession(sessionId: string): Promise<void> {
const client = await getClient();
await client.extMethod("_goose/session/unarchive", { sessionId });
}
export async function renameSession(
sessionId: string,
title: string,
): Promise<void> {
const client = await getClient();
await client.extMethod("_goose/session/rename", { sessionId, title });
}
export async function cancelSession(sessionId: string): Promise<void> {
const client = await getClient();
await client.cancel({ sessionId });
@@ -146,6 +183,7 @@ export async function newSession(
workingDir: string,
providerId?: string,
projectId?: string,
personaId?: string,
): Promise<NewSessionResponse> {
const tClient = performance.now();
const client = await getClient();
@@ -159,6 +197,7 @@ export async function newSession(
const meta: Record<string, string> = {};
if (providerId) meta.provider = providerId;
if (projectId) meta.projectId = projectId;
if (personaId) meta.personaId = personaId;
if (Object.keys(meta).length > 0) request.meta = meta;
const tCall = performance.now();
@@ -192,7 +231,8 @@ export async function loadSession(
export async function prompt(
sessionId: string,
content: ContentBlock[],
meta?: Record<string, unknown>,
): Promise<PromptResponse> {
const client = await getClient();
return client.prompt({ sessionId, prompt: content });
return client.prompt({ sessionId, prompt: content, _meta: meta });
}
@@ -415,11 +415,7 @@ function handleShared(sessionId: string, update: SessionUpdate): void {
if (session && !session.userSetName) {
useChatSessionStore
.getState()
.updateSession(
sessionId,
{ title: info.title as string },
{ persistOverlay: false },
);
.updateSession(sessionId, { title: info.title as string });
}
}
break;
@@ -456,11 +452,10 @@ function handleShared(sessionId: string, update: SessionUpdate): void {
currentModelId;
const sessionStore = useChatSessionStore.getState();
sessionStore.updateSession(
sessionId,
{ modelId: currentModelId, modelName: currentModelName },
{ persistOverlay: false },
);
sessionStore.updateSession(sessionId, {
modelId: currentModelId,
modelName: currentModelName,
});
}
}
break;
@@ -102,7 +102,12 @@ export async function prepareSession(
if (!gooseSessionId) {
const tNew = performance.now();
const response = await acpApi.newSession(workingDir, providerId, projectId);
const response = await acpApi.newSession(
workingDir,
providerId,
projectId,
personaId,
);
gooseSessionId = response.sessionId;
perfLog(
`[perf:prepare] ${sid} tracker newSession done in ${(performance.now() - tNew).toFixed(1)}ms (goose_sid=${gooseSessionId.slice(0, 8)})`,
-1
View File
@@ -55,7 +55,6 @@ export const INITIAL_SESSION_CHAT_RUNTIME: SessionChatRuntime = {
export interface Session {
id: string;
title: string;
agentId?: string;
projectId?: string | null;
providerId?: string;
personaId?: string;