@myagentroam/node 0.1.3 → 0.1.4

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.
Files changed (197) hide show
  1. package/dist/claude-agent-sdk.d.ts +1 -15
  2. package/dist/claude-agent-sdk.js +9 -77
  3. package/dist/claude-agent-sdk.js.map +1 -1
  4. package/dist/codex-app-server.d.ts +4 -0
  5. package/dist/codex-app-server.js +18 -4
  6. package/dist/codex-app-server.js.map +1 -1
  7. package/dist/connector/node-connector-options.d.ts +23 -0
  8. package/dist/connector/node-connector-options.js +2 -0
  9. package/dist/connector/node-connector-options.js.map +1 -0
  10. package/dist/connector/node-operation-router.d.ts +9 -0
  11. package/dist/connector/node-operation-router.js +23 -0
  12. package/dist/connector/node-operation-router.js.map +1 -0
  13. package/dist/connector.d.ts +59 -356
  14. package/dist/connector.js +611 -6175
  15. package/dist/connector.js.map +1 -1
  16. package/dist/control-outbound-scheduler.d.ts +26 -0
  17. package/dist/control-outbound-scheduler.js +122 -0
  18. package/dist/control-outbound-scheduler.js.map +1 -0
  19. package/dist/database.js +1 -1
  20. package/dist/database.js.map +1 -1
  21. package/dist/native-jsonl-reader.d.ts +14 -0
  22. package/dist/native-jsonl-reader.js +98 -0
  23. package/dist/native-jsonl-reader.js.map +1 -0
  24. package/dist/native-session-history.d.ts +22 -3
  25. package/dist/native-session-history.js +275 -156
  26. package/dist/native-session-history.js.map +1 -1
  27. package/dist/runner/abstract-runner.d.ts +148 -0
  28. package/dist/runner/abstract-runner.js +139 -0
  29. package/dist/runner/abstract-runner.js.map +1 -0
  30. package/dist/runner/claude/managed-run-controller.d.ts +52 -0
  31. package/dist/runner/claude/managed-run-controller.js +307 -0
  32. package/dist/runner/claude/managed-run-controller.js.map +1 -0
  33. package/dist/runner/claude-code-runner.d.ts +68 -0
  34. package/dist/runner/claude-code-runner.js +268 -0
  35. package/dist/runner/claude-code-runner.js.map +1 -0
  36. package/dist/runner/codex/conversation-parser.d.ts +61 -0
  37. package/dist/runner/codex/conversation-parser.js +676 -0
  38. package/dist/runner/codex/conversation-parser.js.map +1 -0
  39. package/dist/runner/codex/managed-run-controller.d.ts +79 -0
  40. package/dist/runner/codex/managed-run-controller.js +379 -0
  41. package/dist/runner/codex/managed-run-controller.js.map +1 -0
  42. package/dist/runner/codex-runner.d.ts +81 -0
  43. package/dist/runner/codex-runner.js +342 -0
  44. package/dist/runner/codex-runner.js.map +1 -0
  45. package/dist/runner/fake-test-runner.d.ts +26 -0
  46. package/dist/runner/fake-test-runner.js +48 -0
  47. package/dist/runner/fake-test-runner.js.map +1 -0
  48. package/dist/runner/runner-registry.d.ts +17 -0
  49. package/dist/runner/runner-registry.js +66 -0
  50. package/dist/runner/runner-registry.js.map +1 -0
  51. package/dist/runner-usage.d.ts +2 -2
  52. package/dist/runner-usage.js +3 -5
  53. package/dist/runner-usage.js.map +1 -1
  54. package/dist/runtime-state.js +6 -5
  55. package/dist/runtime-state.js.map +1 -1
  56. package/dist/service/attachment-domain-state.d.ts +5 -0
  57. package/dist/service/attachment-domain-state.js +6 -0
  58. package/dist/service/attachment-domain-state.js.map +1 -0
  59. package/dist/service/conversation-history-service.d.ts +34 -0
  60. package/dist/service/conversation-history-service.js +159 -0
  61. package/dist/service/conversation-history-service.js.map +1 -0
  62. package/dist/service/external-session-resume-service.d.ts +32 -0
  63. package/dist/service/external-session-resume-service.js +99 -0
  64. package/dist/service/external-session-resume-service.js.map +1 -0
  65. package/dist/service/fake-managed-run-service.d.ts +29 -0
  66. package/dist/service/fake-managed-run-service.js +63 -0
  67. package/dist/service/fake-managed-run-service.js.map +1 -0
  68. package/dist/service/managed-runner-session-service.d.ts +10 -0
  69. package/dist/service/managed-runner-session-service.js +31 -0
  70. package/dist/service/managed-runner-session-service.js.map +1 -0
  71. package/dist/service/native-session-projection-service.d.ts +50 -0
  72. package/dist/service/native-session-projection-service.js +268 -0
  73. package/dist/service/native-session-projection-service.js.map +1 -0
  74. package/dist/service/native-session-watch-service.d.ts +37 -0
  75. package/dist/service/native-session-watch-service.js +151 -0
  76. package/dist/service/native-session-watch-service.js.map +1 -0
  77. package/dist/service/node-connection-lifecycle-service.d.ts +37 -0
  78. package/dist/service/node-connection-lifecycle-service.js +84 -0
  79. package/dist/service/node-connection-lifecycle-service.js.map +1 -0
  80. package/dist/service/node-control-channel.d.ts +32 -0
  81. package/dist/service/node-control-channel.js +84 -0
  82. package/dist/service/node-control-channel.js.map +1 -0
  83. package/dist/service/node-control-message-service.d.ts +28 -0
  84. package/dist/service/node-control-message-service.js +105 -0
  85. package/dist/service/node-control-message-service.js.map +1 -0
  86. package/dist/service/node-request-service.d.ts +14 -0
  87. package/dist/service/node-request-service.js +51 -0
  88. package/dist/service/node-request-service.js.map +1 -0
  89. package/dist/service/node-run-event-bridge.d.ts +38 -0
  90. package/dist/service/node-run-event-bridge.js +80 -0
  91. package/dist/service/node-run-event-bridge.js.map +1 -0
  92. package/dist/service/node-terminal-channel.d.ts +29 -0
  93. package/dist/service/node-terminal-channel.js +176 -0
  94. package/dist/service/node-terminal-channel.js.map +1 -0
  95. package/dist/service/node-workspace-coordinator.d.ts +32 -0
  96. package/dist/service/node-workspace-coordinator.js +81 -0
  97. package/dist/service/node-workspace-coordinator.js.map +1 -0
  98. package/dist/service/run-attachment-service.d.ts +37 -0
  99. package/dist/service/run-attachment-service.js +161 -0
  100. package/dist/service/run-attachment-service.js.map +1 -0
  101. package/dist/service/run-domain-state.d.ts +4 -0
  102. package/dist/service/run-domain-state.js +5 -0
  103. package/dist/service/run-domain-state.js.map +1 -0
  104. package/dist/service/run-event-service.d.ts +31 -0
  105. package/dist/service/run-event-service.js +103 -0
  106. package/dist/service/run-event-service.js.map +1 -0
  107. package/dist/service/run-workbench-service.d.ts +27 -0
  108. package/dist/service/run-workbench-service.js +114 -0
  109. package/dist/service/run-workbench-service.js.map +1 -0
  110. package/dist/service/runner-channel-message-service.d.ts +13 -0
  111. package/dist/service/runner-channel-message-service.js +21 -0
  112. package/dist/service/runner-channel-message-service.js.map +1 -0
  113. package/dist/service/runner-interaction-service.d.ts +40 -0
  114. package/dist/service/runner-interaction-service.js +245 -0
  115. package/dist/service/runner-interaction-service.js.map +1 -0
  116. package/dist/service/runner-service.d.ts +43 -0
  117. package/dist/service/runner-service.js +55 -0
  118. package/dist/service/runner-service.js.map +1 -0
  119. package/dist/service/session-catalog-service.d.ts +30 -0
  120. package/dist/service/session-catalog-service.js +145 -0
  121. package/dist/service/session-catalog-service.js.map +1 -0
  122. package/dist/service/session-command-service.d.ts +23 -0
  123. package/dist/service/session-command-service.js +70 -0
  124. package/dist/service/session-command-service.js.map +1 -0
  125. package/dist/service/session-context-service.d.ts +34 -0
  126. package/dist/service/session-context-service.js +88 -0
  127. package/dist/service/session-context-service.js.map +1 -0
  128. package/dist/service/session-domain-state.d.ts +8 -0
  129. package/dist/service/session-domain-state.js +9 -0
  130. package/dist/service/session-domain-state.js.map +1 -0
  131. package/dist/service/session-identity-service.d.ts +24 -0
  132. package/dist/service/session-identity-service.js +87 -0
  133. package/dist/service/session-identity-service.js.map +1 -0
  134. package/dist/service/session-lifecycle-service.d.ts +31 -0
  135. package/dist/service/session-lifecycle-service.js +236 -0
  136. package/dist/service/session-lifecycle-service.js.map +1 -0
  137. package/dist/service/session-message-service.d.ts +33 -0
  138. package/dist/service/session-message-service.js +158 -0
  139. package/dist/service/session-message-service.js.map +1 -0
  140. package/dist/service/session-presentation-service.d.ts +33 -0
  141. package/dist/service/session-presentation-service.js +37 -0
  142. package/dist/service/session-presentation-service.js.map +1 -0
  143. package/dist/service/session-query-service.d.ts +31 -0
  144. package/dist/service/session-query-service.js +78 -0
  145. package/dist/service/session-query-service.js.map +1 -0
  146. package/dist/service/terminal-relay-state.d.ts +6 -0
  147. package/dist/service/terminal-relay-state.js +4 -0
  148. package/dist/service/terminal-relay-state.js.map +1 -0
  149. package/dist/service/terminal-service.d.ts +12 -0
  150. package/dist/service/terminal-service.js +53 -0
  151. package/dist/service/terminal-service.js.map +1 -0
  152. package/dist/service/workbench-event-service.d.ts +21 -0
  153. package/dist/service/workbench-event-service.js +54 -0
  154. package/dist/service/workbench-event-service.js.map +1 -0
  155. package/dist/service/workbench-manifest-service.d.ts +88 -0
  156. package/dist/service/workbench-manifest-service.js +69 -0
  157. package/dist/service/workbench-manifest-service.js.map +1 -0
  158. package/dist/service/workspace-change-service.d.ts +9 -0
  159. package/dist/service/workspace-change-service.js +86 -0
  160. package/dist/service/workspace-change-service.js.map +1 -0
  161. package/dist/service/workspace-domain-state.d.ts +75 -0
  162. package/dist/service/workspace-domain-state.js +41 -0
  163. package/dist/service/workspace-domain-state.js.map +1 -0
  164. package/dist/service/workspace-file-service.d.ts +14 -0
  165. package/dist/service/workspace-file-service.js +77 -0
  166. package/dist/service/workspace-file-service.js.map +1 -0
  167. package/dist/service/workspace-queue-workbench-service.d.ts +55 -0
  168. package/dist/service/workspace-queue-workbench-service.js +227 -0
  169. package/dist/service/workspace-queue-workbench-service.js.map +1 -0
  170. package/dist/service/workspace-service.d.ts +15 -0
  171. package/dist/service/workspace-service.js +54 -0
  172. package/dist/service/workspace-service.js.map +1 -0
  173. package/dist/service/workspace-session-service.d.ts +23 -0
  174. package/dist/service/workspace-session-service.js +140 -0
  175. package/dist/service/workspace-session-service.js.map +1 -0
  176. package/dist/service/workspace-upload-service.d.ts +37 -0
  177. package/dist/service/workspace-upload-service.js +241 -0
  178. package/dist/service/workspace-upload-service.js.map +1 -0
  179. package/dist/service/workspace-watch-service.d.ts +18 -0
  180. package/dist/service/workspace-watch-service.js +121 -0
  181. package/dist/service/workspace-watch-service.js.map +1 -0
  182. package/dist/service/workspace-workbench-service.d.ts +38 -0
  183. package/dist/service/workspace-workbench-service.js +156 -0
  184. package/dist/service/workspace-workbench-service.js.map +1 -0
  185. package/dist/terminal.d.ts +1 -0
  186. package/dist/terminal.js +1 -1
  187. package/dist/terminal.js.map +1 -1
  188. package/dist/util/node-operation-parsers.d.ts +91 -0
  189. package/dist/util/node-operation-parsers.js +380 -0
  190. package/dist/util/node-operation-parsers.js.map +1 -0
  191. package/dist/util/runner-native-session-parsers.d.ts +72 -0
  192. package/dist/util/runner-native-session-parsers.js +337 -0
  193. package/dist/util/runner-native-session-parsers.js.map +1 -0
  194. package/dist/util/secret-environment.d.ts +1 -0
  195. package/dist/util/secret-environment.js +26 -0
  196. package/dist/util/secret-environment.js.map +1 -0
  197. package/package.json +2 -2
