openclaw-openagent 1.0.13 → 1.0.14
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/src/messaging/executor.d.ts +2 -3
- package/dist/src/messaging/executor.js +4 -31
- package/dist/src/plugin-ui/assets/openagent-override.js +4 -5
- package/dist/src/runtime/update-checker.d.ts +1 -1
- package/dist/src/runtime/update-checker.js +9 -46
- package/package.json +1 -3
- package/src/app/channel-tools.ts +0 -249
- package/src/app/discovery-tools.ts +0 -273
- package/src/app/download-file-tool.ts +0 -133
- package/src/app/hooks.ts +0 -144
- package/src/app/index.ts +0 -84
- package/src/app/messaging-tools.ts +0 -79
- package/src/app/ops-tools.ts +0 -155
- package/src/app/remote-agent-tool.ts +0 -762
- package/src/app/types.ts +0 -68
- package/src/app/upload-file-tool.ts +0 -411
- package/src/app/verbose-preflight.ts +0 -190
- package/src/auth/config.ts +0 -266
- package/src/auth/credential-manager.ts +0 -146
- package/src/auth/index.ts +0 -24
- package/src/auth/verify.ts +0 -99
- package/src/channel.ts +0 -566
- package/src/compat.ts +0 -94
- package/src/config/config-schema.ts +0 -45
- package/src/messaging/aggregator.ts +0 -120
- package/src/messaging/collector.ts +0 -89
- package/src/messaging/executor.ts +0 -72
- package/src/messaging/inbound.ts +0 -150
- package/src/messaging/index.ts +0 -11
- package/src/messaging/mention-protocol.ts +0 -94
- package/src/messaging/process-c2c-request.ts +0 -564
- package/src/messaging/process-message.ts +0 -373
- package/src/messaging/scheduler.ts +0 -55
- package/src/messaging/types.ts +0 -38
- package/src/plugin-ui/adapters/oc-2026-04.js +0 -103
- package/src/plugin-ui/adapters/oc-2026-05.js +0 -125
- package/src/plugin-ui/adapters/oc-2026-06.js +0 -125
- package/src/plugin-ui/adapters/oc-unknown.js +0 -48
- package/src/plugin-ui/assets/agentbook-icon.svg +0 -5
- package/src/plugin-ui/assets/bg.png +0 -0
- package/src/plugin-ui/assets/icon.png +0 -0
- package/src/plugin-ui/assets/magic.svg +0 -5
- package/src/plugin-ui/assets/openagent-override.js +0 -11263
- package/src/plugin-ui/build.cjs +0 -463
- package/src/plugin-ui/index.ts +0 -18
- package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -570
- package/src/plugin-ui/modules/agent-book/panel/agent-card.js +0 -170
- package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -643
- package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +0 -665
- package/src/plugin-ui/modules/agent-book/panel/mention-state.js +0 -206
- package/src/plugin-ui/modules/agent-book/panel/styles.js +0 -832
- package/src/plugin-ui/modules/agent-book/panel/theme-adapter.js +0 -86
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +0 -295
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +0 -211
- package/src/plugin-ui/modules/agent-book/scanner.js +0 -131
- package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +0 -500
- package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +0 -652
- package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +0 -262
- package/src/plugin-ui/modules/loader/bootstrap.js +0 -133
- package/src/plugin-ui/modules/loader/shared-state.js +0 -838
- package/src/plugin-ui/modules/loader/ws-intercept.js +0 -199
- package/src/plugin-ui/modules/remote-agent/chunk-parser.js +0 -161
- package/src/plugin-ui/modules/remote-agent/execution-card.js +0 -530
- package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +0 -256
- package/src/plugin-ui/modules/remote-agent/media-links.js +0 -151
- package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +0 -134
- package/src/plugin-ui/modules/remote-agent/output-card.js +0 -342
- package/src/plugin-ui/modules/remote-agent/progress-store.js +0 -363
- package/src/plugin-ui/modules/remote-agent/render-hooks.js +0 -1700
- package/src/plugin-ui/modules/remote-agent/styles.js +0 -903
- package/src/plugin-ui/modules/remote-agent/tool-card-model.js +0 -130
- package/src/plugin-ui/postinstall-deploy.cjs +0 -52
- package/src/plugin-ui/ui-extension-loader/backup.ts +0 -92
- package/src/plugin-ui/ui-extension-loader/index.ts +0 -276
- package/src/plugin-ui/ui-extension-loader/locator.ts +0 -152
- package/src/plugin-ui/ui-extension-loader/manifest.ts +0 -57
- package/src/plugin-ui/ui-extension-loader/registry-regex.ts +0 -944
- package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +0 -70
- package/src/plugin-ui/ui-extension-loader/types.ts +0 -72
- package/src/proxy/auth-proxy.ts +0 -414
- package/src/runtime/account.ts +0 -549
- package/src/runtime/index.ts +0 -7
- package/src/runtime/plugin-runtime.ts +0 -94
- package/src/runtime/registry.ts +0 -71
- package/src/runtime/update-checker.ts +0 -286
- package/src/sdk/CLASS_MAP.md +0 -143
- package/src/sdk/index.d.ts +0 -126
- package/src/sdk/index.js +0 -23990
- package/src/sdk/modules/cloud-search-module.js +0 -1117
- package/src/sdk/modules/follow-module.js +0 -1069
- package/src/sdk/modules/group-module.js +0 -7397
- package/src/sdk/modules/relationship-module.js +0 -2269
- package/src/sdk/modules/signaling-module.js +0 -1468
- package/src/sdk/modules/tim-upload-plugin.js +0 -730
- package/src/sdk/node-env/http-request.js +0 -90
- package/src/sdk/node-env/index.js +0 -57
- package/src/sdk/node-env/storage.js +0 -114
- package/src/sdk/package.json +0 -10
- package/src/sdk/tsconfig.json +0 -16
- package/src/state/pending-invocation-store.ts +0 -43
- package/src/state/store.ts +0 -756
- package/src/tim/c2c.ts +0 -451
- package/src/tim/channels.ts +0 -364
- package/src/tim/client.ts +0 -330
- package/src/tim/index.ts +0 -18
- package/src/tim/messages.ts +0 -166
- package/src/tim/sdk-logger-init.ts +0 -50
- package/src/tools.ts +0 -10
- package/src/transport/factory.ts +0 -95
- package/src/transport/oasn/index.ts +0 -17
- package/src/transport/oasn/oasn-agent-card.ts +0 -111
- package/src/transport/oasn/oasn-discovery.ts +0 -108
- package/src/transport/oasn/oasn-files.ts +0 -210
- package/src/transport/oasn/oasn-http.ts +0 -529
- package/src/transport/oasn/oasn-invocation.ts +0 -604
- package/src/transport/oasn/oasn-normalize.ts +0 -133
- package/src/transport/oasn/oasn-register.ts +0 -33
- package/src/transport/oasn/oasn-transport.ts +0 -318
- package/src/transport/oasn/oasn-types.ts +0 -404
- package/src/transport/tim/index.ts +0 -8
- package/src/transport/tim/tim-transport.ts +0 -515
- package/src/transport/types.ts +0 -538
- package/src/types/openclaw-plugin-sdk-media-store.d.ts +0 -9
- package/src/types/openclaw.d.ts +0 -97
- package/src/types/tencentcloud-chat.d.ts +0 -15
- package/src/util/http.ts +0 -113
- package/src/util/logger.ts +0 -131
- package/src/util/url-resolver.ts +0 -77
|
@@ -1,1700 +0,0 @@
|
|
|
1
|
-
// ── OpenAgent Render Hook v2 — 单一数据源 + 纯渲染 ──
|
|
2
|
-
//
|
|
3
|
-
// 架构:
|
|
4
|
-
// __cl_toolStates: 当前页面生命周期内的 DOM/phase 状态
|
|
5
|
-
// _clRemoteAgentProgressStore: 可替换存储层,保存卡片快照参数
|
|
6
|
-
// 正常流式渲染只读写 __cl_toolStates;store 只是旁路记录,刷新后才用于恢复
|
|
7
|
-
|
|
8
|
-
// ═══════════════════════════════════════════════════════════════
|
|
9
|
-
// 单一数据源
|
|
10
|
-
// ═══════════════════════════════════════════════════════════════
|
|
11
|
-
|
|
12
|
-
var __cl_toolStates = new Map();
|
|
13
|
-
// 每个 entry: { steps: [], phase: 'active'|'completed', cardNode: null, args: {} }
|
|
14
|
-
|
|
15
|
-
var __cl_lastCallModel = null; // 同一 render cycle 里 call card 的 model(供 result card 读取 agent 身份)
|
|
16
|
-
var __cl_outputCardCache = new Map(); // toolCallId → cached output DOM
|
|
17
|
-
var __cl_executionCardCache = new Map(); // toolCallId → cached historical execution DOM
|
|
18
|
-
var __cl_cardUiStates = new Map(); // execution/output 展开状态,避免 OpenClaw rerender 覆盖用户操作
|
|
19
|
-
var __cl_progressMessageMap = new Map(); // toolCallId → 动态进度文字(来自 response.progress?.safe_status_message)
|
|
20
|
-
|
|
21
|
-
// ── 诊断:渲染频率计数器 ──
|
|
22
|
-
var __clDiag = { renderCalls: 0, lastDiagTs: 0, version: 'v4-oneshot-20260630' };
|
|
23
|
-
console.log('[cl-diag] render-hooks loaded, version=' + __clDiag.version);
|
|
24
|
-
|
|
25
|
-
var CL_REMOTE_AGENT_PROGRESS_MODE_TRAVEL_TITLE = 'travel-title';
|
|
26
|
-
var CL_REMOTE_AGENT_PROGRESS_MODE_GENERIC_STREAM = 'generic-stream';
|
|
27
|
-
var CL_TRAVEL_TITLE_AGENT_IDS = {
|
|
28
|
-
'82bc858c-5021-4bda-83bc-1badd7f49049': true
|
|
29
|
-
};
|
|
30
|
-
var CL_TRAVEL_TITLE_AGENT_NAMES = {
|
|
31
|
-
'旅游梦想家': true
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
window.__openagentOwnsToolCards = function(cards) {
|
|
35
|
-
if (!Array.isArray(cards)) return false;
|
|
36
|
-
for (var i = 0; i < cards.length; i++) {
|
|
37
|
-
var card = cards[i] || {};
|
|
38
|
-
var name = String(card.name || '').toLowerCase();
|
|
39
|
-
var tcid = card.toolCallId || '';
|
|
40
|
-
var kind = typeof _clInferToolCardKind === 'function' ? _clInferToolCardKind(card) : (card.kind || '');
|
|
41
|
-
if (name.includes('call_remote_agent') || name.includes('openagent_delegate')) {
|
|
42
|
-
return true;
|
|
43
|
-
}
|
|
44
|
-
if (kind === 'result' && tcid && __cl_lastCallModel && tcid === __cl_lastCallModel.tcid) {
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
return false;
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
// ═══════════════════════════════════════════════════════════════
|
|
52
|
-
// WS 流式事件处理器 — 只写 __cl_toolStates
|
|
53
|
-
// ═══════════════════════════════════════════════════════════════
|
|
54
|
-
|
|
55
|
-
window.__cl_handleStreamEvent = function(msg) {
|
|
56
|
-
if (!msg || msg.stream !== 'tool') return;
|
|
57
|
-
|
|
58
|
-
var d = msg.data || {};
|
|
59
|
-
var phase = d.phase;
|
|
60
|
-
var toolCallId = d.toolCallId || '';
|
|
61
|
-
if (!toolCallId) return;
|
|
62
|
-
|
|
63
|
-
// ── start ──
|
|
64
|
-
if (phase === 'start') {
|
|
65
|
-
var name = d.name || (d.call && d.call.name) || '';
|
|
66
|
-
if (!_cl_isRemoteToolEvent(d, null)) return;
|
|
67
|
-
|
|
68
|
-
var wsArgs = _cl_getStreamArgs(d);
|
|
69
|
-
var existingState = __cl_toolStates.get(toolCallId);
|
|
70
|
-
if (existingState) {
|
|
71
|
-
existingState.args = _cl_mergeArgs(existingState.args, wsArgs);
|
|
72
|
-
existingState.progressMode = _cl_getRemoteAgentProgressMode(existingState.args, existingState.progressMode);
|
|
73
|
-
if (existingState.thinkChunks && existingState.thinkChunks.length > 0) {
|
|
74
|
-
_cl_rebuildThinkStepsByAgentMode(existingState);
|
|
75
|
-
}
|
|
76
|
-
existingState.phase = 'active';
|
|
77
|
-
if (typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore) {
|
|
78
|
-
_clRemoteAgentProgressStore.recordStart(toolCallId, { name: name, args: existingState.args || wsArgs });
|
|
79
|
-
}
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
var state = _cl_createToolState(wsArgs);
|
|
84
|
-
__cl_toolStates.set(toolCallId, state);
|
|
85
|
-
if (typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore) {
|
|
86
|
-
_clRemoteAgentProgressStore.recordStart(toolCallId, { name: name, args: wsArgs });
|
|
87
|
-
}
|
|
88
|
-
console.log('[cl-stream] 🚀 start tcid=' + toolCallId.substring(0, 8));
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ── update ──
|
|
93
|
-
if (phase === 'update') {
|
|
94
|
-
var rawText = _cl_extractText(d.partialResult || d.content);
|
|
95
|
-
if (!rawText) return;
|
|
96
|
-
|
|
97
|
-
_cl_logRawSseUpdate(toolCallId, rawText);
|
|
98
|
-
|
|
99
|
-
var chunks = _cl_parseLiveUpdateChunks(rawText, { toolCallId: toolCallId, rawText: rawText });
|
|
100
|
-
if (!chunks.length) {
|
|
101
|
-
console.log('[cl-stream] update without think chunks tcid=' + toolCallId.substring(0, 8)
|
|
102
|
-
+ ' rawLen=' + rawText.length);
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
var state = _cl_ensureRemoteToolState(toolCallId, d, rawText);
|
|
107
|
-
if (!state) return;
|
|
108
|
-
|
|
109
|
-
var changed = false;
|
|
110
|
-
var lastChunk = null;
|
|
111
|
-
var wasCompleted = state.phase === 'completed';
|
|
112
|
-
for (var ci = 0; ci < chunks.length; ci++) {
|
|
113
|
-
var chunk = chunks[ci];
|
|
114
|
-
lastChunk = chunk;
|
|
115
|
-
|
|
116
|
-
// 正常流程只用内存 state 驱动 UI;store 只是旁路记录,避免影响直播路径。
|
|
117
|
-
if (_cl_applyThinkChunkToLiveState(state, chunk)) changed = true;
|
|
118
|
-
if (typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore) {
|
|
119
|
-
_clRemoteAgentProgressStore.recordChunk(toolCallId, chunk);
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
console.log('[cl-diag][step] tcid=' + toolCallId.substring(0, 8)
|
|
124
|
-
+ ' chunks=' + chunks.length
|
|
125
|
-
+ ' lastIndex=' + (lastChunk && lastChunk.index !== undefined ? lastChunk.index : '')
|
|
126
|
-
+ ' lastType=' + (lastChunk && lastChunk.thinkType || '')
|
|
127
|
-
+ ' changed=' + changed
|
|
128
|
-
+ ' steps=' + state.steps.length);
|
|
129
|
-
|
|
130
|
-
// 直接更新已渲染的 DOM(replay 进行中不直接更新,tick 会自然追上)
|
|
131
|
-
if (changed && state.cardNode && !state._replayActive) {
|
|
132
|
-
_cl_updateCardSteps(state.cardNode, state.steps);
|
|
133
|
-
if (wasCompleted) {
|
|
134
|
-
_cl_finalizeCard(state.cardNode, state.steps);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return;
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
// ── result ──
|
|
141
|
-
if (phase === 'result') {
|
|
142
|
-
var state = _cl_ensureRemoteToolState(toolCallId, d, null);
|
|
143
|
-
if (!state) return;
|
|
144
|
-
|
|
145
|
-
state.phase = 'completed';
|
|
146
|
-
if (typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore) {
|
|
147
|
-
_clRemoteAgentProgressStore.recordResult(toolCallId);
|
|
148
|
-
}
|
|
149
|
-
console.log('[cl-stream] ✅ result: steps=' + state.steps.length
|
|
150
|
-
+ ' tcid=' + toolCallId.substring(0, 8)
|
|
151
|
-
+ ' hasCard=' + !!state.cardNode
|
|
152
|
-
+ ' replayActive=' + !!state._replayActive);
|
|
153
|
-
|
|
154
|
-
// 如果 replay 未完成或 cardNode 未创建,延迟 finalize
|
|
155
|
-
if (state._replayActive || !state.cardNode) {
|
|
156
|
-
state.pendingFinalize = true;
|
|
157
|
-
console.log('[cl-playback] finalize deferred tcid=' + toolCallId.substring(0, 8));
|
|
158
|
-
} else {
|
|
159
|
-
_cl_finalizeCard(state.cardNode, state.steps);
|
|
160
|
-
console.log('[cl-playback] finalize now tcid=' + toolCallId.substring(0, 8));
|
|
161
|
-
}
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
function _cl_logRawSseUpdate(toolCallId, rawText) {
|
|
167
|
-
try {
|
|
168
|
-
if (!_cl_isRawSseDebugEnabled()) return;
|
|
169
|
-
var entry = {
|
|
170
|
-
ts: new Date().toISOString(),
|
|
171
|
-
toolCallId: toolCallId || '',
|
|
172
|
-
rawText: rawText || ''
|
|
173
|
-
};
|
|
174
|
-
window.__openagentRawSseLog = window.__openagentRawSseLog || [];
|
|
175
|
-
window.__openagentRawSseLog.push(entry);
|
|
176
|
-
if (window.__openagentRawSseLog.length > 200) {
|
|
177
|
-
window.__openagentRawSseLog.splice(0, window.__openagentRawSseLog.length - 200);
|
|
178
|
-
}
|
|
179
|
-
_cl_persistRawDebugLog('openagent.rawSseLog.v1', 'openagent-raw-sse-log', window.__openagentRawSseLog);
|
|
180
|
-
console.log('[cl-raw-sse] tcid=' + String(toolCallId || '').substring(0, 8) + ' raw=' + rawText);
|
|
181
|
-
} catch (err) {}
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
function _cl_isRawSseDebugEnabled() {
|
|
185
|
-
try {
|
|
186
|
-
return window.localStorage && window.localStorage.getItem('openagent.debug.rawSse') === '1';
|
|
187
|
-
} catch (err) {
|
|
188
|
-
return false;
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function _cl_persistRawDebugLog(storageKey, elementId, entries) {
|
|
193
|
-
try {
|
|
194
|
-
var json = JSON.stringify(entries || []);
|
|
195
|
-
try {
|
|
196
|
-
window.localStorage && window.localStorage.setItem(storageKey, json);
|
|
197
|
-
} catch (storageErr) {}
|
|
198
|
-
|
|
199
|
-
var doc = window.document;
|
|
200
|
-
if (!doc || !doc.body) return;
|
|
201
|
-
var node = doc.getElementById(elementId);
|
|
202
|
-
if (!node) {
|
|
203
|
-
node = doc.createElement('pre');
|
|
204
|
-
node.id = elementId;
|
|
205
|
-
node.style.display = 'none';
|
|
206
|
-
doc.body.appendChild(node);
|
|
207
|
-
}
|
|
208
|
-
node.textContent = json;
|
|
209
|
-
} catch (err) {}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
function _cl_isRemoteToolEvent(data, rawText) {
|
|
213
|
-
data = data || {};
|
|
214
|
-
var name = String(data.name || (data.call && data.call.name) || '').toLowerCase();
|
|
215
|
-
if (name.includes('call_remote_agent') || name.includes('openagent_delegate')) return true;
|
|
216
|
-
|
|
217
|
-
var args = _cl_getStreamArgs(data);
|
|
218
|
-
var agentId = args.agent_id || args.agentId || '';
|
|
219
|
-
var agentName = args.agent_name || args.agentName || '';
|
|
220
|
-
if (agentId || agentName) return true;
|
|
221
|
-
|
|
222
|
-
if (rawText && /openagent_call_remote_agent|openagent_delegate|call_remote_agent/.test(rawText)) return true;
|
|
223
|
-
if (rawText && rawText.indexOf('"dataType"') !== -1 && rawText.indexOf('"thinkType"') !== -1) return true;
|
|
224
|
-
if (rawText && rawText.indexOf('"dataType"') !== -1 && rawText.indexOf('"msgType"') !== -1) return true;
|
|
225
|
-
return false;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
function _cl_getStreamArgs(data) {
|
|
229
|
-
data = data || {};
|
|
230
|
-
return data.args || (data.call && (data.call.args || data.call.arguments)) || {};
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function _cl_mergeArgs(current, incoming) {
|
|
234
|
-
current = current && typeof current === 'object' ? current : {};
|
|
235
|
-
incoming = incoming && typeof incoming === 'object' ? incoming : {};
|
|
236
|
-
var merged = {};
|
|
237
|
-
var k;
|
|
238
|
-
for (k in current) {
|
|
239
|
-
if (Object.prototype.hasOwnProperty.call(current, k)) merged[k] = current[k];
|
|
240
|
-
}
|
|
241
|
-
for (k in incoming) {
|
|
242
|
-
if (Object.prototype.hasOwnProperty.call(incoming, k) && merged[k] === undefined) {
|
|
243
|
-
merged[k] = incoming[k];
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
return merged;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function _cl_getRemoteAgentProgressMode(args, currentMode) {
|
|
250
|
-
args = args && typeof args === 'object' ? args : {};
|
|
251
|
-
currentMode = currentMode || '';
|
|
252
|
-
|
|
253
|
-
var agentId = String(args.agent_id || args.agentId || '').trim();
|
|
254
|
-
var agentName = String(args.agent_name || args.agentName || '').trim();
|
|
255
|
-
|
|
256
|
-
if (agentId && CL_TRAVEL_TITLE_AGENT_IDS[agentId]) {
|
|
257
|
-
return CL_REMOTE_AGENT_PROGRESS_MODE_TRAVEL_TITLE;
|
|
258
|
-
}
|
|
259
|
-
if (agentName && CL_TRAVEL_TITLE_AGENT_NAMES[agentName]) {
|
|
260
|
-
return CL_REMOTE_AGENT_PROGRESS_MODE_TRAVEL_TITLE;
|
|
261
|
-
}
|
|
262
|
-
if (currentMode === CL_REMOTE_AGENT_PROGRESS_MODE_TRAVEL_TITLE) {
|
|
263
|
-
return currentMode;
|
|
264
|
-
}
|
|
265
|
-
return CL_REMOTE_AGENT_PROGRESS_MODE_GENERIC_STREAM;
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function _cl_createToolState(args) {
|
|
269
|
-
var normalizedArgs = args || {};
|
|
270
|
-
return {
|
|
271
|
-
steps: [],
|
|
272
|
-
phase: 'active',
|
|
273
|
-
progressMode: _cl_getRemoteAgentProgressMode(normalizedArgs, ''),
|
|
274
|
-
thinkChunks: [],
|
|
275
|
-
lastThinkType: '',
|
|
276
|
-
lastTitleIndex: -1,
|
|
277
|
-
seenChunkKeys: Object.create(null),
|
|
278
|
-
unindexedSeq: 0,
|
|
279
|
-
cardNode: null,
|
|
280
|
-
args: normalizedArgs,
|
|
281
|
-
// ── 播放控制 ──
|
|
282
|
-
_replayActive: false,
|
|
283
|
-
_replayTimer: null,
|
|
284
|
-
pendingFinalize: false
|
|
285
|
-
};
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
function _cl_ensureRemoteToolState(toolCallId, data, rawText) {
|
|
289
|
-
var state = __cl_toolStates.get(toolCallId);
|
|
290
|
-
if (state) {
|
|
291
|
-
state.args = _cl_mergeArgs(state.args, _cl_getStreamArgs(data));
|
|
292
|
-
state.progressMode = _cl_getRemoteAgentProgressMode(state.args, state.progressMode);
|
|
293
|
-
if (state.thinkChunks && state.thinkChunks.length > 0) {
|
|
294
|
-
_cl_rebuildThinkStepsByAgentMode(state);
|
|
295
|
-
}
|
|
296
|
-
return state;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (!_cl_isRemoteToolEvent(data, rawText)) return null;
|
|
300
|
-
|
|
301
|
-
var name = data && (data.name || (data.call && data.call.name)) || '';
|
|
302
|
-
var args = _cl_getStreamArgs(data);
|
|
303
|
-
state = _cl_createToolState(args);
|
|
304
|
-
__cl_toolStates.set(toolCallId, state);
|
|
305
|
-
|
|
306
|
-
if (typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore) {
|
|
307
|
-
_clRemoteAgentProgressStore.recordStart(toolCallId, { name: name, args: args });
|
|
308
|
-
}
|
|
309
|
-
console.log('[cl-stream] 🧩 recovered missing start tcid=' + toolCallId.substring(0, 8)
|
|
310
|
-
+ ' phase=' + ((data && data.phase) || ''));
|
|
311
|
-
return state;
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
// ═══════════════════════════════════════════════════════════════
|
|
315
|
-
// 渲染入口 — 只读 __cl_toolStates
|
|
316
|
-
// ═══════════════════════════════════════════════════════════════
|
|
317
|
-
|
|
318
|
-
window.__openagentRenderToolCard = function(card, onOpenSidebar) {
|
|
319
|
-
// ── 诊断:渲染频率计数器 ──
|
|
320
|
-
__clDiag.renderCalls++;
|
|
321
|
-
var diagNow = Date.now();
|
|
322
|
-
if (diagNow - __clDiag.lastDiagTs > 2000) {
|
|
323
|
-
var rps = (__clDiag.renderCalls / ((diagNow - __clDiag.lastDiagTs) / 1000)).toFixed(1);
|
|
324
|
-
console.log('[cl-diag] render rate: ' + rps + ' calls/sec, total=' + __clDiag.renderCalls + ', version=' + __clDiag.version);
|
|
325
|
-
__clDiag.renderCalls = 0;
|
|
326
|
-
__clDiag.lastDiagTs = diagNow;
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
var n = (card && card.name || '').toLowerCase();
|
|
330
|
-
var cardTcid = card && (card.toolCallId || '');
|
|
331
|
-
var cardKind = typeof _clInferToolCardKind === 'function' ? _clInferToolCardKind(card) : (card && card.kind || '');
|
|
332
|
-
var liveState = cardTcid ? __cl_toolStates.get(cardTcid) : null;
|
|
333
|
-
if (cardKind === 'result' && liveState && liveState.phase === 'active' && card && card.inputText) {
|
|
334
|
-
cardKind = 'call';
|
|
335
|
-
}
|
|
336
|
-
var isRemoteName = n.includes('call_remote_agent') || n.includes('openagent_delegate');
|
|
337
|
-
var isLinkedRemoteResult = card && cardKind === 'result' && cardTcid
|
|
338
|
-
&& __cl_lastCallModel && cardTcid === __cl_lastCallModel.tcid;
|
|
339
|
-
if (!isRemoteName && !isLinkedRemoteResult) return null;
|
|
340
|
-
|
|
341
|
-
// Phase 2: lazy 采样原生 ToolCard 尺寸变量
|
|
342
|
-
if (typeof _clEnsureNativeToolStyleVars === 'function') {
|
|
343
|
-
_clEnsureNativeToolStyleVars();
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
var model = _clParseToolCardModel(card);
|
|
347
|
-
|
|
348
|
-
try {
|
|
349
|
-
if (cardKind === 'call') {
|
|
350
|
-
var tcid = card.toolCallId || '';
|
|
351
|
-
var state = liveState || (tcid ? __cl_toolStates.get(tcid) : null);
|
|
352
|
-
|
|
353
|
-
// 保存 call card 的 model,供同一 message 的 result card 使用
|
|
354
|
-
__cl_lastCallModel = { tcid: tcid, agentId: model.agentId, agentName: model.agentName };
|
|
355
|
-
|
|
356
|
-
console.log('[cl-render] 🔍 call: tcid=' + tcid.substring(0, 8)
|
|
357
|
-
+ ' hasState=' + !!state
|
|
358
|
-
+ (state ? ' phase=' + state.phase + ' steps=' + state.steps.length + ' hasCard=' + !!state.cardNode : ''));
|
|
359
|
-
|
|
360
|
-
if (state) {
|
|
361
|
-
if (state.args) {
|
|
362
|
-
_cl_applyStoredRecordToModel(model, { args: state.args });
|
|
363
|
-
}
|
|
364
|
-
if (state.phase === 'active') {
|
|
365
|
-
model.status = 'executing';
|
|
366
|
-
if (typeof _clUpdateAgentStatusTextV2 === 'function' && state.cardNode && state.cardNode.classList.contains('cl-exec-v2')) {
|
|
367
|
-
_clUpdateAgentStatusTextV2(state.cardNode, 'executing');
|
|
368
|
-
} else if (typeof _clUpdateAgentStatusText === 'function') {
|
|
369
|
-
_clUpdateAgentStatusText(state.cardNode, 'executing');
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
// 有 streaming 状态 — 复用或新建
|
|
373
|
-
if (state.cardNode) {
|
|
374
|
-
// Lit 重复调用会复用同一个 DOM 节点;但 OpenClaw 外层 native
|
|
375
|
-
// <details> 可能被 rerender 成 closed。这里重新打开的是外层原生
|
|
376
|
-
// details,不影响卡片内部的”思考中/思考完成”折叠状态。
|
|
377
|
-
_cl_applyCardUiState(state.cardNode, { toolCallId: tcid, cardKind: 'call' });
|
|
378
|
-
if (state.phase === 'active') {
|
|
379
|
-
_cl_autoOpenStepsIfUncontrolled(state.cardNode);
|
|
380
|
-
}
|
|
381
|
-
// ── 更新进度文字:来自 response.progress?.safe_status_message ──
|
|
382
|
-
var progressEl = state.cardNode.querySelector('.cl-exec-progress-text');
|
|
383
|
-
if (progressEl && model.rawText) {
|
|
384
|
-
var msg = (model.rawText || '').trim();
|
|
385
|
-
if (msg) progressEl.textContent = msg;
|
|
386
|
-
}
|
|
387
|
-
// ── 一次性外壳初始化:首次渲染时打开 native details + 隐藏 raw text,之后永久跳过 ──
|
|
388
|
-
if (!state.cardNode.__clShellReady) {
|
|
389
|
-
state.cardNode.__clShellReady = true;
|
|
390
|
-
_cl_forceOpenNativeToolDetails(state.cardNode, 'execution-cache', tcid);
|
|
391
|
-
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(state.cardNode);
|
|
392
|
-
_cl_hideHostRawText(state.cardNode);
|
|
393
|
-
}
|
|
394
|
-
return state.cardNode;
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
// 首次渲染:创建卡片
|
|
398
|
-
model.toolCallId = tcid;
|
|
399
|
-
model.cardKind = 'call';
|
|
400
|
-
// 不直接灌 bufferedSteps,由 replay 逐条展示
|
|
401
|
-
model._bufferedSteps = [];
|
|
402
|
-
var node = _clRenderExecutionCard(model);
|
|
403
|
-
state.cardNode = node;
|
|
404
|
-
_cl_forceOpenNativeToolDetails(node, 'execution', tcid);
|
|
405
|
-
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(node);
|
|
406
|
-
_cl_hideHostRawText(node);
|
|
407
|
-
|
|
408
|
-
if (state.phase === 'completed') {
|
|
409
|
-
// result 已到 — 如果有积压步骤,replay 后 finalize
|
|
410
|
-
if (state.steps.length > 0) {
|
|
411
|
-
state.pendingFinalize = true;
|
|
412
|
-
_cl_replayBufferedSteps(tcid, state);
|
|
413
|
-
} else {
|
|
414
|
-
_cl_finalizeCard(node, state.steps);
|
|
415
|
-
}
|
|
416
|
-
console.log('[cl-render] 🆕 built completed card, tcid=' + tcid.substring(0, 8)
|
|
417
|
-
+ ' steps=' + state.steps.length);
|
|
418
|
-
} else {
|
|
419
|
-
// 仍在活跃 — replay 积压步骤(如有)
|
|
420
|
-
if (state.steps.length > 0) {
|
|
421
|
-
_cl_replayBufferedSteps(tcid, state);
|
|
422
|
-
}
|
|
423
|
-
console.log('[cl-render] 📥 bound active card, tcid=' + tcid.substring(0, 8)
|
|
424
|
-
+ ' buffered=' + state.steps.length);
|
|
425
|
-
}
|
|
426
|
-
return node;
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
// 无状态 → 刷新/历史态。前端 store 如果有同一 toolCallId 的卡片快照,
|
|
430
|
-
// 就用快照参数重建 steps;没有 store 时仍展示完成态外壳。
|
|
431
|
-
|
|
432
|
-
// 缓存:历史态 execution card 只创建一次,Lit 重复调用时复用(与 output card 逻辑一致)
|
|
433
|
-
var cachedExecution = tcid ? __cl_executionCardCache.get(tcid) : null;
|
|
434
|
-
if (cachedExecution && cachedExecution.isConnected) {
|
|
435
|
-
_cl_applyCardUiState(cachedExecution, { toolCallId: tcid, cardKind: 'call' });
|
|
436
|
-
if (!cachedExecution.__clShellReady) {
|
|
437
|
-
cachedExecution.__clShellReady = true;
|
|
438
|
-
_cl_forceOpenNativeToolDetails(cachedExecution, 'execution-history-cache', tcid);
|
|
439
|
-
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(cachedExecution);
|
|
440
|
-
_cl_hideHostRawText(cachedExecution);
|
|
441
|
-
}
|
|
442
|
-
return cachedExecution;
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
var storedCallRecord = tcid && typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore
|
|
446
|
-
? _clRemoteAgentProgressStore.get(tcid)
|
|
447
|
-
: null;
|
|
448
|
-
if (storedCallRecord) {
|
|
449
|
-
_cl_applyStoredRecordToModel(model, storedCallRecord);
|
|
450
|
-
model._bufferedSteps = _clRemoteAgentProgressStore.rebuildSteps(storedCallRecord);
|
|
451
|
-
console.log('[cl-store] restore call model tcid=' + tcid.substring(0, 8)
|
|
452
|
-
+ ' steps=' + model._bufferedSteps.length
|
|
453
|
-
+ ' agent=' + JSON.stringify(model.agentName));
|
|
454
|
-
} else {
|
|
455
|
-
console.log('[cl-store] historical call has no frontend progress record: tcid=' + tcid.substring(0, 8));
|
|
456
|
-
}
|
|
457
|
-
model.toolCallId = tcid;
|
|
458
|
-
model.cardKind = 'call';
|
|
459
|
-
model.status = 'completed';
|
|
460
|
-
var historyNode = _clRenderExecutionCard(model);
|
|
461
|
-
if (historyNode && historyNode.classList && historyNode.classList.contains('cl-exec-v2')) {
|
|
462
|
-
if (typeof _clUpdateAgentStatusTextV2 === 'function') _clUpdateAgentStatusTextV2(historyNode, 'completed');
|
|
463
|
-
} else if (typeof _clUpdateAgentStatusText === 'function') {
|
|
464
|
-
_clUpdateAgentStatusText(historyNode, 'completed');
|
|
465
|
-
}
|
|
466
|
-
_cl_finalizeCard(historyNode, model._bufferedSteps || []);
|
|
467
|
-
_cl_forceOpenNativeToolDetails(historyNode, 'execution-history', tcid);
|
|
468
|
-
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(historyNode);
|
|
469
|
-
_cl_hideHostRawText(historyNode);
|
|
470
|
-
if (tcid) __cl_executionCardCache.set(tcid, historyNode);
|
|
471
|
-
console.log('[cl-render] 🗂️ built historical call card, tcid=' + tcid.substring(0, 8));
|
|
472
|
-
return historyNode;
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
if (cardKind === 'result') {
|
|
476
|
-
var resTcid = card.toolCallId || '';
|
|
477
|
-
|
|
478
|
-
// 从 toolState 合并 agent 身份信息(live 场景)
|
|
479
|
-
var resState = resTcid ? __cl_toolStates.get(resTcid) : null;
|
|
480
|
-
if (resState && resState.args) {
|
|
481
|
-
var ra = resState.args;
|
|
482
|
-
if (!model.agentId && (ra.agent_id || ra.agentId)) {
|
|
483
|
-
model.agentId = ra.agent_id || ra.agentId;
|
|
484
|
-
}
|
|
485
|
-
if (model.agentName === 'Remote Agent') {
|
|
486
|
-
model.agentName = ra.agent_name || ra.agentName || model.agentName;
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
var storedResultRecord = resTcid && typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore
|
|
490
|
-
? _clRemoteAgentProgressStore.get(resTcid)
|
|
491
|
-
: null;
|
|
492
|
-
if (storedResultRecord) {
|
|
493
|
-
_cl_applyStoredRecordToModel(model, storedResultRecord);
|
|
494
|
-
console.log('[cl-store] apply result model tcid=' + resTcid.substring(0, 8)
|
|
495
|
-
+ ' agent=' + JSON.stringify(model.agentName));
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
// 从同一 message 的 call card 复制 agent 身份(历史场景 / WS 漏接)
|
|
499
|
-
// 仅当 toolCallId 匹配时才使用,防止跨消息串身份
|
|
500
|
-
if (model.agentName === 'Remote Agent' && __cl_lastCallModel
|
|
501
|
-
&& resTcid && resTcid === __cl_lastCallModel.tcid) {
|
|
502
|
-
model.agentId = model.agentId || __cl_lastCallModel.agentId;
|
|
503
|
-
model.agentName = __cl_lastCallModel.agentName || model.agentName;
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
var chunkCounts = _cl_countChunkTypes(model.chunks || []);
|
|
507
|
-
console.log('[cl-diag][result] render tcid=' + resTcid.substring(0, 8)
|
|
508
|
-
+ ' rawLen=' + ((model.rawText || '').length)
|
|
509
|
-
+ ' chunks=' + (model.chunks || []).length
|
|
510
|
-
+ ' steps=' + chunkCounts.step
|
|
511
|
-
+ ' text=' + chunkCounts.text
|
|
512
|
-
+ ' result=' + chunkCounts.result
|
|
513
|
-
+ ' hasState=' + !!resState
|
|
514
|
-
+ ' agent=' + JSON.stringify(model.agentName));
|
|
515
|
-
|
|
516
|
-
model.toolCallId = resTcid;
|
|
517
|
-
model.cardKind = 'result';
|
|
518
|
-
if (model.isError) {
|
|
519
|
-
var executionNodeForResult = (resState && resState.cardNode)
|
|
520
|
-
|| (resTcid ? __cl_executionCardCache.get(resTcid) : null);
|
|
521
|
-
if (executionNodeForResult && executionNodeForResult.classList && executionNodeForResult.classList.contains('cl-exec-v2')) {
|
|
522
|
-
if (typeof _clUpdateAgentStatusTextV2 === 'function') _clUpdateAgentStatusTextV2(executionNodeForResult, 'failed');
|
|
523
|
-
} else if (executionNodeForResult && typeof _clUpdateAgentStatusText === 'function') {
|
|
524
|
-
_clUpdateAgentStatusText(executionNodeForResult, 'failed');
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
// 缓存:同一 toolCallId 的 output card 只创建一次,Lit 重复调用时复用
|
|
529
|
-
var cachedOutput = resTcid ? __cl_outputCardCache.get(resTcid) : null;
|
|
530
|
-
if (cachedOutput && cachedOutput.isConnected) {
|
|
531
|
-
_cl_applyCardUiState(cachedOutput, { toolCallId: resTcid, cardKind: 'result' });
|
|
532
|
-
// ── 一次性外壳初始化:首次渲染时打开 native details + 隐藏 raw text,之后永久跳过 ──
|
|
533
|
-
if (!cachedOutput.__clShellReady) {
|
|
534
|
-
cachedOutput.__clShellReady = true;
|
|
535
|
-
_cl_forceOpenNativeToolDetails(cachedOutput, 'output-cache', resTcid);
|
|
536
|
-
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(cachedOutput);
|
|
537
|
-
_cl_hideHostRawText(cachedOutput);
|
|
538
|
-
}
|
|
539
|
-
return cachedOutput;
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
var outputNode = _clRenderOutputCard(model, onOpenSidebar);
|
|
543
|
-
if (!outputNode.__clEmptyOutput) {
|
|
544
|
-
_cl_forceOpenNativeToolDetails(outputNode, 'output', resTcid);
|
|
545
|
-
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(outputNode);
|
|
546
|
-
if (resTcid) {
|
|
547
|
-
__cl_outputCardCache.set(resTcid, outputNode);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
_cl_hideHostRawText(outputNode);
|
|
551
|
-
return outputNode;
|
|
552
|
-
}
|
|
553
|
-
} catch (err) {
|
|
554
|
-
console.error('[cl-render] 💥', err.message);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return null;
|
|
558
|
-
};
|
|
559
|
-
|
|
560
|
-
// ═══════════════════════════════════════════════════════════════
|
|
561
|
-
// Buffered Step Replay — cardNode 创建前积压的 steps 逐条展示
|
|
562
|
-
// ═══════════════════════════════════════════════════════════════
|
|
563
|
-
|
|
564
|
-
function _cl_replayBufferedSteps(toolCallId, state) {
|
|
565
|
-
if (!state || !state.cardNode || state._replayActive) return;
|
|
566
|
-
|
|
567
|
-
var totalSteps = state.steps.length;
|
|
568
|
-
if (totalSteps === 0) return;
|
|
569
|
-
|
|
570
|
-
state._replayActive = true;
|
|
571
|
-
var revealed = 0;
|
|
572
|
-
|
|
573
|
-
console.log('[cl-playback] start replay tcid=' + String(toolCallId || '').substring(0, 8)
|
|
574
|
-
+ ' steps=' + totalSteps);
|
|
575
|
-
|
|
576
|
-
function tick() {
|
|
577
|
-
state._replayTimer = null;
|
|
578
|
-
|
|
579
|
-
if (!state.cardNode) {
|
|
580
|
-
state._replayActive = false;
|
|
581
|
-
return;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
revealed++;
|
|
585
|
-
// 展示前 revealed 步(从 canonical state 切片)
|
|
586
|
-
var visibleSteps = state.steps.slice(0, revealed);
|
|
587
|
-
_cl_updateCardSteps(state.cardNode, visibleSteps);
|
|
588
|
-
|
|
589
|
-
console.log('[cl-playback] tick tcid=' + String(toolCallId || '').substring(0, 8)
|
|
590
|
-
+ ' revealed=' + revealed + '/' + state.steps.length);
|
|
591
|
-
|
|
592
|
-
if (revealed < state.steps.length) {
|
|
593
|
-
// 还有步骤未展示
|
|
594
|
-
state._replayTimer = setTimeout(tick, 120);
|
|
595
|
-
} else {
|
|
596
|
-
// 播放完毕
|
|
597
|
-
state._replayActive = false;
|
|
598
|
-
console.log('[cl-playback] done tcid=' + String(toolCallId || '').substring(0, 8)
|
|
599
|
-
+ ' steps=' + state.steps.length);
|
|
600
|
-
|
|
601
|
-
if (state.pendingFinalize) {
|
|
602
|
-
state.pendingFinalize = false;
|
|
603
|
-
_cl_finalizeCard(state.cardNode, state.steps);
|
|
604
|
-
console.log('[cl-playback] finalize after replay tcid=' + String(toolCallId || '').substring(0, 8));
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
}
|
|
608
|
-
|
|
609
|
-
// 第一步立即展示,后续逐条
|
|
610
|
-
tick();
|
|
611
|
-
}
|
|
612
|
-
|
|
613
|
-
// ═══════════════════════════════════════════════════════════════
|
|
614
|
-
// DOM 操作
|
|
615
|
-
// ═══════════════════════════════════════════════════════════════
|
|
616
|
-
|
|
617
|
-
// ── Phase A: 主动隐藏宿主 raw text ──
|
|
618
|
-
|
|
619
|
-
function _cl_hideHostRawText(cardNode) {
|
|
620
|
-
if (!cardNode) return;
|
|
621
|
-
// 幂等性守卫:如果父链已经标记为隐藏,跳过重复操作
|
|
622
|
-
if (cardNode.closest && cardNode.closest('.cl-remote-agent-raw-hidden')) return;
|
|
623
|
-
function hide() {
|
|
624
|
-
var hosts = _cl_collectRawTextHosts(cardNode);
|
|
625
|
-
for (var h = 0; h < hosts.length; h++) {
|
|
626
|
-
_cl_hideRawTextInHost(hosts[h]);
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
hide();
|
|
630
|
-
if (typeof requestAnimationFrame === 'function') requestAnimationFrame(hide);
|
|
631
|
-
setTimeout(hide, 0);
|
|
632
|
-
setTimeout(hide, 200);
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
function _cl_isRemoteToolNameText(text) {
|
|
636
|
-
var value = String(text || '').toLowerCase();
|
|
637
|
-
return value.indexOf('call_remote_agent') !== -1 || value.indexOf('openagent_delegate') !== -1;
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
function _cl_isRemoteRawTextContent(text) {
|
|
641
|
-
var value = String(text || '');
|
|
642
|
-
if (!value) return false;
|
|
643
|
-
if (/"msgType"\s*:/.test(value) && /"dataType"\s*:/.test(value)) return true;
|
|
644
|
-
if (/"itineraryId"\s*:/.test(value) && /"unitList"\s*:/.test(value)) return true;
|
|
645
|
-
if (/"dayList"\s*:/.test(value) && /"unitContexts"\s*:/.test(value)) return true;
|
|
646
|
-
if (/(?:<|<)(?:sh_card|tr_card|i_card|bg_card|fr_card|time_data_card)(?:>|>)/.test(value)) return true;
|
|
647
|
-
if (value.indexOf('[TRIP_CARDS_READY]') !== -1) return true;
|
|
648
|
-
return false;
|
|
649
|
-
}
|
|
650
|
-
|
|
651
|
-
function _cl_getHostAdapter() {
|
|
652
|
-
return (typeof CL !== 'undefined' && CL.hostAdapter) ? CL.hostAdapter : {};
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
function _cl_collectRawTextHosts(node) {
|
|
656
|
-
var hosts = [];
|
|
657
|
-
var adapter = _cl_getHostAdapter();
|
|
658
|
-
var selectors = adapter.selectors && adapter.selectors.rawTextHostClosest;
|
|
659
|
-
function add(host) {
|
|
660
|
-
if (!host || hosts.indexOf(host) !== -1) return;
|
|
661
|
-
hosts.push(host);
|
|
662
|
-
}
|
|
663
|
-
add(node.parentElement);
|
|
664
|
-
if (node.closest && Array.isArray(selectors)) {
|
|
665
|
-
for (var i = 0; i < selectors.length; i++) {
|
|
666
|
-
add(node.closest(selectors[i]));
|
|
667
|
-
}
|
|
668
|
-
}
|
|
669
|
-
return hosts;
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
function _cl_hideRawTextInHost(host) {
|
|
673
|
-
if (!host || !host.querySelectorAll) return;
|
|
674
|
-
var adapter = _cl_getHostAdapter();
|
|
675
|
-
host.classList.add('cl-remote-agent-raw-hidden');
|
|
676
|
-
if (adapter.isToolBody && adapter.isToolBody(host)) {
|
|
677
|
-
host.classList.add('cl-remote-agent-host-shell');
|
|
678
|
-
}
|
|
679
|
-
var texts = host.querySelectorAll(':scope > .chat-text');
|
|
680
|
-
for (var i = 0; i < texts.length; i++) {
|
|
681
|
-
texts[i].style.display = 'none';
|
|
682
|
-
texts[i].dataset.openagentRawHidden = '1';
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
function _cl_findRemoteNativeToolShell(node) {
|
|
687
|
-
var adapter = _cl_getHostAdapter();
|
|
688
|
-
var cur = node && (node.nodeType === 1 ? node : node.parentElement);
|
|
689
|
-
var hops = 0;
|
|
690
|
-
while (cur && cur !== document.body && hops < 12) {
|
|
691
|
-
if (adapter.isRemoteNativeToolShellCandidate && adapter.isRemoteNativeToolShellCandidate(cur)) {
|
|
692
|
-
if (_cl_isRemoteNativeToolShell(cur)) return cur;
|
|
693
|
-
}
|
|
694
|
-
cur = cur.parentElement;
|
|
695
|
-
hops++;
|
|
696
|
-
}
|
|
697
|
-
return null;
|
|
698
|
-
}
|
|
699
|
-
|
|
700
|
-
function _cl_isRemoteNativeToolShell(shell) {
|
|
701
|
-
if (!shell) return false;
|
|
702
|
-
var adapter = _cl_getHostAdapter();
|
|
703
|
-
var summarySelector = adapter.selectors && adapter.selectors.summary;
|
|
704
|
-
var summaryText = '';
|
|
705
|
-
var summary = shell.querySelector && summarySelector
|
|
706
|
-
? shell.querySelector(summarySelector)
|
|
707
|
-
: null;
|
|
708
|
-
if (summary) summaryText = summary.textContent || '';
|
|
709
|
-
if (_cl_isRemoteToolNameText(summaryText)) return true;
|
|
710
|
-
|
|
711
|
-
var ownText = shell.textContent || '';
|
|
712
|
-
// Limit the expensive fallback to the beginning of the host text so huge
|
|
713
|
-
// raw JSON payloads do not become a broad "contains" matcher.
|
|
714
|
-
return _cl_isRemoteToolNameText(ownText.slice(0, 800));
|
|
715
|
-
}
|
|
716
|
-
|
|
717
|
-
function _cl_tryHideRemoteRawTextNode(node) {
|
|
718
|
-
if (!node) return;
|
|
719
|
-
if (node.nodeType !== 1) {
|
|
720
|
-
node = node.parentElement;
|
|
721
|
-
}
|
|
722
|
-
if (!node || node.nodeType !== 1) return;
|
|
723
|
-
var textNodes = [];
|
|
724
|
-
if (node.matches && node.matches('.chat-text')) {
|
|
725
|
-
textNodes.push(node);
|
|
726
|
-
}
|
|
727
|
-
if (node.querySelectorAll) {
|
|
728
|
-
var found = node.querySelectorAll('.chat-text');
|
|
729
|
-
for (var i = 0; i < found.length; i++) textNodes.push(found[i]);
|
|
730
|
-
}
|
|
731
|
-
for (var j = 0; j < textNodes.length; j++) {
|
|
732
|
-
var textNode = textNodes[j];
|
|
733
|
-
var shell = _cl_findRemoteNativeToolShell(textNode);
|
|
734
|
-
if (!shell && _cl_isRemoteRawTextContent(textNode.textContent || '')) {
|
|
735
|
-
shell = _cl_findNearestToolLikeShell(textNode);
|
|
736
|
-
}
|
|
737
|
-
if (shell && _cl_isRemoteRawTextContent(textNode.textContent || '')) {
|
|
738
|
-
_cl_hideRawTextInHost(textNode.parentElement);
|
|
739
|
-
continue;
|
|
740
|
-
}
|
|
741
|
-
if (!shell) continue;
|
|
742
|
-
var host = textNode.parentElement;
|
|
743
|
-
_cl_hideRawTextInHost(host);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
var shell = _cl_findRemoteNativeToolShell(node);
|
|
747
|
-
if (shell && shell.querySelectorAll) {
|
|
748
|
-
var adapter = _cl_getHostAdapter();
|
|
749
|
-
var hostSelector = adapter.selectors && adapter.selectors.rawTextHostsWithinShell;
|
|
750
|
-
if (hostSelector) {
|
|
751
|
-
var hosts = shell.querySelectorAll(hostSelector);
|
|
752
|
-
for (var h = 0; h < hosts.length; h++) {
|
|
753
|
-
_cl_hideRawTextInHost(hosts[h]);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
function _cl_findNearestToolLikeShell(node) {
|
|
760
|
-
var adapter = _cl_getHostAdapter();
|
|
761
|
-
var cur = node && (node.nodeType === 1 ? node : node.parentElement);
|
|
762
|
-
var hops = 0;
|
|
763
|
-
while (cur && cur !== document.body && hops < 12) {
|
|
764
|
-
if (adapter.isToolLikeShell && adapter.isToolLikeShell(cur)) {
|
|
765
|
-
return cur;
|
|
766
|
-
}
|
|
767
|
-
cur = cur.parentElement;
|
|
768
|
-
hops++;
|
|
769
|
-
}
|
|
770
|
-
return null;
|
|
771
|
-
}
|
|
772
|
-
|
|
773
|
-
function _cl_installRemoteRawTextObserver() {
|
|
774
|
-
if (window.__clRemoteRawTextObserverInstalled) return;
|
|
775
|
-
if (!document.body) {
|
|
776
|
-
setTimeout(_cl_installRemoteRawTextObserver, 0);
|
|
777
|
-
if (document.addEventListener) {
|
|
778
|
-
document.addEventListener('DOMContentLoaded', _cl_installRemoteRawTextObserver, { once: true });
|
|
779
|
-
}
|
|
780
|
-
return;
|
|
781
|
-
}
|
|
782
|
-
window.__clRemoteRawTextObserverInstalled = true;
|
|
783
|
-
function scanExisting() {
|
|
784
|
-
if (!document.querySelectorAll) return;
|
|
785
|
-
var texts = document.querySelectorAll('.chat-text');
|
|
786
|
-
for (var i = 0; i < texts.length; i++) {
|
|
787
|
-
_cl_tryHideRemoteRawTextNode(texts[i]);
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
scanExisting();
|
|
791
|
-
if (typeof MutationObserver !== 'function' || !document.body) return;
|
|
792
|
-
var observer = new MutationObserver(function(records) {
|
|
793
|
-
for (var i = 0; i < records.length; i++) {
|
|
794
|
-
var record = records[i];
|
|
795
|
-
for (var j = 0; j < record.addedNodes.length; j++) {
|
|
796
|
-
var added = record.addedNodes[j];
|
|
797
|
-
_cl_tryHideRemoteRawTextNode(added.nodeType === 1 ? added : added.parentElement);
|
|
798
|
-
}
|
|
799
|
-
if (record.type === 'characterData') {
|
|
800
|
-
_cl_tryHideRemoteRawTextNode(record.target && record.target.parentElement);
|
|
801
|
-
}
|
|
802
|
-
}
|
|
803
|
-
});
|
|
804
|
-
observer.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
805
|
-
window.__clRemoteRawTextObserver = observer;
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
_cl_installRemoteRawTextObserver();
|
|
809
|
-
|
|
810
|
-
// ── 局部打开最近宿主 wrapper(不做全局扫描)──
|
|
811
|
-
|
|
812
|
-
function _cl_findNearestNativeToolShell(node) {
|
|
813
|
-
var adapter = _cl_getHostAdapter();
|
|
814
|
-
var cur = node && node.parentElement;
|
|
815
|
-
var hops = 0;
|
|
816
|
-
while (cur && cur !== document.body && hops < 10) {
|
|
817
|
-
if (adapter.isNativeToolShell && adapter.isNativeToolShell(cur)) {
|
|
818
|
-
return cur;
|
|
819
|
-
}
|
|
820
|
-
cur = cur.parentElement;
|
|
821
|
-
hops++;
|
|
822
|
-
}
|
|
823
|
-
return null;
|
|
824
|
-
}
|
|
825
|
-
|
|
826
|
-
function _cl_forceOpenNativeToolDetails(node, source, tcid) {
|
|
827
|
-
if (!node) return;
|
|
828
|
-
|
|
829
|
-
function openNearest() {
|
|
830
|
-
var shell = _cl_findNearestNativeToolShell(node);
|
|
831
|
-
if (!shell) return false;
|
|
832
|
-
|
|
833
|
-
if (shell.tagName && shell.tagName.toLowerCase() === 'details') {
|
|
834
|
-
if (!shell.open) {
|
|
835
|
-
shell.open = true;
|
|
836
|
-
shell.setAttribute('open', '');
|
|
837
|
-
console.log('[cl-render] 🔓 opened native details source=' + source
|
|
838
|
-
+ ' tcid=' + String(tcid || '').substring(0, 8));
|
|
839
|
-
}
|
|
840
|
-
return true;
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
if (shell.classList && !shell.classList.contains('is-open')) {
|
|
844
|
-
shell.classList.add('is-open');
|
|
845
|
-
var adapter = _cl_getHostAdapter();
|
|
846
|
-
var headerSelector = (adapter.selectors && adapter.selectors.forceOpenHeader) || '';
|
|
847
|
-
var header = headerSelector ? shell.querySelector(headerSelector) : null;
|
|
848
|
-
if (header) header.setAttribute('aria-expanded', 'true');
|
|
849
|
-
console.log('[cl-render] 🔓 opened native collapse source=' + source
|
|
850
|
-
+ ' tcid=' + String(tcid || '').substring(0, 8));
|
|
851
|
-
}
|
|
852
|
-
return true;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
// Lit 先拿 DOM node,稍后才插入 OpenClaw details body,所以需要延迟重试。
|
|
856
|
-
// openNearest 是幂等的(已 open 不重复操作),不需要防抖。
|
|
857
|
-
openNearest();
|
|
858
|
-
if (typeof requestAnimationFrame === 'function') requestAnimationFrame(openNearest);
|
|
859
|
-
setTimeout(openNearest, 300); // 兜底:慢速 Lit render / 异步 wrapper 挂载
|
|
860
|
-
}
|
|
861
|
-
|
|
862
|
-
function _cl_cardUiKey(modelOrNode) {
|
|
863
|
-
if (!modelOrNode) return '';
|
|
864
|
-
|
|
865
|
-
var tcid = '';
|
|
866
|
-
var kind = '';
|
|
867
|
-
|
|
868
|
-
if (modelOrNode.nodeType === 1) {
|
|
869
|
-
tcid = modelOrNode.dataset && (modelOrNode.dataset.clCardTcid || '');
|
|
870
|
-
kind = modelOrNode.dataset && (modelOrNode.dataset.clCardSource || '');
|
|
871
|
-
} else {
|
|
872
|
-
tcid = modelOrNode.toolCallId || modelOrNode.tcid || '';
|
|
873
|
-
kind = modelOrNode.cardKind || modelOrNode.kind || '';
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
if (!tcid) return '';
|
|
877
|
-
if (kind === 'call') kind = 'execution';
|
|
878
|
-
if (kind === 'result') kind = 'output';
|
|
879
|
-
if (!kind) kind = 'card';
|
|
880
|
-
return kind + ':' + tcid;
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
function _cl_getCardUiState(modelOrNode) {
|
|
884
|
-
var key = _cl_cardUiKey(modelOrNode);
|
|
885
|
-
if (!key) return null;
|
|
886
|
-
return __cl_cardUiStates.get(key) || null;
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
function _cl_setCardUiState(modelOrNode, patch) {
|
|
890
|
-
var key = _cl_cardUiKey(modelOrNode);
|
|
891
|
-
if (!key || !patch) return;
|
|
892
|
-
|
|
893
|
-
var current = __cl_cardUiStates.get(key) || {};
|
|
894
|
-
var next = {};
|
|
895
|
-
for (var k in current) {
|
|
896
|
-
if (Object.prototype.hasOwnProperty.call(current, k)) next[k] = current[k];
|
|
897
|
-
}
|
|
898
|
-
for (var p in patch) {
|
|
899
|
-
if (Object.prototype.hasOwnProperty.call(patch, p)) next[p] = patch[p];
|
|
900
|
-
}
|
|
901
|
-
__cl_cardUiStates.set(key, next);
|
|
902
|
-
console.log('[cl-ui-state] save key=' + key
|
|
903
|
-
+ ' contentCollapsed=' + (next.contentCollapsed === undefined ? '' : next.contentCollapsed)
|
|
904
|
-
+ ' stepsExpanded=' + (next.stepsExpanded === undefined ? '' : next.stepsExpanded));
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
function _cl_applyCardUiState(container, modelOrNode) {
|
|
908
|
-
if (!container) return;
|
|
909
|
-
|
|
910
|
-
var state = _cl_getCardUiState(modelOrNode || container);
|
|
911
|
-
if (!state) return;
|
|
912
|
-
|
|
913
|
-
var content = container.querySelector('.cl-thought-chain-content');
|
|
914
|
-
var caret = container.querySelector('.cl-openagent-header-caret');
|
|
915
|
-
if (content && state.contentCollapsed !== undefined) {
|
|
916
|
-
if (state.contentCollapsed) {
|
|
917
|
-
content.classList.add('cl-content-collapsed');
|
|
918
|
-
if (caret) caret.textContent = '▶';
|
|
919
|
-
} else {
|
|
920
|
-
content.classList.remove('cl-content-collapsed');
|
|
921
|
-
if (caret) caret.textContent = '▼';
|
|
922
|
-
}
|
|
923
|
-
if (typeof _clSyncOutputFooterVisibility === 'function') {
|
|
924
|
-
_clSyncOutputFooterVisibility(container, state.contentCollapsed);
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
var body = container.querySelector('.cl-tools-collapse-body');
|
|
929
|
-
var stepIcon = container.querySelector('.cl-tools-collapse-header-icon');
|
|
930
|
-
if (body && state.stepsExpanded !== undefined) {
|
|
931
|
-
if (state.stepsExpanded) {
|
|
932
|
-
body.classList.remove('cl-collapsed');
|
|
933
|
-
body.classList.add('cl-expanded');
|
|
934
|
-
if (stepIcon) stepIcon.classList.remove('cl-collapsed');
|
|
935
|
-
} else {
|
|
936
|
-
body.classList.remove('cl-expanded');
|
|
937
|
-
body.classList.add('cl-collapsed');
|
|
938
|
-
if (stepIcon) stepIcon.classList.add('cl-collapsed');
|
|
939
|
-
}
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
|
|
943
|
-
function _cl_applyStoredRecordToModel(model, record) {
|
|
944
|
-
if (!model || !record) return;
|
|
945
|
-
var args = record.args || {};
|
|
946
|
-
if (!model.agentId && (args.agent_id || args.agentId)) {
|
|
947
|
-
model.agentId = args.agent_id || args.agentId;
|
|
948
|
-
}
|
|
949
|
-
if (model.agentName === 'Remote Agent' || !model.agentName) {
|
|
950
|
-
model.agentName = args.agent_name || args.agentName || model.agentId || 'Remote Agent';
|
|
951
|
-
}
|
|
952
|
-
if (!model.agentAvatar) {
|
|
953
|
-
model.agentAvatar = args.agent_avatar || args.agentAvatar || args.avatar || args.avatar_url || args.avatarUrl || null;
|
|
954
|
-
}
|
|
955
|
-
if (!model.agentBio) {
|
|
956
|
-
model.agentBio = typeof _clPickAgentDescription === 'function'
|
|
957
|
-
? _clPickAgentDescription(args)
|
|
958
|
-
: (args.agent_bio || args.agentBio || args.description || args.agent_description || args.MOM || '');
|
|
959
|
-
}
|
|
960
|
-
if (!model.agentStars) {
|
|
961
|
-
model.agentStars = args.agent_stars || args.agentStars || '3.2万';
|
|
962
|
-
}
|
|
963
|
-
var identity = CL && typeof CL.getAgentIdentity === 'function'
|
|
964
|
-
? CL.getAgentIdentity(model.agentId, model.agentName)
|
|
965
|
-
: null;
|
|
966
|
-
if (identity) {
|
|
967
|
-
model.agentId = model.agentId || identity.id || identity.agent_id;
|
|
968
|
-
model.agentName = (model.agentName && model.agentName !== 'Remote Agent') ? model.agentName : (identity.name || model.agentName);
|
|
969
|
-
model.agentAvatar = model.agentAvatar || identity.avatar || null;
|
|
970
|
-
if (!model.agentBio) {
|
|
971
|
-
model.agentBio = typeof _clPickAgentDescription === 'function'
|
|
972
|
-
? _clPickAgentDescription(identity)
|
|
973
|
-
: (identity.bio || identity.description || identity.agent_bio || identity.agentBio || identity.MOM || '');
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
model.taskText = model.taskText || args.task || args.message || args.instruction || '';
|
|
977
|
-
}
|
|
978
|
-
|
|
979
|
-
function _cl_applyThinkChunkToLiveState(state, chunk) {
|
|
980
|
-
if (!state || !chunk || chunk.dataType !== 'think') return false;
|
|
981
|
-
|
|
982
|
-
if (chunk._clProgressStep) {
|
|
983
|
-
var beforeProgressSig = _cl_stepsSignature(state.steps);
|
|
984
|
-
var stepIndex = Number(chunk.stepIndex);
|
|
985
|
-
if (!Number.isFinite(stepIndex) || stepIndex < 0) return false;
|
|
986
|
-
stepIndex = Math.floor(stepIndex);
|
|
987
|
-
|
|
988
|
-
if (chunk._clTripProgressRoot) {
|
|
989
|
-
state.steps = _cl_pruneGenericProgressSteps(state.steps);
|
|
990
|
-
stepIndex = 0;
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
while (state.steps.length <= stepIndex) {
|
|
994
|
-
state.steps.push({ title: '', detail: '' });
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
var progressStep = state.steps[stepIndex];
|
|
998
|
-
var progressTitle = _cl_normalizeStepTitle(chunk.text || '');
|
|
999
|
-
var progressChanged = false;
|
|
1000
|
-
|
|
1001
|
-
if (progressTitle && progressStep.title !== progressTitle) {
|
|
1002
|
-
progressStep.title = progressTitle;
|
|
1003
|
-
progressChanged = true;
|
|
1004
|
-
}
|
|
1005
|
-
if (progressStep.detail) progressStep.detail = '';
|
|
1006
|
-
|
|
1007
|
-
state.steps = _cl_compactThoughtSteps(state.steps);
|
|
1008
|
-
var afterProgressSig = _cl_stepsSignature(state.steps);
|
|
1009
|
-
if (!_cl_isGenericProgressTitle(progressTitle)) {
|
|
1010
|
-
state.lastThinkType = 'progress-step';
|
|
1011
|
-
}
|
|
1012
|
-
return progressChanged || beforeProgressSig !== afterProgressSig;
|
|
1013
|
-
}
|
|
1014
|
-
|
|
1015
|
-
var key = _cl_getLiveChunkKey(state, chunk);
|
|
1016
|
-
if (key && state.seenChunkKeys && state.seenChunkKeys[key]) {
|
|
1017
|
-
return false;
|
|
1018
|
-
}
|
|
1019
|
-
if (key) {
|
|
1020
|
-
if (!state.seenChunkKeys) state.seenChunkKeys = Object.create(null);
|
|
1021
|
-
state.seenChunkKeys[key] = true;
|
|
1022
|
-
}
|
|
1023
|
-
|
|
1024
|
-
var type = chunk.thinkType || '';
|
|
1025
|
-
var changed = _cl_applyThinkChunkByAgentMode(state, chunk);
|
|
1026
|
-
state.lastThinkType = type;
|
|
1027
|
-
return changed;
|
|
1028
|
-
}
|
|
1029
|
-
|
|
1030
|
-
function _cl_applyThinkChunkByAgentMode(target, chunk) {
|
|
1031
|
-
if (!target || !chunk || chunk.dataType !== 'think') return false;
|
|
1032
|
-
|
|
1033
|
-
var beforeSig = _cl_stepsSignature(target.steps);
|
|
1034
|
-
_cl_storeThinkChunk(target, chunk);
|
|
1035
|
-
_cl_rebuildThinkStepsByAgentMode(target);
|
|
1036
|
-
|
|
1037
|
-
return beforeSig !== _cl_stepsSignature(target.steps);
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
function _cl_rebuildThinkStepsByAgentMode(target) {
|
|
1041
|
-
if (!target) return;
|
|
1042
|
-
target.progressMode = _cl_getRemoteAgentProgressMode(target.args, target.progressMode);
|
|
1043
|
-
if (target.progressMode === CL_REMOTE_AGENT_PROGRESS_MODE_TRAVEL_TITLE) {
|
|
1044
|
-
target.steps = _cl_rebuildTravelTitleSteps(target.thinkChunks || []);
|
|
1045
|
-
} else {
|
|
1046
|
-
target.steps = _cl_rebuildGenericStreamSteps(target.thinkChunks || []);
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
|
|
1050
|
-
function _cl_storeThinkChunk(target, chunk) {
|
|
1051
|
-
if (!target.thinkChunks) target.thinkChunks = [];
|
|
1052
|
-
|
|
1053
|
-
var text = typeof chunk.text === 'string' ? chunk.text : '';
|
|
1054
|
-
var item = {
|
|
1055
|
-
dataType: chunk.dataType,
|
|
1056
|
-
thinkType: chunk.thinkType || '',
|
|
1057
|
-
text: text,
|
|
1058
|
-
index: chunk.index,
|
|
1059
|
-
_clPlainTextUpdate: !!chunk._clPlainTextUpdate,
|
|
1060
|
-
_clLiveUpdateFallback: !!chunk._clLiveUpdateFallback,
|
|
1061
|
-
_clSeq: target.unindexedSeq || 0
|
|
1062
|
-
};
|
|
1063
|
-
target.unindexedSeq = (target.unindexedSeq || 0) + 1;
|
|
1064
|
-
|
|
1065
|
-
var idx = _cl_getChunkIndex(item);
|
|
1066
|
-
if (idx >= 0) {
|
|
1067
|
-
for (var i = 0; i < target.thinkChunks.length; i++) {
|
|
1068
|
-
var existing = target.thinkChunks[i];
|
|
1069
|
-
if (!existing || _cl_getChunkIndex(existing) !== idx || (existing.thinkType || '') !== item.thinkType) {
|
|
1070
|
-
continue;
|
|
1071
|
-
}
|
|
1072
|
-
var existingText = typeof existing.text === 'string' ? existing.text : '';
|
|
1073
|
-
if (item.text && existingText && item.text.indexOf(existingText) === 0) {
|
|
1074
|
-
existing.text = item.text;
|
|
1075
|
-
existing._clSeq = item._clSeq;
|
|
1076
|
-
return;
|
|
1077
|
-
}
|
|
1078
|
-
if (existingText && item.text && existingText.indexOf(item.text) === 0) {
|
|
1079
|
-
return;
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
|
|
1084
|
-
target.thinkChunks.push(item);
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
function _cl_sortThinkChunks(chunks) {
|
|
1088
|
-
var sorted = (chunks || []).slice();
|
|
1089
|
-
sorted.sort(function(a, b) {
|
|
1090
|
-
var ai = _cl_getChunkIndex(a);
|
|
1091
|
-
var bi = _cl_getChunkIndex(b);
|
|
1092
|
-
if (ai >= 0 && bi >= 0 && ai !== bi) return ai - bi;
|
|
1093
|
-
if (ai >= 0 && bi < 0) return -1;
|
|
1094
|
-
if (ai < 0 && bi >= 0) return 1;
|
|
1095
|
-
return ((a && a._clSeq) || 0) - ((b && b._clSeq) || 0);
|
|
1096
|
-
});
|
|
1097
|
-
return sorted;
|
|
1098
|
-
}
|
|
1099
|
-
|
|
1100
|
-
function _cl_rebuildTravelTitleSteps(chunks) {
|
|
1101
|
-
var sorted = _cl_sortThinkChunks(chunks);
|
|
1102
|
-
var steps = [];
|
|
1103
|
-
var pendingTitle = '';
|
|
1104
|
-
|
|
1105
|
-
function flushPending() {
|
|
1106
|
-
var title = _cl_normalizeStepTitle(pendingTitle);
|
|
1107
|
-
if (title) steps.push({ title: title, detail: '' });
|
|
1108
|
-
pendingTitle = '';
|
|
1109
|
-
}
|
|
1110
|
-
|
|
1111
|
-
for (var i = 0; i < sorted.length; i++) {
|
|
1112
|
-
var chunk = sorted[i] || {};
|
|
1113
|
-
var type = chunk.thinkType || '';
|
|
1114
|
-
var text = _cl_normalizeStepTitle(chunk.text || '');
|
|
1115
|
-
|
|
1116
|
-
if (type === 'title') {
|
|
1117
|
-
if (text) pendingTitle = _cl_mergeStepTitle(pendingTitle, text);
|
|
1118
|
-
continue;
|
|
1119
|
-
}
|
|
1120
|
-
|
|
1121
|
-
// 旅游梦想家的 content 是 title 之间的过程说明,只作为 title 分组边界。
|
|
1122
|
-
flushPending();
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
flushPending();
|
|
1126
|
-
return _cl_compactThoughtSteps(steps);
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
function _cl_rebuildGenericStreamSteps(chunks) {
|
|
1130
|
-
var sorted = _cl_sortThinkChunks(chunks);
|
|
1131
|
-
var text = '';
|
|
1132
|
-
var shortPlainSteps = [];
|
|
1133
|
-
var allShortPlain = sorted.length > 0 && sorted.length <= 20;
|
|
1134
|
-
var hasFallbackUpdates = false;
|
|
1135
|
-
|
|
1136
|
-
for (var i = 0; i < sorted.length; i++) {
|
|
1137
|
-
var chunk = sorted[i] || {};
|
|
1138
|
-
var part = typeof chunk.text === 'string' ? chunk.text : '';
|
|
1139
|
-
if (!part) continue;
|
|
1140
|
-
var normalizedPart = _cl_normalizeStepTitle(part);
|
|
1141
|
-
if (chunk._clLiveUpdateFallback) {
|
|
1142
|
-
hasFallbackUpdates = true;
|
|
1143
|
-
}
|
|
1144
|
-
if (!chunk._clPlainTextUpdate || !normalizedPart || normalizedPart.length > 20) {
|
|
1145
|
-
allShortPlain = false;
|
|
1146
|
-
} else if (shortPlainSteps.length === 0 || shortPlainSteps[shortPlainSteps.length - 1].title !== normalizedPart) {
|
|
1147
|
-
shortPlainSteps.push({ title: normalizedPart, detail: '' });
|
|
1148
|
-
}
|
|
1149
|
-
text = _cl_mergeStepTitle(text, part);
|
|
1150
|
-
}
|
|
1151
|
-
|
|
1152
|
-
if (hasFallbackUpdates) {
|
|
1153
|
-
return _cl_rebuildFallbackUpdateSteps(sorted);
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
if (allShortPlain && shortPlainSteps.length > 0) {
|
|
1157
|
-
return shortPlainSteps;
|
|
1158
|
-
}
|
|
1159
|
-
|
|
1160
|
-
text = _cl_normalizeStepTitle(text);
|
|
1161
|
-
return text ? [{ title: text, detail: '' }] : [];
|
|
1162
|
-
}
|
|
1163
|
-
|
|
1164
|
-
function _cl_rebuildFallbackUpdateSteps(chunks) {
|
|
1165
|
-
var steps = [];
|
|
1166
|
-
for (var i = 0; i < chunks.length; i++) {
|
|
1167
|
-
var chunk = chunks[i] || {};
|
|
1168
|
-
var parts = _cl_splitKnownFallbackStatusLine(chunk.text || '');
|
|
1169
|
-
for (var j = 0; j < parts.length; j++) {
|
|
1170
|
-
var part = _cl_normalizeStepTitle(parts[j] || '');
|
|
1171
|
-
if (!part) continue;
|
|
1172
|
-
if (steps.length > 0 && steps[steps.length - 1].title === part) continue;
|
|
1173
|
-
steps.push({ title: part, detail: '', _clKeepSeparate: true });
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
return steps;
|
|
1177
|
-
}
|
|
1178
|
-
|
|
1179
|
-
function _cl_getLiveChunkKey(state, chunk) {
|
|
1180
|
-
if (chunk && chunk._clProgressStep) {
|
|
1181
|
-
return 'p:' + String(chunk.stepIndex) + ':' + (chunk.text || '') + ':' + (chunk.detail || '');
|
|
1182
|
-
}
|
|
1183
|
-
if (chunk && Object.prototype.hasOwnProperty.call(chunk, 'index')
|
|
1184
|
-
&& chunk.index !== null && chunk.index !== undefined && chunk.index !== '') {
|
|
1185
|
-
// 去重 key 包含完整内容:同 index 不同 text 是累计更新,不应跳过
|
|
1186
|
-
return 'i:' + String(chunk.index) + ':' + (chunk.thinkType || '') + ':' + (chunk.text || '');
|
|
1187
|
-
}
|
|
1188
|
-
return 'u:' + (chunk.thinkType || '') + ':' + (chunk.text || '');
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
function _cl_getChunkIndex(chunk) {
|
|
1192
|
-
if (!chunk || chunk.index === null || chunk.index === undefined || chunk.index === '') return -1;
|
|
1193
|
-
var n = Number(chunk.index);
|
|
1194
|
-
if (!Number.isFinite(n) || n < 0) return -1;
|
|
1195
|
-
return Math.floor(n);
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
function _cl_normalizeStepTitle(text) {
|
|
1199
|
-
return String(text || '').replace(/[\u2705\u2611\uFE0F\u2714\uFE0F]/g, '').trim();
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
function _cl_stepsSignature(steps) {
|
|
1203
|
-
if (!Array.isArray(steps) || steps.length === 0) return '';
|
|
1204
|
-
return steps.map(function(step) {
|
|
1205
|
-
return _cl_normalizeStepTitle(step && step.title || '');
|
|
1206
|
-
}).join('|');
|
|
1207
|
-
}
|
|
1208
|
-
|
|
1209
|
-
function _cl_isGenericProgressTitle(title) {
|
|
1210
|
-
title = _cl_normalizeStepTitle(title);
|
|
1211
|
-
if (!title) return true;
|
|
1212
|
-
var genericTitles = {
|
|
1213
|
-
'正在整理行程卡片': true,
|
|
1214
|
-
'远端 Agent 已开始生成': true,
|
|
1215
|
-
'远端 Agent 正在回复': true,
|
|
1216
|
-
'远端 Agent 正在思考': true,
|
|
1217
|
-
'远端 Agent 正在生成回复': true,
|
|
1218
|
-
'正在生成回复内容': true,
|
|
1219
|
-
'远端 Agent 已完成结果生成': true
|
|
1220
|
-
};
|
|
1221
|
-
return !!genericTitles[title];
|
|
1222
|
-
}
|
|
1223
|
-
|
|
1224
|
-
function _cl_isShortTitleFragment(title) {
|
|
1225
|
-
title = _cl_normalizeStepTitle(title).replace(/\s+/g, '');
|
|
1226
|
-
if (!title) return false;
|
|
1227
|
-
if (_cl_normalizeKnownTitlePhrase(title) !== title) return false;
|
|
1228
|
-
if (title.indexOf('查找') !== -1
|
|
1229
|
-
&& (title.indexOf('目的地') !== -1 || title.indexOf('信息') !== -1)
|
|
1230
|
-
&& !(title.indexOf('目的地') !== -1 && title.indexOf('信息') !== -1)
|
|
1231
|
-
&& title.length <= 6) {
|
|
1232
|
-
return true;
|
|
1233
|
-
}
|
|
1234
|
-
return title.length <= 3;
|
|
1235
|
-
}
|
|
1236
|
-
|
|
1237
|
-
function _cl_shouldMergeStepTitle(current, incoming) {
|
|
1238
|
-
current = _cl_normalizeStepTitle(current);
|
|
1239
|
-
incoming = _cl_normalizeStepTitle(incoming);
|
|
1240
|
-
if (!current || !incoming) return false;
|
|
1241
|
-
if (incoming.length > current.length && incoming.indexOf(current) === 0) return true;
|
|
1242
|
-
return _cl_isShortTitleFragment(current) && _cl_isShortTitleFragment(incoming);
|
|
1243
|
-
}
|
|
1244
|
-
|
|
1245
|
-
function _cl_normalizeKnownTitlePhrase(title) {
|
|
1246
|
-
var compact = _cl_normalizeStepTitle(title).replace(/\s+/g, '');
|
|
1247
|
-
if (!compact) return '';
|
|
1248
|
-
|
|
1249
|
-
// 远端有时会把同一个 title 拆成乱序短片段:查找 / 信息 / 目的地。
|
|
1250
|
-
// UI 只展示 title 时,需要把这个产品语义还原成一句话。
|
|
1251
|
-
if (compact.indexOf('了解') !== -1
|
|
1252
|
-
&& compact.indexOf('你的') !== -1
|
|
1253
|
-
&& compact.indexOf('需求') !== -1
|
|
1254
|
-
&& compact.length <= 6) {
|
|
1255
|
-
return '了解你的需求';
|
|
1256
|
-
}
|
|
1257
|
-
|
|
1258
|
-
if (compact.indexOf('查找') !== -1
|
|
1259
|
-
&& compact.indexOf('目的地') !== -1
|
|
1260
|
-
&& compact.indexOf('信息') !== -1
|
|
1261
|
-
&& compact.length <= 8) {
|
|
1262
|
-
return '查找目的地信息';
|
|
1263
|
-
}
|
|
1264
|
-
|
|
1265
|
-
return compact;
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
function _cl_compactThoughtSteps(steps) {
|
|
1269
|
-
if (!Array.isArray(steps) || steps.length === 0) return [];
|
|
1270
|
-
|
|
1271
|
-
var compacted = [];
|
|
1272
|
-
var pendingTitle = '';
|
|
1273
|
-
|
|
1274
|
-
function flushPending() {
|
|
1275
|
-
var normalized = _cl_normalizeKnownTitlePhrase(pendingTitle);
|
|
1276
|
-
if (normalized) compacted.push({ title: normalized, detail: '' });
|
|
1277
|
-
pendingTitle = '';
|
|
1278
|
-
}
|
|
1279
|
-
|
|
1280
|
-
for (var i = 0; i < steps.length; i++) {
|
|
1281
|
-
var title = _cl_normalizeStepTitle(steps[i] && steps[i].title || '');
|
|
1282
|
-
if (!title || _cl_isGenericProgressTitle(title)) continue;
|
|
1283
|
-
|
|
1284
|
-
if (steps[i] && steps[i]._clKeepSeparate) {
|
|
1285
|
-
flushPending();
|
|
1286
|
-
compacted.push({ title: title, detail: steps[i].detail || '', _clKeepSeparate: true });
|
|
1287
|
-
continue;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
var knownTitle = _cl_normalizeKnownTitlePhrase(title);
|
|
1291
|
-
if (knownTitle && knownTitle !== title) {
|
|
1292
|
-
flushPending();
|
|
1293
|
-
compacted.push({ title: knownTitle, detail: '' });
|
|
1294
|
-
continue;
|
|
1295
|
-
}
|
|
1296
|
-
|
|
1297
|
-
if (_cl_isShortTitleFragment(title)) {
|
|
1298
|
-
pendingTitle = _cl_mergeStepTitle(pendingTitle, title);
|
|
1299
|
-
continue;
|
|
1300
|
-
}
|
|
1301
|
-
|
|
1302
|
-
flushPending();
|
|
1303
|
-
compacted.push({ title: title, detail: '' });
|
|
1304
|
-
}
|
|
1305
|
-
|
|
1306
|
-
flushPending();
|
|
1307
|
-
return compacted;
|
|
1308
|
-
}
|
|
1309
|
-
|
|
1310
|
-
function _cl_pruneGenericProgressSteps(steps) {
|
|
1311
|
-
if (!Array.isArray(steps) || steps.length === 0) return [];
|
|
1312
|
-
return steps.filter(function(step) {
|
|
1313
|
-
var title = _cl_normalizeStepTitle(step && step.title || '');
|
|
1314
|
-
return !_cl_isGenericProgressTitle(title);
|
|
1315
|
-
});
|
|
1316
|
-
}
|
|
1317
|
-
|
|
1318
|
-
function _cl_mergeStepTitle(current, incoming) {
|
|
1319
|
-
current = current || '';
|
|
1320
|
-
incoming = incoming || '';
|
|
1321
|
-
if (!incoming) return current;
|
|
1322
|
-
if (!current) return incoming;
|
|
1323
|
-
if (incoming.length > current.length && incoming.indexOf(current) === 0) return incoming;
|
|
1324
|
-
|
|
1325
|
-
var maxOverlap = Math.min(current.length, incoming.length);
|
|
1326
|
-
for (var len = maxOverlap; len > 0; len--) {
|
|
1327
|
-
if (current.slice(current.length - len) === incoming.slice(0, len)) {
|
|
1328
|
-
return current + incoming.slice(len);
|
|
1329
|
-
}
|
|
1330
|
-
}
|
|
1331
|
-
return current + incoming;
|
|
1332
|
-
}
|
|
1333
|
-
|
|
1334
|
-
function _cl_updateCardSteps(card, steps) {
|
|
1335
|
-
var body = card.querySelector('.cl-tools-collapse-body');
|
|
1336
|
-
var header = card.querySelector('.cl-tools-collapse-header-title');
|
|
1337
|
-
if (!body || !header) return;
|
|
1338
|
-
|
|
1339
|
-
steps = _cl_compactThoughtSteps(steps || []);
|
|
1340
|
-
|
|
1341
|
-
header.textContent = '思考中...';
|
|
1342
|
-
|
|
1343
|
-
// 默认产品行为:SSE 传输时步骤应自动展开展示。
|
|
1344
|
-
// 只有用户明确点过“思考中/思考完成”后,才尊重用户保存的折叠状态。
|
|
1345
|
-
_cl_autoOpenStepsIfUncontrolled(card);
|
|
1346
|
-
|
|
1347
|
-
var existing = body.querySelectorAll('.cl-tools-collapse-step');
|
|
1348
|
-
|
|
1349
|
-
// 已存在步骤可能继续收到 title/content token,逐个刷新文本和详情。
|
|
1350
|
-
var updateCount = Math.min(existing.length, steps.length);
|
|
1351
|
-
for (var ei = 0; ei < updateCount; ei++) {
|
|
1352
|
-
_cl_updateStepElement(existing[ei], steps[ei], ei === steps.length - 1);
|
|
1353
|
-
}
|
|
1354
|
-
|
|
1355
|
-
// 合并/过滤后 steps 可能变少,旧 DOM 行必须删除,否则页面会残留错误断句。
|
|
1356
|
-
for (var ri = existing.length - 1; ri >= steps.length; ri--) {
|
|
1357
|
-
existing[ri].remove();
|
|
1358
|
-
}
|
|
1359
|
-
existing = body.querySelectorAll('.cl-tools-collapse-step');
|
|
1360
|
-
|
|
1361
|
-
// 差量添加新步骤
|
|
1362
|
-
for (var i = existing.length; i < steps.length; i++) {
|
|
1363
|
-
if (i > 0) {
|
|
1364
|
-
var prev = body.querySelectorAll('.cl-tools-collapse-step')[i - 1];
|
|
1365
|
-
if (prev) {
|
|
1366
|
-
var prevDot = prev.querySelector('.cl-tools-collapse-step-dot');
|
|
1367
|
-
if (prevDot) prevDot.className = 'cl-tools-collapse-step-check';
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
var stepEl = _clCreateStepElement(steps[i], i === steps.length - 1);
|
|
1371
|
-
body.appendChild(stepEl);
|
|
1372
|
-
}
|
|
1373
|
-
}
|
|
1374
|
-
|
|
1375
|
-
function _cl_autoOpenStepsIfUncontrolled(card) {
|
|
1376
|
-
if (!card) return;
|
|
1377
|
-
var uiState = _cl_getCardUiState(card);
|
|
1378
|
-
if (uiState && uiState.stepsExpanded !== undefined) return;
|
|
1379
|
-
|
|
1380
|
-
// 缓存 body 引用,避免 5-16Hz Lit rerender 时重复 querySelector
|
|
1381
|
-
if (!card.__clStepsBody) {
|
|
1382
|
-
card.__clStepsBody = card.querySelector('.cl-tools-collapse-body');
|
|
1383
|
-
}
|
|
1384
|
-
var body = card.__clStepsBody;
|
|
1385
|
-
if (!body) return;
|
|
1386
|
-
|
|
1387
|
-
body.classList.remove('cl-collapsed');
|
|
1388
|
-
body.classList.add('cl-expanded');
|
|
1389
|
-
|
|
1390
|
-
var headerIcon = card.querySelector('.cl-tools-collapse-header-icon');
|
|
1391
|
-
if (headerIcon) headerIcon.classList.remove('cl-collapsed');
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
function _cl_updateStepElement(stepEl, step, isLatest) {
|
|
1395
|
-
if (!stepEl || !step) return;
|
|
1396
|
-
|
|
1397
|
-
var titleEl = stepEl.querySelector('.cl-tools-collapse-step-title');
|
|
1398
|
-
if (titleEl) {
|
|
1399
|
-
titleEl.textContent = (step.title || '').replace(/[\u2705\u2611\uFE0F\u2714\uFE0F]/g, '').trim();
|
|
1400
|
-
}
|
|
1401
|
-
var detailEl = stepEl.querySelector('.cl-tools-collapse-step-detail');
|
|
1402
|
-
if (detailEl) {
|
|
1403
|
-
detailEl.remove();
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
|
-
var iconWrap = stepEl.querySelector('.cl-tools-collapse-step-icon');
|
|
1407
|
-
if (iconWrap) {
|
|
1408
|
-
var activeDot = iconWrap.querySelector('.cl-tools-collapse-step-dot');
|
|
1409
|
-
var check = iconWrap.querySelector('.cl-tools-collapse-step-check');
|
|
1410
|
-
if (isLatest) {
|
|
1411
|
-
if (check) {
|
|
1412
|
-
iconWrap.innerHTML = '';
|
|
1413
|
-
var dot = document.createElement('div');
|
|
1414
|
-
dot.className = 'cl-tools-collapse-step-dot cl-active';
|
|
1415
|
-
iconWrap.appendChild(dot);
|
|
1416
|
-
} else if (activeDot) {
|
|
1417
|
-
activeDot.className = 'cl-tools-collapse-step-dot cl-active';
|
|
1418
|
-
}
|
|
1419
|
-
} else if (activeDot) {
|
|
1420
|
-
iconWrap.innerHTML = '';
|
|
1421
|
-
var done = document.createElement('div');
|
|
1422
|
-
done.className = 'cl-tools-collapse-step-check';
|
|
1423
|
-
iconWrap.appendChild(done);
|
|
1424
|
-
}
|
|
1425
|
-
}
|
|
1426
|
-
}
|
|
1427
|
-
|
|
1428
|
-
function _cl_countChunkTypes(chunks) {
|
|
1429
|
-
var counts = { step: 0, text: 0, result: 0, content: 0, error: 0, data: 0, other: 0 };
|
|
1430
|
-
for (var i = 0; i < chunks.length; i++) {
|
|
1431
|
-
var type = chunks[i] && chunks[i].type;
|
|
1432
|
-
if (Object.prototype.hasOwnProperty.call(counts, type)) counts[type]++;
|
|
1433
|
-
else counts.other++;
|
|
1434
|
-
}
|
|
1435
|
-
return counts;
|
|
1436
|
-
}
|
|
1437
|
-
|
|
1438
|
-
function _cl_finalizeCard(card, steps) {
|
|
1439
|
-
if (card && card.classList && card.classList.contains('cl-exec-v2')) {
|
|
1440
|
-
if (typeof _clUpdateAgentStatusTextV2 === 'function') _clUpdateAgentStatusTextV2(card, 'completed');
|
|
1441
|
-
} else if (typeof _clUpdateAgentStatusText === 'function') {
|
|
1442
|
-
_clUpdateAgentStatusText(card, 'completed');
|
|
1443
|
-
}
|
|
1444
|
-
var header = card.querySelector('.cl-tools-collapse-header-title');
|
|
1445
|
-
if (header) {
|
|
1446
|
-
header.textContent = '思考完成';
|
|
1447
|
-
}
|
|
1448
|
-
|
|
1449
|
-
var dots = card.querySelectorAll('.cl-tools-collapse-step-dot');
|
|
1450
|
-
for (var i = 0; i < dots.length; i++) {
|
|
1451
|
-
dots[i].className = 'cl-tools-collapse-step-check';
|
|
1452
|
-
}
|
|
1453
|
-
|
|
1454
|
-
// 执行完成后隐藏第一个 chat-bubble(execution card),仅保留 output card
|
|
1455
|
-
// 仅 V2 启用:V1 的 output card 布局不同,不宜隐藏 execution bubble
|
|
1456
|
-
var isV2Finalize = typeof _clIsHostVersionGte === 'function' && _clIsHostVersionGte('2026.6.9');
|
|
1457
|
-
if (isV2Finalize && card && !card.__clBubbleHidden) {
|
|
1458
|
-
card.__clBubbleHidden = true;
|
|
1459
|
-
var bubble = card.closest && card.closest('.chat-bubble');
|
|
1460
|
-
if (bubble) {
|
|
1461
|
-
// 延迟隐藏,等 output card(第二个 bubble)渲染完毕
|
|
1462
|
-
setTimeout(function() {
|
|
1463
|
-
bubble.style.display = 'none';
|
|
1464
|
-
}, 500);
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
// Finalize 只负责把 execution card 标记为完成态。
|
|
1469
|
-
// 不在这里强制折叠 steps:OpenClaw 会周期性 rerender,若 finalize 每次都
|
|
1470
|
-
// 写 cl-collapsed,会覆盖用户手动展开后的状态。
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
// ═══════════════════════════════════════════════════════════════
|
|
1474
|
-
// 解析
|
|
1475
|
-
// ═══════════════════════════════════════════════════════════════
|
|
1476
|
-
|
|
1477
|
-
function _cl_extractText(value) {
|
|
1478
|
-
if (typeof value === 'string') return value;
|
|
1479
|
-
if (!value) return '';
|
|
1480
|
-
if (Array.isArray(value.content)) {
|
|
1481
|
-
return value.content
|
|
1482
|
-
.filter(function(c) { return c.type === 'text'; })
|
|
1483
|
-
.map(function(c) { return c.text || ''; })
|
|
1484
|
-
.join('\n');
|
|
1485
|
-
}
|
|
1486
|
-
if (typeof value.text === 'string') return value.text;
|
|
1487
|
-
try { return JSON.stringify(value, null, 2); } catch(e) { return String(value); }
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
function _cl_parseThinkChunks(rawText, scope) {
|
|
1491
|
-
var chunks = [];
|
|
1492
|
-
if (!rawText || typeof rawText !== 'string') return chunks;
|
|
1493
|
-
var lines = rawText.trim().split('\n');
|
|
1494
|
-
for (var i = 0; i < lines.length; i++) {
|
|
1495
|
-
var line = lines[i].trim();
|
|
1496
|
-
if (!line) continue;
|
|
1497
|
-
try {
|
|
1498
|
-
var obj = JSON.parse(line);
|
|
1499
|
-
_cl_ingestTripCardData(obj, scope);
|
|
1500
|
-
if (obj && obj.dataType === 'think') chunks.push(obj);
|
|
1501
|
-
} catch (e) {}
|
|
1502
|
-
}
|
|
1503
|
-
return chunks;
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
function _cl_parseLiveUpdateChunks(rawText, scope) {
|
|
1507
|
-
_cl_ingestLiveUpdateData(rawText, scope);
|
|
1508
|
-
var chunks = _cl_parseThinkChunks(rawText, scope);
|
|
1509
|
-
if (chunks.length > 0) return chunks;
|
|
1510
|
-
return _cl_extractLiveUpdateFallbackChunks(rawText);
|
|
1511
|
-
}
|
|
1512
|
-
|
|
1513
|
-
function _cl_extractLiveUpdateFallbackChunks(rawText) {
|
|
1514
|
-
var value = String(rawText || '').trim();
|
|
1515
|
-
if (!value) return [];
|
|
1516
|
-
|
|
1517
|
-
var parts = value.split(/\r?\n/).map(function(line) {
|
|
1518
|
-
return String(line || '').trim();
|
|
1519
|
-
}).filter(Boolean);
|
|
1520
|
-
if (parts.length === 0) parts = [value];
|
|
1521
|
-
|
|
1522
|
-
var chunks = [];
|
|
1523
|
-
for (var i = 0; i < parts.length; i++) {
|
|
1524
|
-
var splitParts = _cl_splitKnownFallbackStatusLine(parts[i]);
|
|
1525
|
-
for (var j = 0; j < splitParts.length; j++) {
|
|
1526
|
-
var text = splitParts[j];
|
|
1527
|
-
if (!text) continue;
|
|
1528
|
-
chunks.push({
|
|
1529
|
-
dataType: 'think',
|
|
1530
|
-
thinkType: 'content',
|
|
1531
|
-
text: text,
|
|
1532
|
-
_clPlainTextUpdate: _cl_isPlainLiveUpdateText(text),
|
|
1533
|
-
_clLiveUpdateFallback: true
|
|
1534
|
-
});
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
return chunks;
|
|
1538
|
-
}
|
|
1539
|
-
|
|
1540
|
-
function _cl_splitKnownFallbackStatusLine(line) {
|
|
1541
|
-
line = String(line || '').trim();
|
|
1542
|
-
if (!line) return [];
|
|
1543
|
-
|
|
1544
|
-
var compact = line.replace(/\s+/g, '');
|
|
1545
|
-
var statuses = ['已提交', '生成中', '已完成'];
|
|
1546
|
-
var rest = compact;
|
|
1547
|
-
var pieces = [];
|
|
1548
|
-
|
|
1549
|
-
while (rest) {
|
|
1550
|
-
var matched = '';
|
|
1551
|
-
for (var i = 0; i < statuses.length; i++) {
|
|
1552
|
-
if (rest.indexOf(statuses[i]) === 0) {
|
|
1553
|
-
matched = statuses[i];
|
|
1554
|
-
break;
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
if (!matched) return [line];
|
|
1558
|
-
pieces.push(matched);
|
|
1559
|
-
rest = rest.slice(matched.length);
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
return pieces.length > 1 ? pieces : [line];
|
|
1563
|
-
}
|
|
1564
|
-
|
|
1565
|
-
function _cl_isPlainLiveUpdateText(value) {
|
|
1566
|
-
value = String(value || '').trim();
|
|
1567
|
-
if (!value) return false;
|
|
1568
|
-
return value.charAt(0) !== '{' && value.charAt(0) !== '[';
|
|
1569
|
-
}
|
|
1570
|
-
|
|
1571
|
-
function _cl_ingestLiveUpdateData(rawText, scope) {
|
|
1572
|
-
if (!rawText || typeof rawText !== 'string') return;
|
|
1573
|
-
var lines = rawText.trim().split('\n');
|
|
1574
|
-
for (var i = 0; i < lines.length; i++) {
|
|
1575
|
-
var line = lines[i].trim();
|
|
1576
|
-
if (!line) continue;
|
|
1577
|
-
try {
|
|
1578
|
-
var obj = JSON.parse(line);
|
|
1579
|
-
if (obj && typeof obj === 'object') _cl_ingestTripCardData(obj, scope);
|
|
1580
|
-
} catch (e) {}
|
|
1581
|
-
}
|
|
1582
|
-
}
|
|
1583
|
-
|
|
1584
|
-
function _cl_ingestTripCardData(obj, scope) {
|
|
1585
|
-
if (!obj || typeof obj !== 'object') return;
|
|
1586
|
-
|
|
1587
|
-
function ensureTripCardData() {
|
|
1588
|
-
if (CL && typeof CL.ensureTripCardData === 'function') {
|
|
1589
|
-
return CL.ensureTripCardData();
|
|
1590
|
-
}
|
|
1591
|
-
if (!CL.tripCardData) {
|
|
1592
|
-
CL.tripCardData = { unitContexts: {}, dayList: [], foodData: null, budgetData: null };
|
|
1593
|
-
}
|
|
1594
|
-
if (!CL.tripCardData.unitContexts) CL.tripCardData.unitContexts = {};
|
|
1595
|
-
if (!Array.isArray(CL.tripCardData.dayList)) CL.tripCardData.dayList = [];
|
|
1596
|
-
return CL.tripCardData;
|
|
1597
|
-
}
|
|
1598
|
-
|
|
1599
|
-
function mergeTripCardData(data) {
|
|
1600
|
-
if (!data || typeof data !== 'object') return false;
|
|
1601
|
-
if (CL && typeof CL.mergeTripCardData === 'function') {
|
|
1602
|
-
return CL.mergeTripCardData(data, { replaceDayList: true, scope: scope });
|
|
1603
|
-
}
|
|
1604
|
-
|
|
1605
|
-
var changed = false;
|
|
1606
|
-
var target = ensureTripCardData();
|
|
1607
|
-
|
|
1608
|
-
if (data.unitContexts && typeof data.unitContexts === 'object') {
|
|
1609
|
-
var ids = Object.keys(data.unitContexts);
|
|
1610
|
-
for (var i = 0; i < ids.length; i++) {
|
|
1611
|
-
target.unitContexts[ids[i]] = data.unitContexts[ids[i]];
|
|
1612
|
-
}
|
|
1613
|
-
if (ids.length > 0) changed = true;
|
|
1614
|
-
}
|
|
1615
|
-
|
|
1616
|
-
if (data.unitContext && data.unitContext.id) {
|
|
1617
|
-
target.unitContexts[data.unitContext.id] = data.unitContext;
|
|
1618
|
-
changed = true;
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
if (Array.isArray(data.dayList)) {
|
|
1622
|
-
target.dayList = data.dayList;
|
|
1623
|
-
changed = true;
|
|
1624
|
-
}
|
|
1625
|
-
|
|
1626
|
-
if (data.foodData) {
|
|
1627
|
-
target.foodData = data.foodData;
|
|
1628
|
-
changed = true;
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
|
-
var incomingBudget = data.budgetData
|
|
1632
|
-
|| data.budget
|
|
1633
|
-
|| (data.result && (data.result.budgetData || data.result.budget));
|
|
1634
|
-
if (incomingBudget) {
|
|
1635
|
-
target.budgetData = incomingBudget;
|
|
1636
|
-
changed = true;
|
|
1637
|
-
}
|
|
1638
|
-
|
|
1639
|
-
return changed;
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
function persistTripCardData() {
|
|
1643
|
-
try {
|
|
1644
|
-
if (CL && CL.tripCardData) {
|
|
1645
|
-
localStorage.setItem('openagent_tripCardData', JSON.stringify(CL.tripCardData));
|
|
1646
|
-
}
|
|
1647
|
-
} catch (e) {}
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
var changed = false;
|
|
1651
|
-
|
|
1652
|
-
if (obj.fullJson && typeof obj.fullJson === 'string') {
|
|
1653
|
-
try {
|
|
1654
|
-
var parsedData = JSON.parse(obj.fullJson);
|
|
1655
|
-
changed = mergeTripCardData(parsedData) || changed;
|
|
1656
|
-
} catch (e) {}
|
|
1657
|
-
} else if (obj.fullJson && typeof obj.fullJson === 'object') {
|
|
1658
|
-
changed = mergeTripCardData(obj.fullJson) || changed;
|
|
1659
|
-
}
|
|
1660
|
-
|
|
1661
|
-
if (obj.tripCardData && typeof obj.tripCardData === 'object') {
|
|
1662
|
-
changed = mergeTripCardData(obj.tripCardData) || changed;
|
|
1663
|
-
}
|
|
1664
|
-
|
|
1665
|
-
if (obj.itineraryVersionInfo && typeof obj.itineraryVersionInfo === 'object') {
|
|
1666
|
-
changed = mergeTripCardData(obj.itineraryVersionInfo) || changed;
|
|
1667
|
-
}
|
|
1668
|
-
|
|
1669
|
-
if (obj.itinerary && typeof obj.itinerary === 'object') {
|
|
1670
|
-
changed = mergeTripCardData(obj.itinerary) || changed;
|
|
1671
|
-
}
|
|
1672
|
-
|
|
1673
|
-
var nestedFields = ['data', 'text', 'content', 'result', 'output'];
|
|
1674
|
-
for (var fi = 0; fi < nestedFields.length; fi++) {
|
|
1675
|
-
var nested = obj[nestedFields[fi]];
|
|
1676
|
-
if (!nested) continue;
|
|
1677
|
-
if (typeof nested === 'object') {
|
|
1678
|
-
changed = mergeTripCardData(nested) || changed;
|
|
1679
|
-
continue;
|
|
1680
|
-
}
|
|
1681
|
-
if (typeof nested === 'string'
|
|
1682
|
-
&& nested.charAt(0) === '{'
|
|
1683
|
-
&& /"unitContexts"|"dayList"|"foodData"|"budgetData"|"budget"/.test(nested)) {
|
|
1684
|
-
try {
|
|
1685
|
-
changed = mergeTripCardData(JSON.parse(nested)) || changed;
|
|
1686
|
-
} catch (e) {}
|
|
1687
|
-
}
|
|
1688
|
-
}
|
|
1689
|
-
|
|
1690
|
-
changed = mergeTripCardData(obj) || changed;
|
|
1691
|
-
|
|
1692
|
-
if (changed) {
|
|
1693
|
-
CL.tripCardDataFetchFailed = false;
|
|
1694
|
-
persistTripCardData();
|
|
1695
|
-
}
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
console.log('[openagent] ✅ render hook v2 registered');
|