remote-codex 0.1.10 → 0.11.1
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/apps/supervisor-api/dist/chunk-6M32PPHZ.js +24507 -0
- package/apps/supervisor-api/dist/chunk-7AA2MFXK.js +24499 -0
- package/apps/supervisor-api/dist/chunk-HKBFCPHH.js +24511 -0
- package/apps/supervisor-api/dist/index.js +12525 -28436
- package/apps/supervisor-api/dist/worker-index.d.ts +2 -0
- package/apps/supervisor-api/dist/worker-index.js +33 -0
- package/apps/supervisor-web/dist/assets/{highlighted-body-OFNGDK62-CyMcatlD.js → highlighted-body-OFNGDK62-p31aS0f0.js} +1 -1
- package/apps/supervisor-web/dist/assets/index-BiuFei_K.css +32 -0
- package/apps/supervisor-web/dist/assets/index-D1R9CUnx.js +2161 -0
- package/apps/supervisor-web/dist/assets/{xterm-DbYWMNQ0.js → xterm-D92BViLH.js} +1 -1
- package/apps/supervisor-web/dist/index.html +2 -2
- package/package.json +2 -3
- package/packages/agent-runtime/src/index.ts +4 -0
- package/packages/agent-runtime/src/management-errors.ts +11 -0
- package/packages/agent-runtime/src/model-pricing.ts +325 -0
- package/packages/agent-runtime/src/registry.ts +19 -4
- package/packages/agent-runtime/src/runtime-errors.ts +97 -0
- package/packages/agent-runtime/src/types.ts +36 -3
- package/packages/agent-runtime/src/unavailable-runtime.ts +169 -0
- package/packages/claude/src/historyItems.ts +41 -5
- package/packages/claude/src/runtimeAdapter.test.ts +117 -6
- package/packages/claude/src/runtimeAdapter.ts +421 -65
- package/packages/codex/src/historyItems.test.ts +137 -0
- package/packages/codex/src/historyItems.ts +135 -17
- package/packages/codex/src/hookHistory.test.ts +59 -0
- package/packages/codex/src/index.ts +7 -0
- package/packages/codex/src/local-session-store.ts +390 -0
- package/packages/codex/src/management/codex-management-service.ts +454 -0
- package/packages/codex/src/management/codexHostConfig.test.ts +88 -0
- package/packages/codex/src/management/codexHostConfig.ts +188 -0
- package/packages/codex/src/management/errors.ts +20 -0
- package/packages/codex/src/modelPricing.test.ts +235 -0
- package/packages/codex/src/modelPricing.ts +9 -0
- package/packages/codex/src/runtime-errors.test.ts +72 -0
- package/packages/codex/src/runtime-errors.ts +37 -0
- package/packages/codex/src/runtimeAdapter.ts +15 -0
- package/packages/codex/src/thread-title.ts +1 -0
- package/packages/opencode/src/historyItems.test.ts +504 -0
- package/packages/opencode/src/historyItems.ts +896 -0
- package/packages/opencode/src/index.ts +2 -0
- package/packages/opencode/src/runtimeAdapter.test.ts +1444 -0
- package/packages/opencode/src/runtimeAdapter.ts +1473 -0
- package/packages/shared/src/agent-providers.ts +56 -0
- package/packages/shared/src/index.ts +240 -35
- package/apps/supervisor-web/dist/assets/index-BlAhoIuq.js +0 -379
- package/apps/supervisor-web/dist/assets/index-DI0NRNgr.css +0 -32
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
markTransientAgentHistoryItem,
|
|
5
|
+
type AgentHistoryItem,
|
|
6
|
+
} from '../../agent-runtime/src/index';
|
|
7
|
+
import {
|
|
8
|
+
agentTurnToThreadTurnDto,
|
|
9
|
+
codexTurnToAgentTurn,
|
|
10
|
+
liveCodexItemToHistoryItem,
|
|
11
|
+
shouldPersistLiveHistoryItem,
|
|
12
|
+
shouldPersistRuntimeFinalHistoryItem,
|
|
13
|
+
} from './historyItems';
|
|
14
|
+
|
|
15
|
+
describe('codex history item persistence policy', () => {
|
|
16
|
+
it('keeps streamed assistant text out of live history persistence', () => {
|
|
17
|
+
expect(
|
|
18
|
+
shouldPersistLiveHistoryItem({
|
|
19
|
+
id: 'agent-live-1',
|
|
20
|
+
kind: 'agentMessage',
|
|
21
|
+
text: 'Streaming draft',
|
|
22
|
+
}),
|
|
23
|
+
).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('keeps transient streamed assistant text out of final runtime persistence', () => {
|
|
27
|
+
const transientMessage = markTransientAgentHistoryItem<AgentHistoryItem>({
|
|
28
|
+
id: 'agent-live-1',
|
|
29
|
+
kind: 'agentMessage',
|
|
30
|
+
text: 'Streaming draft',
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
expect(shouldPersistRuntimeFinalHistoryItem(transientMessage, [transientMessage])).toBe(
|
|
34
|
+
false,
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('hides transient streamed assistant text once a final assistant message exists', () => {
|
|
39
|
+
const transientMessage = markTransientAgentHistoryItem<AgentHistoryItem>({
|
|
40
|
+
id: 'agent-live-1',
|
|
41
|
+
kind: 'agentMessage',
|
|
42
|
+
text: 'Streaming draft',
|
|
43
|
+
});
|
|
44
|
+
const finalMessage: AgentHistoryItem = {
|
|
45
|
+
id: 'agent-final-1',
|
|
46
|
+
kind: 'agentMessage',
|
|
47
|
+
text: 'Final answer',
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
expect(
|
|
51
|
+
agentTurnToThreadTurnDto({
|
|
52
|
+
providerTurnId: 'turn-1',
|
|
53
|
+
status: 'completed',
|
|
54
|
+
error: null,
|
|
55
|
+
items: [transientMessage, finalMessage],
|
|
56
|
+
}).items,
|
|
57
|
+
).toEqual([finalMessage]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('maps Codex collab agent tool calls to dedicated agent tool call items', () => {
|
|
61
|
+
const turn = codexTurnToAgentTurn({
|
|
62
|
+
id: 'turn-1',
|
|
63
|
+
status: 'inProgress',
|
|
64
|
+
error: null,
|
|
65
|
+
items: [
|
|
66
|
+
{
|
|
67
|
+
id: 'agent-tool-1',
|
|
68
|
+
type: 'collabAgentToolCall',
|
|
69
|
+
status: 'running',
|
|
70
|
+
action: {
|
|
71
|
+
name: 'Review checkout flow',
|
|
72
|
+
input: {
|
|
73
|
+
prompt: 'Inspect checkout UI regressions.',
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
expect(turn.items[0]).toMatchObject({
|
|
81
|
+
id: 'agent-tool-1',
|
|
82
|
+
kind: 'agentToolCall',
|
|
83
|
+
text: 'Agent: Review checkout flow',
|
|
84
|
+
previewText: 'Agent',
|
|
85
|
+
status: 'running',
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('keeps Codex collab agent tool calls visible while running', () => {
|
|
90
|
+
expect(
|
|
91
|
+
liveCodexItemToHistoryItem(
|
|
92
|
+
{
|
|
93
|
+
id: 'agent-tool-1',
|
|
94
|
+
type: 'collabAgentToolCall',
|
|
95
|
+
status: 'running',
|
|
96
|
+
action: {
|
|
97
|
+
name: 'Inspect backend runtime boundaries',
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
'started',
|
|
101
|
+
),
|
|
102
|
+
).toMatchObject({
|
|
103
|
+
id: 'agent-tool-1',
|
|
104
|
+
kind: 'agentToolCall',
|
|
105
|
+
text: 'Agent: Inspect backend runtime boundaries',
|
|
106
|
+
previewText: 'Agent',
|
|
107
|
+
status: 'running',
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('shows file changes using project-relative paths when absolute paths are reported', () => {
|
|
112
|
+
const turn = codexTurnToAgentTurn({
|
|
113
|
+
id: 'turn-1',
|
|
114
|
+
status: 'completed',
|
|
115
|
+
error: null,
|
|
116
|
+
items: [
|
|
117
|
+
{
|
|
118
|
+
id: 'file-change-1',
|
|
119
|
+
type: 'fileChange',
|
|
120
|
+
changes: [
|
|
121
|
+
{
|
|
122
|
+
path: '/home/u/dev/remoteCodex/apps/supervisor-web/src/App.tsx',
|
|
123
|
+
additions: 4,
|
|
124
|
+
deletions: 1,
|
|
125
|
+
},
|
|
126
|
+
],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
expect(turn.items[0]).toMatchObject({
|
|
132
|
+
kind: 'fileChange',
|
|
133
|
+
text: 'apps/supervisor-web/src/App.tsx',
|
|
134
|
+
detailText: '- apps/supervisor-web/src/App.tsx (+4 -1)',
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
});
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
CodexTurnItem,
|
|
4
4
|
} from './types';
|
|
5
5
|
import type { AgentTurn } from '../../agent-runtime/src/index';
|
|
6
|
+
import { isTransientAgentHistoryItem } from '../../agent-runtime/src/index';
|
|
6
7
|
import type {
|
|
7
8
|
ThreadHistoryItemDetailDto,
|
|
8
9
|
ThreadHistoryItemDto,
|
|
@@ -13,6 +14,7 @@ import { parseCodexHookPromptText } from './hookHistory';
|
|
|
13
14
|
|
|
14
15
|
const DEFERRED_COMMAND_DETAIL_TITLE = 'Command Output';
|
|
15
16
|
const DEFERRED_TOOL_DETAIL_TITLE = 'Tool Call Details';
|
|
17
|
+
const DEFERRED_AGENT_TOOL_DETAIL_TITLE = 'Agent Details';
|
|
16
18
|
|
|
17
19
|
export type TurnItemOrderSnapshot = Map<string, Map<string, number>>;
|
|
18
20
|
|
|
@@ -76,6 +78,40 @@ function uniqueStrings(values: Array<string | null | undefined>) {
|
|
|
76
78
|
return [...new Set(values.filter((value): value is string => Boolean(value?.trim())))];
|
|
77
79
|
}
|
|
78
80
|
|
|
81
|
+
function projectRelativePathLabel(value: string | null | undefined) {
|
|
82
|
+
const normalized = value?.trim();
|
|
83
|
+
if (!normalized) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const slashNormalized = normalized.replace(/\\/g, '/');
|
|
88
|
+
if (!slashNormalized.startsWith('/')) {
|
|
89
|
+
return slashNormalized.replace(/^\.\//, '');
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const markers = [
|
|
93
|
+
'/apps/',
|
|
94
|
+
'/packages/',
|
|
95
|
+
'/src/',
|
|
96
|
+
'/test/',
|
|
97
|
+
'/tests/',
|
|
98
|
+
'/docs/',
|
|
99
|
+
'/config/',
|
|
100
|
+
'/scripts/',
|
|
101
|
+
'/e2e/',
|
|
102
|
+
'/.agents/',
|
|
103
|
+
'/.codex/',
|
|
104
|
+
];
|
|
105
|
+
for (const marker of markers) {
|
|
106
|
+
const markerIndex = slashNormalized.indexOf(marker);
|
|
107
|
+
if (markerIndex >= 0) {
|
|
108
|
+
return slashNormalized.slice(markerIndex + 1);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return slashNormalized;
|
|
113
|
+
}
|
|
114
|
+
|
|
79
115
|
function normalizeTextLines(text: string) {
|
|
80
116
|
const lines = text.replace(/\r\n/g, '\n').split('\n');
|
|
81
117
|
|
|
@@ -213,14 +249,19 @@ function formatCommandHistoryItem(
|
|
|
213
249
|
}
|
|
214
250
|
|
|
215
251
|
function deferToolCallHistoryItem(
|
|
216
|
-
item: ThreadHistoryItemDto & { kind: 'toolCall' },
|
|
252
|
+
item: ThreadHistoryItemDto & { kind: 'toolCall' | 'agentToolCall' | 'skillToolCall' },
|
|
217
253
|
deferredDetails: Map<string, ThreadHistoryItemDetailDto>,
|
|
218
254
|
): ThreadHistoryItemDto {
|
|
219
255
|
const fullText = item.detailText?.trim() || item.text || 'Tool call';
|
|
220
256
|
deferredDetails.set(item.id, {
|
|
221
257
|
id: item.id,
|
|
222
258
|
kind: item.kind,
|
|
223
|
-
title:
|
|
259
|
+
title:
|
|
260
|
+
item.kind === 'agentToolCall'
|
|
261
|
+
? DEFERRED_AGENT_TOOL_DETAIL_TITLE
|
|
262
|
+
: item.kind === 'skillToolCall'
|
|
263
|
+
? 'Skill Details'
|
|
264
|
+
: DEFERRED_TOOL_DETAIL_TITLE,
|
|
224
265
|
text: fullText,
|
|
225
266
|
});
|
|
226
267
|
|
|
@@ -267,6 +308,7 @@ function valueFromNestedRecords(
|
|
|
267
308
|
function formatToolCallHistoryItem(
|
|
268
309
|
item: CodexTurnItem,
|
|
269
310
|
deferredDetails?: Map<string, ThreadHistoryItemDetailDto>,
|
|
311
|
+
kind: 'toolCall' | 'agentToolCall' | 'skillToolCall' = 'toolCall',
|
|
270
312
|
): ThreadHistoryItemDto {
|
|
271
313
|
const { action, result, input, output } = extractToolCallRecords(item);
|
|
272
314
|
const nestedRecords = [item, action, result, input, output];
|
|
@@ -295,14 +337,18 @@ function formatToolCallHistoryItem(
|
|
|
295
337
|
const summaryLine = serverName && toolName
|
|
296
338
|
? `${serverName}/${toolName}`
|
|
297
339
|
: toolName ?? serverName ?? stringOrNull(item.text) ?? item.type;
|
|
340
|
+
const displaySummary =
|
|
341
|
+
kind === 'agentToolCall' && !/^agent\b/i.test(summaryLine)
|
|
342
|
+
? `Agent: ${summaryLine}`
|
|
343
|
+
: summaryLine;
|
|
298
344
|
|
|
299
|
-
const detailLines = [
|
|
345
|
+
const detailLines = [displaySummary];
|
|
300
346
|
if (status) {
|
|
301
347
|
detailLines.push(`Status: ${status}`);
|
|
302
348
|
}
|
|
303
349
|
|
|
304
350
|
const text = stringOrNull(item.text);
|
|
305
|
-
if (text && text !== summaryLine) {
|
|
351
|
+
if (text && text !== summaryLine && text !== displaySummary) {
|
|
306
352
|
detailLines.push('', text);
|
|
307
353
|
}
|
|
308
354
|
|
|
@@ -320,9 +366,9 @@ function formatToolCallHistoryItem(
|
|
|
320
366
|
|
|
321
367
|
const historyItem: ThreadHistoryItemDto = {
|
|
322
368
|
id: item.id,
|
|
323
|
-
kind
|
|
324
|
-
text:
|
|
325
|
-
previewText:
|
|
369
|
+
kind,
|
|
370
|
+
text: displaySummary,
|
|
371
|
+
previewText: kind === 'agentToolCall' ? 'Agent' : displaySummary,
|
|
326
372
|
detailText: detailLines.join('\n'),
|
|
327
373
|
status,
|
|
328
374
|
};
|
|
@@ -334,7 +380,9 @@ function formatToolCallHistoryItem(
|
|
|
334
380
|
(historyItem.detailText?.length ?? 0) > 240)
|
|
335
381
|
) {
|
|
336
382
|
return deferToolCallHistoryItem(
|
|
337
|
-
historyItem as ThreadHistoryItemDto & {
|
|
383
|
+
historyItem as ThreadHistoryItemDto & {
|
|
384
|
+
kind: 'toolCall' | 'agentToolCall' | 'skillToolCall';
|
|
385
|
+
},
|
|
338
386
|
deferredDetails,
|
|
339
387
|
);
|
|
340
388
|
}
|
|
@@ -355,8 +403,12 @@ export function deferLargeHistoryItemDetails(
|
|
|
355
403
|
deferredDetails,
|
|
356
404
|
)
|
|
357
405
|
: item.kind === 'toolCall'
|
|
406
|
+
|| item.kind === 'agentToolCall'
|
|
407
|
+
|| item.kind === 'skillToolCall'
|
|
358
408
|
? deferToolCallHistoryItem(
|
|
359
|
-
item as ThreadHistoryItemDto & {
|
|
409
|
+
item as ThreadHistoryItemDto & {
|
|
410
|
+
kind: 'toolCall' | 'agentToolCall' | 'skillToolCall';
|
|
411
|
+
},
|
|
360
412
|
deferredDetails,
|
|
361
413
|
)
|
|
362
414
|
: item,
|
|
@@ -366,15 +418,45 @@ export function deferLargeHistoryItemDetails(
|
|
|
366
418
|
|
|
367
419
|
export function shouldPersistLiveHistoryItem(item: ThreadHistoryItemDto) {
|
|
368
420
|
return (
|
|
369
|
-
item.kind === 'agentMessage' ||
|
|
370
421
|
item.kind === 'commandExecution' ||
|
|
371
422
|
item.kind === 'fileChange' ||
|
|
423
|
+
item.kind === 'fileRead' ||
|
|
372
424
|
item.kind === 'hook' ||
|
|
425
|
+
item.kind === 'agentToolCall' ||
|
|
426
|
+
item.kind === 'skillToolCall' ||
|
|
373
427
|
item.kind === 'toolCall' ||
|
|
374
428
|
item.kind === 'webSearch'
|
|
375
429
|
);
|
|
376
430
|
}
|
|
377
431
|
|
|
432
|
+
export function shouldPersistFinalHistoryItem(item: ThreadHistoryItemDto) {
|
|
433
|
+
return item.kind === 'agentMessage' || shouldPersistLiveHistoryItem(item);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export function shouldPersistRuntimeFinalHistoryItem(
|
|
437
|
+
item: ThreadHistoryItemDto,
|
|
438
|
+
allItems: ThreadHistoryItemDto[],
|
|
439
|
+
) {
|
|
440
|
+
if (item.kind === 'agentMessage' && isTransientAgentHistoryItem(item)) {
|
|
441
|
+
return false;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return shouldPersistFinalHistoryItem(item);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function visibleRuntimeTurnItems(items: ThreadHistoryItemDto[]) {
|
|
448
|
+
const hasFinalAgentMessage = items.some(
|
|
449
|
+
(item) => item.kind === 'agentMessage' && !isTransientAgentHistoryItem(item),
|
|
450
|
+
);
|
|
451
|
+
if (!hasFinalAgentMessage) {
|
|
452
|
+
return items;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return items.filter(
|
|
456
|
+
(item) => !(item.kind === 'agentMessage' && isTransientAgentHistoryItem(item)),
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
|
|
378
460
|
export function parseStoredHistoryItem(value: string): ThreadHistoryItemDto | null {
|
|
379
461
|
try {
|
|
380
462
|
const parsed = JSON.parse(value);
|
|
@@ -562,6 +644,24 @@ function copyPersistedSequence(
|
|
|
562
644
|
return item.sequence === sequence ? item : { ...item, sequence };
|
|
563
645
|
}
|
|
564
646
|
|
|
647
|
+
function shouldAppendPersistedMissingItem(
|
|
648
|
+
turn: ThreadTurnDto,
|
|
649
|
+
item: ThreadHistoryItemDto,
|
|
650
|
+
) {
|
|
651
|
+
if (item.kind !== 'agentMessage') {
|
|
652
|
+
return true;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// Older builds persisted streaming assistant drafts. Once the provider
|
|
656
|
+
// transcript has final assistant text, do not resurrect those draft rows.
|
|
657
|
+
const isCrossTurnProjection = Boolean(item.sourceTurnId && item.sourceTurnId !== turn.id);
|
|
658
|
+
return !(
|
|
659
|
+
turn.status === 'completed' &&
|
|
660
|
+
turn.items.some((turnItem) => turnItem.kind === 'agentMessage') &&
|
|
661
|
+
!isCrossTurnProjection
|
|
662
|
+
);
|
|
663
|
+
}
|
|
664
|
+
|
|
565
665
|
export function mergePersistedHistoryItemsIntoTurns(
|
|
566
666
|
turns: ThreadTurnDto[],
|
|
567
667
|
persistedItemsByTurnId: Map<string, ThreadHistoryItemDto[]>,
|
|
@@ -596,7 +696,12 @@ export function mergePersistedHistoryItemsIntoTurns(
|
|
|
596
696
|
changed = true;
|
|
597
697
|
}
|
|
598
698
|
|
|
599
|
-
if (
|
|
699
|
+
if (
|
|
700
|
+
persistedItem.kind === 'commandExecution' ||
|
|
701
|
+
persistedItem.kind === 'toolCall' ||
|
|
702
|
+
persistedItem.kind === 'agentToolCall' ||
|
|
703
|
+
persistedItem.kind === 'skillToolCall'
|
|
704
|
+
) {
|
|
600
705
|
const existingText = item.detailText?.trim() || item.text.trim();
|
|
601
706
|
const persistedText = persistedItem.detailText?.trim() || persistedItem.text.trim();
|
|
602
707
|
if (persistedText.length > existingText.length) {
|
|
@@ -607,7 +712,9 @@ export function mergePersistedHistoryItemsIntoTurns(
|
|
|
607
712
|
deferredDetails,
|
|
608
713
|
)
|
|
609
714
|
: deferToolCallHistoryItem(
|
|
610
|
-
persistedItem as ThreadHistoryItemDto & {
|
|
715
|
+
persistedItem as ThreadHistoryItemDto & {
|
|
716
|
+
kind: 'toolCall' | 'agentToolCall' | 'skillToolCall';
|
|
717
|
+
},
|
|
611
718
|
deferredDetails,
|
|
612
719
|
);
|
|
613
720
|
}
|
|
@@ -619,6 +726,7 @@ export function mergePersistedHistoryItemsIntoTurns(
|
|
|
619
726
|
const existingItemIds = new Set(nextItems.map((item) => item.id));
|
|
620
727
|
const missingItems = [...persistedItemsById.values()]
|
|
621
728
|
.filter((item) => !existingItemIds.has(item.id))
|
|
729
|
+
.filter((item) => shouldAppendPersistedMissingItem(turn, item))
|
|
622
730
|
.map((item) =>
|
|
623
731
|
item.kind === 'commandExecution'
|
|
624
732
|
? deferCommandHistoryItem(
|
|
@@ -626,8 +734,12 @@ export function mergePersistedHistoryItemsIntoTurns(
|
|
|
626
734
|
deferredDetails,
|
|
627
735
|
)
|
|
628
736
|
: item.kind === 'toolCall'
|
|
737
|
+
|| item.kind === 'agentToolCall'
|
|
738
|
+
|| item.kind === 'skillToolCall'
|
|
629
739
|
? deferToolCallHistoryItem(
|
|
630
|
-
item as ThreadHistoryItemDto & {
|
|
740
|
+
item as ThreadHistoryItemDto & {
|
|
741
|
+
kind: 'toolCall' | 'agentToolCall' | 'skillToolCall';
|
|
742
|
+
},
|
|
631
743
|
deferredDetails,
|
|
632
744
|
)
|
|
633
745
|
: item,
|
|
@@ -958,7 +1070,9 @@ function extractFileChangeEntries(item: CodexTurnItem) {
|
|
|
958
1070
|
'old_path',
|
|
959
1071
|
]),
|
|
960
1072
|
),
|
|
961
|
-
])
|
|
1073
|
+
])
|
|
1074
|
+
.map(projectRelativePathLabel)
|
|
1075
|
+
.find((entry): entry is string => Boolean(entry)) ?? null;
|
|
962
1076
|
|
|
963
1077
|
const explicitAdditions =
|
|
964
1078
|
numberOrNull(
|
|
@@ -997,7 +1111,8 @@ function extractFileChangeEntries(item: CodexTurnItem) {
|
|
|
997
1111
|
: null;
|
|
998
1112
|
const additions = explicitAdditions || diffStats?.additions || 0;
|
|
999
1113
|
const deletions = explicitDeletions || diffStats?.deletions || 0;
|
|
1000
|
-
const normalizedPath =
|
|
1114
|
+
const normalizedPath =
|
|
1115
|
+
path ?? (diffText ? projectRelativePathLabel(extractPathFromDiffText(diffText)) : null);
|
|
1001
1116
|
|
|
1002
1117
|
if (!normalizedPath && additions === 0 && deletions === 0) {
|
|
1003
1118
|
return null;
|
|
@@ -1175,8 +1290,9 @@ function itemToHistoryItem(
|
|
|
1175
1290
|
return formatFileChangeHistoryItem(item);
|
|
1176
1291
|
case 'mcpToolCall':
|
|
1177
1292
|
case 'dynamicToolCall':
|
|
1178
|
-
case 'collabAgentToolCall':
|
|
1179
1293
|
return formatToolCallHistoryItem(item, deferredDetails);
|
|
1294
|
+
case 'collabAgentToolCall':
|
|
1295
|
+
return formatToolCallHistoryItem(item, deferredDetails, 'agentToolCall');
|
|
1180
1296
|
default:
|
|
1181
1297
|
return {
|
|
1182
1298
|
id: item.id,
|
|
@@ -1195,6 +1311,8 @@ export function liveCodexItemToHistoryItem(
|
|
|
1195
1311
|
if (
|
|
1196
1312
|
historyItem.kind !== 'commandExecution' &&
|
|
1197
1313
|
historyItem.kind !== 'toolCall' &&
|
|
1314
|
+
historyItem.kind !== 'agentToolCall' &&
|
|
1315
|
+
historyItem.kind !== 'skillToolCall' &&
|
|
1198
1316
|
historyItem.kind !== 'fileChange' &&
|
|
1199
1317
|
historyItem.kind !== 'webSearch'
|
|
1200
1318
|
) {
|
|
@@ -1218,7 +1336,7 @@ export function agentTurnToThreadTurnDto(
|
|
|
1218
1336
|
startedAt: turn.startedAt ?? parseUuidV7Timestamp(turn.providerTurnId),
|
|
1219
1337
|
status: turn.status,
|
|
1220
1338
|
error: turn.error?.message ?? null,
|
|
1221
|
-
items: turn.items,
|
|
1339
|
+
items: visibleRuntimeTurnItems(turn.items),
|
|
1222
1340
|
};
|
|
1223
1341
|
|
|
1224
1342
|
return deferredDetails ? deferLargeHistoryItemDetails(baseTurn, deferredDetails) : baseTurn;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
codexHookRunToHistoryItem,
|
|
5
|
+
parseCodexHookPromptText,
|
|
6
|
+
} from './index';
|
|
7
|
+
|
|
8
|
+
describe('codex hook history mapping', () => {
|
|
9
|
+
it('parses hook prompt XML emitted as assistant text', () => {
|
|
10
|
+
expect(
|
|
11
|
+
parseCodexHookPromptText(
|
|
12
|
+
'<hook_prompt hook_run_id="stop:0:/tmp/demo/.codex/hooks.json">remote-codex hook ran</hook_prompt>',
|
|
13
|
+
),
|
|
14
|
+
).toMatchObject({
|
|
15
|
+
hookRunId: 'stop:0:/tmp/demo/.codex/hooks.json',
|
|
16
|
+
output: 'remote-codex hook ran',
|
|
17
|
+
eventName: 'stop',
|
|
18
|
+
eventLabel: 'Stop',
|
|
19
|
+
sourcePath: '/tmp/demo/.codex/hooks.json',
|
|
20
|
+
outputEntries: [{ kind: 'warning', text: 'remote-codex hook ran' }],
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('maps Codex hook runs into provider-neutral history items', () => {
|
|
25
|
+
expect(
|
|
26
|
+
codexHookRunToHistoryItem({
|
|
27
|
+
id: 'run-1',
|
|
28
|
+
eventName: 'preToolUse',
|
|
29
|
+
handlerType: 'command',
|
|
30
|
+
executionMode: 'blocking',
|
|
31
|
+
scope: 'project',
|
|
32
|
+
sourcePath: '/tmp/demo/.codex/hooks.json',
|
|
33
|
+
source: 'project',
|
|
34
|
+
status: 'completed',
|
|
35
|
+
statusMessage: 'Checking Bash',
|
|
36
|
+
durationMs: 42,
|
|
37
|
+
outputEntries: [{ kind: 'context', text: 'allowed' }],
|
|
38
|
+
stderr: 'diagnostic',
|
|
39
|
+
}),
|
|
40
|
+
).toMatchObject({
|
|
41
|
+
id: 'hook:run-1',
|
|
42
|
+
kind: 'hook',
|
|
43
|
+
text: 'PreToolUse hook',
|
|
44
|
+
previewText: 'Checking Bash',
|
|
45
|
+
status: 'Completed',
|
|
46
|
+
hookEventName: 'preToolUse',
|
|
47
|
+
hookEventLabel: 'PreToolUse',
|
|
48
|
+
hookHandlerType: 'command',
|
|
49
|
+
hookScope: 'project',
|
|
50
|
+
hookSource: 'project',
|
|
51
|
+
hookSourcePath: '/tmp/demo/.codex/hooks.json',
|
|
52
|
+
hookStatusMessage: 'Checking Bash',
|
|
53
|
+
hookOutputEntries: [
|
|
54
|
+
{ kind: 'context', text: 'allowed' },
|
|
55
|
+
{ kind: 'warning', text: 'diagnostic' },
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
});
|
|
@@ -2,5 +2,12 @@ export * from './appServerManager';
|
|
|
2
2
|
export * from './historyItems';
|
|
3
3
|
export * from './hookHistory';
|
|
4
4
|
export * from './jsonrpc';
|
|
5
|
+
export * from './local-session-store';
|
|
6
|
+
export * from './management/codex-management-service';
|
|
7
|
+
export * from './management/codexHostConfig';
|
|
8
|
+
export * from './management/errors';
|
|
9
|
+
export * from './modelPricing';
|
|
10
|
+
export * from './runtime-errors';
|
|
5
11
|
export * from './runtimeAdapter';
|
|
12
|
+
export * from './thread-title';
|
|
6
13
|
export * from './types';
|