Fix agent turn timing persistence
This commit is contained in:
@@ -1418,6 +1418,68 @@ describe("Codex app-server provider", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test("uses Codex turn timestamps for timestamp-less persisted history items", async () => {
|
||||
const session = createSession();
|
||||
session.client = {
|
||||
request: vi.fn(async (method: string) => {
|
||||
if (method !== "thread/read") {
|
||||
return {};
|
||||
}
|
||||
return {
|
||||
thread: {
|
||||
turns: [
|
||||
{
|
||||
startedAt: 1_778_832_941,
|
||||
completedAt: 1_778_833_094,
|
||||
items: [
|
||||
{
|
||||
type: "userMessage",
|
||||
id: "user-history",
|
||||
content: [{ type: "text", text: "Check OpenCode timestamps." }],
|
||||
},
|
||||
{
|
||||
type: "agentMessage",
|
||||
id: "message-history",
|
||||
text: "History loaded.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
}),
|
||||
};
|
||||
|
||||
await asInternals(session).loadPersistedHistory();
|
||||
|
||||
const history: AgentStreamEvent[] = [];
|
||||
for await (const event of session.streamHistory()) {
|
||||
history.push(event);
|
||||
}
|
||||
|
||||
expect(history).toEqual([
|
||||
{
|
||||
type: "timeline",
|
||||
provider: "codex",
|
||||
timestamp: "2026-05-15T08:15:41.000Z",
|
||||
item: {
|
||||
type: "user_message",
|
||||
text: "Check OpenCode timestamps.",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: "timeline",
|
||||
provider: "codex",
|
||||
timestamp: "2026-05-15T08:18:14.000Z",
|
||||
item: {
|
||||
type: "assistant_message",
|
||||
text: "History loaded.",
|
||||
messageId: "message-history",
|
||||
},
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
test("preserves Codex app-server assistant item ids in persisted history", async () => {
|
||||
const session = createSession();
|
||||
session.client = {
|
||||
|
||||
@@ -1462,6 +1462,28 @@ function readCodexHistoryTimestamp(item: unknown): string | null {
|
||||
);
|
||||
}
|
||||
|
||||
function readCodexTurnHistoryTimestamp(
|
||||
turn: unknown,
|
||||
timelineItem: AgentTimelineItem,
|
||||
): string | null {
|
||||
const record = toObjectRecord(turn);
|
||||
if (!record) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const startedAt =
|
||||
normalizeProviderReplayTimestamp(record.startedAt) ??
|
||||
normalizeProviderReplayTimestamp(record.started_at);
|
||||
const completedAt =
|
||||
normalizeProviderReplayTimestamp(record.completedAt) ??
|
||||
normalizeProviderReplayTimestamp(record.completed_at);
|
||||
|
||||
if (timelineItem.type === "user_message") {
|
||||
return startedAt ?? completedAt;
|
||||
}
|
||||
return completedAt ?? startedAt;
|
||||
}
|
||||
|
||||
function codexImageOutputFromResult(result: unknown): ProviderImageOutput | null {
|
||||
if (typeof result === "string") {
|
||||
const trimmed = result.trim();
|
||||
@@ -1616,7 +1638,8 @@ async function loadCodexThreadHistoryTimeline(params: {
|
||||
for (const item of turn.items) {
|
||||
const timelineItem = threadItemToTimeline(item, { cwd: params.cwd });
|
||||
if (timelineItem) {
|
||||
const timestamp = readCodexHistoryTimestamp(item);
|
||||
const timestamp =
|
||||
readCodexHistoryTimestamp(item) ?? readCodexTurnHistoryTimestamp(turn, timelineItem);
|
||||
timeline.push({
|
||||
item: timelineItem,
|
||||
timestamp: timestamp ?? undefined,
|
||||
|
||||
Reference in New Issue
Block a user