Speed up session import
This commit is contained in:
@@ -212,7 +212,7 @@ test("listImportableProviderSessions filters, sorts, limits, and projects import
|
|||||||
});
|
});
|
||||||
|
|
||||||
expect(listImportablePersistedAgents).toHaveBeenCalledWith({
|
expect(listImportablePersistedAgents).toHaveBeenCalledWith({
|
||||||
limit: 200,
|
limit: 2,
|
||||||
providerFilter: new Set(["codex"]),
|
providerFilter: new Set(["codex"]),
|
||||||
cwd,
|
cwd,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export async function listImportableProviderSessions(
|
|||||||
const importedHandles = await collectImportedProviderSessionHandles(agentManager, agentStorage);
|
const importedHandles = await collectImportedProviderSessionHandles(agentManager, agentStorage);
|
||||||
|
|
||||||
const descriptors = await agentManager.listImportablePersistedAgents({
|
const descriptors = await agentManager.listImportablePersistedAgents({
|
||||||
limit: 200,
|
limit,
|
||||||
providerFilter,
|
providerFilter,
|
||||||
cwd: request.cwd,
|
cwd: request.cwd,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2638,12 +2638,13 @@ describe("Codex app-server provider", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe("Codex persisted sessions", () => {
|
describe("Codex persisted sessions", () => {
|
||||||
test("listPersistedAgents returns only sessions whose cwd matches the requested cwd", async () => {
|
test("listPersistedAgents uses thread list metadata without hydrating thread history", async () => {
|
||||||
const allThreads = [
|
const allThreads = [
|
||||||
{
|
{
|
||||||
id: "thread-a1",
|
id: "thread-a1",
|
||||||
cwd: "/workspace/project-a",
|
cwd: "/workspace/project-a",
|
||||||
preview: "First A session",
|
preview: "First A session",
|
||||||
|
name: "Named first A session",
|
||||||
createdAt: 1000,
|
createdAt: 1000,
|
||||||
updatedAt: 2000,
|
updatedAt: 2000,
|
||||||
},
|
},
|
||||||
@@ -2662,11 +2663,12 @@ describe("Codex persisted sessions", () => {
|
|||||||
updatedAt: 4000,
|
updatedAt: 4000,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
const calls: Array<{ method: string; params?: unknown }> = [];
|
||||||
|
|
||||||
const fakeClient = {
|
const fakeClient = {
|
||||||
request: async (method: string) => {
|
request: async (method: string, params?: unknown) => {
|
||||||
|
calls.push({ method, params });
|
||||||
if (method === "thread/list") return { data: allThreads };
|
if (method === "thread/list") return { data: allThreads };
|
||||||
if (method === "thread/read") return { thread: { turns: [] } };
|
|
||||||
return {};
|
return {};
|
||||||
},
|
},
|
||||||
notify: () => {},
|
notify: () => {},
|
||||||
@@ -2693,5 +2695,16 @@ describe("Codex persisted sessions", () => {
|
|||||||
|
|
||||||
expect(descriptors.map((d) => d.sessionId).sort()).toEqual(["thread-a1", "thread-a2"]);
|
expect(descriptors.map((d) => d.sessionId).sort()).toEqual(["thread-a1", "thread-a2"]);
|
||||||
expect(descriptors.every((d) => d.cwd === "/workspace/project-a")).toBe(true);
|
expect(descriptors.every((d) => d.cwd === "/workspace/project-a")).toBe(true);
|
||||||
|
expect(descriptors[0]).toEqual(
|
||||||
|
expect.objectContaining({
|
||||||
|
sessionId: "thread-a1",
|
||||||
|
title: "Named first A session",
|
||||||
|
timeline: [{ type: "user_message", text: "First A session" }],
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
expect(calls).toEqual([
|
||||||
|
{ method: "initialize", params: expect.any(Object) },
|
||||||
|
{ method: "thread/list", params: { limit: 50, cwd: "/workspace/project-a" } },
|
||||||
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -831,6 +831,11 @@ function filterCodexThreadsByCwd(
|
|||||||
return threads.filter((thread) => typeof thread.cwd === "string" && matchesCwd(thread.cwd));
|
return threads.filter((thread) => typeof thread.cwd === "string" && matchesCwd(thread.cwd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildCodexThreadListTimeline(thread: Record<string, unknown>): AgentTimelineItem[] {
|
||||||
|
const preview = typeof thread.preview === "string" ? thread.preview.trim() : "";
|
||||||
|
return preview ? [{ type: "user_message", text: preview }] : [];
|
||||||
|
}
|
||||||
|
|
||||||
export function toAgentUsage(tokenUsage: unknown): AgentUsage | undefined {
|
export function toAgentUsage(tokenUsage: unknown): AgentUsage | undefined {
|
||||||
const usage = toObjectRecord(tokenUsage);
|
const usage = toObjectRecord(tokenUsage);
|
||||||
if (!usage) return undefined;
|
if (!usage) return undefined;
|
||||||
@@ -5486,58 +5491,48 @@ export class CodexAppServerAgentClient implements AgentClient {
|
|||||||
client.notify("initialized", {});
|
client.notify("initialized", {});
|
||||||
|
|
||||||
const limit = options?.limit ?? 20;
|
const limit = options?.limit ?? 20;
|
||||||
// thread/list returns the cheap `cwd` field. When the caller supplied
|
// thread/list returns the cheap `cwd` field. Fetch a wider window when
|
||||||
// a cwd hint we filter here so the per-thread `thread/read includeTurns`
|
// filtering since most threads will be from other cwds, then keep the
|
||||||
// hydration below only runs for matching threads. Fetch a wider window
|
// local realpath-aware filter for symlink-equivalent workspace paths.
|
||||||
// when filtering since most threads will be from other cwds.
|
|
||||||
const listLimit = options?.cwd ? Math.max(limit, 50) : limit;
|
const listLimit = options?.cwd ? Math.max(limit, 50) : limit;
|
||||||
const response = toObjectRecord(await client.request("thread/list", { limit: listLimit }));
|
const response = toObjectRecord(
|
||||||
const allThreads = Array.isArray(response?.data) ? response.data.filter(isRecord) : [];
|
await client.request("thread/list", {
|
||||||
const threads = filterCodexThreadsByCwd(allThreads, options?.cwd);
|
limit: listLimit,
|
||||||
const descriptors: PersistedAgentDescriptor[] = await Promise.all(
|
...(options?.cwd ? { cwd: options.cwd } : {}),
|
||||||
threads.slice(0, limit).map(async (thread) => {
|
|
||||||
const threadId = typeof thread.id === "string" ? thread.id : "";
|
|
||||||
const cwd = typeof thread.cwd === "string" ? thread.cwd : process.cwd();
|
|
||||||
const title = typeof thread.preview === "string" ? thread.preview : null;
|
|
||||||
let timeline: PersistedTimelineEntry[] = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
timeline = await loadCodexThreadHistoryTimeline({
|
|
||||||
threadId,
|
|
||||||
cwd,
|
|
||||||
requestThread: (threadIdToRead) => {
|
|
||||||
return readCodexThread(client, threadIdToRead);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
} catch {
|
|
||||||
timeline = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
provider: CODEX_PROVIDER,
|
|
||||||
sessionId: threadId,
|
|
||||||
cwd,
|
|
||||||
title,
|
|
||||||
lastActivityAt: new Date(
|
|
||||||
((typeof thread.updatedAt === "number" ? thread.updatedAt : undefined) ??
|
|
||||||
(typeof thread.createdAt === "number" ? thread.createdAt : undefined) ??
|
|
||||||
0) * 1000,
|
|
||||||
),
|
|
||||||
persistence: {
|
|
||||||
provider: CODEX_PROVIDER,
|
|
||||||
sessionId: threadId,
|
|
||||||
nativeHandle: threadId,
|
|
||||||
metadata: {
|
|
||||||
provider: CODEX_PROVIDER,
|
|
||||||
cwd,
|
|
||||||
title,
|
|
||||||
threadId,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
timeline: timeline.map((entry) => entry.item),
|
|
||||||
};
|
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
const allThreads = Array.isArray(response?.data) ? response.data.filter(isRecord) : [];
|
||||||
|
const threads = filterCodexThreadsByCwd(allThreads, options?.cwd);
|
||||||
|
const descriptors: PersistedAgentDescriptor[] = threads.slice(0, limit).map((thread) => {
|
||||||
|
const threadId = typeof thread.id === "string" ? thread.id : "";
|
||||||
|
const cwd = typeof thread.cwd === "string" ? thread.cwd : process.cwd();
|
||||||
|
const preview = typeof thread.preview === "string" ? thread.preview : null;
|
||||||
|
const title = typeof thread.name === "string" && thread.name.trim() ? thread.name : preview;
|
||||||
|
|
||||||
|
return {
|
||||||
|
provider: CODEX_PROVIDER,
|
||||||
|
sessionId: threadId,
|
||||||
|
cwd,
|
||||||
|
title,
|
||||||
|
lastActivityAt: new Date(
|
||||||
|
((typeof thread.updatedAt === "number" ? thread.updatedAt : undefined) ??
|
||||||
|
(typeof thread.createdAt === "number" ? thread.createdAt : undefined) ??
|
||||||
|
0) * 1000,
|
||||||
|
),
|
||||||
|
persistence: {
|
||||||
|
provider: CODEX_PROVIDER,
|
||||||
|
sessionId: threadId,
|
||||||
|
nativeHandle: threadId,
|
||||||
|
metadata: {
|
||||||
|
provider: CODEX_PROVIDER,
|
||||||
|
cwd,
|
||||||
|
title,
|
||||||
|
threadId,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
timeline: buildCodexThreadListTimeline(thread),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
return descriptors;
|
return descriptors;
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user