openclaw-openagent 1.0.8 → 1.0.11
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/app/remote-agent-tool.js +108 -10
- package/dist/src/auth/config.js +65 -10
- package/dist/src/channel.js +2 -1
- package/dist/src/plugin-ui/assets/bg.png +0 -0
- package/dist/src/plugin-ui/assets/icon.png +0 -0
- package/dist/src/plugin-ui/assets/openagent-override.js +1753 -774
- package/dist/src/plugin-ui/ui-extension-loader/registry-regex.js +53 -5
- package/dist/src/proxy/auth-proxy.d.ts +1 -0
- package/dist/src/proxy/auth-proxy.js +28 -9
- package/dist/src/transport/oasn/oasn-http.d.ts +12 -0
- package/dist/src/transport/oasn/oasn-http.js +45 -14
- package/dist/src/util/url-resolver.d.ts +6 -0
- package/dist/src/util/url-resolver.js +24 -8
- package/openclaw.plugin.json +16 -1
- package/package.json +3 -3
- package/src/app/remote-agent-tool.ts +126 -11
- package/src/auth/config.ts +79 -10
- package/src/channel.ts +2 -1
- package/src/plugin-ui/assets/bg.png +0 -0
- package/src/plugin-ui/assets/icon.png +0 -0
- package/src/plugin-ui/assets/openagent-override.js +1753 -774
- package/src/plugin-ui/build.cjs +80 -4
- package/src/plugin-ui/modules/agent-book/panel/agent-book.js +92 -9
- package/src/plugin-ui/modules/agent-book/panel/agent-card.js +26 -10
- package/src/plugin-ui/modules/agent-book/panel/agent-data.js +1 -1
- package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +64 -0
- package/src/plugin-ui/modules/agent-book/panel/styles.js +313 -178
- package/src/plugin-ui/modules/loader/bootstrap.js +1 -1
- package/src/plugin-ui/modules/loader/shared-state.js +54 -0
- package/src/plugin-ui/modules/remote-agent/execution-card.js +347 -124
- package/src/plugin-ui/modules/remote-agent/media-links.js +151 -0
- package/src/plugin-ui/modules/remote-agent/output-card.js +110 -33
- package/src/plugin-ui/modules/remote-agent/render-hooks.js +97 -18
- package/src/plugin-ui/modules/remote-agent/styles.js +488 -402
- package/src/plugin-ui/modules/remote-agent/tool-card-model.js +6 -0
- package/src/plugin-ui/ui-extension-loader/registry-regex.ts +50 -5
- package/src/proxy/auth-proxy.ts +30 -10
- package/src/transport/oasn/oasn-http.ts +60 -14
- package/src/util/url-resolver.ts +24 -8
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
// ── OpenAgent Media Links — toolResult MEDIA: protocol renderer ──
|
|
2
|
+
//
|
|
3
|
+
// OpenClaw host parses MEDIA: links in assistant text, but remote-agent
|
|
4
|
+
// toolResult text is rendered through the plugin card path. Keep this parser
|
|
5
|
+
// local to the card so OASN artifacts become visible downloads.
|
|
6
|
+
|
|
7
|
+
function _clExtractOpenagentMediaLinksFromText(rawText) {
|
|
8
|
+
var value = String(rawText || '');
|
|
9
|
+
var links = [];
|
|
10
|
+
var seen = Object.create(null);
|
|
11
|
+
|
|
12
|
+
function addUrl(rawUrl) {
|
|
13
|
+
var url = _clNormalizeOpenagentMediaUrl(rawUrl);
|
|
14
|
+
if (!url || seen[url]) return;
|
|
15
|
+
seen[url] = true;
|
|
16
|
+
|
|
17
|
+
var fileName = _clGetOpenagentMediaFileName(url);
|
|
18
|
+
links.push({
|
|
19
|
+
url: url,
|
|
20
|
+
fileName: fileName,
|
|
21
|
+
extension: _clInferOpenagentMediaExtension(fileName),
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
var re = /^\s*MEDIA:\s*(\S+)\s*$/gm;
|
|
26
|
+
var match;
|
|
27
|
+
|
|
28
|
+
while ((match = re.exec(value)) !== null) {
|
|
29
|
+
addUrl(match[1]);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
var markdownRe = /\[[^\]]+\]\((https?:\/\/[^)\s]+|\/[^)\s]+)\)/g;
|
|
33
|
+
while ((match = markdownRe.exec(value)) !== null) {
|
|
34
|
+
addUrl(match[1]);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return links;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function _clExtractOpenagentMediaLinksFromModel(model) {
|
|
41
|
+
var allText = [];
|
|
42
|
+
if (model && model.rawText) allText.push(model.rawText);
|
|
43
|
+
var chunks = model && Array.isArray(model.chunks) ? model.chunks : [];
|
|
44
|
+
for (var i = 0; i < chunks.length; i++) {
|
|
45
|
+
if (chunks[i] && chunks[i].text) allText.push(chunks[i].text);
|
|
46
|
+
}
|
|
47
|
+
return _clExtractOpenagentMediaLinksFromText(allText.join('\n'));
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function _clNormalizeOpenagentMediaUrl(rawUrl) {
|
|
51
|
+
var value = String(rawUrl || '').trim();
|
|
52
|
+
if (!value) return '';
|
|
53
|
+
value = value.replace(/^[`'"]+/, '').replace(/[`'".,;)\]]+$/, '');
|
|
54
|
+
|
|
55
|
+
if (value.charAt(0) === '/') return value;
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
var parsed = new URL(value);
|
|
59
|
+
if (parsed.protocol === 'http:' || parsed.protocol === 'https:') return value;
|
|
60
|
+
} catch (e) {}
|
|
61
|
+
|
|
62
|
+
return '';
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function _clGetOpenagentMediaFileName(url) {
|
|
66
|
+
var pathValue = '';
|
|
67
|
+
try {
|
|
68
|
+
var base = (typeof window !== 'undefined' && window.location && window.location.href)
|
|
69
|
+
? window.location.href
|
|
70
|
+
: 'http://127.0.0.1/';
|
|
71
|
+
pathValue = new URL(url, base).pathname || '';
|
|
72
|
+
} catch (e) {
|
|
73
|
+
pathValue = String(url || '').split('?')[0] || '';
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
var parts = pathValue.split('/');
|
|
77
|
+
var fileName = parts[parts.length - 1] || 'artifact';
|
|
78
|
+
try {
|
|
79
|
+
fileName = decodeURIComponent(fileName);
|
|
80
|
+
} catch (e) {}
|
|
81
|
+
return fileName || 'artifact';
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function _clInferOpenagentMediaExtension(fileName) {
|
|
85
|
+
var match = String(fileName || '').toLowerCase().match(/\.([a-z0-9]{1,12})$/);
|
|
86
|
+
return match ? match[1] : '';
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
function _clStripOpenagentMediaLines(rawText) {
|
|
90
|
+
return String(rawText || '')
|
|
91
|
+
.split(/\r?\n/)
|
|
92
|
+
.filter(function(line) { return !/^\s*MEDIA:\s*/.test(line); })
|
|
93
|
+
.join('\n')
|
|
94
|
+
.trim();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
function _clCreateOpenagentMediaLinksSection(links) {
|
|
98
|
+
if (!Array.isArray(links) || links.length === 0) return null;
|
|
99
|
+
|
|
100
|
+
var section = document.createElement('div');
|
|
101
|
+
section.className = 'cl-openagent-media-links';
|
|
102
|
+
|
|
103
|
+
for (var i = 0; i < links.length; i++) {
|
|
104
|
+
var link = links[i] || {};
|
|
105
|
+
if (!link.url) continue;
|
|
106
|
+
|
|
107
|
+
var anchor = document.createElement('a');
|
|
108
|
+
anchor.className = 'cl-openagent-media-link';
|
|
109
|
+
anchor.href = link.url;
|
|
110
|
+
anchor.target = '_blank';
|
|
111
|
+
anchor.rel = 'noopener noreferrer';
|
|
112
|
+
anchor.download = link.fileName || '';
|
|
113
|
+
anchor.title = link.fileName || link.url;
|
|
114
|
+
|
|
115
|
+
var icon = document.createElement('span');
|
|
116
|
+
icon.className = 'cl-openagent-media-link-icon';
|
|
117
|
+
icon.textContent = _clGetOpenagentMediaIconText(link.extension);
|
|
118
|
+
anchor.appendChild(icon);
|
|
119
|
+
|
|
120
|
+
var text = document.createElement('span');
|
|
121
|
+
text.className = 'cl-openagent-media-link-text';
|
|
122
|
+
text.textContent = _clGetOpenagentMediaActionText(link.extension);
|
|
123
|
+
anchor.appendChild(text);
|
|
124
|
+
|
|
125
|
+
var file = document.createElement('span');
|
|
126
|
+
file.className = 'cl-openagent-media-link-file';
|
|
127
|
+
file.textContent = link.fileName || 'artifact';
|
|
128
|
+
anchor.appendChild(file);
|
|
129
|
+
|
|
130
|
+
section.appendChild(anchor);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return section.childNodes.length > 0 ? section : null;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function _clGetOpenagentMediaActionText(extension) {
|
|
137
|
+
var ext = String(extension || '').toUpperCase();
|
|
138
|
+
if (!ext) return '下载附件';
|
|
139
|
+
return '下载 ' + ext;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function _clGetOpenagentMediaIconText(extension) {
|
|
143
|
+
extension = String(extension || '').toLowerCase();
|
|
144
|
+
if (extension === 'pptx' || extension === 'ppt') return 'P';
|
|
145
|
+
if (extension === 'docx' || extension === 'doc') return 'D';
|
|
146
|
+
if (extension === 'xlsx' || extension === 'xls' || extension === 'csv') return 'X';
|
|
147
|
+
if (extension === 'json') return '{}';
|
|
148
|
+
if (extension === 'md' || extension === 'txt') return 'T';
|
|
149
|
+
if (extension === 'zip') return 'Z';
|
|
150
|
+
return 'F';
|
|
151
|
+
}
|
|
@@ -11,24 +11,43 @@
|
|
|
11
11
|
// UI 结构复用 shared thought-chain styles;数据来源是 RenderHook model。
|
|
12
12
|
|
|
13
13
|
function _clRenderOutputCard(model, onOpenSidebar) {
|
|
14
|
+
var mediaLinks = typeof _clExtractOpenagentMediaLinksFromModel === 'function'
|
|
15
|
+
? _clExtractOpenagentMediaLinksFromModel(model)
|
|
16
|
+
: [];
|
|
17
|
+
|
|
14
18
|
// ── 从 chunks 提取最终结果。SSE 思考链只由 call/execution card 展示,避免重复。──
|
|
15
19
|
var resultTexts = [];
|
|
16
20
|
for (var i = 0; i < model.chunks.length; i++) {
|
|
17
21
|
var chunk = model.chunks[i];
|
|
18
22
|
if (chunk.type === 'result') {
|
|
19
|
-
|
|
23
|
+
var resultText = typeof _clStripOpenagentMediaLines === 'function'
|
|
24
|
+
? _clStripOpenagentMediaLines(chunk.text)
|
|
25
|
+
: chunk.text;
|
|
26
|
+
if (_clShouldRenderOutputText(resultText)) resultTexts.push(resultText);
|
|
20
27
|
} else if (chunk.type === 'text') {
|
|
21
28
|
// 远端 Agent 最终回复是普通文本(toolResult(reply.content)),
|
|
22
29
|
// chunk-parser 归为 type='text',也应作为最终结果显示
|
|
23
|
-
|
|
30
|
+
var textChunk = typeof _clStripOpenagentMediaLines === 'function'
|
|
31
|
+
? _clStripOpenagentMediaLines(chunk.text)
|
|
32
|
+
: chunk.text;
|
|
33
|
+
if (_clShouldRenderOutputText(textChunk)) resultTexts.push(textChunk);
|
|
24
34
|
}
|
|
25
35
|
}
|
|
26
36
|
|
|
27
|
-
|
|
37
|
+
// ── V2 版本判断 ──
|
|
38
|
+
var isV2 = typeof _clIsHostVersionGte === 'function' && _clIsHostVersionGte('2026.6.9');
|
|
39
|
+
|
|
40
|
+
if (resultTexts.length === 0 && mediaLinks.length === 0) {
|
|
28
41
|
var placeholder = document.createElement('span');
|
|
29
42
|
placeholder.className = 'cl-remote-agent-card cl-remote-agent-output-placeholder';
|
|
30
43
|
placeholder.style.display = 'none';
|
|
31
44
|
placeholder.__clEmptyOutput = true;
|
|
45
|
+
// 防止 OpenClaw native 代码读 .textContent 报 undefined.trim()
|
|
46
|
+
var hiddenText = document.createElement('span');
|
|
47
|
+
hiddenText.className = 'chat-text';
|
|
48
|
+
hiddenText.style.display = 'none';
|
|
49
|
+
hiddenText.textContent = '';
|
|
50
|
+
placeholder.appendChild(hiddenText);
|
|
32
51
|
if (model.toolCallId) {
|
|
33
52
|
placeholder.dataset.clCardTcid = model.toolCallId;
|
|
34
53
|
}
|
|
@@ -37,33 +56,60 @@ function _clRenderOutputCard(model, onOpenSidebar) {
|
|
|
37
56
|
}
|
|
38
57
|
|
|
39
58
|
var container = document.createElement('div');
|
|
40
|
-
|
|
59
|
+
var cardClasses = 'cl-remote-agent-card cl-thought-chain cl-output-card'
|
|
60
|
+
+ (resultTexts.length > 0 ? ' cl-output-card--pending' : '');
|
|
61
|
+
if (isV2) cardClasses += ' cl-exec-v2';
|
|
62
|
+
container.className = cardClasses;
|
|
41
63
|
container.dataset.clCardRole = 'output';
|
|
64
|
+
// 防止 OpenClaw native 代码读 .textContent 报 undefined.trim()
|
|
65
|
+
var safetyText = document.createElement('div');
|
|
66
|
+
safetyText.className = 'chat-text';
|
|
67
|
+
safetyText.style.display = 'none';
|
|
68
|
+
safetyText.textContent = '';
|
|
69
|
+
container.appendChild(safetyText);
|
|
70
|
+
if (model.toolCallId) container.dataset.clCardTcid = model.toolCallId;
|
|
71
|
+
// 阻止点击冒泡到原生 tool card handler
|
|
72
|
+
container.addEventListener('click', function(e) { e.stopPropagation(); });
|
|
42
73
|
if (CL && typeof CL.diagMarkCard === 'function') {
|
|
43
74
|
CL.diagMarkCard(container, 'output', { tcid: model.toolCallId || '' });
|
|
44
75
|
}
|
|
45
76
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
if (
|
|
49
|
-
|
|
77
|
+
model._outputMode = true;
|
|
78
|
+
model.status = 'completed';
|
|
79
|
+
if (isV2) {
|
|
80
|
+
var v2Header = _clCreateOpenAgentHeaderV2(model);
|
|
81
|
+
v2Header.classList.remove('cl-openagent-header--output');
|
|
82
|
+
container.appendChild(v2Header);
|
|
83
|
+
if (typeof _clUpdateAgentStatusTextV2 === 'function') {
|
|
84
|
+
_clUpdateAgentStatusTextV2(container, 'completed');
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
var shellHeader = _clCreateOpenAgentHeader(model);
|
|
88
|
+
container.appendChild(shellHeader);
|
|
89
|
+
if (typeof _clSetOpenAgentHeaderAgent === 'function') {
|
|
90
|
+
_clSetOpenAgentHeaderAgent(container, model.agentName || model.agentId || 'Remote Agent');
|
|
91
|
+
}
|
|
50
92
|
}
|
|
51
93
|
|
|
52
94
|
var content = document.createElement('div');
|
|
53
95
|
content.className = 'cl-thought-chain-content';
|
|
54
96
|
container.appendChild(content);
|
|
55
97
|
|
|
56
|
-
// ── Agent
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
98
|
+
// ── V2 Agent 详情卡片 ──
|
|
99
|
+
if (isV2) {
|
|
100
|
+
try {
|
|
101
|
+
var detailCard = _clCreateAgentDetailCardV2(model);
|
|
102
|
+
content.appendChild(detailCard);
|
|
103
|
+
} catch(e) {
|
|
104
|
+
console.warn('[cl-output-v2] detail card creation failed:', e);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
62
107
|
|
|
63
|
-
// ──
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
108
|
+
// ── 附件下载链接 ──
|
|
109
|
+
if (mediaLinks.length > 0 && typeof _clCreateOpenagentMediaLinksSection === 'function') {
|
|
110
|
+
var mediaSection = _clCreateOpenagentMediaLinksSection(mediaLinks);
|
|
111
|
+
if (mediaSection) content.appendChild(mediaSection);
|
|
112
|
+
}
|
|
67
113
|
|
|
68
114
|
// ── 最终结果展示 ──
|
|
69
115
|
if (resultTexts.length > 0) {
|
|
@@ -102,12 +148,23 @@ function _clRenderOutputCard(model, onOpenSidebar) {
|
|
|
102
148
|
}
|
|
103
149
|
|
|
104
150
|
// ── onOpenSidebar 支持:点击展开到侧边栏 ──
|
|
105
|
-
|
|
151
|
+
// 宿主 sidebar 渲染器要求 content 为 { kind: 'markdown', content, rawText } 对象,
|
|
152
|
+
// kind 必须为 'markdown' 才会进入 markdown 渲染路径,否则显示 "No previewable markdown content."。
|
|
153
|
+
// travel card 标签(<sh_card>等)sidebar 原生 markdown 解析不认,先 strip 再传。
|
|
154
|
+
var sidebarRaw = resultText || model.rawText || '';
|
|
155
|
+
var sidebarText = String(sidebarRaw).replace(/<\/?[a-z]+_card[^>]*>/gi, '');
|
|
156
|
+
if (typeof _clStripSuppressedTravelTags === 'function') {
|
|
157
|
+
sidebarText = _clStripSuppressedTravelTags(sidebarText);
|
|
158
|
+
}
|
|
159
|
+
if (onOpenSidebar && sidebarText.trim()) {
|
|
106
160
|
container.style.cursor = 'pointer';
|
|
107
161
|
container.addEventListener('click', function(e) {
|
|
108
|
-
// 不拦截折叠/展开点击
|
|
109
162
|
if (e.target.closest('.cl-tools-collapse-header')) return;
|
|
110
|
-
onOpenSidebar(
|
|
163
|
+
onOpenSidebar({ kind: 'markdown', content: sidebarText, rawText: sidebarText });
|
|
164
|
+
setTimeout(function() {
|
|
165
|
+
var titleEl = document.querySelector('.chat-sidebar .sidebar-title');
|
|
166
|
+
if (titleEl) titleEl.textContent = 'OpenAgent @' + (model.agentName || 'Remote Agent');
|
|
167
|
+
}, 100);
|
|
111
168
|
});
|
|
112
169
|
}
|
|
113
170
|
|
|
@@ -115,18 +172,18 @@ function _clRenderOutputCard(model, onOpenSidebar) {
|
|
|
115
172
|
if ((model.agentId || model.agentName) && typeof fetchAgentById === 'function') {
|
|
116
173
|
fetchAgentById(model.agentId, model.agentName).then(function(agent) {
|
|
117
174
|
if (!agent) return;
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
var
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
175
|
+
if (isV2) {
|
|
176
|
+
var avatarElV2 = container.querySelector('.cl-exec-agent-avatar-v2');
|
|
177
|
+
var nameElV2 = container.querySelector('.cl-exec-agent-name-v2');
|
|
178
|
+
var bioElV2 = container.querySelector('.cl-exec-agent-bio-v2');
|
|
179
|
+
if (nameElV2) nameElV2.textContent = agent.name || model.agentName;
|
|
180
|
+
if (bioElV2 && (agent.bio || agent.description)) bioElV2.textContent = agent.bio || agent.description;
|
|
181
|
+
var starsElV2 = container.querySelector('.cl-exec-star-count-v2');
|
|
182
|
+
if (starsElV2 && agent.claws) starsElV2.textContent = _cl_formatStarCount(agent.claws);
|
|
183
|
+
if (starsElV2 && agent.stars && !agent.claws) starsElV2.textContent = _cl_formatStarCount(agent.stars);
|
|
184
|
+
} else {
|
|
185
|
+
_clSetOpenAgentHeaderAgent(container, agent.name || model.agentName);
|
|
127
186
|
}
|
|
128
|
-
_clSetAgentPillName(container, agent.name || model.agentName);
|
|
129
|
-
_clSetOpenAgentHeaderAgent(container, agent.name || model.agentName);
|
|
130
187
|
}).catch(function() {});
|
|
131
188
|
}
|
|
132
189
|
|
|
@@ -134,7 +191,25 @@ function _clRenderOutputCard(model, onOpenSidebar) {
|
|
|
134
191
|
_cl_applyCardUiState(container, model);
|
|
135
192
|
}
|
|
136
193
|
|
|
137
|
-
|
|
194
|
+
// ── Footer ──
|
|
195
|
+
if (isV2) {
|
|
196
|
+
var footerV2 = document.createElement('div');
|
|
197
|
+
footerV2.className = 'cl-output-footer cl-output-footer-v2';
|
|
198
|
+
footerV2.innerHTML = '<span class="cl-output-footer-text">-由' + (model.agentName || 'Remote Agent') + '完成</span>'
|
|
199
|
+
+ '<span class="cl-output-footer-star"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1.16L8.356 5.33H12.78L9.195 7.94L10.565 12.1L7 9.51L3.435 12.1L4.805 7.94L1.22 5.33H5.644L7 1.16Z" stroke="#999" stroke-width="0.8"/></svg></span>'
|
|
200
|
+
+ '<span class="cl-output-footer-count">' + (model.agentStars || '3.2万') + '</span>';
|
|
201
|
+
container.appendChild(footerV2);
|
|
202
|
+
} else {
|
|
203
|
+
// ── Footer(Figma 131:2091) ──
|
|
204
|
+
var footer = document.createElement('div');
|
|
205
|
+
footer.className = 'cl-output-footer';
|
|
206
|
+
footer.innerHTML = '<span class="cl-output-footer-text">-由' + (model.agentName || 'Remote Agent') + '完成</span>'
|
|
207
|
+
+ '<span class="cl-output-footer-star"><svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M7 1.16L8.356 5.33H12.78L9.195 7.94L10.565 12.1L7 9.51L3.435 12.1L4.805 7.94L1.22 5.33H5.644L7 1.16Z" stroke="#999" stroke-width="0.8"/></svg></span>'
|
|
208
|
+
+ '<span class="cl-output-footer-count">' + (model.agentStars || '3.2万') + '</span>';
|
|
209
|
+
container.appendChild(footer);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
console.log('[cl-output] ✅ output card built: results=' + resultTexts.length + ' v2=' + isV2);
|
|
138
213
|
return container;
|
|
139
214
|
}
|
|
140
215
|
|
|
@@ -257,3 +332,5 @@ function _clScheduleOutputCardProcessing(resultSection, model) {
|
|
|
257
332
|
|
|
258
333
|
setTimeout(run, 0);
|
|
259
334
|
}
|
|
335
|
+
|
|
336
|
+
// ── Sidebar Figma 145:5712 内联样式 ──
|
|
@@ -13,8 +13,14 @@ var __cl_toolStates = new Map();
|
|
|
13
13
|
// 每个 entry: { steps: [], phase: 'active'|'completed', cardNode: null, args: {} }
|
|
14
14
|
|
|
15
15
|
var __cl_lastCallModel = null; // 同一 render cycle 里 call card 的 model(供 result card 读取 agent 身份)
|
|
16
|
-
var __cl_outputCardCache = new Map();
|
|
17
|
-
var
|
|
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);
|
|
18
24
|
|
|
19
25
|
var CL_REMOTE_AGENT_PROGRESS_MODE_TRAVEL_TITLE = 'travel-title';
|
|
20
26
|
var CL_REMOTE_AGENT_PROGRESS_MODE_GENERIC_STREAM = 'generic-stream';
|
|
@@ -310,6 +316,16 @@ function _cl_ensureRemoteToolState(toolCallId, data, rawText) {
|
|
|
310
316
|
// ═══════════════════════════════════════════════════════════════
|
|
311
317
|
|
|
312
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
|
+
|
|
313
329
|
var n = (card && card.name || '').toLowerCase();
|
|
314
330
|
var cardTcid = card && (card.toolCallId || '');
|
|
315
331
|
var cardKind = typeof _clInferToolCardKind === 'function' ? _clInferToolCardKind(card) : (card && card.kind || '');
|
|
@@ -347,19 +363,34 @@ window.__openagentRenderToolCard = function(card, onOpenSidebar) {
|
|
|
347
363
|
}
|
|
348
364
|
if (state.phase === 'active') {
|
|
349
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
|
+
}
|
|
350
371
|
}
|
|
351
372
|
// 有 streaming 状态 — 复用或新建
|
|
352
373
|
if (state.cardNode) {
|
|
353
374
|
// Lit 重复调用会复用同一个 DOM 节点;但 OpenClaw 外层 native
|
|
354
375
|
// <details> 可能被 rerender 成 closed。这里重新打开的是外层原生
|
|
355
|
-
// details
|
|
376
|
+
// details,不影响卡片内部的”思考中/思考完成”折叠状态。
|
|
356
377
|
_cl_applyCardUiState(state.cardNode, { toolCallId: tcid, cardKind: 'call' });
|
|
357
378
|
if (state.phase === 'active') {
|
|
358
379
|
_cl_autoOpenStepsIfUncontrolled(state.cardNode);
|
|
359
380
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
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
|
+
}
|
|
363
394
|
return state.cardNode;
|
|
364
395
|
}
|
|
365
396
|
|
|
@@ -397,6 +428,20 @@ window.__openagentRenderToolCard = function(card, onOpenSidebar) {
|
|
|
397
428
|
|
|
398
429
|
// 无状态 → 刷新/历史态。前端 store 如果有同一 toolCallId 的卡片快照,
|
|
399
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
|
+
|
|
400
445
|
var storedCallRecord = tcid && typeof _clRemoteAgentProgressStore !== 'undefined' && _clRemoteAgentProgressStore
|
|
401
446
|
? _clRemoteAgentProgressStore.get(tcid)
|
|
402
447
|
: null;
|
|
@@ -413,10 +458,16 @@ window.__openagentRenderToolCard = function(card, onOpenSidebar) {
|
|
|
413
458
|
model.cardKind = 'call';
|
|
414
459
|
model.status = 'completed';
|
|
415
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
|
+
}
|
|
416
466
|
_cl_finalizeCard(historyNode, model._bufferedSteps || []);
|
|
417
467
|
_cl_forceOpenNativeToolDetails(historyNode, 'execution-history', tcid);
|
|
418
468
|
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(historyNode);
|
|
419
469
|
_cl_hideHostRawText(historyNode);
|
|
470
|
+
if (tcid) __cl_executionCardCache.set(tcid, historyNode);
|
|
420
471
|
console.log('[cl-render] 🗂️ built historical call card, tcid=' + tcid.substring(0, 8));
|
|
421
472
|
return historyNode;
|
|
422
473
|
}
|
|
@@ -469,9 +520,13 @@ window.__openagentRenderToolCard = function(card, onOpenSidebar) {
|
|
|
469
520
|
var cachedOutput = resTcid ? __cl_outputCardCache.get(resTcid) : null;
|
|
470
521
|
if (cachedOutput && cachedOutput.isConnected) {
|
|
471
522
|
_cl_applyCardUiState(cachedOutput, { toolCallId: resTcid, cardKind: 'result' });
|
|
472
|
-
|
|
473
|
-
if (
|
|
474
|
-
|
|
523
|
+
// ── 一次性外壳初始化:首次渲染时打开 native details + 隐藏 raw text,之后永久跳过 ──
|
|
524
|
+
if (!cachedOutput.__clShellReady) {
|
|
525
|
+
cachedOutput.__clShellReady = true;
|
|
526
|
+
_cl_forceOpenNativeToolDetails(cachedOutput, 'output-cache', resTcid);
|
|
527
|
+
if (typeof _cl_scheduleHostShellMark === 'function') _cl_scheduleHostShellMark(cachedOutput);
|
|
528
|
+
_cl_hideHostRawText(cachedOutput);
|
|
529
|
+
}
|
|
475
530
|
return cachedOutput;
|
|
476
531
|
}
|
|
477
532
|
|
|
@@ -554,6 +609,8 @@ function _cl_replayBufferedSteps(toolCallId, state) {
|
|
|
554
609
|
|
|
555
610
|
function _cl_hideHostRawText(cardNode) {
|
|
556
611
|
if (!cardNode) return;
|
|
612
|
+
// 幂等性守卫:如果父链已经标记为隐藏,跳过重复操作
|
|
613
|
+
if (cardNode.closest && cardNode.closest('.cl-remote-agent-raw-hidden')) return;
|
|
557
614
|
function hide() {
|
|
558
615
|
var hosts = _cl_collectRawTextHosts(cardNode);
|
|
559
616
|
for (var h = 0; h < hosts.length; h++) {
|
|
@@ -563,10 +620,7 @@ function _cl_hideHostRawText(cardNode) {
|
|
|
563
620
|
hide();
|
|
564
621
|
if (typeof requestAnimationFrame === 'function') requestAnimationFrame(hide);
|
|
565
622
|
setTimeout(hide, 0);
|
|
566
|
-
setTimeout(hide,
|
|
567
|
-
setTimeout(hide, 250);
|
|
568
|
-
setTimeout(hide, 800);
|
|
569
|
-
setTimeout(hide, 2000);
|
|
623
|
+
setTimeout(hide, 200);
|
|
570
624
|
}
|
|
571
625
|
|
|
572
626
|
function _cl_isRemoteToolNameText(text) {
|
|
@@ -800,8 +854,6 @@ function _cl_forceOpenNativeToolDetails(node, source, tcid) {
|
|
|
800
854
|
// openNearest 是幂等的(已 open 不重复操作),不需要防抖。
|
|
801
855
|
openNearest();
|
|
802
856
|
if (typeof requestAnimationFrame === 'function') requestAnimationFrame(openNearest);
|
|
803
|
-
setTimeout(openNearest, 0);
|
|
804
|
-
setTimeout(openNearest, 80);
|
|
805
857
|
setTimeout(openNearest, 300); // 兜底:慢速 Lit render / 异步 wrapper 挂载
|
|
806
858
|
}
|
|
807
859
|
|
|
@@ -895,6 +947,12 @@ function _cl_applyStoredRecordToModel(model, record) {
|
|
|
895
947
|
if (!model.agentAvatar) {
|
|
896
948
|
model.agentAvatar = args.agent_avatar || args.agentAvatar || args.avatar || args.avatar_url || args.avatarUrl || null;
|
|
897
949
|
}
|
|
950
|
+
if (!model.agentBio) {
|
|
951
|
+
model.agentBio = args.agent_bio || args.agentBio || '';
|
|
952
|
+
}
|
|
953
|
+
if (!model.agentStars) {
|
|
954
|
+
model.agentStars = args.agent_stars || args.agentStars || '3.2万';
|
|
955
|
+
}
|
|
898
956
|
var identity = CL && typeof CL.getAgentIdentity === 'function'
|
|
899
957
|
? CL.getAgentIdentity(model.agentId, model.agentName)
|
|
900
958
|
: null;
|
|
@@ -1300,8 +1358,6 @@ function _cl_updateCardSteps(card, steps) {
|
|
|
1300
1358
|
var stepEl = _clCreateStepElement(steps[i], i === steps.length - 1);
|
|
1301
1359
|
body.appendChild(stepEl);
|
|
1302
1360
|
}
|
|
1303
|
-
|
|
1304
|
-
_cl_forceOpenNativeToolDetails(card, 'steps-update', card.dataset && card.dataset.clCardTcid || '');
|
|
1305
1361
|
}
|
|
1306
1362
|
|
|
1307
1363
|
function _cl_autoOpenStepsIfUncontrolled(card) {
|
|
@@ -1309,7 +1365,11 @@ function _cl_autoOpenStepsIfUncontrolled(card) {
|
|
|
1309
1365
|
var uiState = _cl_getCardUiState(card);
|
|
1310
1366
|
if (uiState && uiState.stepsExpanded !== undefined) return;
|
|
1311
1367
|
|
|
1312
|
-
|
|
1368
|
+
// 缓存 body 引用,避免 5-16Hz Lit rerender 时重复 querySelector
|
|
1369
|
+
if (!card.__clStepsBody) {
|
|
1370
|
+
card.__clStepsBody = card.querySelector('.cl-tools-collapse-body');
|
|
1371
|
+
}
|
|
1372
|
+
var body = card.__clStepsBody;
|
|
1313
1373
|
if (!body) return;
|
|
1314
1374
|
|
|
1315
1375
|
body.classList.remove('cl-collapsed');
|
|
@@ -1364,6 +1424,11 @@ function _cl_countChunkTypes(chunks) {
|
|
|
1364
1424
|
}
|
|
1365
1425
|
|
|
1366
1426
|
function _cl_finalizeCard(card, steps) {
|
|
1427
|
+
if (card && card.classList && card.classList.contains('cl-exec-v2')) {
|
|
1428
|
+
if (typeof _clUpdateAgentStatusTextV2 === 'function') _clUpdateAgentStatusTextV2(card, 'completed');
|
|
1429
|
+
} else if (typeof _clUpdateAgentStatusText === 'function') {
|
|
1430
|
+
_clUpdateAgentStatusText(card, 'completed');
|
|
1431
|
+
}
|
|
1367
1432
|
var header = card.querySelector('.cl-tools-collapse-header-title');
|
|
1368
1433
|
if (header) {
|
|
1369
1434
|
header.textContent = '思考完成';
|
|
@@ -1374,6 +1439,20 @@ function _cl_finalizeCard(card, steps) {
|
|
|
1374
1439
|
dots[i].className = 'cl-tools-collapse-step-check';
|
|
1375
1440
|
}
|
|
1376
1441
|
|
|
1442
|
+
// 执行完成后隐藏第一个 chat-bubble(execution card),仅保留 output card
|
|
1443
|
+
// 仅 V2 启用:V1 的 output card 布局不同,不宜隐藏 execution bubble
|
|
1444
|
+
var isV2Finalize = typeof _clIsHostVersionGte === 'function' && _clIsHostVersionGte('2026.6.9');
|
|
1445
|
+
if (isV2Finalize && card && !card.__clBubbleHidden) {
|
|
1446
|
+
card.__clBubbleHidden = true;
|
|
1447
|
+
var bubble = card.closest && card.closest('.chat-bubble');
|
|
1448
|
+
if (bubble) {
|
|
1449
|
+
// 延迟隐藏,等 output card(第二个 bubble)渲染完毕
|
|
1450
|
+
setTimeout(function() {
|
|
1451
|
+
bubble.style.display = 'none';
|
|
1452
|
+
}, 500);
|
|
1453
|
+
}
|
|
1454
|
+
}
|
|
1455
|
+
|
|
1377
1456
|
// Finalize 只负责把 execution card 标记为完成态。
|
|
1378
1457
|
// 不在这里强制折叠 steps:OpenClaw 会周期性 rerender,若 finalize 每次都
|
|
1379
1458
|
// 写 cl-collapsed,会覆盖用户手动展开后的状态。
|