replicas-engine 0.1.868 → 0.1.870

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -946,16 +946,26 @@ function coerceClaudePartialMessagePayload(payload) {
946
946
  status: payload.status === "completed" ? "completed" : "in_progress"
947
947
  };
948
948
  }
949
- function getClaudePartialMessageStreamId(event) {
950
- if (event.type !== CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE) return null;
951
- return typeof event.payload.streamId === "string" && event.payload.streamId ? event.payload.streamId : null;
952
- }
953
949
  var ACCEPTED_USER_MESSAGE_SOURCE = "replicas-chat-turn-accepted";
954
950
  var QUEUED_MESSAGE_REMOVED_EVENT_TYPE = "replicas-queued-message-removed";
955
951
  var REMOVED_MESSAGE_IDS_PAYLOAD_KEY = "removedMessageIds";
956
952
  var USER_MESSAGE_ID_PAYLOAD_KEY = "replicasMessageId";
957
953
  var CODEX_ASP_ITEM_ID_PAYLOAD_KEY = "codexAspItemId";
958
954
  var CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE = "codex-asp-transcript-updated";
955
+ var CODEX_ITEM_EVENT_TYPE = "codex-item";
956
+ var CODEX_ITEM_PARTIAL_EVENT_TYPE = "codex-item-partial";
957
+ var CODEX_TURN_EVENT_TYPE = "codex-turn";
958
+ var CODEX_HISTORY_FORMAT_EVENT_TYPE = "codex-history-format";
959
+ function getEventStreamId(event) {
960
+ if (event.type === CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE) {
961
+ return typeof event.payload.streamId === "string" && event.payload.streamId ? event.payload.streamId : null;
962
+ }
963
+ if (event.type === CODEX_ITEM_EVENT_TYPE || event.type === CODEX_ITEM_PARTIAL_EVENT_TYPE) {
964
+ const item = event.payload.item;
965
+ return isRecord(item) && typeof item.id === "string" ? item.id : null;
966
+ }
967
+ return null;
968
+ }
959
969
  var CODEX_QUOTA_STATUS_EVENT_TYPE = "codex-quota-status";
960
970
  var COMPACTION_STATUS_EVENT_TYPE = "compaction-status";
961
971
  var CHAT_INTERRUPTED_EVENT_TYPE = "replicas-interrupted";
@@ -1146,16 +1156,66 @@ function getCodexAspTurnResponse(turn) {
1146
1156
  if (normalizeCodexAspTranscriptStatus(turn.status) === "in_progress") return null;
1147
1157
  return turn.items.findLast((item) => item.type === "agentMessage") ?? null;
1148
1158
  }
