openclaw-openagent 1.0.0
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/index.ts +114 -0
- package/openclaw.plugin.json +159 -0
- package/package.json +79 -0
- package/skills/clawlink/SKILL.md +145 -0
- package/skills/clawlink/SKILL.md.bak +165 -0
- package/src/app/channel-tools.ts +249 -0
- package/src/app/discovery-tools.ts +273 -0
- package/src/app/hooks.ts +60 -0
- package/src/app/index.ts +78 -0
- package/src/app/messaging-tools.ts +79 -0
- package/src/app/ops-tools.ts +155 -0
- package/src/app/remote-agent-tool.ts +476 -0
- package/src/app/types.ts +67 -0
- package/src/app/verbose-preflight.ts +190 -0
- package/src/auth/config.ts +197 -0
- package/src/auth/credential-manager.ts +146 -0
- package/src/auth/index.ts +24 -0
- package/src/auth/verify.ts +99 -0
- package/src/channel.ts +565 -0
- package/src/compat.ts +82 -0
- package/src/config/config-schema.ts +39 -0
- package/src/messaging/aggregator.ts +120 -0
- package/src/messaging/collector.ts +89 -0
- package/src/messaging/executor.ts +72 -0
- package/src/messaging/inbound.ts +150 -0
- package/src/messaging/index.ts +11 -0
- package/src/messaging/mention-protocol.ts +94 -0
- package/src/messaging/process-c2c-request.ts +564 -0
- package/src/messaging/process-message.ts +373 -0
- package/src/messaging/scheduler.ts +55 -0
- package/src/messaging/types.ts +38 -0
- package/src/plugin-ui/assets/agentbook-icon.svg +5 -0
- package/src/plugin-ui/assets/magic.svg +5 -0
- package/src/plugin-ui/assets/openagent-override.js +9329 -0
- package/src/plugin-ui/build.cjs +175 -0
- package/src/plugin-ui/index.ts +18 -0
- package/src/plugin-ui/modules/agent-book/panel/agent-book.js +458 -0
- package/src/plugin-ui/modules/agent-book/panel/agent-card.js +154 -0
- package/src/plugin-ui/modules/agent-book/panel/agent-data.js +644 -0
- package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +456 -0
- package/src/plugin-ui/modules/agent-book/panel/mention-state.js +206 -0
- package/src/plugin-ui/modules/agent-book/panel/styles.js +670 -0
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +293 -0
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +208 -0
- package/src/plugin-ui/modules/agent-book/scanner.js +119 -0
- package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +500 -0
- package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +652 -0
- package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +251 -0
- package/src/plugin-ui/modules/loader/bootstrap.js +38 -0
- package/src/plugin-ui/modules/loader/shared-state.js +560 -0
- package/src/plugin-ui/modules/loader/ws-intercept.js +199 -0
- package/src/plugin-ui/modules/remote-agent/chunk-parser.js +161 -0
- package/src/plugin-ui/modules/remote-agent/execution-card.js +269 -0
- package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +256 -0
- package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +146 -0
- package/src/plugin-ui/modules/remote-agent/output-card.js +259 -0
- package/src/plugin-ui/modules/remote-agent/progress-store.js +363 -0
- package/src/plugin-ui/modules/remote-agent/render-hooks.js +1609 -0
- package/src/plugin-ui/modules/remote-agent/styles.js +668 -0
- package/src/plugin-ui/modules/remote-agent/tool-card-model.js +56 -0
- package/src/plugin-ui/ui-extension-loader/backup.ts +92 -0
- package/src/plugin-ui/ui-extension-loader/index.ts +276 -0
- package/src/plugin-ui/ui-extension-loader/locator.ts +152 -0
- package/src/plugin-ui/ui-extension-loader/manifest.ts +57 -0
- package/src/plugin-ui/ui-extension-loader/registry-regex.ts +729 -0
- package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +70 -0
- package/src/plugin-ui/ui-extension-loader/types.ts +68 -0
- package/src/proxy/auth-proxy.ts +356 -0
- package/src/runtime/account.ts +572 -0
- package/src/runtime/index.ts +7 -0
- package/src/runtime/plugin-runtime.ts +94 -0
- package/src/runtime/registry.ts +71 -0
- package/src/sdk/CLASS_MAP.md +143 -0
- package/src/sdk/index.d.ts +126 -0
- package/src/sdk/index.js +23990 -0
- package/src/sdk/modules/cloud-search-module.js +1117 -0
- package/src/sdk/modules/follow-module.js +1069 -0
- package/src/sdk/modules/group-module.js +7397 -0
- package/src/sdk/modules/relationship-module.js +2269 -0
- package/src/sdk/modules/signaling-module.js +1468 -0
- package/src/sdk/modules/tim-upload-plugin.js +730 -0
- package/src/sdk/node-env/http-request.js +90 -0
- package/src/sdk/node-env/index.js +57 -0
- package/src/sdk/node-env/storage.js +114 -0
- package/src/sdk/package.json +10 -0
- package/src/sdk/tsconfig.json +16 -0
- package/src/state/pending-invocation-store.ts +43 -0
- package/src/state/store.ts +676 -0
- package/src/tim/c2c.ts +451 -0
- package/src/tim/channels.ts +364 -0
- package/src/tim/client.ts +330 -0
- package/src/tim/index.ts +18 -0
- package/src/tim/messages.ts +166 -0
- package/src/tim/sdk-logger-init.ts +50 -0
- package/src/tools.ts +10 -0
- package/src/transport/factory.ts +95 -0
- package/src/transport/oasn/index.ts +17 -0
- package/src/transport/oasn/oasn-agent-card.ts +111 -0
- package/src/transport/oasn/oasn-discovery.ts +108 -0
- package/src/transport/oasn/oasn-files.ts +210 -0
- package/src/transport/oasn/oasn-http.ts +483 -0
- package/src/transport/oasn/oasn-invocation.ts +527 -0
- package/src/transport/oasn/oasn-normalize.ts +159 -0
- package/src/transport/oasn/oasn-register.ts +106 -0
- package/src/transport/oasn/oasn-transport.ts +341 -0
- package/src/transport/oasn/oasn-types.ts +353 -0
- package/src/transport/tim/index.ts +8 -0
- package/src/transport/tim/tim-transport.ts +515 -0
- package/src/transport/types.ts +541 -0
- package/src/types/openclaw.d.ts +97 -0
- package/src/types/tencentcloud-chat.d.ts +15 -0
- package/src/util/http.ts +113 -0
- package/src/util/logger.ts +131 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// ══════════════════════════════════════════════════════════════
|
|
2
|
+
// 方案 A: WebSocket 构造函数拦截(主力)
|
|
3
|
+
// 直接给每个 WS 实例加 message listener,不依赖 JSON.parse
|
|
4
|
+
// ══════════════════════════════════════════════════════════════
|
|
5
|
+
const _OrigWebSocket = window.WebSocket;
|
|
6
|
+
window.WebSocket = function(url, protocols) {
|
|
7
|
+
const ws = protocols !== undefined
|
|
8
|
+
? new _OrigWebSocket(url, protocols)
|
|
9
|
+
: new _OrigWebSocket(url);
|
|
10
|
+
|
|
11
|
+
ws.addEventListener('message', function(event) {
|
|
12
|
+
try {
|
|
13
|
+
const raw = String(event.data || '');
|
|
14
|
+
const msg = JSON.parse(raw);
|
|
15
|
+
if (!msg || typeof msg !== 'object') return;
|
|
16
|
+
|
|
17
|
+
const p = _extractToolStreamPayload(msg);
|
|
18
|
+
if (p) {
|
|
19
|
+
if (_isRawToolStreamDebugEnabled()) {
|
|
20
|
+
_logRawToolStreamPayload(p, msg);
|
|
21
|
+
}
|
|
22
|
+
if (typeof CL.handleDelegateWsEvent === 'function') {
|
|
23
|
+
CL.handleDelegateWsEvent(p);
|
|
24
|
+
}
|
|
25
|
+
_interceptTripData(p);
|
|
26
|
+
}
|
|
27
|
+
} catch (err) {
|
|
28
|
+
// silent — non-JSON messages or parsing errors
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
return ws;
|
|
33
|
+
};
|
|
34
|
+
// 保留静态属性和原型链
|
|
35
|
+
window.WebSocket.prototype = _OrigWebSocket.prototype;
|
|
36
|
+
window.WebSocket.CONNECTING = _OrigWebSocket.CONNECTING;
|
|
37
|
+
window.WebSocket.OPEN = _OrigWebSocket.OPEN;
|
|
38
|
+
window.WebSocket.CLOSING = _OrigWebSocket.CLOSING;
|
|
39
|
+
window.WebSocket.CLOSED = _OrigWebSocket.CLOSED;
|
|
40
|
+
|
|
41
|
+
/* muted */ void 0;
|
|
42
|
+
|
|
43
|
+
function _extractToolStreamPayload(msg) {
|
|
44
|
+
if (!msg || msg.type !== 'event') return null;
|
|
45
|
+
|
|
46
|
+
// Current OpenClaw gateway frames use:
|
|
47
|
+
// { type: "event", event: "agent", payload: { stream: "tool", data: ... } }
|
|
48
|
+
if (msg.event === 'agent' && msg.payload && msg.payload.stream === 'tool') {
|
|
49
|
+
return msg.payload;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Keep compatibility with older/local frames that already put the tool
|
|
53
|
+
// stream payload directly under payload, or one level deeper.
|
|
54
|
+
if (msg.payload && msg.payload.stream === 'tool') return msg.payload;
|
|
55
|
+
if (msg.payload && msg.payload.payload && msg.payload.payload.stream === 'tool') {
|
|
56
|
+
return msg.payload.payload;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function _logRawToolStreamPayload(payload, frame) {
|
|
63
|
+
try {
|
|
64
|
+
const data = payload && payload.data || {};
|
|
65
|
+
const entry = {
|
|
66
|
+
ts: new Date().toISOString(),
|
|
67
|
+
phase: data.phase || '',
|
|
68
|
+
toolCallId: data.toolCallId || '',
|
|
69
|
+
payload,
|
|
70
|
+
frame
|
|
71
|
+
};
|
|
72
|
+
window.__openagentRawToolStreamLog = window.__openagentRawToolStreamLog || [];
|
|
73
|
+
window.__openagentRawToolStreamLog.push(entry);
|
|
74
|
+
if (window.__openagentRawToolStreamLog.length > 200) {
|
|
75
|
+
window.__openagentRawToolStreamLog.splice(0, window.__openagentRawToolStreamLog.length - 200);
|
|
76
|
+
}
|
|
77
|
+
_persistRawToolStreamDebugLog(window.__openagentRawToolStreamLog);
|
|
78
|
+
console.log('[cl-raw-tool-stream] tcid=' + String(entry.toolCallId || '').substring(0, 8)
|
|
79
|
+
+ ' phase=' + entry.phase
|
|
80
|
+
+ ' payload=' + JSON.stringify(payload));
|
|
81
|
+
} catch (err) {
|
|
82
|
+
// debug logging must never affect the stream path
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function _isRawToolStreamDebugEnabled() {
|
|
87
|
+
try {
|
|
88
|
+
return window.localStorage && window.localStorage.getItem('openagent.debug.rawSse') === '1';
|
|
89
|
+
} catch (err) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _persistRawToolStreamDebugLog(entries) {
|
|
95
|
+
try {
|
|
96
|
+
const json = JSON.stringify(entries || []);
|
|
97
|
+
try {
|
|
98
|
+
window.localStorage && window.localStorage.setItem('openagent.rawToolStream.v1', json);
|
|
99
|
+
} catch (storageErr) {}
|
|
100
|
+
|
|
101
|
+
const doc = window.document;
|
|
102
|
+
if (!doc || !doc.body) return;
|
|
103
|
+
let node = doc.getElementById('openagent-raw-tool-stream-log');
|
|
104
|
+
if (!node) {
|
|
105
|
+
node = doc.createElement('pre');
|
|
106
|
+
node.id = 'openagent-raw-tool-stream-log';
|
|
107
|
+
node.style.display = 'none';
|
|
108
|
+
doc.body.appendChild(node);
|
|
109
|
+
}
|
|
110
|
+
node.textContent = json;
|
|
111
|
+
} catch (err) {}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function _interceptTripData(payload) {
|
|
115
|
+
try {
|
|
116
|
+
const data = payload?.data;
|
|
117
|
+
|
|
118
|
+
// 深度检查 payload 结构
|
|
119
|
+
if (data) {
|
|
120
|
+
const keys = Object.keys(data);
|
|
121
|
+
const strFields = keys.filter(k => typeof data[k] === 'string' && data[k].length > 50);
|
|
122
|
+
const hasTripInAny = keys.some(k => typeof data[k] === 'string' && data[k].includes('TRIP_DATA'));
|
|
123
|
+
/* muted */ void 0;
|
|
124
|
+
|
|
125
|
+
// 深入一层
|
|
126
|
+
if (data.data && typeof data.data === 'object') {
|
|
127
|
+
const dk = Object.keys(data.data);
|
|
128
|
+
const dHas = dk.some(k => typeof data.data[k] === 'string' && data.data[k].includes('TRIP_DATA'));
|
|
129
|
+
/* muted */ void 0;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (!data) return;
|
|
133
|
+
|
|
134
|
+
// 检测 [TRIP_CARDS_READY] 信号标记,然后 fetch 卡片数据文件
|
|
135
|
+
const textFields = ['text', 'content', 'result', 'output'];
|
|
136
|
+
|
|
137
|
+
function tryDetectSignal(obj, field) {
|
|
138
|
+
if (typeof obj[field] !== 'string') return false;
|
|
139
|
+
const val = obj[field];
|
|
140
|
+
if (!val.includes('[TRIP_CARDS_READY]')) return false;
|
|
141
|
+
// 移除信号标记
|
|
142
|
+
obj[field] = val.replace(/\n*\[TRIP_CARDS_READY\]/, '');
|
|
143
|
+
CL.fetchTripCardDataOnce('ws-ready-marker');
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
for (const field of textFields) {
|
|
148
|
+
if (tryDetectSignal(data, field)) return;
|
|
149
|
+
}
|
|
150
|
+
if (data.data && typeof data.data === 'object') {
|
|
151
|
+
for (const field of textFields) {
|
|
152
|
+
if (tryDetectSignal(data.data, field)) return;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
} catch (err) {
|
|
156
|
+
// silent
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
CL.fetchTripCardDataOnce = function(source, options) {
|
|
162
|
+
const force = !!(options && options.force);
|
|
163
|
+
const scope = options && options.scope;
|
|
164
|
+
if (scope && typeof CL.getScopedTripCardData === 'function') {
|
|
165
|
+
const scoped = CL.getScopedTripCardData(scope);
|
|
166
|
+
if (scoped && !force) return Promise.resolve(scoped);
|
|
167
|
+
}
|
|
168
|
+
if (CL.tripCardData && !force && (!scope || (typeof CL.tripCardDataMatchesScope === 'function' && CL.tripCardDataMatchesScope(CL.tripCardData, scope)))) {
|
|
169
|
+
return Promise.resolve(CL.tripCardData);
|
|
170
|
+
}
|
|
171
|
+
if (CL.tripCardDataFetchPromise) return CL.tripCardDataFetchPromise;
|
|
172
|
+
if (CL.tripCardDataFetchFailed) return Promise.resolve(null);
|
|
173
|
+
|
|
174
|
+
CL.tripCardDataFetchPromise = fetch('./trip-card-data.json?t=' + Date.now())
|
|
175
|
+
.then(r => {
|
|
176
|
+
if (!r.ok) throw new Error('HTTP ' + r.status);
|
|
177
|
+
return r.json();
|
|
178
|
+
})
|
|
179
|
+
.then(cardData => {
|
|
180
|
+
if (typeof CL.mergeTripCardData === 'function') {
|
|
181
|
+
CL.mergeTripCardData(cardData, { replaceDayList: true, scope: scope });
|
|
182
|
+
} else {
|
|
183
|
+
CL.tripCardData = cardData;
|
|
184
|
+
}
|
|
185
|
+
CL.tripCardDataFetchFailed = false;
|
|
186
|
+
/* muted */ void 0;
|
|
187
|
+
return cardData;
|
|
188
|
+
})
|
|
189
|
+
.catch(e => {
|
|
190
|
+
CL.tripCardDataFetchFailed = true;
|
|
191
|
+
console.warn('[trip-cards] File fetch failed:', e.message, 'via', source || 'unknown');
|
|
192
|
+
return null;
|
|
193
|
+
})
|
|
194
|
+
.finally(() => {
|
|
195
|
+
CL.tripCardDataFetchPromise = null;
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
return CL.tripCardDataFetchPromise;
|
|
199
|
+
};
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
// ── OpenAgent Chunk Parser — card.text → Chunk[] ──
|
|
2
|
+
//
|
|
3
|
+
// 解析 ToolCard.text 中的 JSON 数据块。
|
|
4
|
+
// 数据格式来自远端 Agent 的 SSE 流:
|
|
5
|
+
// {"msgType":2,"dataType":"think","thinkType":"title|content","text":"..."}
|
|
6
|
+
//
|
|
7
|
+
// 输出 Chunk 类型:
|
|
8
|
+
// { type: 'step', title: string } — 仅 dataType=think + thinkType=title
|
|
9
|
+
// { type: 'result', text: string } — 最终结果
|
|
10
|
+
// { type: 'error', text: string } — 错误信息
|
|
11
|
+
// { type: 'data', raw: object } — 结构化数据(tripCard 等)
|
|
12
|
+
// { type: 'text', text: string } — 纯文本 fallback
|
|
13
|
+
|
|
14
|
+
function _clParseChunks(text, scope) {
|
|
15
|
+
if (!text) return [];
|
|
16
|
+
var chunks = [];
|
|
17
|
+
|
|
18
|
+
// text 通常是多行 JSON,但历史/不同版本里也可能是连续 JSON 或
|
|
19
|
+
// 带换行的完整 JSON。先按平衡大括号切出 record,避免 data event 退化成正文。
|
|
20
|
+
var parts = _clSplitJsonRecords(text);
|
|
21
|
+
for (var pi = 0; pi < parts.length; pi++) {
|
|
22
|
+
var part = parts[pi];
|
|
23
|
+
if (part.type === 'json') {
|
|
24
|
+
chunks.push(_clNormalizeChunk(part.raw, scope));
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
var lines = String(part.text || '').split('\n');
|
|
29
|
+
for (var i = 0; i < lines.length; i++) {
|
|
30
|
+
var line = lines[i].trim();
|
|
31
|
+
if (!line) continue;
|
|
32
|
+
|
|
33
|
+
try {
|
|
34
|
+
var obj = JSON.parse(line);
|
|
35
|
+
if (obj && typeof obj === 'object') {
|
|
36
|
+
chunks.push(_clNormalizeChunk(obj, scope));
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// not JSON — treat as plain text fallback
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 纯文本 fallback
|
|
44
|
+
chunks.push({ type: 'text', text: line });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return chunks;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function _clReadJsonRecordAt(text, start) {
|
|
52
|
+
if (!text || text.charAt(start) !== '{') return null;
|
|
53
|
+
var depth = 0;
|
|
54
|
+
var inString = false;
|
|
55
|
+
var escaping = false;
|
|
56
|
+
|
|
57
|
+
for (var i = start; i < text.length; i++) {
|
|
58
|
+
var ch = text.charAt(i);
|
|
59
|
+
|
|
60
|
+
if (inString) {
|
|
61
|
+
if (escaping) {
|
|
62
|
+
escaping = false;
|
|
63
|
+
} else if (ch === '\\') {
|
|
64
|
+
escaping = true;
|
|
65
|
+
} else if (ch === '"') {
|
|
66
|
+
inString = false;
|
|
67
|
+
}
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
if (ch === '"') {
|
|
72
|
+
inString = true;
|
|
73
|
+
} else if (ch === '{') {
|
|
74
|
+
depth++;
|
|
75
|
+
} else if (ch === '}') {
|
|
76
|
+
depth--;
|
|
77
|
+
if (depth === 0) {
|
|
78
|
+
var rawText = text.slice(start, i + 1);
|
|
79
|
+
try {
|
|
80
|
+
var parsed = JSON.parse(rawText);
|
|
81
|
+
if (parsed && typeof parsed === 'object') {
|
|
82
|
+
return { raw: parsed, end: i + 1 };
|
|
83
|
+
}
|
|
84
|
+
} catch (e) {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function _clSplitJsonRecords(text) {
|
|
95
|
+
var parts = [];
|
|
96
|
+
var last = 0;
|
|
97
|
+
|
|
98
|
+
for (var i = 0; i < text.length; i++) {
|
|
99
|
+
if (text.charAt(i) !== '{') continue;
|
|
100
|
+
var record = _clReadJsonRecordAt(text, i);
|
|
101
|
+
if (!record) continue;
|
|
102
|
+
|
|
103
|
+
if (i > last) {
|
|
104
|
+
parts.push({ type: 'text', text: text.slice(last, i) });
|
|
105
|
+
}
|
|
106
|
+
parts.push({ type: 'json', raw: record.raw });
|
|
107
|
+
i = record.end - 1;
|
|
108
|
+
last = record.end;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
if (last < text.length) {
|
|
112
|
+
parts.push({ type: 'text', text: text.slice(last) });
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return parts.length ? parts : [{ type: 'text', text: text }];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
function _clNormalizeChunk(obj, scope) {
|
|
119
|
+
if (typeof _cl_ingestTripCardData === 'function') {
|
|
120
|
+
try { _cl_ingestTripCardData(obj, scope); } catch (e) {}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// 远端 Agent SSE 格式: {msgType, dataType, thinkType, text, ...}
|
|
124
|
+
if (obj.dataType === 'think') {
|
|
125
|
+
if (obj.thinkType === 'title') {
|
|
126
|
+
return { type: 'step', title: obj.text || '' };
|
|
127
|
+
}
|
|
128
|
+
return { type: 'data', raw: obj };
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (obj.dataType === 'data') {
|
|
132
|
+
return { type: 'data', raw: obj };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 结构化数据(tripCardData, unitContext 等)
|
|
136
|
+
if (obj.fullJson || obj.unitContext || obj.unitContexts || obj.dayList
|
|
137
|
+
|| obj.foodData || obj.budgetData || obj.budget || obj.tripCardData
|
|
138
|
+
|| obj.itineraryVersionInfo || obj.itinerary) {
|
|
139
|
+
return { type: 'data', raw: obj };
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// 错误:只接受显式错误事件。不能把普通业务 JSON 里的 error 字段直接当成
|
|
143
|
+
// OpenClaw tool error,否则刷新历史卡片时会把 output 外壳染成错误态。
|
|
144
|
+
if (obj.type === 'error' || obj.dataType === 'error' || obj.isError === true) {
|
|
145
|
+
return { type: 'error', text: obj.message || obj.error || obj.text || '' };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 结果
|
|
149
|
+
if (obj.type === 'result' || obj.dataType === 'result') {
|
|
150
|
+
return { type: 'result', text: obj.content || obj.text || '' };
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// 通用 thinking/step/progress 不再生成过程 UI;只保留为数据。
|
|
154
|
+
if (obj.type === 'thinking' || obj.type === 'thought'
|
|
155
|
+
|| obj.type === 'step' || obj.type === 'progress') {
|
|
156
|
+
return { type: 'data', raw: obj };
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// fallback: 整个对象当数据
|
|
160
|
+
return { type: 'data', raw: obj };
|
|
161
|
+
}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
// ── OpenAgent Execution Card — Agent 执行态 UI ──
|
|
2
|
+
//
|
|
3
|
+
// 输入: OpenAgentCardModel (from tool-card-model.js)
|
|
4
|
+
// 输出: DOM Node (嵌入 Lit template)
|
|
5
|
+
//
|
|
6
|
+
// 显示内容:
|
|
7
|
+
// - Agent Pill(头像 + @名称)
|
|
8
|
+
// - 分隔线
|
|
9
|
+
// - 思考步骤列表(从 model.chunks 中提取 step 类型)
|
|
10
|
+
//
|
|
11
|
+
// UI 结构使用 shared thought-chain styles,数据来源是 RenderHook model。
|
|
12
|
+
|
|
13
|
+
function _clRenderExecutionCard(model) {
|
|
14
|
+
var container = document.createElement('div');
|
|
15
|
+
container.className = 'cl-remote-agent-card cl-thought-chain';
|
|
16
|
+
if (CL && typeof CL.diagMarkCard === 'function') {
|
|
17
|
+
CL.diagMarkCard(container, 'execution', { tcid: model.toolCallId || '' });
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
container.appendChild(_clCreateOpenAgentHeader(model));
|
|
21
|
+
|
|
22
|
+
var content = document.createElement('div');
|
|
23
|
+
content.className = 'cl-thought-chain-content cl-thought-chain-content--execution';
|
|
24
|
+
container.appendChild(content);
|
|
25
|
+
|
|
26
|
+
// ── Agent Pill ──
|
|
27
|
+
console.log('[cl-exec] 🏷️ agentName=' + JSON.stringify(model.agentName) + ' agentId=' + JSON.stringify(model.agentId));
|
|
28
|
+
var pillSlot = document.createElement('div');
|
|
29
|
+
pillSlot.className = 'cl-thought-chain-pill-slot';
|
|
30
|
+
var pill = _clCreateAgentPill(model.agentName, model.agentId, model.agentAvatar);
|
|
31
|
+
pillSlot.appendChild(pill);
|
|
32
|
+
content.appendChild(pillSlot);
|
|
33
|
+
|
|
34
|
+
// ── 分隔线 ──
|
|
35
|
+
var divider = document.createElement('div');
|
|
36
|
+
divider.className = 'cl-thought-chain-divider';
|
|
37
|
+
content.appendChild(divider);
|
|
38
|
+
|
|
39
|
+
// ── 思考步骤区 ──
|
|
40
|
+
var stepsSection = document.createElement('div');
|
|
41
|
+
stepsSection.className = 'cl-thought-chain-steps-section';
|
|
42
|
+
|
|
43
|
+
// 标题栏
|
|
44
|
+
var header = document.createElement('div');
|
|
45
|
+
header.className = 'cl-tools-collapse-header';
|
|
46
|
+
|
|
47
|
+
var headerIcon = document.createElement('span');
|
|
48
|
+
headerIcon.className = 'cl-tools-collapse-header-icon';
|
|
49
|
+
headerIcon.textContent = '▼';
|
|
50
|
+
|
|
51
|
+
var headerTitle = document.createElement('span');
|
|
52
|
+
headerTitle.className = 'cl-tools-collapse-header-title';
|
|
53
|
+
|
|
54
|
+
// 从 chunks 提取步骤
|
|
55
|
+
var steps = [];
|
|
56
|
+
for (var i = 0; i < model.chunks.length; i++) {
|
|
57
|
+
var chunk = model.chunks[i];
|
|
58
|
+
if (chunk.type === 'step') {
|
|
59
|
+
steps.push({ title: chunk.title, detail: chunk.detail || '' });
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 合并预缓冲步骤(WS 先于 Lit 渲染到达时)
|
|
64
|
+
if (model._bufferedSteps && model._bufferedSteps.length > 0) {
|
|
65
|
+
steps = model._bufferedSteps;
|
|
66
|
+
}
|
|
67
|
+
if (typeof _cl_compactThoughtSteps === 'function') {
|
|
68
|
+
steps = _cl_compactThoughtSteps(steps);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
headerTitle.textContent = '思考中...';
|
|
72
|
+
|
|
73
|
+
header.appendChild(headerIcon);
|
|
74
|
+
header.appendChild(headerTitle);
|
|
75
|
+
|
|
76
|
+
// 步骤列表(可折叠)
|
|
77
|
+
var body = document.createElement('div');
|
|
78
|
+
body.className = 'cl-tools-collapse-body cl-expanded';
|
|
79
|
+
|
|
80
|
+
for (var si = 0; si < steps.length; si++) {
|
|
81
|
+
var isLatest = (si === steps.length - 1);
|
|
82
|
+
var stepEl = _clCreateStepElement(steps[si], isLatest);
|
|
83
|
+
body.appendChild(stepEl);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// 折叠/展开
|
|
87
|
+
header.style.cursor = 'pointer';
|
|
88
|
+
header.addEventListener('click', function(evt) {
|
|
89
|
+
evt.stopPropagation(); // 防止外层容器拦截
|
|
90
|
+
var isExpanded = body.classList.contains('cl-expanded');
|
|
91
|
+
console.log('[cl-exec] 🖱️ header click: expanded=' + isExpanded + ' bodyChildren=' + body.childElementCount);
|
|
92
|
+
if (isExpanded) {
|
|
93
|
+
body.classList.remove('cl-expanded');
|
|
94
|
+
body.classList.add('cl-collapsed');
|
|
95
|
+
headerIcon.classList.add('cl-collapsed');
|
|
96
|
+
if (typeof _cl_setCardUiState === 'function') {
|
|
97
|
+
_cl_setCardUiState(model, { stepsExpanded: false });
|
|
98
|
+
}
|
|
99
|
+
} else {
|
|
100
|
+
body.classList.remove('cl-collapsed');
|
|
101
|
+
body.classList.add('cl-expanded');
|
|
102
|
+
headerIcon.classList.remove('cl-collapsed');
|
|
103
|
+
if (typeof _cl_setCardUiState === 'function') {
|
|
104
|
+
_cl_setCardUiState(model, { stepsExpanded: true });
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
stepsSection.appendChild(header);
|
|
110
|
+
stepsSection.appendChild(body);
|
|
111
|
+
content.appendChild(stepsSection);
|
|
112
|
+
|
|
113
|
+
// ── 异步更新真实 Agent 身份 ──
|
|
114
|
+
if ((model.agentId || model.agentName) && typeof fetchAgentById === 'function') {
|
|
115
|
+
fetchAgentById(model.agentId, model.agentName).then(function(agent) {
|
|
116
|
+
if (!agent) return;
|
|
117
|
+
var pa = container.querySelector('.cl-agent-pill-avatar');
|
|
118
|
+
var pn = container.querySelector('.cl-agent-pill-name');
|
|
119
|
+
if (pa && typeof avatarUrl === 'function') {
|
|
120
|
+
var resolvedAvatar = avatarUrl(agent);
|
|
121
|
+
console.log('[cl-diag][pill] fetch-update agentId=' + JSON.stringify(model.agentId)
|
|
122
|
+
+ ' name=' + JSON.stringify(agent.name || model.agentName)
|
|
123
|
+
+ ' src=' + JSON.stringify(resolvedAvatar));
|
|
124
|
+
pa.src = resolvedAvatar;
|
|
125
|
+
pa.style.display = '';
|
|
126
|
+
}
|
|
127
|
+
_clSetAgentPillName(container, agent.name || model.agentName);
|
|
128
|
+
_clSetOpenAgentHeaderAgent(container, agent.name || model.agentName);
|
|
129
|
+
}).catch(function() {});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (typeof _cl_applyCardUiState === 'function') {
|
|
133
|
+
_cl_applyCardUiState(container, model);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
console.log('[cl-exec] ✅ execution card built: steps=' + steps.length);
|
|
137
|
+
return container;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// ── 共用 DOM 构建函数 ──
|
|
141
|
+
|
|
142
|
+
function _clCreateOpenAgentHeader(model) {
|
|
143
|
+
var header = document.createElement('div');
|
|
144
|
+
header.className = 'cl-openagent-header';
|
|
145
|
+
header.style.cursor = 'pointer';
|
|
146
|
+
|
|
147
|
+
var caret = document.createElement('span');
|
|
148
|
+
caret.className = 'cl-openagent-header-caret';
|
|
149
|
+
caret.textContent = '▼';
|
|
150
|
+
header.appendChild(caret);
|
|
151
|
+
|
|
152
|
+
var icon = document.createElement('span');
|
|
153
|
+
icon.className = 'cl-openagent-header-icon';
|
|
154
|
+
icon.setAttribute('aria-hidden', 'true');
|
|
155
|
+
header.appendChild(icon);
|
|
156
|
+
|
|
157
|
+
var title = document.createElement('div');
|
|
158
|
+
title.className = 'cl-openagent-header-title';
|
|
159
|
+
|
|
160
|
+
var primary = document.createElement('span');
|
|
161
|
+
primary.className = 'cl-openagent-header-primary';
|
|
162
|
+
primary.textContent = 'OpenAgent @' + (model.agentName || 'Remote Agent');
|
|
163
|
+
title.appendChild(primary);
|
|
164
|
+
|
|
165
|
+
var secondary = document.createElement('span');
|
|
166
|
+
secondary.className = 'cl-openagent-header-secondary';
|
|
167
|
+
title.appendChild(secondary);
|
|
168
|
+
|
|
169
|
+
header.appendChild(title);
|
|
170
|
+
|
|
171
|
+
// 点击 header 折叠/展开卡片内容
|
|
172
|
+
header.addEventListener('click', function(e) {
|
|
173
|
+
e.stopPropagation();
|
|
174
|
+
var card = header.closest('.cl-remote-agent-card');
|
|
175
|
+
if (!card) return;
|
|
176
|
+
var content = card.querySelector('.cl-thought-chain-content');
|
|
177
|
+
if (!content) return;
|
|
178
|
+
var isCollapsed = content.classList.toggle('cl-content-collapsed');
|
|
179
|
+
caret.textContent = isCollapsed ? '▶' : '▼';
|
|
180
|
+
if (typeof _cl_setCardUiState === 'function') {
|
|
181
|
+
_cl_setCardUiState(model, { contentCollapsed: isCollapsed });
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return header;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function _clSetOpenAgentHeaderAgent(container, agentName) {
|
|
189
|
+
var title = container && container.querySelector('.cl-openagent-header-primary');
|
|
190
|
+
if (title) title.textContent = 'OpenAgent @' + (agentName || 'Remote Agent');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function _clCreateAgentPill(agentName, agentId, agentAvatar) {
|
|
194
|
+
var pill = document.createElement('div');
|
|
195
|
+
pill.className = 'cl-agent-pill';
|
|
196
|
+
|
|
197
|
+
var avatar = document.createElement('img');
|
|
198
|
+
avatar.className = 'cl-agent-pill-avatar';
|
|
199
|
+
avatar.alt = agentName || 'Agent';
|
|
200
|
+
var identity = CL && typeof CL.getAgentIdentity === 'function'
|
|
201
|
+
? CL.getAgentIdentity(agentId, agentName)
|
|
202
|
+
: null;
|
|
203
|
+
var avatarAgent = agentAvatar
|
|
204
|
+
? { name: agentName, avatar: agentAvatar }
|
|
205
|
+
: identity;
|
|
206
|
+
avatar.src = (avatarAgent && avatarAgent.avatar && typeof avatarUrl === 'function')
|
|
207
|
+
? avatarUrl(avatarAgent)
|
|
208
|
+
: 'https://ui-avatars.com/api/?name=' + encodeURIComponent(agentName || 'A') + '&background=7c3aed&color=fff&size=64';
|
|
209
|
+
console.log('[cl-diag][pill] create agentName=' + JSON.stringify(agentName || '')
|
|
210
|
+
+ ' agentId=' + JSON.stringify(agentId || '')
|
|
211
|
+
+ ' src=' + JSON.stringify(avatar.getAttribute('src')));
|
|
212
|
+
avatar.onerror = function() { this.style.display = 'none'; };
|
|
213
|
+
pill.appendChild(avatar);
|
|
214
|
+
|
|
215
|
+
var nameEl = document.createElement('span');
|
|
216
|
+
nameEl.className = 'cl-agent-pill-name';
|
|
217
|
+
var atEl = document.createElement('span');
|
|
218
|
+
atEl.className = 'cl-agent-pill-at';
|
|
219
|
+
atEl.textContent = '@';
|
|
220
|
+
var labelEl = document.createElement('span');
|
|
221
|
+
labelEl.className = 'cl-agent-pill-label';
|
|
222
|
+
labelEl.textContent = agentName || 'Remote Agent';
|
|
223
|
+
nameEl.appendChild(atEl);
|
|
224
|
+
nameEl.appendChild(labelEl);
|
|
225
|
+
pill.appendChild(nameEl);
|
|
226
|
+
|
|
227
|
+
return pill;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function _clSetAgentPillName(container, agentName) {
|
|
231
|
+
var label = container && container.querySelector('.cl-agent-pill-label');
|
|
232
|
+
if (label) {
|
|
233
|
+
label.textContent = agentName || 'Remote Agent';
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
var name = container && container.querySelector('.cl-agent-pill-name');
|
|
237
|
+
if (name) name.textContent = '@' + (agentName || 'Remote Agent');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function _clCreateStepElement(step, isLatest) {
|
|
241
|
+
var item = document.createElement('div');
|
|
242
|
+
item.className = 'cl-tools-collapse-step';
|
|
243
|
+
|
|
244
|
+
var row = document.createElement('div');
|
|
245
|
+
row.className = 'cl-tools-collapse-step-row';
|
|
246
|
+
|
|
247
|
+
var iconWrap = document.createElement('div');
|
|
248
|
+
iconWrap.className = 'cl-tools-collapse-step-icon';
|
|
249
|
+
|
|
250
|
+
if (isLatest) {
|
|
251
|
+
var dot = document.createElement('div');
|
|
252
|
+
dot.className = 'cl-tools-collapse-step-dot cl-active';
|
|
253
|
+
iconWrap.appendChild(dot);
|
|
254
|
+
} else {
|
|
255
|
+
var check = document.createElement('div');
|
|
256
|
+
check.className = 'cl-tools-collapse-step-check';
|
|
257
|
+
iconWrap.appendChild(check);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
var titleEl = document.createElement('span');
|
|
261
|
+
titleEl.className = 'cl-tools-collapse-step-title';
|
|
262
|
+
titleEl.textContent = (step.title || '').replace(/[\u2705\u2611\uFE0F\u2714\uFE0F]/g, '').trim();
|
|
263
|
+
|
|
264
|
+
row.appendChild(iconWrap);
|
|
265
|
+
row.appendChild(titleEl);
|
|
266
|
+
item.appendChild(row);
|
|
267
|
+
|
|
268
|
+
return item;
|
|
269
|
+
}
|