@axhub/genie 0.2.11 → 0.2.12
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/api-docs.html +2 -2
- package/dist/assets/App-Clb2COtW.js +274 -0
- package/dist/assets/ImagePlaygroundPage-DqhMSbM8.js +106 -0
- package/dist/assets/ImagePlaygroundPage-MEn3NN80.css +1 -0
- package/dist/assets/ReviewApp-CDcLYe-u.js +1 -0
- package/dist/assets/{_basePickBy-BDnj7-0Z.js → _basePickBy-jUZsM51q.js} +1 -1
- package/dist/assets/{_baseUniq-Bl0JKOyl.js → _baseUniq-BXglE6_v.js} +1 -1
- package/dist/assets/{arc-DY-4Kev3.js → arc-D-oFCFBv.js} +1 -1
- package/dist/assets/{architectureDiagram-2XIMDMQ5-qw7crNVd.js → architectureDiagram-2XIMDMQ5-DC8bAnQt.js} +1 -1
- package/dist/assets/{blockDiagram-WCTKOSBZ-B9xg7ep3.js → blockDiagram-WCTKOSBZ-C4semIRc.js} +1 -1
- package/dist/assets/{c4Diagram-IC4MRINW-H9xp3ytb.js → c4Diagram-IC4MRINW-FHj1QO3y.js} +1 -1
- package/dist/assets/channel-BF4woPXX.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-B3EVDUxI.js → chunk-4BX2VUAB-D-LjsQ_s.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-CGv945ef.js → chunk-55IACEB6-DI3j_d7A.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-uAT4CKWM.js → chunk-FMBD7UC4-BEVnaLFN.js} +1 -1
- package/dist/assets/{chunk-JSJVCQXG-Cbvlpkf7.js → chunk-JSJVCQXG-CSxpcErk.js} +1 -1
- package/dist/assets/{chunk-KX2RTZJC-CcqIuGat.js → chunk-KX2RTZJC-BbuhDN4h.js} +1 -1
- package/dist/assets/{chunk-NQ4KR5QH-CgrcsRuX.js → chunk-NQ4KR5QH-C3x61XQa.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-Cx0APOoV.js → chunk-QZHKN3VN-DxWOFtPh.js} +1 -1
- package/dist/assets/{chunk-WL4C6EOR-BbZirvBk.js → chunk-WL4C6EOR-Bt2OauD2.js} +1 -1
- package/dist/assets/classDiagram-VBA2DB6C-D2kHlnQ7.js +1 -0
- package/dist/assets/classDiagram-v2-RAHNMMFH-D2kHlnQ7.js +1 -0
- package/dist/assets/clone-CqBvwCJW.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-CrvmGFLD.js → cose-bilkent-S5V4N54A-Dexadrue.js} +1 -1
- package/dist/assets/{dagre-KLK3FWXG-C-W6VPjS.js → dagre-KLK3FWXG-F9U4X2xC.js} +1 -1
- package/dist/assets/{diagram-E7M64L7V-IP2q3bL0.js → diagram-E7M64L7V-B3V17aH3.js} +1 -1
- package/dist/assets/{diagram-IFDJBPK2-CQaL-XyV.js → diagram-IFDJBPK2-CdHAmLL1.js} +1 -1
- package/dist/assets/{diagram-P4PSJMXO-BxBLThfv.js → diagram-P4PSJMXO-CrTNfk8K.js} +1 -1
- package/dist/assets/{erDiagram-INFDFZHY-Dyl7bJTt.js → erDiagram-INFDFZHY-vDh9SWK9.js} +1 -1
- package/dist/assets/{flowDiagram-PKNHOUZH-B7NFMgFK.js → flowDiagram-PKNHOUZH-DpltMg7L.js} +1 -1
- package/dist/assets/{ganttDiagram-A5KZAMGK-hReWSDu2.js → ganttDiagram-A5KZAMGK-COTk2xur.js} +1 -1
- package/dist/assets/{gitGraphDiagram-K3NZZRJ6-gVgcr0ST.js → gitGraphDiagram-K3NZZRJ6-BNV7bvvj.js} +1 -1
- package/dist/assets/{graph-DNDiJhTn.js → graph-Dkeg9oys.js} +1 -1
- package/dist/assets/{highlighted-body-TPN3WLV5-DclLmTou.js → highlighted-body-TPN3WLV5-DaiQEBwR.js} +1 -1
- package/dist/assets/index-DgGmiqsP.css +1 -0
- package/dist/assets/index-DvA901Vs.js +2 -0
- package/dist/assets/{infoDiagram-LFFYTUFH-CqQOOzDA.js → infoDiagram-LFFYTUFH-CZioW3Gt.js} +1 -1
- package/dist/assets/{ishikawaDiagram-PHBUUO56-CZ0iLiHg.js → ishikawaDiagram-PHBUUO56-BbqR3i1B.js} +1 -1
- package/dist/assets/{journeyDiagram-4ABVD52K-DdfYKfNh.js → journeyDiagram-4ABVD52K-wfb-WHzl.js} +1 -1
- package/dist/assets/{kanban-definition-K7BYSVSG-C5Vf32u6.js → kanban-definition-K7BYSVSG-B3c4y3VN.js} +1 -1
- package/dist/assets/{layout-rvTEu2KS.js → layout-Xr9Z2VGF.js} +1 -1
- package/dist/assets/{linear-CD9SiYze.js → linear-JBmzAJtl.js} +1 -1
- package/dist/assets/{mermaid-O7DHMXV3-OZ8qWWwa.js → mermaid-O7DHMXV3-fDuyNLKe.js} +230 -222
- package/dist/assets/{mindmap-definition-YRQLILUH-CQxrLNVc.js → mindmap-definition-YRQLILUH-B5NTN_jD.js} +1 -1
- package/dist/assets/{pieDiagram-SKSYHLDU-XgAUByWg.js → pieDiagram-SKSYHLDU-CuO98GVu.js} +1 -1
- package/dist/assets/{quadrantDiagram-337W2JSQ-CH16ls7G.js → quadrantDiagram-337W2JSQ-LL3f4vLf.js} +1 -1
- package/dist/assets/{requirementDiagram-Z7DCOOCP-B_kQO06L.js → requirementDiagram-Z7DCOOCP-Di-2O6LH.js} +1 -1
- package/dist/assets/{sankeyDiagram-WA2Y5GQK-ofe78CyS.js → sankeyDiagram-WA2Y5GQK-9lHqrXqR.js} +1 -1
- package/dist/assets/{sequenceDiagram-2WXFIKYE-Ckbxwny6.js → sequenceDiagram-2WXFIKYE-BQu-SoGr.js} +1 -1
- package/dist/assets/{stateDiagram-RAJIS63D-DNtzCk14.js → stateDiagram-RAJIS63D-BUxvd2BC.js} +1 -1
- package/dist/assets/stateDiagram-v2-FVOUBMTO-CDVexTiR.js +1 -0
- package/dist/assets/{timeline-definition-YZTLITO2-zT6CklKt.js → timeline-definition-YZTLITO2-oP47UEU6.js} +1 -1
- package/dist/assets/{treemap-KZPCXAKY-y0U2c3xG.js → treemap-KZPCXAKY-BRjDo2aE.js} +1 -1
- package/dist/assets/{vendor-codemirror-CMHSJ_9p.js → vendor-codemirror-BiCeS-y4.js} +1 -1
- package/dist/assets/{vendor-react-xmA_f8ig.js → vendor-react-DVlYPmi3.js} +1 -1
- package/dist/assets/{vennDiagram-LZ73GAT5-xKj3SjYG.js → vennDiagram-LZ73GAT5-DrRqcDqo.js} +1 -1
- package/dist/assets/{xychartDiagram-JWTSCODW-Da_qyEoX.js → xychartDiagram-JWTSCODW-DUXrymAi.js} +1 -1
- package/dist/index.html +4 -4
- package/package.json +25 -6
- package/scripts/refresh-acp-default-capabilities.mjs +160 -0
- package/server/acp-runtime/client.js +1137 -181
- package/server/acp-runtime/command-overrides.js +48 -0
- package/server/acp-runtime/index.js +576 -16
- package/server/acp-runtime/registry.js +6 -4
- package/server/acp-runtime/session-store.js +235 -92
- package/server/database/db.js +12 -3
- package/server/external-agent/ws.js +212 -11
- package/server/index.js +145 -52
- package/server/projects-watcher-config.js +4 -0
- package/server/projects.js +466 -125
- package/server/routes/cc-connect.js +5 -4
- package/server/routes/codex.js +24 -0
- package/server/routes/commands.js +144 -1
- package/server/routes/runs.js +641 -0
- package/server/routes/session-core.js +357 -109
- package/server/session-core/eventStore.js +0 -121
- package/server/session-core/providerAdapters.js +644 -163
- package/server/session-core/providerDiscovery.js +66 -38
- package/server/session-core/runRegistry.js +244 -0
- package/server/session-core/runtimeState.js +75 -3
- package/server/session-core/runtimeWriter.js +132 -10
- package/server/utils/codexImagePlayground.js +479 -0
- package/server/utils/localTerminal.js +56 -0
- package/server/utils/shellCommand.js +70 -0
- package/shared/acpCapabilities.js +393 -0
- package/shared/acpDefaultCapabilities.generated.json +141 -0
- package/shared/conversationEvents.js +425 -121
- package/dist/assets/App-VH1wNUHs.js +0 -259
- package/dist/assets/ReviewApp-D_9EN4TM.js +0 -1
- package/dist/assets/channel-CyNUnRfc.js +0 -1
- package/dist/assets/classDiagram-VBA2DB6C-DxBtyz2A.js +0 -1
- package/dist/assets/classDiagram-v2-RAHNMMFH-DxBtyz2A.js +0 -1
- package/dist/assets/clone-C341l3d0.js +0 -1
- package/dist/assets/index-DBkz_W_P.css +0 -1
- package/dist/assets/index-DdRyoXKh.js +0 -2
- package/dist/assets/stateDiagram-v2-FVOUBMTO-B3VPhiE1.js +0 -1
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildAcpCapabilities,
|
|
3
|
+
normalizeAcpAvailableCommands,
|
|
4
|
+
normalizeAcpConfigOptions,
|
|
5
|
+
normalizeAcpModeState,
|
|
6
|
+
normalizeAcpTokenUsage
|
|
7
|
+
} from './acpCapabilities.js';
|
|
8
|
+
|
|
1
9
|
export const SUPPORTED_PROVIDERS = ['claude', 'codex', 'gemini', 'opencode'];
|
|
2
10
|
|
|
3
11
|
export const SESSION_STATES = [
|
|
@@ -6,6 +14,7 @@ export const SESSION_STATES = [
|
|
|
6
14
|
'idle',
|
|
7
15
|
'streaming',
|
|
8
16
|
'awaiting_approval',
|
|
17
|
+
'awaiting_input',
|
|
9
18
|
'completed',
|
|
10
19
|
'aborted',
|
|
11
20
|
'errored'
|
|
@@ -32,6 +41,8 @@ export const CONVERSATION_EVENT_KINDS = {
|
|
|
32
41
|
USAGE_UPDATE: 'usage_update',
|
|
33
42
|
APPROVAL_REQUEST: 'approval_request',
|
|
34
43
|
APPROVAL_RESOLVED: 'approval_resolved',
|
|
44
|
+
ELICITATION_REQUEST: 'elicitation_request',
|
|
45
|
+
ELICITATION_RESOLVED: 'elicitation_resolved',
|
|
35
46
|
ARTIFACT_CREATED: 'artifact_created',
|
|
36
47
|
SESSION_STATE_CHANGED: 'session_state_changed',
|
|
37
48
|
SYSTEM_NOTICE: 'system_notice',
|
|
@@ -75,6 +86,43 @@ export function createConversationEvent({
|
|
|
75
86
|
};
|
|
76
87
|
}
|
|
77
88
|
|
|
89
|
+
export function createUserMessageConversationEvent({
|
|
90
|
+
provider = 'claude',
|
|
91
|
+
sessionId = null,
|
|
92
|
+
timestamp,
|
|
93
|
+
text = '',
|
|
94
|
+
contentBlocks = [],
|
|
95
|
+
clientRequestId = null,
|
|
96
|
+
eventId = null,
|
|
97
|
+
extensions = {},
|
|
98
|
+
rawRef = null
|
|
99
|
+
} = {}) {
|
|
100
|
+
const normalizedClientRequestId = typeof clientRequestId === 'string' && clientRequestId.trim()
|
|
101
|
+
? clientRequestId.trim()
|
|
102
|
+
: null;
|
|
103
|
+
|
|
104
|
+
return createConversationEvent({
|
|
105
|
+
kind: CONVERSATION_EVENT_KINDS.USER_MESSAGE,
|
|
106
|
+
provider,
|
|
107
|
+
sessionId,
|
|
108
|
+
timestamp,
|
|
109
|
+
eventId,
|
|
110
|
+
payload: {
|
|
111
|
+
text: String(text || ''),
|
|
112
|
+
contentBlocks: normalizeMessageContentBlocks(contentBlocks)
|
|
113
|
+
},
|
|
114
|
+
extensions: {
|
|
115
|
+
runtimeSource: 'acp',
|
|
116
|
+
...(normalizedClientRequestId ? { clientRequestId: normalizedClientRequestId } : {}),
|
|
117
|
+
...extensions
|
|
118
|
+
},
|
|
119
|
+
rawRef: rawRef || {
|
|
120
|
+
runtime: 'acp',
|
|
121
|
+
sourceType: 'acp-user-prompt'
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
|
|
78
126
|
export function isConversationEvent(value) {
|
|
79
127
|
return !!(
|
|
80
128
|
value &&
|
|
@@ -208,11 +256,23 @@ function hasAcpProtocolTags(value) {
|
|
|
208
256
|
return /<\/?(?:subagent_notification|environment_context|dynamic_context|user_message)(?:\s[^>]*)?>/i.test(String(value || ''));
|
|
209
257
|
}
|
|
210
258
|
|
|
211
|
-
|
|
259
|
+
function stripAssistantThoughtProtocolPrelude(value) {
|
|
260
|
+
const text = String(value || '');
|
|
261
|
+
const markerPattern = /\[\s*Thought\s*:\s*true\s*\]/gi;
|
|
262
|
+
let markerEnd = -1;
|
|
263
|
+
let match;
|
|
264
|
+
while ((match = markerPattern.exec(text)) !== null) {
|
|
265
|
+
markerEnd = markerPattern.lastIndex;
|
|
266
|
+
}
|
|
267
|
+
return markerEnd >= 0 ? text.slice(markerEnd) : value;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export function stripAssistantProtocolTags(text, options = {}) {
|
|
212
271
|
if (typeof text !== 'string') {
|
|
213
272
|
return text;
|
|
214
273
|
}
|
|
215
274
|
|
|
275
|
+
const shouldTrim = options.trim !== false;
|
|
216
276
|
const visibleUserMessage = extractProtocolUserMessage(text);
|
|
217
277
|
if (visibleUserMessage != null) {
|
|
218
278
|
return visibleUserMessage;
|
|
@@ -230,7 +290,9 @@ export function stripAssistantProtocolTags(text) {
|
|
|
230
290
|
result = result.replace(/["']?\s*\}\s*\}\s*$/g, '');
|
|
231
291
|
}
|
|
232
292
|
|
|
233
|
-
|
|
293
|
+
result = stripAssistantThoughtProtocolPrelude(result);
|
|
294
|
+
|
|
295
|
+
return shouldTrim ? result.trim() : result;
|
|
234
296
|
}
|
|
235
297
|
|
|
236
298
|
function extractVisibleUserMessage(value) {
|
|
@@ -331,6 +393,153 @@ function getTimelineMessageClientRequestId(message) {
|
|
|
331
393
|
: null;
|
|
332
394
|
}
|
|
333
395
|
|
|
396
|
+
function getConversationEventMessageId(event, payload = {}) {
|
|
397
|
+
const rawValue = payload?.messageId || event?.extensions?.messageId || null;
|
|
398
|
+
return typeof rawValue === 'string' && rawValue.trim()
|
|
399
|
+
? rawValue.trim()
|
|
400
|
+
: null;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function isReplayConversationEvent(event) {
|
|
404
|
+
const sourceType = String(event?.rawRef?.sourceType || '').trim().toLowerCase();
|
|
405
|
+
return Boolean(event?.extensions?.runtimeReplay) || sourceType === 'acp-session-loaded-replay';
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function isUserEchoConversationEvent(event) {
|
|
409
|
+
const sourceType = String(event?.rawRef?.sourceType || '').trim().toLowerCase();
|
|
410
|
+
return sourceType === 'acp-user-message-chunk' || isReplayConversationEvent(event);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function getAppliedConversationEventIds(message) {
|
|
414
|
+
const ids = new Set();
|
|
415
|
+
if (typeof message?.eventId === 'string' && message.eventId.trim()) {
|
|
416
|
+
ids.add(message.eventId.trim());
|
|
417
|
+
}
|
|
418
|
+
if (Array.isArray(message?.appliedConversationEventIds)) {
|
|
419
|
+
message.appliedConversationEventIds.forEach((eventId) => {
|
|
420
|
+
if (typeof eventId === 'string' && eventId.trim()) {
|
|
421
|
+
ids.add(eventId.trim());
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
}
|
|
425
|
+
return ids;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function hasAppliedConversationEvent(messages, event) {
|
|
429
|
+
const eventId = typeof event?.eventId === 'string' && event.eventId.trim()
|
|
430
|
+
? event.eventId.trim()
|
|
431
|
+
: null;
|
|
432
|
+
if (!eventId) {
|
|
433
|
+
return false;
|
|
434
|
+
}
|
|
435
|
+
return messages.some((message) => getAppliedConversationEventIds(message).has(eventId));
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
function markConversationEventApplied(message, event) {
|
|
439
|
+
const eventId = typeof event?.eventId === 'string' && event.eventId.trim()
|
|
440
|
+
? event.eventId.trim()
|
|
441
|
+
: null;
|
|
442
|
+
if (!eventId || !message || typeof message !== 'object') {
|
|
443
|
+
return isReplayConversationEvent(event) && message && typeof message === 'object'
|
|
444
|
+
? { ...message, runtimeReplay: true }
|
|
445
|
+
: message;
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
const existingIds = getAppliedConversationEventIds(message);
|
|
449
|
+
if (existingIds.has(eventId)) {
|
|
450
|
+
return isReplayConversationEvent(event) && message.runtimeReplay !== true
|
|
451
|
+
? { ...message, runtimeReplay: true }
|
|
452
|
+
: message;
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return {
|
|
456
|
+
...message,
|
|
457
|
+
...(isReplayConversationEvent(event) ? { runtimeReplay: true } : {}),
|
|
458
|
+
appliedConversationEventIds: [
|
|
459
|
+
...(Array.isArray(message.appliedConversationEventIds) ? message.appliedConversationEventIds : []),
|
|
460
|
+
eventId
|
|
461
|
+
]
|
|
462
|
+
};
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
function findCompletedTextMessageIndex(messages, { messageId, isThinking = false } = {}) {
|
|
466
|
+
if (!messageId) {
|
|
467
|
+
return -1;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
return findLatestTimelineMessageIndex(messages, (message) => (
|
|
471
|
+
message?.eventMessageId === messageId &&
|
|
472
|
+
!message.isToolUse &&
|
|
473
|
+
!!message.isThinking === !!isThinking &&
|
|
474
|
+
message.isStreaming === false
|
|
475
|
+
));
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function isAssistantTextTimelineMessage(message, { isThinking = false } = {}) {
|
|
479
|
+
return (
|
|
480
|
+
String(message?.type || '').trim().toLowerCase() === 'assistant' &&
|
|
481
|
+
!message.isToolUse &&
|
|
482
|
+
!!message.isThinking === !!isThinking
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
function getTimelineMessageText(message) {
|
|
487
|
+
return String(message?.content || message?.reasoning || '').trim();
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
function getTimelineTextSignature(message, { isThinking = false } = {}) {
|
|
491
|
+
if (!isAssistantTextTimelineMessage(message, { isThinking })) {
|
|
492
|
+
return null;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const text = getTimelineMessageText(message);
|
|
496
|
+
if (!text) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return `${isThinking ? 'reasoning' : 'answer'}\u0000${text}`;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function removeDuplicateReplayTextMessages(messages, { isThinking = false } = {}) {
|
|
504
|
+
const seenSignatures = new Set();
|
|
505
|
+
const completedTexts = [];
|
|
506
|
+
const nextMessages = [];
|
|
507
|
+
|
|
508
|
+
for (const message of messages) {
|
|
509
|
+
const isTextMessage = isAssistantTextTimelineMessage(message, { isThinking });
|
|
510
|
+
const text = isTextMessage ? getTimelineMessageText(message) : '';
|
|
511
|
+
const signature = getTimelineTextSignature(message, { isThinking });
|
|
512
|
+
if (message?.runtimeReplay === true && isTextMessage) {
|
|
513
|
+
const replayIsCoveredByCompletedMessage = completedTexts.some((completedText) => (
|
|
514
|
+
!text || completedText === text || completedText.includes(text)
|
|
515
|
+
));
|
|
516
|
+
if ((signature && seenSignatures.has(signature)) || replayIsCoveredByCompletedMessage) {
|
|
517
|
+
continue;
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (signature) {
|
|
521
|
+
seenSignatures.add(signature);
|
|
522
|
+
}
|
|
523
|
+
if (isTextMessage && message?.isStreaming === false && text) {
|
|
524
|
+
completedTexts.push(text);
|
|
525
|
+
}
|
|
526
|
+
nextMessages.push(message);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
return nextMessages;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function shouldDedupeReplayTextEvent(event) {
|
|
533
|
+
return isReplayConversationEvent(event) && (
|
|
534
|
+
event.kind === CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_START ||
|
|
535
|
+
event.kind === CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_DELTA ||
|
|
536
|
+
event.kind === CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_END ||
|
|
537
|
+
event.kind === CONVERSATION_EVENT_KINDS.REASONING_START ||
|
|
538
|
+
event.kind === CONVERSATION_EVENT_KINDS.REASONING_DELTA ||
|
|
539
|
+
event.kind === CONVERSATION_EVENT_KINDS.REASONING_END
|
|
540
|
+
);
|
|
541
|
+
}
|
|
542
|
+
|
|
334
543
|
function buildComparableUserMessageContentBlocks(message = {}) {
|
|
335
544
|
const imageBlocks = Array.isArray(message?.images)
|
|
336
545
|
? message.images.map((image) => ({
|
|
@@ -349,22 +558,36 @@ function buildComparableUserMessageContentBlocks(message = {}) {
|
|
|
349
558
|
|
|
350
559
|
function findMatchingOptimisticUserMessageIndex(messages, event, payload = {}) {
|
|
351
560
|
const clientRequestId = getConversationEventClientRequestId(event);
|
|
352
|
-
if (!clientRequestId) {
|
|
561
|
+
if (!clientRequestId && !isUserEchoConversationEvent(event)) {
|
|
353
562
|
return -1;
|
|
354
563
|
}
|
|
355
564
|
|
|
356
565
|
const expectedContentBlocks = JSON.stringify(normalizeMessageContentBlocks(payload.contentBlocks));
|
|
566
|
+
const rawText = typeof payload.text === 'string' ? payload.text : '';
|
|
567
|
+
const visibleText = rawText ? extractVisibleUserMessage(rawText) : '';
|
|
568
|
+
const expectedText = visibleText || rawText;
|
|
357
569
|
|
|
358
570
|
return findLatestTimelineMessageIndex(messages, (message) => {
|
|
359
571
|
if (String(message?.type || '').trim().toLowerCase() !== 'user') {
|
|
360
572
|
return false;
|
|
361
573
|
}
|
|
362
574
|
|
|
363
|
-
|
|
575
|
+
const messageClientRequestId = getTimelineMessageClientRequestId(message);
|
|
576
|
+
if (clientRequestId) {
|
|
577
|
+
if (messageClientRequestId !== clientRequestId) {
|
|
578
|
+
return false;
|
|
579
|
+
}
|
|
580
|
+
} else if (!messageClientRequestId) {
|
|
364
581
|
return false;
|
|
582
|
+
} else {
|
|
583
|
+
const eventProvider = String(event?.provider || '').trim().toLowerCase();
|
|
584
|
+
const messageProvider = String(message?.provider || message?.__provider || '').trim().toLowerCase();
|
|
585
|
+
if (eventProvider && messageProvider && eventProvider !== messageProvider) {
|
|
586
|
+
return false;
|
|
587
|
+
}
|
|
365
588
|
}
|
|
366
589
|
|
|
367
|
-
if (String(message?.content || '') !== String(
|
|
590
|
+
if (String(message?.content || '') !== String(expectedText || '')) {
|
|
368
591
|
return false;
|
|
369
592
|
}
|
|
370
593
|
|
|
@@ -373,70 +596,6 @@ function findMatchingOptimisticUserMessageIndex(messages, event, payload = {}) {
|
|
|
373
596
|
});
|
|
374
597
|
}
|
|
375
598
|
|
|
376
|
-
function normalizeAcpModeState(value) {
|
|
377
|
-
if (!value || typeof value !== 'object') {
|
|
378
|
-
return null;
|
|
379
|
-
}
|
|
380
|
-
|
|
381
|
-
const availableModes = Array.isArray(value.availableModes)
|
|
382
|
-
? value.availableModes
|
|
383
|
-
.filter((mode) => mode && typeof mode === 'object' && String(mode.id || '').trim())
|
|
384
|
-
.map((mode) => ({
|
|
385
|
-
id: String(mode.id).trim(),
|
|
386
|
-
name: String(mode.name || mode.id || '').trim() || String(mode.id).trim(),
|
|
387
|
-
description: mode.description == null ? null : String(mode.description)
|
|
388
|
-
}))
|
|
389
|
-
: [];
|
|
390
|
-
const currentModeId = typeof value.currentModeId === 'string' && value.currentModeId.trim()
|
|
391
|
-
? value.currentModeId.trim()
|
|
392
|
-
: null;
|
|
393
|
-
|
|
394
|
-
if (!availableModes.length && !currentModeId) {
|
|
395
|
-
return null;
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
return {
|
|
399
|
-
availableModes,
|
|
400
|
-
currentModeId: currentModeId || availableModes[0]?.id || null
|
|
401
|
-
};
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
function normalizeAcpAvailableCommands(value) {
|
|
405
|
-
const commands = Array.isArray(value?.availableCommands)
|
|
406
|
-
? value.availableCommands
|
|
407
|
-
: Array.isArray(value)
|
|
408
|
-
? value
|
|
409
|
-
: [];
|
|
410
|
-
|
|
411
|
-
return commands
|
|
412
|
-
.filter((command) => command && typeof command === 'object' && String(command.name || '').trim())
|
|
413
|
-
.map((command) => ({
|
|
414
|
-
name: String(command.name).trim(),
|
|
415
|
-
description: command.description == null ? '' : String(command.description),
|
|
416
|
-
input: command.input && typeof command.input === 'object' ? cloneJsonValue(command.input) : null,
|
|
417
|
-
source: 'acp',
|
|
418
|
-
namespace: 'acp',
|
|
419
|
-
type: 'acp'
|
|
420
|
-
}));
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
function normalizeAcpConfigOptions(value) {
|
|
424
|
-
const configOptions = Array.isArray(value?.configOptions)
|
|
425
|
-
? value.configOptions
|
|
426
|
-
: Array.isArray(value)
|
|
427
|
-
? value
|
|
428
|
-
: [];
|
|
429
|
-
|
|
430
|
-
return configOptions
|
|
431
|
-
.filter((option) => option && typeof option === 'object' && String(option.key || '').trim())
|
|
432
|
-
.map((option) => ({
|
|
433
|
-
key: String(option.key).trim(),
|
|
434
|
-
description: typeof option.description === 'string' ? option.description : '',
|
|
435
|
-
value: cloneJsonValue(option.value),
|
|
436
|
-
schema: option.schema && typeof option.schema === 'object' ? cloneJsonValue(option.schema) : null
|
|
437
|
-
}));
|
|
438
|
-
}
|
|
439
|
-
|
|
440
599
|
function normalizeAcpSessionInfo(value) {
|
|
441
600
|
if (!value || typeof value !== 'object') {
|
|
442
601
|
return null;
|
|
@@ -459,32 +618,6 @@ function normalizeAcpSessionInfo(value) {
|
|
|
459
618
|
};
|
|
460
619
|
}
|
|
461
620
|
|
|
462
|
-
function normalizeAcpTokenUsage(value) {
|
|
463
|
-
if (!value || typeof value !== 'object') {
|
|
464
|
-
return null;
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const used = Number(value.used);
|
|
468
|
-
const total = Number(value.size);
|
|
469
|
-
if (!Number.isFinite(used) || used < 0 || !Number.isFinite(total) || total < 0) {
|
|
470
|
-
return null;
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
const safeUsed = Math.round(used);
|
|
474
|
-
const safeTotal = Math.round(total);
|
|
475
|
-
const percentage = safeTotal > 0
|
|
476
|
-
? Math.min(100, Math.max(0, Math.round((safeUsed / safeTotal) * 100)))
|
|
477
|
-
: 0;
|
|
478
|
-
|
|
479
|
-
return {
|
|
480
|
-
used: safeUsed,
|
|
481
|
-
total: safeTotal,
|
|
482
|
-
percentage,
|
|
483
|
-
remaining: Math.max(0, safeTotal - safeUsed),
|
|
484
|
-
cost: value.cost && typeof value.cost === 'object' ? cloneJsonValue(value.cost) : null
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
|
|
488
621
|
function mergeToolCallSnapshot(existingSnapshot = null, payload = {}) {
|
|
489
622
|
const nextSnapshot = existingSnapshot && typeof existingSnapshot === 'object'
|
|
490
623
|
? { ...existingSnapshot }
|
|
@@ -555,6 +688,20 @@ function appendDeltaText(existing = '', delta = '') {
|
|
|
555
688
|
return `${existing}${delta}`;
|
|
556
689
|
}
|
|
557
690
|
|
|
691
|
+
function closeOpenStreamingTextMessages(messages) {
|
|
692
|
+
for (let index = 0; index < messages.length; index += 1) {
|
|
693
|
+
const message = messages[index];
|
|
694
|
+
if (!message || message.isStreaming !== true || message.isToolUse) {
|
|
695
|
+
continue;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
messages[index] = {
|
|
699
|
+
...message,
|
|
700
|
+
isStreaming: false
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
558
705
|
function ensureStreamingTextMessage(messages, {
|
|
559
706
|
messageId,
|
|
560
707
|
timestamp,
|
|
@@ -562,10 +709,30 @@ function ensureStreamingTextMessage(messages, {
|
|
|
562
709
|
isThinking = false,
|
|
563
710
|
kind = 'assistant'
|
|
564
711
|
}) {
|
|
565
|
-
const
|
|
712
|
+
const hasRoleBoundaryAfter = (candidateIndex) => {
|
|
713
|
+
const targetRole = String(kind || 'assistant').trim().toLowerCase();
|
|
714
|
+
for (let index = candidateIndex + 1; index < messages.length; index += 1) {
|
|
715
|
+
const messageRole = String(messages[index]?.type || messages[index]?.role || '').trim().toLowerCase();
|
|
716
|
+
if (messageRole && messageRole !== targetRole) {
|
|
717
|
+
return true;
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
return false;
|
|
721
|
+
};
|
|
722
|
+
|
|
723
|
+
const index = findLatestTimelineMessageIndex(messages, (message, messageIndex) => (
|
|
566
724
|
message?.eventMessageId === messageId &&
|
|
567
725
|
!message.isToolUse &&
|
|
568
|
-
!!message.isThinking === !!isThinking
|
|
726
|
+
!!message.isThinking === !!isThinking &&
|
|
727
|
+
!hasRoleBoundaryAfter(messageIndex) &&
|
|
728
|
+
(
|
|
729
|
+
message.isStreaming !== false ||
|
|
730
|
+
(
|
|
731
|
+
!String(message?.content || '').trim() &&
|
|
732
|
+
Array.isArray(message?.contentBlocks) &&
|
|
733
|
+
message.contentBlocks.length > 0
|
|
734
|
+
)
|
|
735
|
+
)
|
|
569
736
|
));
|
|
570
737
|
|
|
571
738
|
if (index >= 0) {
|
|
@@ -776,6 +943,7 @@ export function normalizeLegacyHistoryEntries(rawMessages = [], provider = 'clau
|
|
|
776
943
|
export function applyConversationEventToTimelineMessages(messages = [], event, sessionProvider = 'claude') {
|
|
777
944
|
const nextMessages = Array.isArray(messages) ? [...messages] : [];
|
|
778
945
|
if (!isConversationEvent(event)) return nextMessages;
|
|
946
|
+
if (hasAppliedConversationEvent(nextMessages, event)) return nextMessages;
|
|
779
947
|
|
|
780
948
|
const provider = event.provider || sessionProvider;
|
|
781
949
|
const timestamp = event.timestamp || new Date().toISOString();
|
|
@@ -783,6 +951,7 @@ export function applyConversationEventToTimelineMessages(messages = [], event, s
|
|
|
783
951
|
|
|
784
952
|
switch (event.kind) {
|
|
785
953
|
case CONVERSATION_EVENT_KINDS.USER_MESSAGE: {
|
|
954
|
+
closeOpenStreamingTextMessages(nextMessages);
|
|
786
955
|
const clientRequestId = getConversationEventClientRequestId(event);
|
|
787
956
|
const optimisticIndex = findMatchingOptimisticUserMessageIndex(nextMessages, event, payload);
|
|
788
957
|
const normalizedContentBlocks = normalizeMessageContentBlocks(payload.contentBlocks);
|
|
@@ -799,7 +968,7 @@ export function applyConversationEventToTimelineMessages(messages = [], event, s
|
|
|
799
968
|
? normalizedContentBlocks.filter((block) => block?.type !== 'image')
|
|
800
969
|
: normalizedContentBlocks;
|
|
801
970
|
|
|
802
|
-
nextMessages[optimisticIndex] = {
|
|
971
|
+
nextMessages[optimisticIndex] = markConversationEventApplied({
|
|
803
972
|
...existingMessage,
|
|
804
973
|
type: 'user',
|
|
805
974
|
content: visibleText || existingMessage.content || '',
|
|
@@ -809,46 +978,65 @@ export function applyConversationEventToTimelineMessages(messages = [], event, s
|
|
|
809
978
|
clientRequestId: clientRequestId || existingMessage.clientRequestId || null,
|
|
810
979
|
eventId: event.eventId || existingMessage.eventId,
|
|
811
980
|
id: existingMessage.id || event.eventId || existingMessage.id
|
|
812
|
-
};
|
|
981
|
+
}, event);
|
|
813
982
|
break;
|
|
814
983
|
}
|
|
815
984
|
|
|
816
|
-
nextMessages.push({
|
|
985
|
+
nextMessages.push(markConversationEventApplied({
|
|
817
986
|
type: 'user',
|
|
818
987
|
content: visibleText,
|
|
819
988
|
timestamp,
|
|
820
989
|
provider,
|
|
821
990
|
contentBlocks: normalizedContentBlocks,
|
|
822
|
-
clientRequestId
|
|
823
|
-
|
|
991
|
+
clientRequestId,
|
|
992
|
+
eventId: event.eventId
|
|
993
|
+
}, event));
|
|
824
994
|
break;
|
|
825
995
|
}
|
|
826
996
|
|
|
827
997
|
case CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_START: {
|
|
828
|
-
const messageId = payload
|
|
829
|
-
|
|
998
|
+
const messageId = getConversationEventMessageId(event, payload) || createEventId('assistant_text');
|
|
999
|
+
const completedReplayIndex = isReplayConversationEvent(event)
|
|
1000
|
+
? findCompletedTextMessageIndex(nextMessages, { messageId, isThinking: false })
|
|
1001
|
+
: -1;
|
|
1002
|
+
if (completedReplayIndex >= 0) {
|
|
1003
|
+
nextMessages[completedReplayIndex] = markConversationEventApplied(nextMessages[completedReplayIndex], event);
|
|
1004
|
+
break;
|
|
1005
|
+
}
|
|
1006
|
+
const { index } = ensureStreamingTextMessage(nextMessages, { messageId, timestamp, provider, isThinking: false });
|
|
1007
|
+
nextMessages[index] = markConversationEventApplied(nextMessages[index], event);
|
|
830
1008
|
break;
|
|
831
1009
|
}
|
|
832
1010
|
|
|
833
1011
|
case CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_DELTA: {
|
|
834
|
-
const messageId = payload
|
|
1012
|
+
const messageId = getConversationEventMessageId(event, payload) || createEventId('assistant_text');
|
|
1013
|
+
const completedReplayIndex = isReplayConversationEvent(event)
|
|
1014
|
+
? findCompletedTextMessageIndex(nextMessages, { messageId, isThinking: false })
|
|
1015
|
+
: -1;
|
|
1016
|
+
if (completedReplayIndex >= 0) {
|
|
1017
|
+
nextMessages[completedReplayIndex] = markConversationEventApplied(nextMessages[completedReplayIndex], event);
|
|
1018
|
+
break;
|
|
1019
|
+
}
|
|
835
1020
|
const { index } = ensureStreamingTextMessage(nextMessages, { messageId, timestamp, provider, isThinking: false });
|
|
836
1021
|
const target = { ...nextMessages[index] };
|
|
837
|
-
target.content =
|
|
1022
|
+
target.content = stripAssistantProtocolTags(
|
|
1023
|
+
appendDeltaText(target.content || '', payload.text || ''),
|
|
1024
|
+
{ trim: false }
|
|
1025
|
+
);
|
|
838
1026
|
target.timestamp = target.timestamp || timestamp;
|
|
839
1027
|
target.provider = target.provider || provider;
|
|
840
|
-
nextMessages[index] = target;
|
|
1028
|
+
nextMessages[index] = markConversationEventApplied(target, event);
|
|
841
1029
|
break;
|
|
842
1030
|
}
|
|
843
1031
|
|
|
844
1032
|
case CONVERSATION_EVENT_KINDS.ASSISTANT_TEXT_END: {
|
|
845
|
-
const messageId = payload
|
|
1033
|
+
const messageId = getConversationEventMessageId(event, payload);
|
|
846
1034
|
if (!messageId) break;
|
|
847
1035
|
const index = findLatestTimelineMessageIndex(nextMessages, (message) => (
|
|
848
1036
|
message?.eventMessageId === messageId && !message.isToolUse && !message.isThinking
|
|
849
1037
|
));
|
|
850
1038
|
if (index >= 0) {
|
|
851
|
-
nextMessages[index] = { ...nextMessages[index], isStreaming: false };
|
|
1039
|
+
nextMessages[index] = markConversationEventApplied({ ...nextMessages[index], isStreaming: false }, event);
|
|
852
1040
|
}
|
|
853
1041
|
break;
|
|
854
1042
|
}
|
|
@@ -874,31 +1062,46 @@ export function applyConversationEventToTimelineMessages(messages = [], event, s
|
|
|
874
1062
|
}
|
|
875
1063
|
|
|
876
1064
|
case CONVERSATION_EVENT_KINDS.REASONING_START: {
|
|
877
|
-
const messageId = payload
|
|
878
|
-
|
|
1065
|
+
const messageId = getConversationEventMessageId(event, payload) || createEventId('reasoning');
|
|
1066
|
+
const completedReplayIndex = isReplayConversationEvent(event)
|
|
1067
|
+
? findCompletedTextMessageIndex(nextMessages, { messageId, isThinking: true })
|
|
1068
|
+
: -1;
|
|
1069
|
+
if (completedReplayIndex >= 0) {
|
|
1070
|
+
nextMessages[completedReplayIndex] = markConversationEventApplied(nextMessages[completedReplayIndex], event);
|
|
1071
|
+
break;
|
|
1072
|
+
}
|
|
1073
|
+
const { index } = ensureStreamingTextMessage(nextMessages, { messageId, timestamp, provider, isThinking: true });
|
|
1074
|
+
nextMessages[index] = markConversationEventApplied(nextMessages[index], event);
|
|
879
1075
|
break;
|
|
880
1076
|
}
|
|
881
1077
|
|
|
882
1078
|
case CONVERSATION_EVENT_KINDS.REASONING_DELTA: {
|
|
883
|
-
const messageId = payload
|
|
1079
|
+
const messageId = getConversationEventMessageId(event, payload) || createEventId('reasoning');
|
|
1080
|
+
const completedReplayIndex = isReplayConversationEvent(event)
|
|
1081
|
+
? findCompletedTextMessageIndex(nextMessages, { messageId, isThinking: true })
|
|
1082
|
+
: -1;
|
|
1083
|
+
if (completedReplayIndex >= 0) {
|
|
1084
|
+
nextMessages[completedReplayIndex] = markConversationEventApplied(nextMessages[completedReplayIndex], event);
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
884
1087
|
const { index } = ensureStreamingTextMessage(nextMessages, { messageId, timestamp, provider, isThinking: true });
|
|
885
1088
|
const target = { ...nextMessages[index] };
|
|
886
1089
|
target.content = appendDeltaText(target.content || '', payload.text || '');
|
|
887
1090
|
target.timestamp = target.timestamp || timestamp;
|
|
888
1091
|
target.provider = target.provider || provider;
|
|
889
1092
|
target.isThinking = true;
|
|
890
|
-
nextMessages[index] = target;
|
|
1093
|
+
nextMessages[index] = markConversationEventApplied(target, event);
|
|
891
1094
|
break;
|
|
892
1095
|
}
|
|
893
1096
|
|
|
894
1097
|
case CONVERSATION_EVENT_KINDS.REASONING_END: {
|
|
895
|
-
const messageId = payload
|
|
1098
|
+
const messageId = getConversationEventMessageId(event, payload);
|
|
896
1099
|
if (!messageId) break;
|
|
897
1100
|
const index = findLatestTimelineMessageIndex(nextMessages, (message) => (
|
|
898
1101
|
message?.eventMessageId === messageId && !!message.isThinking
|
|
899
1102
|
));
|
|
900
1103
|
if (index >= 0) {
|
|
901
|
-
nextMessages[index] = { ...nextMessages[index], isStreaming: false, isThinking: true };
|
|
1104
|
+
nextMessages[index] = markConversationEventApplied({ ...nextMessages[index], isStreaming: false, isThinking: true }, event);
|
|
902
1105
|
}
|
|
903
1106
|
break;
|
|
904
1107
|
}
|
|
@@ -1069,28 +1272,79 @@ export function applyConversationEventToTimelineMessages(messages = [], event, s
|
|
|
1069
1272
|
break;
|
|
1070
1273
|
}
|
|
1071
1274
|
|
|
1275
|
+
if (shouldDedupeReplayTextEvent(event)) {
|
|
1276
|
+
return removeDuplicateReplayTextMessages(nextMessages, {
|
|
1277
|
+
isThinking: (
|
|
1278
|
+
event.kind === CONVERSATION_EVENT_KINDS.REASONING_START ||
|
|
1279
|
+
event.kind === CONVERSATION_EVENT_KINDS.REASONING_DELTA ||
|
|
1280
|
+
event.kind === CONVERSATION_EVENT_KINDS.REASONING_END
|
|
1281
|
+
)
|
|
1282
|
+
});
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1072
1285
|
return nextMessages;
|
|
1073
1286
|
}
|
|
1074
1287
|
|
|
1288
|
+
function normalizeConversationTimelineEntries(entries = [], sessionProvider = 'claude') {
|
|
1289
|
+
const normalizedEvents = [];
|
|
1290
|
+
let legacyEntries = [];
|
|
1291
|
+
|
|
1292
|
+
const flushLegacyEntries = () => {
|
|
1293
|
+
if (legacyEntries.length === 0) {
|
|
1294
|
+
return;
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
normalizedEvents.push(...normalizeLegacyHistoryEntries(legacyEntries, sessionProvider));
|
|
1298
|
+
legacyEntries = [];
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
for (const entry of entries) {
|
|
1302
|
+
if (isConversationEvent(entry)) {
|
|
1303
|
+
flushLegacyEntries();
|
|
1304
|
+
normalizedEvents.push(entry);
|
|
1305
|
+
} else {
|
|
1306
|
+
legacyEntries.push(entry);
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
flushLegacyEntries();
|
|
1311
|
+
return normalizedEvents;
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1075
1314
|
export function conversationEventsToTimelineMessages(events = [], sessionProvider = 'claude') {
|
|
1076
1315
|
if (!Array.isArray(events)) return [];
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1316
|
+
const normalizedEvents = events.every((event) => isConversationEvent(event))
|
|
1317
|
+
? events
|
|
1318
|
+
: normalizeConversationTimelineEntries(events, sessionProvider);
|
|
1080
1319
|
|
|
1081
|
-
return
|
|
1320
|
+
return normalizedEvents.reduce(
|
|
1082
1321
|
(messages, event) => applyConversationEventToTimelineMessages(messages, event, sessionProvider),
|
|
1083
1322
|
[]
|
|
1084
1323
|
);
|
|
1085
1324
|
}
|
|
1086
1325
|
|
|
1326
|
+
function mergeAcpConfigOptions(previousOptions = [], nextOptions = []) {
|
|
1327
|
+
const mergedByKey = new Map();
|
|
1328
|
+
|
|
1329
|
+
for (const option of normalizeAcpConfigOptions(previousOptions)) {
|
|
1330
|
+
mergedByKey.set(option.key, option);
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
for (const option of normalizeAcpConfigOptions(nextOptions)) {
|
|
1334
|
+
mergedByKey.set(option.key, option);
|
|
1335
|
+
}
|
|
1336
|
+
|
|
1337
|
+
return Array.from(mergedByKey.values());
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1087
1340
|
export function extractAcpSessionMetadataFromConversationEvents(events = []) {
|
|
1088
1341
|
const metadata = {
|
|
1089
1342
|
modeState: null,
|
|
1090
1343
|
availableCommands: [],
|
|
1091
1344
|
configOptions: [],
|
|
1092
1345
|
sessionInfo: null,
|
|
1093
|
-
tokenUsage: null
|
|
1346
|
+
tokenUsage: null,
|
|
1347
|
+
capabilitySnapshot: null
|
|
1094
1348
|
};
|
|
1095
1349
|
|
|
1096
1350
|
for (const event of Array.isArray(events) ? events : []) {
|
|
@@ -1117,7 +1371,7 @@ export function extractAcpSessionMetadataFromConversationEvents(events = []) {
|
|
|
1117
1371
|
}
|
|
1118
1372
|
|
|
1119
1373
|
if (event.kind === CONVERSATION_EVENT_KINDS.CONFIG_OPTION_UPDATE) {
|
|
1120
|
-
metadata.configOptions =
|
|
1374
|
+
metadata.configOptions = mergeAcpConfigOptions(metadata.configOptions, event.payload || {});
|
|
1121
1375
|
}
|
|
1122
1376
|
|
|
1123
1377
|
if (event.kind === CONVERSATION_EVENT_KINDS.SESSION_INFO_UPDATE) {
|
|
@@ -1138,6 +1392,14 @@ export function extractAcpSessionMetadataFromConversationEvents(events = []) {
|
|
|
1138
1392
|
}
|
|
1139
1393
|
}
|
|
1140
1394
|
|
|
1395
|
+
metadata.capabilitySnapshot = buildAcpCapabilities({
|
|
1396
|
+
configOptions: metadata.configOptions,
|
|
1397
|
+
modeState: metadata.modeState,
|
|
1398
|
+
tokenUsage: metadata.tokenUsage,
|
|
1399
|
+
availableCommands: metadata.availableCommands,
|
|
1400
|
+
source: 'history'
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1141
1403
|
return metadata;
|
|
1142
1404
|
}
|
|
1143
1405
|
|
|
@@ -1241,6 +1503,48 @@ export function normalizeRealtimePayloadToConversationEvents(payload, fallbackPr
|
|
|
1241
1503
|
);
|
|
1242
1504
|
}
|
|
1243
1505
|
|
|
1506
|
+
const initialAvailableCommands = normalizeAcpAvailableCommands(payload.availableCommands || []);
|
|
1507
|
+
if (initialAvailableCommands.length > 0) {
|
|
1508
|
+
events.push(
|
|
1509
|
+
createConversationEvent({
|
|
1510
|
+
kind: CONVERSATION_EVENT_KINDS.AVAILABLE_COMMANDS_UPDATE,
|
|
1511
|
+
provider,
|
|
1512
|
+
sessionId,
|
|
1513
|
+
timestamp,
|
|
1514
|
+
payload: { availableCommands: initialAvailableCommands },
|
|
1515
|
+
rawRef
|
|
1516
|
+
})
|
|
1517
|
+
);
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
const initialConfigOptions = normalizeAcpConfigOptions(payload.configOptions || []);
|
|
1521
|
+
if (initialConfigOptions.length > 0) {
|
|
1522
|
+
events.push(
|
|
1523
|
+
createConversationEvent({
|
|
1524
|
+
kind: CONVERSATION_EVENT_KINDS.CONFIG_OPTION_UPDATE,
|
|
1525
|
+
provider,
|
|
1526
|
+
sessionId,
|
|
1527
|
+
timestamp,
|
|
1528
|
+
payload: { configOptions: initialConfigOptions },
|
|
1529
|
+
rawRef
|
|
1530
|
+
})
|
|
1531
|
+
);
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
const initialTokenUsage = normalizeAcpTokenUsage(payload.tokenUsage || null);
|
|
1535
|
+
if (initialTokenUsage) {
|
|
1536
|
+
events.push(
|
|
1537
|
+
createConversationEvent({
|
|
1538
|
+
kind: CONVERSATION_EVENT_KINDS.USAGE_UPDATE,
|
|
1539
|
+
provider,
|
|
1540
|
+
sessionId,
|
|
1541
|
+
timestamp,
|
|
1542
|
+
payload: initialTokenUsage,
|
|
1543
|
+
rawRef
|
|
1544
|
+
})
|
|
1545
|
+
);
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1244
1548
|
return events;
|
|
1245
1549
|
}
|
|
1246
1550
|
|