1149
- function renumberCodexAspTranscriptItems(transcript) {
1150
- let sequence = 0;
1159
+ function codexItemEvent(turnId, item, partial = false) {
1160
+ const { sequence: _sequence, ...payloadItem } = item;
1161
+ return {
1162
+ timestamp: item.timestamp,
1163
+ type: partial ? CODEX_ITEM_PARTIAL_EVENT_TYPE : CODEX_ITEM_EVENT_TYPE,
1164
+ payload: { turnId, item: payloadItem }
1165
+ };
1166
+ }
1167
+ function codexTurnEvent(turnId, status, timestamp, error) {
1151
1168
  return {
1152
- ...transcript,
1153
- turns: transcript.turns.map((turn) => ({
1154
- ...turn,
1155
- items: turn.items.map((item) => ({ ...item, sequence: sequence++ }))
1156
- }))
1169
+ timestamp,
1170
+ type: CODEX_TURN_EVENT_TYPE,
1171
+ payload: { turnId, status, ...error ? { error } : {} }
1157
1172
  };
1158
1173
  }
1174
+ function isTranscriptItemStatus(value) {
1175
+ return value === "in_progress" || value === "completed" || value === "failed";
1176
+ }
1177
+ var CODEX_ITEM_FIELD_CHECKS = {
1178
+ userMessage: (item) => typeof item.content === "string",
1179
+ agentMessage: (item) => typeof item.text === "string",
1180
+ reasoning: (item) => typeof item.text === "string" && isTranscriptItemStatus(item.status),
1181
+ commandExecution: (item) => typeof item.command === "string" && isTranscriptItemStatus(item.status),
1182
+ fileChange: (item) => Array.isArray(item.operations) && isTranscriptItemStatus(item.status),
1183
+ toolCall: (item) => typeof item.server === "string" && typeof item.tool === "string" && isTranscriptItemStatus(item.status),
1184
+ subagent: (item) => typeof item.description === "string" && typeof item.prompt === "string" && typeof item.subagentType === "string" && isTranscriptItemStatus(item.status),
1185
+ webSearch: (item) => typeof item.query === "string" && isTranscriptItemStatus(item.status),
1186
+ plan: (item) => typeof item.text === "string" && isTranscriptItemStatus(item.status),
1187
+ contextCompaction: (item) => isTranscriptItemStatus(item.status),
1188
+ error: (item) => typeof item.message === "string"
1189
+ };
1190
+ function isCodexAspTranscriptItem(value) {
1191
+ if (!isRecord(value) || typeof value.id !== "string" || typeof value.timestamp !== "string") return false;
1192
+ if (value.sequence !== void 0 && typeof value.sequence !== "number") return false;
1193
+ if (typeof value.type !== "string" || !Object.hasOwn(CODEX_ITEM_FIELD_CHECKS, value.type)) return false;
1194
+ return CODEX_ITEM_FIELD_CHECKS[value.type](value);
1195
+ }
1196
+ function codexItemFromEvent(event) {
1197
+ if (event.type !== CODEX_ITEM_EVENT_TYPE && event.type !== CODEX_ITEM_PARTIAL_EVENT_TYPE) return null;
1198
+ const { turnId, item } = event.payload;
1199
+ return typeof turnId === "string" && isCodexAspTranscriptItem(item) ? { turnId, item } : null;
1200
+ }
1201
+ function codexTurnFromEvent(event) {
1202
+ if (event.type !== CODEX_TURN_EVENT_TYPE) return null;
1203
+ const { turnId, status, error } = event.payload;
1204
+ return typeof turnId === "string" && typeof status === "string" ? { turnId, status, ...typeof error === "string" ? { error } : {} } : null;
1205
+ }
1206
+ function codexTranscriptToEvents(transcript) {
1207
+ return transcript.turns.flatMap((turn) => {
1208
+ const events = turn.items.map((item) => codexItemEvent(turn.id, item));
1209
+ if (normalizeCodexAspTranscriptStatus(turn.status) !== "in_progress") {
1210
+ events.push(codexTurnEvent(
1211
+ turn.id,
1212
+ turn.status,
1213
+ turn.completedAt ?? turn.items.at(-1)?.timestamp ?? turn.startedAt
1214
+ ));
1215
+ }
1216
+ return events;
1217
+ });
1218
+ }
1159
1219
  function isCodexAspTranscript(value) {
1160
1220
  if (!isRecord(value)) return false;
1161
1221
  return typeof value.threadId === "string" && typeof value.updatedAt === "string" && Array.isArray(value.turns);
@@ -1280,20 +1340,11 @@ function paginateChatHistory(full, params) {
1280
1340
  params.limit,
1281
1341
  params.beforeEvent
1282
1342
  );
1283
- const turns = full.codexAspTranscript?.turns;
1284
- const { startIndex: turnsStartIndex, endIndex: turnsEnd } = getChatHistoryPageWindow(
1285
- turns?.length ?? 0,
1286
- params.limit,
1287
- params.beforeTurn
1288
- );
1289
- const codexAspTranscript = full.codexAspTranscript && turns && (turnsStartIndex > 0 || turnsEnd < turns.length) ? { ...full.codexAspTranscript, turns: turns.slice(turnsStartIndex, turnsEnd) } : full.codexAspTranscript;
1290
1343
  return {
1291
1344
  ...full,
1292
1345
  events: full.events.slice(eventsStartIndex, eventsEnd),
1293
1346
  eventsStartIndex,
1294
- totalEvents: full.events.length,
1295
- codexAspTranscript,
1296
- ...full.codexAspTranscript ? { turnsStartIndex } : {}
1347
+ totalEvents: full.events.length
1297
1348
  };
1298
1349
  }
1299
1350
 
@@ -3844,6 +3895,201 @@ function removeReplicasInstructions(text) {
3844
3895
  return removeTag(text, REPLICAS_INSTRUCTIONS_TAG);
3845
3896
  }
3846
3897
 
3898
+ // ../shared/src/display-message/parsers/codex-asp-parser.ts
3899
+ function collectCodexTurns(events) {
3900
+ const turns = /* @__PURE__ */ new Map();
3901
+ const turnFor = (id) => {
3902
+ const existing = turns.get(id);
3903
+ if (existing) return existing;
3904
+ const turn = { id, status: "inProgress", items: [] };
3905
+ turns.set(id, turn);
3906
+ return turn;
3907
+ };
3908
+ for (const event of events) {
3909
+ const item = codexItemFromEvent(event);
3910
+ if (item) {
3911
+ const turn = turnFor(item.turnId);
3912
+ const index = turn.items.findIndex((candidate) => candidate.id === item.item.id);
3913
+ if (index === -1) turn.items.push(item.item);
3914
+ else turn.items[index] = item.item;
3915
+ continue;
3916
+ }
3917
+ const turnEvent = codexTurnFromEvent(event);
3918
+ if (turnEvent) {
3919
+ const turn = turnFor(turnEvent.turnId);
3920
+ turn.status = turnEvent.status;
3921
+ turn.completedAt = event.timestamp;
3922
+ turn.error = turnEvent.error;
3923
+ }
3924
+ }
3925
+ return turns;
3926
+ }
3927
+ function messagesForCodexTurn(turn) {
3928
+ const items = turn.items.map((item, index) => ({ item, index })).sort((a, b) => parseTimestampMs(a.item.timestamp) - parseTimestampMs(b.item.timestamp) || a.index - b.index).map(({ item }) => item);
3929
+ const reasoning = items.filter(
3930
+ (item) => item.type === "reasoning" && item.text.trim().length > 0
3931
+ );
3932
+ const firstReasoningIndex = items.findIndex((item) => item.type === "reasoning");
3933
+ const coalesced = items.flatMap((item, index) => {
3934
+ if (item.type !== "reasoning") return [item];
3935
+ if (index !== firstReasoningIndex || reasoning.length === 0) return [];
3936
+ return [{
3937
+ type: "reasoning",
3938
+ id: turn.id,
3939
+ text: reasoning.map(({ text }) => text.trim()).join("\n\n"),
3940
+ timestamp: reasoning[0].timestamp,
3941
+ status: reasoning.at(-1)?.status ?? "completed"
3942
+ }];
3943
+ });
3944
+ const response = getCodexAspTurnResponse({ status: turn.status, items: coalesced });
3945
+ const reasoningIndex = coalesced.findIndex((item) => item.type === "reasoning");
3946
+ const responseIndex = response ? coalesced.indexOf(response) : -1;
3947
+ if (responseIndex !== -1 && reasoningIndex > responseIndex) {
3948
+ coalesced.splice(responseIndex, 0, ...coalesced.splice(reasoningIndex, 1));
3949
+ }
3950
+ const messages = coalesced.flatMap((item) => {
3951
+ const message = messageForItem(item);
3952
+ return [...message ? [message] : [], ...skillMessagesForItem(item)];
3953
+ });
3954
+ if (turn.error) {
3955
+ messages.push({
3956
+ id: `error-${turn.id}`,
3957
+ type: "error",
3958
+ message: turn.error,
3959
+ timestamp: turn.completedAt ?? items.at(-1)?.timestamp ?? (/* @__PURE__ */ new Date(0)).toISOString()
3960
+ });
3961
+ }
3962
+ return messages;
3963
+ }
3964
+ function inputForDisplay(input) {
3965
+ if (input === void 0 || input === null) return void 0;
3966
+ if (typeof input === "string") return input;
3967
+ if (isRecord(input)) return input;
3968
+ return String(input);
3969
+ }
3970
+ function isInternalUserMessage(content) {
3971
+ const trimmed = content.trim();
3972
+ return trimmed.startsWith("<environment_context>") || trimmed.startsWith("<goal_context>");
3973
+ }
3974
+ function messageForItem(item) {
3975
+ if (item.type === "userMessage") {
3976
+ if (isInternalUserMessage(item.content)) return null;
3977
+ return {
3978
+ id: `user-${item.id}`,
3979
+ type: "user",
3980
+ content: item.content,
3981
+ images: item.images,
3982
+ timestamp: item.timestamp
3983
+ };
3984
+ }
3985
+ if (item.type === "agentMessage" || item.type === "plan") {
3986
+ if (!item.text) return null;
3987
+ return {
3988
+ id: `agent-${item.id}`,
3989
+ type: "agent",
3990
+ content: item.text,
3991
+ timestamp: item.timestamp,
3992
+ ...item.type === "plan" ? { isPlan: true } : {}
3993
+ };
3994
+ }
3995
+ if (item.type === "reasoning") {
3996
+ if (!item.text) return null;
3997
+ return {
3998
+ id: `reasoning-${item.id}`,
3999
+ type: "reasoning",
4000
+ content: item.text,
4001
+ status: normalizeCodexAspTranscriptStatus(item.status),
4002
+ timestamp: item.timestamp,
4003
+ ...item.sourceTimestamp ? { sourceTimestamp: item.sourceTimestamp } : {}
4004
+ };
4005
+ }
4006
+ if (item.type === "commandExecution") {
4007
+ const skillNames = skillNamesFromCommand(item.command);
4008
+ return {
4009
+ id: `command-${item.id}`,
4010
+ type: "command",
4011
+ command: item.command,
4012
+ ...skillNames.length > 0 ? { skillNames } : {},
4013
+ output: item.output,
4014
+ exitCode: item.exitCode ?? void 0,
4015
+ status: normalizeCodexAspTranscriptStatus(item.status),
4016
+ timestamp: item.timestamp
4017
+ };
4018
+ }
4019
+ if (item.type === "fileChange") {
4020
+ return {
4021
+ id: `patch-${item.id}`,
4022
+ type: "patch",
4023
+ operations: item.operations,
4024
+ output: item.output,
4025
+ exitCode: item.exitCode ?? void 0,
4026
+ status: normalizeCodexAspTranscriptStatus(item.status),
4027
+ timestamp: item.timestamp
4028
+ };
4029
+ }
4030
+ if (item.type === "toolCall") {
4031
+ return createCallDisplayMessage({
4032
+ id: `toolcall-${item.id}`,
4033
+ server: item.server,
4034
+ tool: item.tool,
4035
+ input: inputForDisplay(item.input),
4036
+ output: item.output,
4037
+ status: normalizeCodexAspTranscriptStatus(item.status),
4038
+ timestamp: item.timestamp
4039
+ });
4040
+ }
4041
+ if (item.type === "subagent") {
4042
+ return {
4043
+ id: `subagent-${item.id}`,
4044
+ type: "subagent",
4045
+ toolUseId: item.id,
4046
+ description: item.description,
4047
+ prompt: item.prompt,
4048
+ subagentType: item.subagentType,
4049
+ ...item.receiverThreadIds ? { receiverThreadIds: item.receiverThreadIds } : {},
4050
+ ...item.model ? { model: item.model } : {},
4051
+ status: normalizeCodexAspTranscriptStatus(item.status),
4052
+ ...item.output ? { output: item.output } : {},
4053
+ nestedEvents: [],
4054
+ timestamp: item.timestamp
4055
+ };
4056
+ }
4057
+ if (item.type === "webSearch") {
4058
+ return {
4059
+ id: `web-search-${item.id}`,
4060
+ type: "web_search",
4061
+ query: item.query,
4062
+ status: normalizeCodexAspTranscriptStatus(item.status),
4063
+ timestamp: item.timestamp
4064
+ };
4065
+ }
4066
+ if (item.type === "contextCompaction") {
4067
+ return {
4068
+ id: `reasoning-${item.id}`,
4069
+ type: "reasoning",
4070
+ content: "Context compacted",
4071
+ status: normalizeCodexAspTranscriptStatus(item.status),
4072
+ timestamp: item.timestamp
4073
+ };
4074
+ }
4075
+ return {
4076
+ id: `error-${item.id}`,
4077
+ type: "error",
4078
+ message: item.message,
4079
+ timestamp: item.timestamp
4080
+ };
4081
+ }
4082
+ function skillMessagesForItem(item) {
4083
+ if (item.type !== "userMessage" || !item.skillNames) return [];
4084
+ return item.skillNames.filter((skillName) => skillName.trim().length > 0).map((skillName, index) => ({
4085
+ id: `skill-${item.id}-${index}`,
4086
+ type: "skill",
4087
+ skillName,
4088
+ status: "completed",
4089
+ timestamp: item.timestamp
4090
+ }));
4091
+ }
4092
+
3847
4093
  // ../shared/src/display-message/parsers/codex-parser.ts
3848
4094
  function getStatusFromExitCode(exitCode) {
3849
4095
  return exitCode === 0 ? "completed" : "failed";
@@ -3918,17 +4164,29 @@ function parsePatch(input) {
3918
4164
  }
3919
4165
  function parseCodexEvents(events) {
3920
4166
  const messages = [];
4167
+ const turns = collectCodexTurns(events);
4168
+ const turnInsertions = [];
3921
4169
  const pendingCommands = /* @__PURE__ */ new Map();
3922
4170
  const pendingToolCalls = /* @__PURE__ */ new Map();
3923
4171
  const pendingPatches = /* @__PURE__ */ new Map();
3924
4172
  events.forEach((event, eventIndex) => {
4173
+ const turnId = codexItemFromEvent(event)?.turnId ?? codexTurnFromEvent(event)?.turnId;
4174
+ if (turnId !== void 0) {
4175
+ if (!turnInsertions.some((insertion) => insertion.turnId === turnId)) {
4176
+ turnInsertions.push({ index: messages.length, turnId });
4177
+ }
4178
+ return;
4179
+ }
3925
4180
  if (event.type === "codex-asp-error") {
3926
- messages.push({
3927
- id: displayId(event, eventIndex, "error"),
3928
- type: "error",
3929
- message: getPayloadString(event, "message") ?? "Codex run failed",
3930
- timestamp: event.timestamp
3931
- });
4181
+ const failedTurnId = getPayloadString(event, CODEX_ASP_ITEM_ID_PAYLOAD_KEY);
4182
+ if (!(failedTurnId && turns.has(failedTurnId))) {
4183
+ messages.push({
4184
+ id: displayId(event, eventIndex, "error"),
4185
+ type: "error",
4186
+ message: getPayloadString(event, "message") ?? "Codex run failed",
4187
+ timestamp: event.timestamp
4188
+ });
4189
+ }
3932
4190
  return;
3933
4191
  }
3934
4192
  if (event.type === CODEX_QUOTA_STATUS_EVENT_TYPE) {
@@ -4087,6 +4345,25 @@ function parseCodexEvents(events) {
4087
4345
  }
4088
4346
  }
4089
4347
  });
4348
+ const claimedPrompts = /* @__PURE__ */ new Set();
4349
+ for (const { index, turnId } of turnInsertions.reverse()) {
4350
+ const turn = turns.get(turnId);
4351
+ if (!turn) continue;
4352
+ const kept = [];
4353
+ for (const message of messagesForCodexTurn(turn)) {
4354
+ const recordedIndex = message.type === "user" ? messages.findLastIndex((candidate, candidateIndex) => candidateIndex < index && candidate.type === "user" && candidate.content === message.content && !claimedPrompts.has(candidateIndex)) : -1;
4355
+ if (recordedIndex === -1) {
4356
+ kept.push(message);
4357
+ continue;
4358
+ }
4359
+ claimedPrompts.add(recordedIndex);
4360
+ const recorded = messages[recordedIndex];
4361
+ if (recorded.type === "user" && message.type === "user" && !recorded.images && message.images) {
4362
+ messages[recordedIndex] = { ...recorded, images: message.images };
4363
+ }
4364
+ }
4365
+ messages.splice(index, 0, ...kept);
4366
+ }
4090
4367
  return messages;
4091
4368
  }
4092
4369
 
@@ -5659,296 +5936,6 @@ function parseClaudeEvents(events, parentToolUseId) {
5659
5936
  return messages.filter((_2, index) => !staleIndexes.has(index));
5660
5937
  }
5661
5938
 
5662
- // ../shared/src/display-message/parsers/codex-asp-parser.ts
5663
- var DUPLICATE_WINDOW_MS = 5 * 60 * 1e3;
5664
- function nearTimestamp(a, b) {
5665
- return Math.abs(parseTimestampMs(a) - parseTimestampMs(b)) <= DUPLICATE_WINDOW_MS;
5666
- }
5667
- function inputForDisplay(input) {
5668
- if (input === void 0 || input === null) return void 0;
5669
- if (typeof input === "string") return input;
5670
- if (isRecord(input)) return input;
5671
- return String(input);
5672
- }
5673
- function isInternalUserMessage(content) {
5674
- const trimmed = content.trim();
5675
- return trimmed.startsWith("<environment_context>") || trimmed.startsWith("<goal_context>");
5676
- }
5677
- function messageForItem(item) {
5678
- if (item.type === "userMessage") {
5679
- if (isInternalUserMessage(item.content)) return null;
5680
- return {
5681
- id: `user-${item.id}`,
5682
- type: "user",
5683
- content: item.content,
5684
- images: item.images,
5685
- timestamp: item.timestamp
5686
- };
5687
- }
5688
- if (item.type === "agentMessage" || item.type === "plan") {
5689
- if (!item.text) return null;
5690
- return {
5691
- id: `agent-${item.id}`,
5692
- type: "agent",
5693
- content: item.text,
5694
- timestamp: item.timestamp,
5695
- ...item.type === "plan" ? { isPlan: true } : {}
5696
- };
5697
- }
5698
- if (item.type === "reasoning") {
5699
- if (!item.text) return null;
5700
- return {
5701
- id: `reasoning-${item.id}`,
5702
- type: "reasoning",
5703
- content: item.text,
5704
- status: normalizeCodexAspTranscriptStatus(item.status),
5705
- timestamp: item.timestamp,
5706
- ...item.sourceTimestamp ? { sourceTimestamp: item.sourceTimestamp } : {}
5707
- };
5708
- }
5709
- if (item.type === "commandExecution") {
5710
- const skillNames = skillNamesFromCommand(item.command);
5711
- return {
5712
- id: `command-${item.id}`,
5713
- type: "command",
5714
- command: item.command,
5715
- ...skillNames.length > 0 ? { skillNames } : {},
5716
- output: item.output,
5717
- exitCode: item.exitCode ?? void 0,
5718
- status: normalizeCodexAspTranscriptStatus(item.status),
5719
- timestamp: item.timestamp
5720
- };
5721
- }
5722
- if (item.type === "fileChange") {
5723
- return {
5724
- id: `patch-${item.id}`,
5725
- type: "patch",
5726
- operations: item.operations,
5727
- output: item.output,
5728
- exitCode: item.exitCode ?? void 0,
5729
- status: normalizeCodexAspTranscriptStatus(item.status),
5730
- timestamp: item.timestamp
5731
- };
5732
- }
5733
- if (item.type === "toolCall") {
5734
- return createCallDisplayMessage({
5735
- id: `toolcall-${item.id}`,
5736
- server: item.server,
5737
- tool: item.tool,
5738
- input: inputForDisplay(item.input),
5739
- output: item.output,
5740
- status: normalizeCodexAspTranscriptStatus(item.status),
5741
- timestamp: item.timestamp
5742
- });
5743
- }
5744
- if (item.type === "subagent") {
5745
- return {
5746
- id: `subagent-${item.id}`,
5747
- type: "subagent",
5748
- toolUseId: item.id,
5749
- description: item.description,
5750
- prompt: item.prompt,
5751
- subagentType: item.subagentType,
5752
- ...item.receiverThreadIds ? { receiverThreadIds: item.receiverThreadIds } : {},
5753
- ...item.model ? { model: item.model } : {},
5754
- status: normalizeCodexAspTranscriptStatus(item.status),
5755
- ...item.output ? { output: item.output } : {},
5756
- nestedEvents: [],
5757
- timestamp: item.timestamp
5758
- };
5759
- }
5760
- if (item.type === "webSearch") {
5761
- return {
5762
- id: `web-search-${item.id}`,
5763
- type: "web_search",
5764
- query: item.query,
5765
- status: normalizeCodexAspTranscriptStatus(item.status),
5766
- timestamp: item.timestamp
5767
- };
5768
- }
5769
- if (item.type === "contextCompaction") {
5770
- return {
5771
- id: `reasoning-${item.id}`,
5772
- type: "reasoning",
5773
- content: "Context compacted",
5774
- status: normalizeCodexAspTranscriptStatus(item.status),
5775
- timestamp: item.timestamp
5776
- };
5777
- }
5778
- return {
5779
- id: `error-${item.id}`,
5780
- type: "error",
5781
- message: item.message,
5782
- timestamp: item.timestamp
5783
- };
5784
- }
5785
- function skillMessagesForItem(item) {
5786
- if (item.type !== "userMessage" || !item.skillNames) return [];
5787
- return item.skillNames.filter((skillName) => skillName.trim().length > 0).map((skillName, index) => ({
5788
- id: `skill-${item.id}-${index}`,
5789
- type: "skill",
5790
- skillName,
5791
- status: "completed",
5792
- timestamp: item.timestamp
5793
- }));
5794
- }
5795
- function parseLatestCodexAspTranscriptTurn(transcript) {
5796
- const latestTurn = transcript.turns.reduce((latest, turn) => !latest || Date.parse(turn.startedAt) >= Date.parse(latest.startedAt) ? turn : latest, null);
5797
- return latestTurn ? parseCodexAspTranscript({ ...transcript, turns: [latestTurn] }) : [];
5798
- }
5799
- function stableString(value) {
5800
- if (value === void 0) return "";
5801
- if (typeof value !== "object" || value === null) return String(value);
5802
- try {
5803
- return JSON.stringify(value, Object.keys(value).sort());
5804
- } catch {
5805
- return String(value);
5806
- }
5807
- }
5808
- function duplicateKey(message) {
5809
- if (message.type === "user" || message.type === "agent" || message.type === "reasoning") {
5810
- return JSON.stringify([message.type, message.content]);
5811
- }
5812
- if (message.type === "command") return JSON.stringify([message.type, message.command]);
5813
- if (message.type === "web_search") return JSON.stringify([message.type, message.query]);
5814
- if (message.type === "subagent") {
5815
- return JSON.stringify([
5816
- message.type,
5817
- message.description,
5818
- message.prompt,
5819
- message.subagentType,
5820
- message.model
5821
- ]);
5822
- }
5823
- if (message.type === "todo_list") {
5824
- return JSON.stringify([message.type, stableString(message.items)]);
5825
- }
5826
- if (message.type === "patch") {
5827
- return JSON.stringify([message.type, stableString(message.operations)]);
5828
- }
5829
- if (message.type === "tool_call") {
5830
- return JSON.stringify([
5831
- message.type,
5832
- message.server,
5833
- message.tool,
5834
- stableString(message.input)
5835
- ]);
5836
- }
5837
- return null;
5838
- }
5839
- function duplicateBucketKey(message, bucketOffset = 0) {
5840
- const key = duplicateKey(message);
5841
- if (key === null) return null;
5842
- const bucket = Math.floor(parseTimestampMs(message.timestamp) / DUPLICATE_WINDOW_MS) + bucketOffset;
5843
- return JSON.stringify([bucket, key]);
5844
- }
5845
- function mergeCodexAspDisplayMessages(primary, supplemental) {
5846
- const merged = [...primary];
5847
- const primaryCount = primary.length;
5848
- const firstIndexById = /* @__PURE__ */ new Map();
5849
- const indexesByDuplicateBucket = /* @__PURE__ */ new Map();
5850
- const indexMessage = (message, index) => {
5851
- if (!firstIndexById.has(message.id)) firstIndexById.set(message.id, index);
5852
- const key = duplicateBucketKey(message);
5853
- if (key === null) return;
5854
- const indexes = indexesByDuplicateBucket.get(key) ?? /* @__PURE__ */ new Set();
5855
- indexes.add(index);
5856
- indexesByDuplicateBucket.set(key, indexes);
5857
- };
5858
- const unindexMessage = (message, index) => {
5859
- const key = duplicateBucketKey(message);
5860
- if (key === null) return;
5861
- const indexes = indexesByDuplicateBucket.get(key);
5862
- indexes?.delete(index);
5863
- if (indexes?.size === 0) indexesByDuplicateBucket.delete(key);
5864
- };
5865
- merged.forEach(indexMessage);
5866
- for (const message of supplemental) {
5867
- let duplicateIndex = firstIndexById.get(message.id);
5868
- if (duplicateIndex === void 0) {
5869
- for (let bucketOffset = -1; bucketOffset <= 1; bucketOffset += 1) {
5870
- const key = duplicateBucketKey(message, bucketOffset);
5871
- for (const index of (key === null ? void 0 : indexesByDuplicateBucket.get(key)) ?? []) {
5872
- if (nearTimestamp(merged[index].timestamp, message.timestamp) && (duplicateIndex === void 0 || index < duplicateIndex)) {
5873
- duplicateIndex = index;
5874
- }
5875
- }
5876
- }
5877
- }
5878
- if (duplicateIndex === void 0) {
5879
- indexMessage(message, merged.push(message) - 1);
5880
- } else if (message.type === "user") {
5881
- unindexMessage(merged[duplicateIndex], duplicateIndex);
5882
- merged[duplicateIndex] = {
5883
- ...merged[duplicateIndex],
5884
- id: message.id
5885
- };
5886
- firstIndexById.set(message.id, duplicateIndex);
5887
- indexMessage(merged[duplicateIndex], duplicateIndex);
5888
- }
5889
- }
5890
- const ordered = merged.slice(0, primaryCount);
5891
- const supplementalOnly = merged.slice(primaryCount).map((message, index) => ({ message, index })).sort((a, b) => parseTimestampMs(a.message.timestamp) - parseTimestampMs(b.message.timestamp) || a.index - b.index);
5892
- for (const { message } of supplementalOnly) {
5893
- insertDisplayMessageByTimestamp(ordered, message);
5894
- }
5895
- return ordered;
5896
- }
5897
- function parseCodexAspTranscript(transcript) {
5898
- const messages = [];
5899
- const orderedItems = transcript.turns.map((turn, turnIndex) => ({ turn, turnIndex })).flatMap(({ turn, turnIndex }) => turn.items.map((item, itemIndex) => ({ item, turn, turnIndex, itemIndex }))).sort((a, b) => {
5900
- const aSequence = a.item.sequence ?? Number.MAX_SAFE_INTEGER;
5901
- const bSequence = b.item.sequence ?? Number.MAX_SAFE_INTEGER;
5902
- return aSequence - bSequence || parseTimestampMs(a.item.timestamp) - parseTimestampMs(b.item.timestamp) || a.turnIndex - b.turnIndex || a.itemIndex - b.itemIndex;
5903
- });
5904
- const reasoningByTurnId = /* @__PURE__ */ new Map();
5905
- for (const { item, turn } of orderedItems) {
5906
- if (item.type !== "reasoning" || !item.text.trim()) continue;
5907
- const reasoning = reasoningByTurnId.get(turn.id) ?? [];
5908
- reasoning.push(item);
5909
- reasoningByTurnId.set(turn.id, reasoning);
5910
- }
5911
- const emittedReasoningTurnIds = /* @__PURE__ */ new Set();
5912
- const coalescedItems = orderedItems.flatMap((entry) => {
5913
- if (entry.item.type !== "reasoning") return [entry];
5914
- const reasoning = reasoningByTurnId.get(entry.turn.id);
5915
- if (!reasoning || emittedReasoningTurnIds.has(entry.turn.id)) return [];
5916
- emittedReasoningTurnIds.add(entry.turn.id);
5917
- return [{
5918
- ...entry,
5919
- item: {
5920
- type: "reasoning",
5921
- id: entry.turn.id,
5922
- text: reasoning.map(({ text }) => text.trim()).join("\n\n"),
5923
- timestamp: entry.turn.startedAt,
5924
- ...reasoning[0] ? { sourceTimestamp: reasoning[0].timestamp } : {},
5925
- status: reasoning.at(-1)?.status ?? "completed",
5926
- sequence: entry.item.sequence
5927
- }
5928
- }];
5929
- });
5930
- for (const turn of transcript.turns) {
5931
- const reasoningIndex = coalescedItems.findIndex(({ item, turn: itemTurn }) => itemTurn.id === turn.id && item.type === "reasoning");
5932
- if (reasoningIndex === -1) continue;
5933
- const responseItem = getCodexAspTurnResponse({
5934
- status: turn.status,
5935
- items: coalescedItems.filter(({ turn: itemTurn }) => itemTurn.id === turn.id).map(({ item }) => item)
5936
- });
5937
- const finalAnswerIndex = responseItem ? coalescedItems.findIndex(({ item }) => item === responseItem) : -1;
5938
- if (finalAnswerIndex === -1 || reasoningIndex < finalAnswerIndex) continue;
5939
- const [reasoning] = coalescedItems.splice(reasoningIndex, 1);
5940
- coalescedItems.splice(finalAnswerIndex, 0, reasoning);
5941
- }
5942
- for (const { item } of coalescedItems) {
5943
- const message = messageForItem(item);
5944
- if (message) {
5945
- messages.push(message);
5946
- }
5947
- messages.push(...skillMessagesForItem(item));
5948
- }
5949
- return messages;
5950
- }
5951
-
5952
5939
  // ../shared/src/display-message/parsers/index.ts
5953
5940
  var INTERRUPTION_DEDUP_WINDOW_MS = 15e3;
5954
5941
  function parseAgentEvents(events, agentType) {
@@ -5982,22 +5969,19 @@ function parseAgentEvents(events, agentType) {
5982
5969
  }
5983
5970
  return parseClaudeEvents(events);
5984
5971
  }
5985
- function parseDisplayMessages(events, agentType, codexAspTranscript, options = {}) {
5972
+ function parseDisplayMessages(events, agentType, options = {}) {
5986
5973
  events = excludeQueuedAcceptedEvents(events, []);
5987
- const shouldFilter = options.filter ?? true;
5988
5974
  const parsedEvents = agentType === "claude" || agentType === "relay" ? parseClaudeEvents(events, options.parentToolUseId) : parseAgentEvents(events, agentType);
5989
5975
  const reconciledEvents = [];
5990
5976
  for (const message of parsedEvents) {
5991
5977
  if (message.type === "user") upsertDisplayMessage(reconciledEvents, message);
5992
5978
  else reconciledEvents.push(message);
5993
5979
  }
5994
- const legacyMessages = shouldFilter ? filterDisplayMessages(reconciledEvents, agentType) : reconciledEvents;
5995
- const applySyntheticNotices = (messages) => shouldFilter ? applyAuthFallbackNotices(applyInterruptions(messages, events), events) : messages;
5996
- if (agentType !== "codex" || !codexAspTranscript) {
5997
- return applySyntheticNotices(legacyMessages);
5998
- }
5999
- const nativeCodexMessages = shouldFilter ? filterDisplayMessages(parseCodexAspTranscript(codexAspTranscript), agentType) : parseCodexAspTranscript(codexAspTranscript);
6000
- return applySyntheticNotices(mergeCodexAspDisplayMessages(nativeCodexMessages, legacyMessages));
5980
+ if (options.filter === false) return reconciledEvents;
5981
+ return applyAuthFallbackNotices(
5982
+ applyInterruptions(filterDisplayMessages(reconciledEvents, agentType), events),
5983
+ events
5984
+ );
6001
5985
  }
6002
5986
  function applyInterruptions(messages, events) {
6003
5987
  const result = [...messages];
@@ -6171,52 +6155,64 @@ function areSameUserMessageEvents(a, b) {
6171
6155
  { content: bMessage, timestamp: b.timestamp }
6172
6156
  );
6173
6157
  }
6158
+ function parseAgentEventJsonlLine(line, options = {}) {
6159
+ const trimmed = line.trim();
6160
+ if (!trimmed) return null;
6161
+ try {
6162
+ const parsed = JSON.parse(trimmed);
6163
+ if (isAgentBackendEvent(parsed)) return parsed;
6164
+ options.onInvalidLine?.({ line: trimmed });
6165
+ } catch (error) {
6166
+ options.onInvalidLine?.({ line: trimmed, error });
6167
+ }
6168
+ return null;
6169
+ }
6174
6170
  function parseAgentEventJsonl(content, options = {}) {
6175
6171
  const events = [];
6176
6172
  for (const line of content.split("\n")) {
6177
- const trimmed = line.trim();
6178
- if (!trimmed) continue;
6179
- try {
6180
- const parsed = JSON.parse(trimmed);
6181
- if (isAgentBackendEvent(parsed)) {
6182
- events.push(parsed);
6183
- } else {
6184
- options.onInvalidLine?.({ line: trimmed });
6185
- }
6186
- } catch (error) {
6187
- options.onInvalidLine?.({ line: trimmed, error });
6188
- }
6173
+ const event = parseAgentEventJsonlLine(line, options);
6174
+ if (event) events.push(event);
6189
6175
  }
6190
6176
  return events;
6191
6177
  }
6192
- function parseAgentEventJsonlWithCodexAspTranscript(content, options = {}) {
6193
- const events = [];
6194
- let transcript = null;
6195
- const transcriptsByThreadId = /* @__PURE__ */ new Map();
6196
- for (const event of parseAgentEventJsonl(content, options)) {
6178
+
6179
+ // ../shared/src/codex-history.ts
6180
+ function isChatHistoryEvent(value) {
6181
+ return isAgentBackendEvent(value) && value.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE && value.type !== CODEX_HISTORY_FORMAT_EVENT_TYPE;
6182
+ }
6183
+ function codexHistoryFormatEvent() {
6184
+ return { timestamp: (/* @__PURE__ */ new Date()).toISOString(), type: CODEX_HISTORY_FORMAT_EVENT_TYPE, payload: { version: 2 } };
6185
+ }
6186
+ function chronological(events) {
6187
+ return [...events].sort((a, b) => getEventTimestampMs(a) - getEventTimestampMs(b));
6188
+ }
6189
+ var CodexHistoryEventFolder = class {
6190
+ events = [];
6191
+ transcripts = /* @__PURE__ */ new Map();
6192
+ push(event) {
6193
+ if (event.type === CODEX_HISTORY_FORMAT_EVENT_TYPE) return;
6197
6194
  if (event.type !== CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE) {
6198
- events.push(event);
6199
- continue;
6195
+ this.events.push(event);
6196
+ return;
6200
6197
  }
6201
6198
  const delta = event.payload.transcriptDelta;
6202
- if (isCodexAspTranscriptDelta(delta)) {
6203
- const previous = transcriptsByThreadId.get(delta.threadId) ?? null;
6204
- transcript = applyCodexAspTranscriptDelta(previous, delta);
6205
- } else if (isCodexAspTranscript(event.payload.transcript)) {
6206
- transcript = event.payload.transcript;
6207
- }
6208
- if (transcript) {
6209
- transcriptsByThreadId.set(transcript.threadId, transcript);
6210
- }
6199
+ const transcript = isCodexAspTranscriptDelta(delta) ? applyCodexAspTranscriptDelta(this.transcripts.get(delta.threadId) ?? null, delta) : isCodexAspTranscript(event.payload.transcript) ? event.payload.transcript : null;
6200
+ if (transcript) this.transcripts.set(transcript.threadId, transcript);
6201
+ }
6202
+ finish() {
6203
+ return chronological([...this.events, ...[...this.transcripts.values()].flatMap(codexTranscriptToEvents)]);
6211
6204
  }
6212
- return { events, transcript, transcriptsByThreadId };
6205
+ };
6206
+ function parseCodexHistoryEvents(content, options) {
6207
+ const folder = new CodexHistoryEventFolder();
6208
+ for (const event of parseAgentEventJsonl(content, options)) folder.push(event);
6209
+ return folder.finish();
6213
6210
  }
6214
6211
 
6215
6212
  // ../shared/src/transcript-canonicalize.ts
6216
6213
  function canonicalizeChatTranscriptBlocks(content, provider, senders) {
6217
- const parsed = parseAgentEventJsonlWithCodexAspTranscript(content);
6218
6214
  const messages = attachSendersToMessages(
6219
- parseDisplayMessages(parsed.events, provider, parsed.transcript),
6215
+ parseDisplayMessages(parseCodexHistoryEvents(content), provider),
6220
6216
  senders
6221
6217
  );
6222
6218
  return messages.flatMap((message) => {
@@ -7768,33 +7764,6 @@ function parseChatTranscriptHistoryIndex(value) {
7768
7764
  }
7769
7765
  };
7770
7766
  }
7771
- function getChatTranscriptHistorySize(index) {
7772
- return index.codexAspTranscript?.size ?? 0;
7773
- }
7774
- function createChatTranscriptPages(sourceBytes) {
7775
- const history = parseAgentEventJsonlWithCodexAspTranscript(new TextDecoder("utf-8", { fatal: true }).decode(sourceBytes));
7776
- const removedMessageIds = /* @__PURE__ */ new Set();
7777
- for (const event of history.events) {
7778
- for (const messageId of getRemovedMessageIds(event)) removedMessageIds.add(messageId);
7779
- }
7780
- const bytes = new TextEncoder().encode(history.transcript?.turns.length ? `${history.transcript.turns.map((turn) => JSON.stringify(turn)).join("\n")}
7781
- ` : "");
7782
- return {
7783
- bytes,
7784
- index: {
7785
- version: 2,
7786
- sourceSize: sourceBytes.byteLength,
7787
- ...removedMessageIds.size ? { removedMessageIds: [...removedMessageIds] } : {},
7788
- ...history.transcript ? {
7789
- codexAspTranscript: {
7790
- threadId: history.transcript.threadId,
7791
- updatedAt: history.transcript.updatedAt,
7792
- size: bytes.byteLength
7793
- }
7794
- } : {}
7795
- }
7796
- };
7797
- }
7798
7767
  function isNonNegativeInteger(value) {
7799
7768
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
7800
7769
  }
@@ -7997,13 +7966,13 @@ export {
7997
7966
  agentQuotaExhaustedPayloadSchema,
7998
7967
  defaultForkChatTitle,
7999
7968
  CLAUDE_PARTIAL_MESSAGE_EVENT_TYPE,
8000
- getClaudePartialMessageStreamId,
8001
7969
  ACCEPTED_USER_MESSAGE_SOURCE,
8002
7970
  QUEUED_MESSAGE_REMOVED_EVENT_TYPE,
8003
7971
  REMOVED_MESSAGE_IDS_PAYLOAD_KEY,
8004
7972
  USER_MESSAGE_ID_PAYLOAD_KEY,
8005
7973
  CODEX_ASP_ITEM_ID_PAYLOAD_KEY,
8006
- CODEX_ASP_TRANSCRIPT_UPDATED_EVENT_TYPE,
7974
+ CODEX_HISTORY_FORMAT_EVENT_TYPE,
7975
+ getEventStreamId,
8007
7976
  CODEX_QUOTA_STATUS_EVENT_TYPE,
8008
7977
  COMPACTION_STATUS_EVENT_TYPE,
8009
7978
  CHAT_INTERRUPTED_EVENT_TYPE,
@@ -8028,17 +7997,15 @@ export {
8028
7997
  normalizeCodexAspTranscriptStatus,
8029
7998
  imageContentToUserMessageImages,
8030
7999
  createAcceptedUserMessageEvent,
8031
- getCodexAspTurnResponse,
8032
- renumberCodexAspTranscriptItems,
8033
- isCodexAspTranscript,
8034
- isCodexAspTranscriptDelta,
8035
- applyCodexAspTranscriptDelta,
8000
+ codexItemEvent,
8001
+ codexTurnEvent,
8002
+ codexTurnFromEvent,
8003
+ codexTranscriptToEvents,
8036
8004
  isLatestChatHistoryPage,
8037
8005
  getChatHistoryPageSenders,
8038
8006
  parseChatHistoryCursor,
8039
8007
  createChatHistoryCursor,
8040
8008
  chatHistoryPageParamsFromQuery,
8041
- getChatHistoryPageWindow,
8042
8009
  paginateChatHistory,
8043
8010
  coerceBackgroundTaskPayload,
8044
8011
  isGitHubUrl,
@@ -8057,17 +8024,18 @@ export {
8057
8024
  coerceClaudeResultPayload,
8058
8025
  stripAgentDiagnosticErrors,
8059
8026
  isClaudeResultError,
8060
- parseLatestCodexAspTranscriptTurn,
8061
8027
  parseAgentEvents,
8062
8028
  parseDisplayMessages,
8063
- isAgentBackendEvent,
8064
8029
  getUserMessage,
8065
8030
  getUserMessageId,
8066
8031
  getRemovedMessageIds,
8067
8032
  excludeQueuedAcceptedEvents,
8068
8033
  getEventTimestampMs,
8069
8034
  areSameUserMessageEvents,
8070
- parseAgentEventJsonlWithCodexAspTranscript,
8035
+ parseAgentEventJsonlLine,
8036
+ isChatHistoryEvent,
8037
+ codexHistoryFormatEvent,
8038
+ CodexHistoryEventFolder,
8071
8039
  getMemoryOutputSafetyViolation,
8072
8040
  canonicalizeChatTranscriptBlocks,
8073
8041
  lastUserBlockText,
@@ -8133,8 +8101,6 @@ export {
8133
8101
  isExcludedRepoFilePath,
8134
8102
  formatChatForkHandoffMessage,
8135
8103
  readJsonlPage,
8136
- getChatTranscriptHistorySize,
8137
- createChatTranscriptPages,
8138
8104
  parseChatTranscriptArtifact,
8139
8105
  readSseStream,
8140
8106
  parseFrontmatter,