@@ -0,0 +1,676 @@
1
+ const MAX_COMPOSER_ATTACHMENT_BYTES = 5 * 1024 * 1024;
2
+ const MAX_COMPOSER_ATTACHMENTS_BYTES = 10 * 1024 * 1024;
3
+ export * from '../../util/runner-native-session-parsers.js';
4
+ export function codexOfficialConversationPage(session, result, input, managedTurnForNative) {
5
+ if (!isPlainRecord(result) || !isPlainRecord(result.thread))
6
+ return undefined;
7
+ const thread = result.thread;
8
+ if (thread.id !== session.externalSessionId || !Array.isArray(thread.turns))
9
+ return undefined;
10
+ const allTurns = thread.turns.flatMap((value, sequence) => {
11
+ const turn = codexOfficialTurn(session, value, sequence, typeof value === 'object' &&
12
+ value !== null &&
13
+ typeof value.id === 'string'
14
+ ? managedTurnForNative(value.id)
15
+ : undefined);
16
+ return turn === undefined ? [] : [turn];
17
+ });
18
+ if (allTurns.length === 0)
19
+ return undefined;
20
+ const limit = Math.min(Math.max(input.limit ?? 30, 1), 500);
21
+ const end = nativePageEnd(input.cursor, session.id, allTurns.length);
22
+ const start = Math.max(0, end - limit);
23
+ return {
24
+ turns: allTurns.slice(start, end),
25
+ nextCursor: start > 0
26
+ ? Buffer.from(JSON.stringify({ sessionId: session.id, end: start })).toString('base64url')
27
+ : null
28
+ };
29
+ }
30
+ export function codexOfficialTurn(session, value, sequence, managedTurn) {
31
+ if (!isPlainRecord(value) || typeof value.id !== 'string' || !Array.isArray(value.items))
32
+ return undefined;
33
+ const startedAt = codexTimestamp(value.startedAt);
34
+ const completedAt = codexTimestamp(value.completedAt) ?? startedAt;
35
+ const items = codexOfficialItems(session, value.id, value.items, sequence, startedAt, completedAt);
36
+ if (items.length === 0)
37
+ return undefined;
38
+ if (managedTurn !== undefined) {
39
+ const localUser = managedTurn.items.find((item) => item.kind === 'user_message');
40
+ const officialNativeItemIds = codexNativeItemIds(value.items);
41
+ const officialAssistantMessage = items.some((item) => item.kind === 'assistant_message');
42
+ const assistantLength = (values) => values.reduce((length, item) => {
43
+ if (item.kind !== 'assistant_message' || !isPlainRecord(item.payload))
44
+ return length;
45
+ return length + (typeof item.payload.text === 'string' ? item.payload.text.length : 0);
46
+ }, 0);
47
+ const preferLocalAssistant = officialAssistantMessage &&
48
+ (assistantLength(managedTurn.items) > assistantLength(items) ||
49
+ ((managedTurn.completedAt ?? 0) > (completedAt ?? 0) &&
50
+ assistantLength(managedTurn.items) > 0));
51
+ const localLiveItems = managedTurn.items.filter((item) => {
52
+ if (item.kind === 'user_message')
53
+ return false;
54
+ // `item/agentMessage/delta` uses a synthetic runtime ID. Once
55
+ // `thread/read` returns the final Agent message, it is the same reply
56
+ // without a shared native item ID and must replace that transient item.
57
+ if (item.kind === 'assistant_message' && officialAssistantMessage && !preferLocalAssistant)
58
+ return false;
59
+ const nativeItemId = conversationItemNativeId(item.id);
60
+ return nativeItemId === undefined || !officialNativeItemIds.has(nativeItemId);
61
+ });
62
+ const officialItems = [
63
+ ...retainManagedImageAttachments(managedTurn, value.id, items
64
+ .filter((item) => item.kind !== 'assistant_message' || !preferLocalAssistant)
65
+ .map((item) => item.kind === 'user_message' && localUser !== undefined
66
+ ? { ...localUser, turnId: managedTurn.id }
67
+ : { ...item, turnId: managedTurn.id, runId: managedTurn.runId }))
68
+ ];
69
+ if (localUser !== undefined && !officialItems.some((item) => item.kind === 'user_message'))
70
+ officialItems.unshift({ ...localUser, turnId: managedTurn.id });
71
+ return {
72
+ ...managedTurn,
73
+ status: 'SUCCEEDED',
74
+ // App Server history is authoritative, but can lag a live item that is
75
+ // not represented in `thread/read`. A planning result is terminal for
76
+ // this turn, so any such retained tool card belongs before it; never
77
+ // append it after the plan/Implement affordance.
78
+ items: orderCodexConversationItems([...officialItems, ...localLiveItems]),
79
+ startedAt,
80
+ completedAt
81
+ };
82
+ }
83
+ return {
84
+ id: `${session.id}:official:${value.id}`,
85
+ sessionId: session.id,
86
+ runId: null,
87
+ userItemId: items.find((item) => item.kind === 'user_message')?.id ?? null,
88
+ status: 'SUCCEEDED',
89
+ model: null,
90
+ effort: null,
91
+ access: null,
92
+ items,
93
+ startedAt,
94
+ completedAt
95
+ };
96
+ }
97
+ /**
98
+ * Codex's authoritative thread records omit MAR's Node-local generated-image
99
+ * references. Preserve those references like user-image metadata: cache expiry
100
+ * only makes the bytes unavailable, while the conversation still renders its
101
+ * image placeholder.
102
+ */
103
+ export function retainManagedImageAttachments(managedTurn, nativeTurnId, officialItems) {
104
+ const localAttachments = new Map();
105
+ for (const item of managedTurn.items) {
106
+ const nativeItemId = conversationItemNativeId(item.id);
107
+ if (nativeItemId === undefined || !isPlainRecord(item.payload))
108
+ continue;
109
+ if (!Array.isArray(item.payload.attachments) || item.payload.attachments.length === 0)
110
+ continue;
111
+ localAttachments.set(nativeItemId, item.payload.attachments);
112
+ }
113
+ if (localAttachments.size === 0)
114
+ return officialItems;
115
+ const marker = `:official:${nativeTurnId}:`;
116
+ return officialItems.map((item) => {
117
+ if (!isPlainRecord(item.payload) || Array.isArray(item.payload.attachments))
118
+ return item;
119
+ const markerIndex = item.id.lastIndexOf(marker);
120
+ if (markerIndex < 0)
121
+ return item;
122
+ const attachments = localAttachments.get(item.id.slice(markerIndex + marker.length));
123
+ return attachments === undefined
124
+ ? item
125
+ : { ...item, payload: { ...item.payload, attachments } };
126
+ });
127
+ }
128
+ export function codexNativeItemIds(values) {
129
+ return new Set(values.flatMap((value) => {
130
+ if (!isPlainRecord(value))
131
+ return [];
132
+ const id = typeof value.call_id === 'string'
133
+ ? value.call_id
134
+ : typeof value.id === 'string'
135
+ ? value.id
136
+ : undefined;
137
+ return id === undefined ? [] : [id];
138
+ }));
139
+ }
140
+ export function conversationItemNativeId(itemId) {
141
+ if (itemId.startsWith('codex:'))
142
+ return itemId.slice('codex:'.length);
143
+ const marker = ':codex:';
144
+ const markerIndex = itemId.lastIndexOf(marker);
145
+ return markerIndex < 0 ? undefined : itemId.slice(markerIndex + marker.length);
146
+ }
147
+ /** Keep a custom tool invocation and its output in one Workbench card. */
148
+ export function codexOfficialItems(session, nativeTurnId, values, turnSequence, startedAt, completedAt) {
149
+ const items = [];
150
+ const pairedToolIndexes = new Map();
151
+ // App Server preserves execution order within a Turn. Keep that order while
152
+ // merging a paired tool invocation with its output into one Workbench card.
153
+ for (const [itemSequence, value] of values.entries()) {
154
+ const item = codexOfficialItem(session, nativeTurnId, value, turnSequence, itemSequence, startedAt, completedAt);
155
+ if (item === undefined)
156
+ continue;
157
+ const key = codexPairedToolCallId(value);
158
+ if (key === undefined) {
159
+ items.push(item);
160
+ continue;
161
+ }
162
+ const existingIndex = pairedToolIndexes.get(key);
163
+ if (existingIndex === undefined) {
164
+ pairedToolIndexes.set(key, items.length);
165
+ items.push(item);
166
+ continue;
167
+ }
168
+ const previous = items[existingIndex];
169
+ const invocation = isPlainRecord(value) && (value.type === 'custom_tool_call' || value.type === 'function_call')
170
+ ? item
171
+ : previous;
172
+ const result = invocation === item ? previous : item;
173
+ items[existingIndex] = mergeCodexCustomToolItems(invocation, result);
174
+ }
175
+ // A tool card is evidence for the reply. Keep the prompt first, then show
176
+ // every command/tool action before Agent prose so the visible narrative does
177
+ // not claim a result before its supporting execution is available.
178
+ return orderCodexConversationItems(items);
179
+ }
180
+ /** Keep history-only and history-plus-live projections in the same narrative order. */
181
+ export function orderCodexConversationItems(items) {
182
+ return [
183
+ ...items.filter((item) => item.kind === 'user_message'),
184
+ ...items.filter((item) => item.kind === 'command_execution' || item.kind === 'tool_call'),
185
+ ...items.filter((item) => item.kind !== 'user_message' &&
186
+ item.kind !== 'command_execution' &&
187
+ item.kind !== 'tool_call')
188
+ ];
189
+ }
190
+ export function codexPairedToolCallId(value) {
191
+ if (!isPlainRecord(value))
192
+ return undefined;
193
+ if (value.type !== 'custom_tool_call' &&
194
+ value.type !== 'custom_tool_call_output' &&
195
+ value.type !== 'function_call' &&
196
+ value.type !== 'function_call_output')
197
+ return undefined;
198
+ return typeof value.call_id === 'string'
199
+ ? value.call_id
200
+ : typeof value.id === 'string'
201
+ ? value.id
202
+ : undefined;
203
+ }
204
+ export function mergeCodexCustomToolItems(invocation, result) {
205
+ if (invocation.kind !== 'tool_call' || result.kind !== 'tool_call')
206
+ return invocation;
207
+ const invocationPayload = isPlainRecord(invocation.payload) ? invocation.payload : {};
208
+ const resultPayload = isPlainRecord(result.payload) ? result.payload : {};
209
+ return {
210
+ ...invocation,
211
+ status: result.status,
212
+ completedAt: result.completedAt,
213
+ payload: {
214
+ ...invocationPayload,
215
+ outputSummary: resultPayload.outputSummary ?? invocationPayload.outputSummary,
216
+ errorCode: resultPayload.errorCode ?? invocationPayload.errorCode,
217
+ truncated: invocationPayload.truncated === true || resultPayload.truncated === true,
218
+ ...(resultPayload.attachments === undefined ? {} : { attachments: resultPayload.attachments })
219
+ }
220
+ };
221
+ }
222
+ export function coalesceImageGenerationItems(items) {
223
+ const merged = [];
224
+ for (const item of items) {
225
+ const payload = isPlainRecord(item.payload) ? item.payload : undefined;
226
+ const previous = merged.at(-1);
227
+ const previousPayload = previous !== undefined && isPlainRecord(previous.payload) ? previous.payload : undefined;
228
+ if (item.kind !== 'tool_call' ||
229
+ payload?.toolName !== 'imagegen' ||
230
+ previous?.kind !== 'tool_call' ||
231
+ previousPayload?.toolName !== 'imagegen') {
232
+ merged.push(item);
233
+ continue;
234
+ }
235
+ const attachments = [
236
+ ...(Array.isArray(previousPayload.attachments) ? previousPayload.attachments : []),
237
+ ...(Array.isArray(payload.attachments) ? payload.attachments : [])
238
+ ];
239
+ merged[merged.length - 1] = {
240
+ ...previous,
241
+ completedAt: item.completedAt ?? previous.completedAt,
242
+ payload: { ...previousPayload, attachments }
243
+ };
244
+ }
245
+ return merged;
246
+ }
247
+ export function codexPlanText(value) {
248
+ if (typeof value.type !== 'string' || typeof value.text !== 'string')
249
+ return undefined;
250
+ const text = value.text.trim();
251
+ if (text.length === 0)
252
+ return undefined;
253
+ if (value.type.toLocaleLowerCase() === 'plan')
254
+ return text;
255
+ if (value.type !== 'agentMessage' || !text.startsWith('<proposed_plan>'))
256
+ return undefined;
257
+ const plan = text
258
+ .slice('<proposed_plan>'.length)
259
+ .replace(/<\/proposed_plan>\s*$/, '')
260
+ .trim();
261
+ return plan.length > 0 ? plan : undefined;
262
+ }
263
+ /**
264
+ * Claude 标签式 Plan Mode 的最终计划以 `<proposed_plan>` 完整包裹输出;
265
+ * 未闭合或缺失标签的文本保持普通 assistant 消息。
266
+ */
267
+ export function codexOfficialItem(session, nativeTurnId, value, turnSequence, itemSequence, startedAt, completedAt) {
268
+ if (!isPlainRecord(value) || typeof value.type !== 'string')
269
+ return undefined;
270
+ const id = (value.type === 'custom_tool_call' ||
271
+ value.type === 'custom_tool_call_output' ||
272
+ value.type === 'function_call' ||
273
+ value.type === 'function_call_output') &&
274
+ typeof value.call_id === 'string'
275
+ ? value.call_id
276
+ : typeof value.id === 'string'
277
+ ? value.id
278
+ : typeof value.call_id === 'string'
279
+ ? value.call_id
280
+ : `${nativeTurnId}:${itemSequence}`;
281
+ const base = {
282
+ id: `${session.id}:official:${nativeTurnId}:${id}`,
283
+ sessionId: session.id,
284
+ turnId: `${session.id}:official:${nativeTurnId}`,
285
+ runId: null,
286
+ parentItemId: null,
287
+ sourceSequence: turnSequence * 10_000 + itemSequence,
288
+ revision: 0,
289
+ status: 'COMPLETED',
290
+ startedAt,
291
+ completedAt
292
+ };
293
+ if (value.type === 'userMessage') {
294
+ const text = codexContentText(value.content);
295
+ return text.length === 0
296
+ ? undefined
297
+ : {
298
+ ...base,
299
+ kind: 'user_message',
300
+ payload: { clientMessageId: null, text, contexts: [], delivery: 'ACCEPTED' }
301
+ };
302
+ }
303
+ const planText = codexPlanText(value);
304
+ if (planText !== undefined)
305
+ return { ...base, kind: 'plan', payload: { explanation: planText, steps: [] } };
306
+ if (value.type === 'agentMessage' &&
307
+ typeof value.text === 'string' &&
308
+ value.text.trim().length > 0)
309
+ return {
310
+ ...base,
311
+ kind: 'assistant_message',
312
+ payload: { text: value.text, format: 'markdown', source: 'codex-app-server' }
313
+ };
314
+ if (value.type === 'mcpToolCall')
315
+ return {
316
+ ...base,
317
+ kind: 'tool_call',
318
+ payload: {
319
+ title: [
320
+ typeof value.server === 'string' ? value.server : '',
321
+ typeof value.tool === 'string' ? value.tool : ''
322
+ ]
323
+ .filter(Boolean)
324
+ .join('.'),
325
+ namespace: typeof value.server === 'string' ? value.server : '',
326
+ toolName: typeof value.tool === 'string' ? value.tool : '',
327
+ inputSummary: codexCompactJson(value.arguments),
328
+ outputSummary: codexCompactJson(value.result),
329
+ ...(value.error === undefined ? {} : { errorCode: codexCompactJson(value.error) })
330
+ }
331
+ };
332
+ if (value.type === 'webSearch')
333
+ return {
334
+ ...base,
335
+ kind: 'tool_call',
336
+ payload: {
337
+ title: 'Web Search',
338
+ namespace: 'web',
339
+ toolName: 'search',
340
+ inputSummary: typeof value.query === 'string' ? value.query : ''
341
+ }
342
+ };
343
+ if (value.type === 'imageGeneration')
344
+ return {
345
+ ...base,
346
+ kind: 'tool_call',
347
+ payload: {
348
+ title: 'imagegen',
349
+ namespace: 'codex',
350
+ toolName: 'imagegen',
351
+ inputSummary: typeof value.revisedPrompt === 'string' ? value.revisedPrompt : null,
352
+ outputSummary: value.status === 'completed' ? '图片生成完成' : '图片生成失败',
353
+ progressLabel: null,
354
+ errorCode: value.status === 'failed' ? 'IMAGE_GENERATION_FAILED' : null,
355
+ truncated: false
356
+ }
357
+ };
358
+ if (value.type === 'dynamicToolCall' ||
359
+ value.type === 'custom_tool_call' ||
360
+ value.type === 'custom_tool_call_output' ||
361
+ value.type === 'function_call' ||
362
+ value.type === 'function_call_output' ||
363
+ value.type === 'customToolCall' ||
364
+ value.type === 'customToolCallOutput' ||
365
+ value.type === 'functionCall' ||
366
+ value.type === 'functionCallOutput') {
367
+ const name = typeof value.tool === 'string'
368
+ ? value.tool
369
+ : typeof value.name === 'string'
370
+ ? value.name
371
+ : 'tool';
372
+ return {
373
+ ...base,
374
+ kind: 'tool_call',
375
+ payload: {
376
+ title: name,
377
+ namespace: typeof value.namespace === 'string' ? value.namespace : 'codex',
378
+ toolName: name,
379
+ inputSummary: codexCompactJson(value.arguments ?? value.input),
380
+ outputSummary: codexToolOutputSummary(value.contentItems ?? value.output),
381
+ progressLabel: null,
382
+ errorCode: null,
383
+ truncated: false
384
+ }
385
+ };
386
+ }
387
+ if (value.type === 'fileChange' && Array.isArray(value.changes))
388
+ return { ...base, kind: 'file_change', payload: { changes: value.changes } };
389
+ if (value.type === 'contextCompaction')
390
+ return { ...base, kind: 'context_compaction', payload: { summary: '上下文已整理' } };
391
+ return undefined;
392
+ }
393
+ export function codexLiveConversationItem(value, completed, imageAttachments = []) {
394
+ if (typeof value.type !== 'string')
395
+ return undefined;
396
+ const nativeId = typeof value.call_id === 'string'
397
+ ? value.call_id
398
+ : typeof value.id === 'string'
399
+ ? value.id
400
+ : undefined;
401
+ if (nativeId === undefined)
402
+ return undefined;
403
+ const itemId = boundedConversationItemId('codex', nativeId);
404
+ if (value.type === 'reasoning') {
405
+ const sections = Array.isArray(value.summary)
406
+ ? value.summary.flatMap((text, index) => typeof text === 'string' && text.trim().length > 0
407
+ ? [{ index, text: compactRunnerText(text, 10_000) }]
408
+ : [])
409
+ : [];
410
+ return {
411
+ itemId,
412
+ kind: 'reasoning_summary',
413
+ status: completed ? 'COMPLETED' : 'IN_PROGRESS',
414
+ payload: { sections }
415
+ };
416
+ }
417
+ const planText = codexPlanText(value);
418
+ if (planText !== undefined)
419
+ return {
420
+ itemId,
421
+ kind: 'plan',
422
+ status: completed ? 'COMPLETED' : 'IN_PROGRESS',
423
+ payload: { explanation: compactRunnerText(planText, 20_000), steps: [] }
424
+ };
425
+ if (value.type === 'commandExecution') {
426
+ const output = typeof value.aggregatedOutput === 'string' ? value.aggregatedOutput : '';
427
+ return {
428
+ itemId,
429
+ kind: 'command_execution',
430
+ status: codexItemStatus(value.status, completed),
431
+ payload: {
432
+ command: typeof value.command === 'string'
433
+ ? compactRunnerText(value.command, 10_000)
434
+ : '(未提供命令)',
435
+ cwd: typeof value.cwd === 'string' ? compactRunnerText(value.cwd, 4_096) : null,
436
+ outputPreview: compactRunnerText(output, 10_000),
437
+ outputRef: null,
438
+ exitCode: typeof value.exitCode === 'number' && Number.isInteger(value.exitCode)
439
+ ? value.exitCode
440
+ : null,
441
+ durationMs: typeof value.durationMs === 'number' &&
442
+ Number.isInteger(value.durationMs) &&
443
+ value.durationMs >= 0
444
+ ? value.durationMs
445
+ : null,
446
+ truncated: output.length > 10_000
447
+ }
448
+ };
449
+ }
450
+ if (value.type === 'mcpToolCall') {
451
+ const input = compactRunnerValue(value.arguments, 10_000);
452
+ const output = compactRunnerValue(value.result, 10_000);
453
+ const error = compactRunnerValue(value.error, 80);
454
+ const server = typeof value.server === 'string' ? value.server : 'mcp';
455
+ const tool = typeof value.tool === 'string' ? value.tool : 'tool';
456
+ return {
457
+ itemId,
458
+ kind: 'tool_call',
459
+ status: codexItemStatus(value.status, completed),
460
+ payload: {
461
+ namespace: compactRunnerText(server, 128),
462
+ toolName: compactRunnerText(tool, 128),
463
+ title: compactRunnerText(`${server}.${tool}`, 500),
464
+ inputSummary: input.text || null,
465
+ outputSummary: output.text || null,
466
+ progressLabel: null,
467
+ errorCode: error.text || null,
468
+ truncated: input.truncated || output.truncated || error.truncated
469
+ }
470
+ };
471
+ }
472
+ if (value.type === 'dynamicToolCall' ||
473
+ value.type === 'custom_tool_call' ||
474
+ value.type === 'custom_tool_call_output' ||
475
+ value.type === 'function_call' ||
476
+ value.type === 'function_call_output' ||
477
+ value.type === 'customToolCall' ||
478
+ value.type === 'customToolCallOutput' ||
479
+ value.type === 'functionCall' ||
480
+ value.type === 'functionCallOutput') {
481
+ const name = typeof value.tool === 'string'
482
+ ? value.tool
483
+ : typeof value.name === 'string'
484
+ ? value.name
485
+ : 'tool';
486
+ const input = compactRunnerValue(value.arguments ?? value.input, 10_000);
487
+ const output = compactRunnerValue(codexToolOutput(value.contentItems ?? value.output), 10_000);
488
+ if (value.type === 'custom_tool_call_output' ||
489
+ value.type === 'function_call_output' ||
490
+ value.type === 'customToolCallOutput' ||
491
+ value.type === 'functionCallOutput')
492
+ return {
493
+ itemId,
494
+ kind: 'tool_call',
495
+ status: codexItemStatus(value.status, completed),
496
+ payload: {
497
+ outputSummary: output.text || null,
498
+ ...(imageAttachments.length === 0 ? {} : { attachments: imageAttachments })
499
+ },
500
+ merge: true
501
+ };
502
+ return {
503
+ itemId,
504
+ kind: 'tool_call',
505
+ status: codexItemStatus(value.status, completed),
506
+ payload: {
507
+ namespace: typeof value.namespace === 'string' ? compactRunnerText(value.namespace, 128) : 'codex',
508
+ toolName: compactRunnerText(name, 128),
509
+ title: compactRunnerText(name, 500),
510
+ inputSummary: input.text || null,
511
+ outputSummary: output.text || null,
512
+ progressLabel: null,
513
+ errorCode: null,
514
+ truncated: input.truncated || output.truncated,
515
+ ...(imageAttachments.length === 0 ? {} : { attachments: imageAttachments })
516
+ }
517
+ };
518
+ }
519
+ return undefined;
520
+ }
521
+ export function codexImageAttachments(value) {
522
+ const found = [];
523
+ let totalBytes = 0;
524
+ const visit = (current, depth) => {
525
+ if (found.length >= 5 || depth > 4 || current === null || current === undefined)
526
+ return;
527
+ if (Array.isArray(current)) {
528
+ for (const entry of current)
529
+ visit(entry, depth + 1);
530
+ return;
531
+ }
532
+ if (!isPlainRecord(current))
533
+ return;
534
+ const type = typeof current.type === 'string' ? current.type : '';
535
+ if (type === 'input_text' && typeof current.text === 'string') {
536
+ const embeddedImage = /["']image_url["']\s*:\s*["'](data:image\/[^"']+)["']/.exec(current.text)?.[1];
537
+ if (embeddedImage !== undefined) {
538
+ visit({ type: 'input_image', image_url: embeddedImage }, depth + 1);
539
+ }
540
+ }
541
+ const rawData = typeof current.data === 'string' ? current.data : undefined;
542
+ const rawUrl = isPlainRecord(current.image_url)
543
+ ? typeof current.image_url.url === 'string'
544
+ ? current.image_url.url
545
+ : undefined
546
+ : typeof current.image_url === 'string'
547
+ ? current.image_url
548
+ : undefined;
549
+ const data = rawData ?? (rawUrl?.startsWith('data:') ? rawUrl : undefined);
550
+ if ((type === 'image' || type === 'input_image' || type === 'output_image') &&
551
+ data !== undefined) {
552
+ const match = /^data:([^;,]+);base64,(.*)$/.exec(data);
553
+ const mime = typeof current.mimeType === 'string'
554
+ ? current.mimeType
555
+ : typeof current.mime === 'string'
556
+ ? current.mime
557
+ : (match?.[1] ?? 'image/png');
558
+ const dataBase64 = match?.[2] ?? data;
559
+ if (mime.startsWith('image/') &&
560
+ isCanonicalBase64(dataBase64) &&
561
+ dataBase64.length > 0 &&
562
+ Buffer.byteLength(dataBase64, 'base64') <= MAX_COMPOSER_ATTACHMENT_BYTES &&
563
+ totalBytes + Buffer.byteLength(dataBase64, 'base64') <= MAX_COMPOSER_ATTACHMENTS_BYTES) {
564
+ totalBytes += Buffer.byteLength(dataBase64, 'base64');
565
+ found.push({
566
+ name: typeof current.name === 'string' ? current.name : `生成图片-${found.length + 1}.png`,
567
+ mime,
568
+ dataBase64
569
+ });
570
+ }
571
+ }
572
+ for (const [key, child] of Object.entries(current)) {
573
+ if (key === 'data' || key === 'image_url')
574
+ continue;
575
+ visit(child, depth + 1);
576
+ }
577
+ };
578
+ visit(value, 0);
579
+ return found;
580
+ }
581
+ export function codexUserInputQuestions(value) {
582
+ if (!Array.isArray(value) || value.length === 0 || value.length > 3)
583
+ return [];
584
+ const questions = value.map((raw) => {
585
+ if (!isPlainRecord(raw) || typeof raw.id !== 'string' || typeof raw.question !== 'string')
586
+ return undefined;
587
+ const options = Array.isArray(raw.options)
588
+ ? raw.options.flatMap((option) => isPlainRecord(option) && typeof option.label === 'string'
589
+ ? [
590
+ {
591
+ value: compactRunnerText(option.label, 500),
592
+ label: compactRunnerText(option.label, 500),
593
+ description: typeof option.description === 'string'
594
+ ? compactRunnerText(option.description, 1_000)
595
+ : null
596
+ }
597
+ ]
598
+ : [])
599
+ : [];
600
+ return {
601
+ id: compactRunnerText(raw.id, 128),
602
+ prompt: compactRunnerText(raw.question, 5_000),
603
+ options,
604
+ allowOther: raw.isOther === true
605
+ };
606
+ });
607
+ return questions.some((question) => question === undefined)
608
+ ? []
609
+ : questions;
610
+ }
611
+ export function codexItemStatus(value, completed) {
612
+ if (value === 'failed')
613
+ return 'FAILED';
614
+ if (value === 'declined')
615
+ return 'DECLINED';
616
+ return completed || value === 'completed' ? 'COMPLETED' : 'IN_PROGRESS';
617
+ }
618
+ export function codexContentText(value) {
619
+ if (!Array.isArray(value))
620
+ return '';
621
+ return value
622
+ .flatMap((part) => {
623
+ if (typeof part === 'string')
624
+ return [part];
625
+ if (!isPlainRecord(part))
626
+ return [];
627
+ return typeof part.text === 'string' ? [part.text] : [];
628
+ })
629
+ .join('\n')
630
+ .trim();
631
+ }
632
+ export function codexCompactJson(value) {
633
+ if (value === undefined || value === null)
634
+ return '';
635
+ if (typeof value === 'string')
636
+ return compactRunnerText(value, 10_000);
637
+ try {
638
+ return compactRunnerText(JSON.stringify(value), 10_000);
639
+ }
640
+ catch {
641
+ return '';
642
+ }
643
+ }
644
+ export function codexToolOutputSummary(value) {
645
+ return codexCompactJson(codexToolOutput(value));
646
+ }
647
+ /** App Server custom output is an array of text blocks, not JSON to show verbatim. */
648
+ export function codexToolOutput(value) {
649
+ if (!Array.isArray(value))
650
+ return value;
651
+ const text = value.flatMap((block) => {
652
+ if (typeof block === 'string')
653
+ return [block];
654
+ if (!isPlainRecord(block))
655
+ return [];
656
+ if (typeof block.text === 'string') {
657
+ const visible = codexVisibleToolText(block.text);
658
+ return visible.length > 0 ? [visible] : [];
659
+ }
660
+ if (typeof block.content === 'string')
661
+ return [block.content];
662
+ return [];
663
+ });
664
+ return text.length > 0 ? text.join('') : value.some(isCodexImageBlock) ? '图片已生成' : value;
665
+ }
666
+ export function codexVisibleToolText(value) {
667
+ return value.replace(/(["']image_url["']\s*:\s*["'])data:image\/[^"']+(["'])/g, '$1[图片内容已提取]$2');
668
+ }
669
+ export function isCodexImageBlock(value) {
670
+ if (!isPlainRecord(value))
671
+ return false;
672
+ return value.type === 'image' || value.type === 'input_image' || value.type === 'output_image';
673
+ }
674
+ import { codexTimestamp, compactRunnerText, compactRunnerValue, boundedConversationItemId, isCanonicalBase64, isPlainRecord, nativePageEnd } from '../../util/node-operation-parsers.js';
675
+ export * from '../../util/node-operation-parsers.js';
676
+ //# sourceMappingURL=conversation-parser.js.map