@myagentroam/node 0.1.2 → 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.
- package/dist/claude-agent-sdk.d.ts +1 -15
- package/dist/claude-agent-sdk.js +9 -77
- package/dist/claude-agent-sdk.js.map +1 -1
- package/dist/codex-app-server.d.ts +4 -0
- package/dist/codex-app-server.js +18 -4
- package/dist/codex-app-server.js.map +1 -1
- package/dist/connector/node-connector-options.d.ts +23 -0
- package/dist/connector/node-connector-options.js +2 -0
- package/dist/connector/node-connector-options.js.map +1 -0
- package/dist/connector/node-operation-router.d.ts +9 -0
- package/dist/connector/node-operation-router.js +23 -0
- package/dist/connector/node-operation-router.js.map +1 -0
- package/dist/connector.d.ts +59 -353
- package/dist/connector.js +614 -5936
- package/dist/connector.js.map +1 -1
- package/dist/control-outbound-scheduler.d.ts +26 -0
- package/dist/control-outbound-scheduler.js +122 -0
- package/dist/control-outbound-scheduler.js.map +1 -0
- package/dist/database.js +1 -1
- package/dist/database.js.map +1 -1
- package/dist/native-jsonl-reader.d.ts +14 -0
- package/dist/native-jsonl-reader.js +98 -0
- package/dist/native-jsonl-reader.js.map +1 -0
- package/dist/native-session-history.d.ts +22 -3
- package/dist/native-session-history.js +281 -157
- package/dist/native-session-history.js.map +1 -1
- package/dist/runner/abstract-runner.d.ts +148 -0
- package/dist/runner/abstract-runner.js +139 -0
- package/dist/runner/abstract-runner.js.map +1 -0
- package/dist/runner/claude/managed-run-controller.d.ts +52 -0
- package/dist/runner/claude/managed-run-controller.js +307 -0
- package/dist/runner/claude/managed-run-controller.js.map +1 -0
- package/dist/runner/claude-code-runner.d.ts +68 -0
- package/dist/runner/claude-code-runner.js +268 -0
- package/dist/runner/claude-code-runner.js.map +1 -0
- package/dist/runner/codex/conversation-parser.d.ts +61 -0
- package/dist/runner/codex/conversation-parser.js +676 -0
- package/dist/runner/codex/conversation-parser.js.map +1 -0
- package/dist/runner/codex/managed-run-controller.d.ts +79 -0
- package/dist/runner/codex/managed-run-controller.js +379 -0
- package/dist/runner/codex/managed-run-controller.js.map +1 -0
- package/dist/runner/codex-runner.d.ts +81 -0
- package/dist/runner/codex-runner.js +342 -0
- package/dist/runner/codex-runner.js.map +1 -0
- package/dist/runner/fake-test-runner.d.ts +26 -0
- package/dist/runner/fake-test-runner.js +48 -0
- package/dist/runner/fake-test-runner.js.map +1 -0
- package/dist/runner/runner-registry.d.ts +17 -0
- package/dist/runner/runner-registry.js +66 -0
- package/dist/runner/runner-registry.js.map +1 -0
- package/dist/runner-command-engine.d.ts +9 -0
- package/dist/runner-command-engine.js +24 -0
- package/dist/runner-command-engine.js.map +1 -1
- package/dist/runner-profiles.js +12 -0
- package/dist/runner-profiles.js.map +1 -1
- package/dist/runner-usage.d.ts +2 -2
- package/dist/runner-usage.js +3 -5
- package/dist/runner-usage.js.map +1 -1
- package/dist/runtime-state.js +6 -5
- package/dist/runtime-state.js.map +1 -1
- package/dist/service/attachment-domain-state.d.ts +5 -0
- package/dist/service/attachment-domain-state.js +6 -0
- package/dist/service/attachment-domain-state.js.map +1 -0
- package/dist/service/conversation-history-service.d.ts +34 -0
- package/dist/service/conversation-history-service.js +159 -0
- package/dist/service/conversation-history-service.js.map +1 -0
- package/dist/service/external-session-resume-service.d.ts +32 -0
- package/dist/service/external-session-resume-service.js +99 -0
- package/dist/service/external-session-resume-service.js.map +1 -0
- package/dist/service/fake-managed-run-service.d.ts +29 -0
- package/dist/service/fake-managed-run-service.js +63 -0
- package/dist/service/fake-managed-run-service.js.map +1 -0
- package/dist/service/managed-runner-session-service.d.ts +10 -0
- package/dist/service/managed-runner-session-service.js +31 -0
- package/dist/service/managed-runner-session-service.js.map +1 -0
- package/dist/service/native-session-projection-service.d.ts +50 -0
- package/dist/service/native-session-projection-service.js +268 -0
- package/dist/service/native-session-projection-service.js.map +1 -0
- package/dist/service/native-session-watch-service.d.ts +37 -0
- package/dist/service/native-session-watch-service.js +151 -0
- package/dist/service/native-session-watch-service.js.map +1 -0
- package/dist/service/node-connection-lifecycle-service.d.ts +37 -0
- package/dist/service/node-connection-lifecycle-service.js +84 -0
- package/dist/service/node-connection-lifecycle-service.js.map +1 -0
- package/dist/service/node-control-channel.d.ts +32 -0
- package/dist/service/node-control-channel.js +84 -0
- package/dist/service/node-control-channel.js.map +1 -0
- package/dist/service/node-control-message-service.d.ts +28 -0
- package/dist/service/node-control-message-service.js +105 -0
- package/dist/service/node-control-message-service.js.map +1 -0
- package/dist/service/node-request-service.d.ts +14 -0
- package/dist/service/node-request-service.js +51 -0
- package/dist/service/node-request-service.js.map +1 -0
- package/dist/service/node-run-event-bridge.d.ts +38 -0
- package/dist/service/node-run-event-bridge.js +80 -0
- package/dist/service/node-run-event-bridge.js.map +1 -0
- package/dist/service/node-terminal-channel.d.ts +29 -0
- package/dist/service/node-terminal-channel.js +176 -0
- package/dist/service/node-terminal-channel.js.map +1 -0
- package/dist/service/node-workspace-coordinator.d.ts +32 -0
- package/dist/service/node-workspace-coordinator.js +81 -0
- package/dist/service/node-workspace-coordinator.js.map +1 -0
- package/dist/service/run-attachment-service.d.ts +37 -0
- package/dist/service/run-attachment-service.js +161 -0
- package/dist/service/run-attachment-service.js.map +1 -0
- package/dist/service/run-domain-state.d.ts +4 -0
- package/dist/service/run-domain-state.js +5 -0
- package/dist/service/run-domain-state.js.map +1 -0
- package/dist/service/run-event-service.d.ts +31 -0
- package/dist/service/run-event-service.js +103 -0
- package/dist/service/run-event-service.js.map +1 -0
- package/dist/service/run-workbench-service.d.ts +27 -0
- package/dist/service/run-workbench-service.js +114 -0
- package/dist/service/run-workbench-service.js.map +1 -0
- package/dist/service/runner-channel-message-service.d.ts +13 -0
- package/dist/service/runner-channel-message-service.js +21 -0
- package/dist/service/runner-channel-message-service.js.map +1 -0
- package/dist/service/runner-interaction-service.d.ts +40 -0
- package/dist/service/runner-interaction-service.js +245 -0
- package/dist/service/runner-interaction-service.js.map +1 -0
- package/dist/service/runner-service.d.ts +43 -0
- package/dist/service/runner-service.js +55 -0
- package/dist/service/runner-service.js.map +1 -0
- package/dist/service/session-catalog-service.d.ts +30 -0
- package/dist/service/session-catalog-service.js +145 -0
- package/dist/service/session-catalog-service.js.map +1 -0
- package/dist/service/session-command-service.d.ts +23 -0
- package/dist/service/session-command-service.js +70 -0
- package/dist/service/session-command-service.js.map +1 -0
- package/dist/service/session-context-service.d.ts +34 -0
- package/dist/service/session-context-service.js +88 -0
- package/dist/service/session-context-service.js.map +1 -0
- package/dist/service/session-domain-state.d.ts +8 -0
- package/dist/service/session-domain-state.js +9 -0
- package/dist/service/session-domain-state.js.map +1 -0
- package/dist/service/session-identity-service.d.ts +24 -0
- package/dist/service/session-identity-service.js +87 -0
- package/dist/service/session-identity-service.js.map +1 -0
- package/dist/service/session-lifecycle-service.d.ts +31 -0
- package/dist/service/session-lifecycle-service.js +236 -0
- package/dist/service/session-lifecycle-service.js.map +1 -0
- package/dist/service/session-message-service.d.ts +33 -0
- package/dist/service/session-message-service.js +158 -0
- package/dist/service/session-message-service.js.map +1 -0
- package/dist/service/session-presentation-service.d.ts +33 -0
- package/dist/service/session-presentation-service.js +37 -0
- package/dist/service/session-presentation-service.js.map +1 -0
- package/dist/service/session-query-service.d.ts +31 -0
- package/dist/service/session-query-service.js +78 -0
- package/dist/service/session-query-service.js.map +1 -0
- package/dist/service/terminal-relay-state.d.ts +6 -0
- package/dist/service/terminal-relay-state.js +4 -0
- package/dist/service/terminal-relay-state.js.map +1 -0
- package/dist/service/terminal-service.d.ts +12 -0
- package/dist/service/terminal-service.js +53 -0
- package/dist/service/terminal-service.js.map +1 -0
- package/dist/service/workbench-event-service.d.ts +21 -0
- package/dist/service/workbench-event-service.js +54 -0
- package/dist/service/workbench-event-service.js.map +1 -0
- package/dist/service/workbench-manifest-service.d.ts +88 -0
- package/dist/service/workbench-manifest-service.js +69 -0
- package/dist/service/workbench-manifest-service.js.map +1 -0
- package/dist/service/workspace-change-service.d.ts +9 -0
- package/dist/service/workspace-change-service.js +86 -0
- package/dist/service/workspace-change-service.js.map +1 -0
- package/dist/service/workspace-domain-state.d.ts +75 -0
- package/dist/service/workspace-domain-state.js +41 -0
- package/dist/service/workspace-domain-state.js.map +1 -0
- package/dist/service/workspace-file-service.d.ts +14 -0
- package/dist/service/workspace-file-service.js +77 -0
- package/dist/service/workspace-file-service.js.map +1 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +55 -0
- package/dist/service/workspace-queue-workbench-service.js +227 -0
- package/dist/service/workspace-queue-workbench-service.js.map +1 -0
- package/dist/service/workspace-service.d.ts +15 -0
- package/dist/service/workspace-service.js +54 -0
- package/dist/service/workspace-service.js.map +1 -0
- package/dist/service/workspace-session-service.d.ts +23 -0
- package/dist/service/workspace-session-service.js +140 -0
- package/dist/service/workspace-session-service.js.map +1 -0
- package/dist/service/workspace-upload-service.d.ts +37 -0
- package/dist/service/workspace-upload-service.js +241 -0
- package/dist/service/workspace-upload-service.js.map +1 -0
- package/dist/service/workspace-watch-service.d.ts +18 -0
- package/dist/service/workspace-watch-service.js +121 -0
- package/dist/service/workspace-watch-service.js.map +1 -0
- package/dist/service/workspace-workbench-service.d.ts +38 -0
- package/dist/service/workspace-workbench-service.js +156 -0
- package/dist/service/workspace-workbench-service.js.map +1 -0
- package/dist/terminal.d.ts +1 -0
- package/dist/terminal.js +1 -1
- package/dist/terminal.js.map +1 -1
- package/dist/util/node-operation-parsers.d.ts +91 -0
- package/dist/util/node-operation-parsers.js +380 -0
- package/dist/util/node-operation-parsers.js.map +1 -0
- package/dist/util/runner-native-session-parsers.d.ts +72 -0
- package/dist/util/runner-native-session-parsers.js +337 -0
- package/dist/util/runner-native-session-parsers.js.map +1 -0
- package/dist/util/secret-environment.d.ts +1 -0
- package/dist/util/secret-environment.js +26 -0
- package/dist/util/secret-environment.js.map +1 -0
- package/dist/workspace.d.ts +9 -2
- package/dist/workspace.js +41 -0
- package/dist/workspace.js.map +1 -1
- 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
|