Speed up session import
This commit is contained in:
@@ -212,7 +212,7 @@ test("listImportableProviderSessions filters, sorts, limits, and projects import
|
||||
});
|
||||
|
||||
expect(listImportablePersistedAgents).toHaveBeenCalledWith({
|
||||
limit: 200,
|
||||
limit: 2,
|
||||
providerFilter: new Set(["codex"]),
|
||||
cwd,
|
||||
});
|
||||
|
||||
@@ -109,7 +109,7 @@ export async function listImportableProviderSessions(
|
||||
const importedHandles = await collectImportedProviderSessionHandles(agentManager, agentStorage);
|
||||
|
||||
const descriptors = await agentManager.listImportablePersistedAgents({
|
||||
limit: 200,
|
||||
limit,
|
||||
providerFilter,
|
||||
cwd: request.cwd,
|
||||
});
|
||||
|
||||
@@ -2638,12 +2638,13 @@ describe("Codex app-server provider", () => {
|
||||
});
|
||||
|
||||
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 = [
|
||||
{
|
||||
id: "thread-a1",
|
||||
cwd: "/workspace/project-a",
|
||||
preview: "First A session",
|
||||
name: "Named first A session",
|
||||
createdAt: 1000,
|
||||
updatedAt: 2000,
|
||||
},
|
||||
@@ -2662,11 +2663,12 @@ describe("Codex persisted sessions", () => {
|
||||
updatedAt: 4000,
|
||||
},
|
||||
];
|
||||
const calls: Array<{ method: string; params?: unknown }> = [];
|
||||
|
||||
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/read") return { thread: { turns: [] } };
|
||||
return {};
|
||||
},
|
||||
notify: () => {},
|
||||
@@ -2693,5 +2695,16 @@ describe("Codex persisted sessions", () => {
|
||||
|
||||
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[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));
|
||||
}
|
||||
|
||||
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 {
|
||||
const usage = toObjectRecord(tokenUsage);
|
||||
if (!usage) return undefined;
|
||||
@@ -5486,58 +5491,48 @@ export class CodexAppServerAgentClient implements AgentClient {
|
||||
client.notify("initialized", {});
|
||||
|
||||
const limit = options?.limit ?? 20;
|
||||
// thread/list returns the cheap `cwd` field. When the caller supplied
|
||||
// a cwd hint we filter here so the per-thread `thread/read includeTurns`
|
||||
// hydration below only runs for matching threads. Fetch a wider window
|
||||
// when filtering since most threads will be from other cwds.
|
||||
// thread/list returns the cheap `cwd` field. Fetch a wider window when
|
||||
// filtering since most threads will be from other cwds, then keep the
|
||||
// local realpath-aware filter for symlink-equivalent workspace paths.
|
||||
const listLimit = options?.cwd ? Math.max(limit, 50) : limit;
|
||||
const response = toObjectRecord(await client.request("thread/list", { limit: listLimit }));
|
||||
const allThreads = Array.isArray(response?.data) ? response.data.filter(isRecord) : [];
|
||||
const threads = filterCodexThreadsByCwd(allThreads, options?.cwd);
|
||||
const descriptors: PersistedAgentDescriptor[] = await Promise.all(
|
||||
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 response = toObjectRecord(
|
||||
await client.request("thread/list", {
|
||||
limit: listLimit,
|
||||
...(options?.cwd ? { cwd: options.cwd } : {}),
|
||||
}),
|
||||
);
|
||||
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;
|
||||
} finally {
|
||||
|
||||
Reference in New Issue
Block a user