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.
Files changed (128) hide show
  1. package/dist/src/messaging/executor.d.ts +2 -3
  2. package/dist/src/messaging/executor.js +4 -31
  3. package/dist/src/plugin-ui/assets/openagent-override.js +4 -5
  4. package/dist/src/runtime/update-checker.d.ts +1 -1
  5. package/dist/src/runtime/update-checker.js +9 -46
  6. package/package.json +1 -3
  7. package/src/app/channel-tools.ts +0 -249
  8. package/src/app/discovery-tools.ts +0 -273
  9. package/src/app/download-file-tool.ts +0 -133
  10. package/src/app/hooks.ts +0 -144
  11. package/src/app/index.ts +0 -84
  12. package/src/app/messaging-tools.ts +0 -79
  13. package/src/app/ops-tools.ts +0 -155
  14. package/src/app/remote-agent-tool.ts +0 -762
  15. package/src/app/types.ts +0 -68
  16. package/src/app/upload-file-tool.ts +0 -411
  17. package/src/app/verbose-preflight.ts +0 -190
  18. package/src/auth/config.ts +0 -266
  19. package/src/auth/credential-manager.ts +0 -146
  20. package/src/auth/index.ts +0 -24
  21. package/src/auth/verify.ts +0 -99
  22. package/src/channel.ts +0 -566
  23. package/src/compat.ts +0 -94
  24. package/src/config/config-schema.ts +0 -45
  25. package/src/messaging/aggregator.ts +0 -120
  26. package/src/messaging/collector.ts +0 -89
  27. package/src/messaging/executor.ts +0 -72
  28. package/src/messaging/inbound.ts +0 -150
  29. package/src/messaging/index.ts +0 -11
  30. package/src/messaging/mention-protocol.ts +0 -94
  31. package/src/messaging/process-c2c-request.ts +0 -564
  32. package/src/messaging/process-message.ts +0 -373
  33. package/src/messaging/scheduler.ts +0 -55
  34. package/src/messaging/types.ts +0 -38
  35. package/src/plugin-ui/adapters/oc-2026-04.js +0 -103
  36. package/src/plugin-ui/adapters/oc-2026-05.js +0 -125
  37. package/src/plugin-ui/adapters/oc-2026-06.js +0 -125
  38. package/src/plugin-ui/adapters/oc-unknown.js +0 -48
  39. package/src/plugin-ui/assets/agentbook-icon.svg +0 -5
  40. package/src/plugin-ui/assets/bg.png +0 -0
  41. package/src/plugin-ui/assets/icon.png +0 -0
  42. package/src/plugin-ui/assets/magic.svg +0 -5
  43. package/src/plugin-ui/assets/openagent-override.js +0 -11263
  44. package/src/plugin-ui/build.cjs +0 -463
  45. package/src/plugin-ui/index.ts +0 -18
  46. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -570
  47. package/src/plugin-ui/modules/agent-book/panel/agent-card.js +0 -170
  48. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -643
  49. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +0 -665
  50. package/src/plugin-ui/modules/agent-book/panel/mention-state.js +0 -206
  51. package/src/plugin-ui/modules/agent-book/panel/styles.js +0 -832
  52. package/src/plugin-ui/modules/agent-book/panel/theme-adapter.js +0 -86
  53. package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +0 -295
  54. package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +0 -211
  55. package/src/plugin-ui/modules/agent-book/scanner.js +0 -131
  56. package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +0 -500
  57. package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +0 -652
  58. package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +0 -262
  59. package/src/plugin-ui/modules/loader/bootstrap.js +0 -133
  60. package/src/plugin-ui/modules/loader/shared-state.js +0 -838
  61. package/src/plugin-ui/modules/loader/ws-intercept.js +0 -199
  62. package/src/plugin-ui/modules/remote-agent/chunk-parser.js +0 -161
  63. package/src/plugin-ui/modules/remote-agent/execution-card.js +0 -530
  64. package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +0 -256
  65. package/src/plugin-ui/modules/remote-agent/media-links.js +0 -151
  66. package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +0 -134
  67. package/src/plugin-ui/modules/remote-agent/output-card.js +0 -342
  68. package/src/plugin-ui/modules/remote-agent/progress-store.js +0 -363
  69. package/src/plugin-ui/modules/remote-agent/render-hooks.js +0 -1700
  70. package/src/plugin-ui/modules/remote-agent/styles.js +0 -903
  71. package/src/plugin-ui/modules/remote-agent/tool-card-model.js +0 -130
  72. package/src/plugin-ui/postinstall-deploy.cjs +0 -52
  73. package/src/plugin-ui/ui-extension-loader/backup.ts +0 -92
  74. package/src/plugin-ui/ui-extension-loader/index.ts +0 -276
  75. package/src/plugin-ui/ui-extension-loader/locator.ts +0 -152
  76. package/src/plugin-ui/ui-extension-loader/manifest.ts +0 -57
  77. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +0 -944
  78. package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +0 -70
  79. package/src/plugin-ui/ui-extension-loader/types.ts +0 -72
  80. package/src/proxy/auth-proxy.ts +0 -414
  81. package/src/runtime/account.ts +0 -549
  82. package/src/runtime/index.ts +0 -7
  83. package/src/runtime/plugin-runtime.ts +0 -94
  84. package/src/runtime/registry.ts +0 -71
  85. package/src/runtime/update-checker.ts +0 -286
  86. package/src/sdk/CLASS_MAP.md +0 -143
  87. package/src/sdk/index.d.ts +0 -126
  88. package/src/sdk/index.js +0 -23990
  89. package/src/sdk/modules/cloud-search-module.js +0 -1117
  90. package/src/sdk/modules/follow-module.js +0 -1069
  91. package/src/sdk/modules/group-module.js +0 -7397
  92. package/src/sdk/modules/relationship-module.js +0 -2269
  93. package/src/sdk/modules/signaling-module.js +0 -1468
  94. package/src/sdk/modules/tim-upload-plugin.js +0 -730
  95. package/src/sdk/node-env/http-request.js +0 -90
  96. package/src/sdk/node-env/index.js +0 -57
  97. package/src/sdk/node-env/storage.js +0 -114
  98. package/src/sdk/package.json +0 -10
  99. package/src/sdk/tsconfig.json +0 -16
  100. package/src/state/pending-invocation-store.ts +0 -43
  101. package/src/state/store.ts +0 -756
  102. package/src/tim/c2c.ts +0 -451
  103. package/src/tim/channels.ts +0 -364
  104. package/src/tim/client.ts +0 -330
  105. package/src/tim/index.ts +0 -18
  106. package/src/tim/messages.ts +0 -166
  107. package/src/tim/sdk-logger-init.ts +0 -50
  108. package/src/tools.ts +0 -10
  109. package/src/transport/factory.ts +0 -95
  110. package/src/transport/oasn/index.ts +0 -17
  111. package/src/transport/oasn/oasn-agent-card.ts +0 -111
  112. package/src/transport/oasn/oasn-discovery.ts +0 -108
  113. package/src/transport/oasn/oasn-files.ts +0 -210
  114. package/src/transport/oasn/oasn-http.ts +0 -529
  115. package/src/transport/oasn/oasn-invocation.ts +0 -604
  116. package/src/transport/oasn/oasn-normalize.ts +0 -133
  117. package/src/transport/oasn/oasn-register.ts +0 -33
  118. package/src/transport/oasn/oasn-transport.ts +0 -318
  119. package/src/transport/oasn/oasn-types.ts +0 -404
  120. package/src/transport/tim/index.ts +0 -8
  121. package/src/transport/tim/tim-transport.ts +0 -515
  122. package/src/transport/types.ts +0 -538
  123. package/src/types/openclaw-plugin-sdk-media-store.d.ts +0 -9
  124. package/src/types/openclaw.d.ts +0 -97
  125. package/src/types/tencentcloud-chat.d.ts +0 -15
  126. package/src/util/http.ts +0 -113
  127. package/src/util/logger.ts +0 -131
  128. package/src/util/url-resolver.ts +0 -77
@@ -1,643 +0,0 @@
1
- // ── Agent 数据(OASN API 适配)──
2
- //
3
- // OASN Discovery 端点:
4
- // GET /api/agent-card-categories 分类树
5
- // POST /api/agent-cards/search/by-query 自然语言搜索
6
- // POST /api/agent-cards/search/by-category 分类浏览
7
- // POST /api/agent-cards/search/by-tags 标签筛选
8
- //
9
- // 旧 TIM 端点(/api/agents、/api/agents/search)已废弃。
10
-
11
- const SEARCH_API = CL.AUTH_API + '/api/agent-cards/search/by-query';
12
- const SEARCH_BY_CATEGORY_API = CL.AUTH_API + '/api/agent-cards/search/by-category';
13
- const CATEGORIES_API = CL.AUTH_API + '/api/agent-card-categories';
14
-
15
- // ── Mock 数据(仅显式调试时使用)──
16
- // 格式对齐 OASN AgentCardResponse。生产路径不在 API 失败或空结果时自动回退。
17
-
18
- const _MOCK_AGENTS_BY_CATEGORY = {
19
- 'Travel': [
20
- { agent_id: 'mock_travel_planner', agent_type: 'service', name: 'Travel Planner',
21
- description: '智能旅行规划助手,根据你的预算和偏好生成个性化行程',
22
- MOM: null,
23
- tags: [{ tag_id: 't1', name: 'travel' }, { tag_id: 't2', name: 'planning' }],
24
- category: ['Travel'], avatar_url: null, visibility: 'public' },
25
- { agent_id: 'mock_hotel_finder', agent_type: 'service', name: 'Hotel Finder',
26
- description: '全球酒店比价搜索,帮你找到最优住宿方案',
27
- MOM: null,
28
- tags: [{ tag_id: 't1', name: 'travel' }, { tag_id: 't3', name: 'hotel' }],
29
- category: ['Travel'], avatar_url: null, visibility: 'public' },
30
- { agent_id: 'mock_flight_deals', agent_type: 'service', name: 'Flight Deals',
31
- description: '机票价格追踪与低价提醒,覆盖 200+ 航空公司',
32
- MOM: null,
33
- tags: [{ tag_id: 't1', name: 'travel' }, { tag_id: 't4', name: 'flight' }],
34
- category: ['Travel'], avatar_url: null, visibility: 'public' },
35
- ],
36
- 'Demo': [
37
- { agent_id: 'mock_echo_bot', agent_type: 'service', name: 'Echo Bot',
38
- description: '回声演示 Agent,原样返回你的输入内容',
39
- MOM: null,
40
- tags: [{ tag_id: 't5', name: 'demo' }, { tag_id: 't6', name: 'echo' }],
41
- category: ['Demo'], avatar_url: null, visibility: 'public' },
42
- { agent_id: 'mock_weather', agent_type: 'service', name: 'Weather Now',
43
- description: '实时天气查询,支持全球 10 万+ 城市',
44
- MOM: null,
45
- tags: [{ tag_id: 't5', name: 'demo' }, { tag_id: 't7', name: 'weather' }],
46
- category: ['Demo'], avatar_url: null, visibility: 'public' },
47
- ],
48
- 'Tool': [
49
- { agent_id: 'mock_translator', agent_type: 'service', name: 'Universal Translator',
50
- description: '多语言实时翻译,支持 50+ 语言互译',
51
- MOM: null,
52
- tags: [{ tag_id: 't8', name: 'tool' }, { tag_id: 't9', name: 'translation' }],
53
- category: ['Tool'], avatar_url: null, visibility: 'public' },
54
- { agent_id: 'mock_code_reviewer', agent_type: 'service', name: 'Code Reviewer',
55
- description: '自动代码审查,检测常见 bug 和安全漏洞',
56
- MOM: null,
57
- tags: [{ tag_id: 't8', name: 'tool' }, { tag_id: 't10', name: 'code' }],
58
- category: ['Tool'], avatar_url: null, visibility: 'public' },
59
- { agent_id: 'mock_image_gen', agent_type: 'service', name: 'Image Generator',
60
- description: 'AI 图片生成,用文字描述创造精美图像',
61
- MOM: null,
62
- tags: [{ tag_id: 't8', name: 'tool' }, { tag_id: 't11', name: 'image' }],
63
- category: ['Tool'], avatar_url: null, visibility: 'public' },
64
- { agent_id: 'mock_summarizer', agent_type: 'service', name: 'Text Summarizer',
65
- description: '长文摘要提取,一键获取文章核心要点',
66
- MOM: null,
67
- tags: [{ tag_id: 't8', name: 'tool' }, { tag_id: 't12', name: 'text' }],
68
- category: ['Tool'], avatar_url: null, visibility: 'public' },
69
- ],
70
- };
71
-
72
- /** 所有 mock agents 的扁平列表(供搜索用) */
73
- const _MOCK_AGENTS_ALL = Object.values(_MOCK_AGENTS_BY_CATEGORY).reduce(
74
- function(acc, arr) { return acc.concat(arr); }, []
75
- );
76
-
77
- function _setAgentBookError(message) {
78
- CL.agentBookLastError = message || '';
79
- }
80
-
81
- function _clearAgentBookError() {
82
- CL.agentBookLastError = '';
83
- }
84
-
85
- async function _readApiError(res) {
86
- try {
87
- const data = await res.json();
88
- return data.detail || data.error || ('API ' + res.status);
89
- } catch {
90
- return 'API ' + res.status;
91
- }
92
- }
93
-
94
- /**
95
- * 实时语义搜索 Agent(OASN: POST /api/agent-cards/search/by-query)
96
- * @param {string} query - 搜索词(用户输入文本去掉 @ 符号)
97
- * @param {AbortSignal} [signal] - 可选的 AbortController 信号
98
- * @returns {Promise<Array>} agent 列表
99
- */
100
- async function searchAgents(query, signal) {
101
- const q = (query || '').trim();
102
- if (!q) {
103
- return fetchAgents();
104
- }
105
- const cacheKey = q.toLowerCase();
106
- const now = Date.now();
107
- CL._agentSearchCache = CL._agentSearchCache || {};
108
- CL._agentSearchInflight = CL._agentSearchInflight || {};
109
- CL._agentSearchLogSeen = CL._agentSearchLogSeen || {};
110
-
111
- const cached = CL._agentSearchCache[cacheKey];
112
- if (cached && now - cached.ts < CL.CACHE_TTL) {
113
- return cached.results;
114
- }
115
- if (!signal && CL._agentSearchInflight[cacheKey]) {
116
- return CL._agentSearchInflight[cacheKey];
117
- }
118
-
119
- const runSearch = async function() {
120
- try {
121
- const res = await fetch(SEARCH_API, {
122
- method: 'POST',
123
- headers: { 'Content-Type': 'application/json' },
124
- body: JSON.stringify({ query: q, agentTypes: ['service'], pageSize: 10 }),
125
- signal,
126
- });
127
- if (!res.ok) {
128
- _setAgentBookError(await _readApiError(res));
129
- return _isMockEnabled() ? _mockSearch(q).map(function(agent) {
130
- return mapAgent(agent, { matchType: 'query', query: q });
131
- }) : [];
132
- }
133
- const data = await res.json();
134
- // OASN SearchResponse: 真实 API 用 agentCards,mock 用 agent_cards
135
- let list = data.agentCards || data.agent_cards || [];
136
- if (!list.length && _isMockEnabled()) {
137
- list = _mockSearch(q);
138
- }
139
- const mapped = list.map(function(agent) {
140
- return mapAgent(agent, { matchType: 'query', query: q });
141
- });
142
- _clearAgentBookError();
143
- CL._agentSearchCache[cacheKey] = { ts: Date.now(), results: mapped };
144
- const logKey = cacheKey + '|' + mapped.map(a => a.id || a.name || '').join(',');
145
- if (!CL._agentSearchLogSeen[logKey]) {
146
- CL._agentSearchLogSeen[logKey] = true;
147
- console.log('[cl-diag][agent-search] q=' + q +
148
- ' raw=' + list.length +
149
- ' mapped=' + mapped.length +
150
- ' ids=' + mapped.map(a => a.id || 'null').join('|') +
151
- ' names=' + mapped.map(a => a.name || 'null').join('|'));
152
- }
153
- return mapped;
154
- } catch (err) {
155
- if (err.name === 'AbortError') return []; // 正常取消
156
- console.warn('[openagent] searchAgents error:', err);
157
- _setAgentBookError(err.message || 'Agent Book API error');
158
- return [];
159
- }
160
- };
161
-
162
- if (!signal) {
163
- CL._agentSearchInflight[cacheKey] = runSearch().finally(function() {
164
- delete CL._agentSearchInflight[cacheKey];
165
- });
166
- return CL._agentSearchInflight[cacheKey];
167
- }
168
- return runSearch();
169
- }
170
-
171
- /**
172
- * 获取默认 Agent 列表(默认展示用)。
173
- * OASN 没有"列出全部"接口,从缓存的 sections 中提取,或加载分类后取首批。
174
- */
175
- async function fetchAgents() {
176
- const now = Date.now();
177
- if (CL.agentCache.length > 0 && now - CL.lastFetchTime < CL.CACHE_TTL) {
178
- return CL.agentCache;
179
- }
180
-
181
- // 优先从 sections 缓存提取
182
- if (CL.agentSectionsCache && CL.agentSectionsCache.length > 0) {
183
- const all = [];
184
- CL.agentSectionsCache.forEach(function(s) {
185
- if (s.children && s.children.length > 0) {
186
- s.children.forEach(function(c) { all.push.apply(all, c.agents || []); });
187
- } else {
188
- all.push.apply(all, s.agents || []);
189
- }
190
- });
191
- CL.agentCache = all;
192
- return all;
193
- }
194
-
195
- // 无缓存:先加载 sections 再提取
196
- const sections = await fetchAgentSections();
197
- const all = [];
198
- sections.forEach(function(s) {
199
- if (s.children && s.children.length > 0) {
200
- s.children.forEach(function(c) { all.push.apply(all, c.agents || []); });
201
- } else {
202
- all.push.apply(all, s.agents || []);
203
- }
204
- });
205
- CL.agentCache = all;
206
- return all;
207
- }
208
-
209
- /**
210
- * 获取服务端分类后的 Agent 列表。
211
- * OASN: GET /api/agent-card-categories → 分类树
212
- * POST /api/agent-cards/search/by-category → 每个分类的 agent 列表
213
- */
214
- async function fetchAgentSections() {
215
- const now = Date.now();
216
- if (CL.agentSectionsCache && now - CL.lastFetchTime < CL.CACHE_TTL) {
217
- return CL.agentSectionsCache;
218
- }
219
- if (CL._agentSectionsInflight) {
220
- return CL._agentSectionsInflight;
221
- }
222
-
223
- CL._agentSectionsInflight = (async function() {
224
- try {
225
- // Step 1: 获取分类树
226
- let categories;
227
- try {
228
- const catRes = await fetch(CATEGORIES_API + '?agent_type=service');
229
- if (!catRes.ok) throw new Error(await _readApiError(catRes));
230
- const catData = await catRes.json();
231
- // OASN CategoryTreeResponse: { categories: CategoryNodeResponse[], updated_at }
232
- categories = catData.categories || [];
233
- _clearAgentBookError();
234
- } catch (err) {
235
- console.warn('[openagent] fetchAgentSections categories error:', err);
236
- _setAgentBookError(err.message || 'Agent Book API error');
237
- categories = [];
238
- }
239
- if ((!Array.isArray(categories) || categories.length === 0) && _isMockEnabled()) {
240
- categories = _MOCK_CATEGORIES;
241
- }
242
- if (!Array.isArray(categories) || categories.length === 0) {
243
- CL.agentCache = [];
244
- CL.agentSectionsCache = [];
245
- CL.lastFetchTime = now;
246
- return [];
247
- }
248
-
249
- // Step 2 & 3: 加载各叶子分类的 agent 列表。
250
- // openPanel 和 textarea input 可能在同一轮 @ mention 中同时触发默认列表加载;
251
- // inflight 复用避免重复请求,统一限并发避免按父分类串行拖慢首屏。
252
- // 结构:{ title, children: [{title, agents}] } 或 { title, agents } (顶层即叶子)
253
- const sections = [];
254
- const allAgents = [];
255
- const CONCURRENCY = 6;
256
- const groups = categories.map(function(group) {
257
- return {
258
- group: group,
259
- leaves: (group.children && group.children.length > 0)
260
- ? group.children
261
- : [group],
262
- childSections: [],
263
- };
264
- });
265
- const jobs = [];
266
-
267
- groups.forEach(function(groupState) {
268
- groupState.leaves.forEach(function(cat) {
269
- jobs.push({ groupState: groupState, cat: cat });
270
- });
271
- });
272
-
273
- let results = await fetchCategoryAgentsBatch(jobs);
274
- if (!results) {
275
- results = [];
276
- for (let i = 0; i < jobs.length; i += CONCURRENCY) {
277
- const batch = jobs.slice(i, i + CONCURRENCY);
278
- const batchResults = await Promise.all(batch.map(function(job) {
279
- return fetchCategoryAgents(_categoryId(job.cat), job.cat.name);
280
- }));
281
- results.push.apply(results, batchResults);
282
- }
283
- }
284
-
285
- jobs.forEach(function(job, idx) {
286
- const cat = job.cat;
287
- const mapped = results[idx];
288
- if (mapped.length > 0) {
289
- allAgents.push.apply(allAgents, mapped);
290
- job.groupState.childSections.push({
291
- title: cat.name || cat.categoryId || cat.category_id || '',
292
- agents: mapped,
293
- });
294
- }
295
- });
296
-
297
- groups.forEach(function(groupState) {
298
- const group = groupState.group;
299
- const childSections = groupState.childSections;
300
- if (childSections.length === 0) return;
301
-
302
- if (group.children && group.children.length > 0) {
303
- // 有子分类 → 层级结构(父标题 + 子 sections)
304
- sections.push({
305
- title: group.name || group.categoryId || group.category_id || '',
306
- children: childSections,
307
- });
308
- } else {
309
- // 顶层即叶子 → 平铺(无父标题)
310
- sections.push({
311
- title: childSections[0].title,
312
- children: [],
313
- agents: childSections[0].agents,
314
- });
315
- }
316
- });
317
-
318
- CL.agentCache = allAgents;
319
- CL.agentSectionsCache = sections;
320
- CL.lastFetchTime = now;
321
- _clearAgentBookError();
322
- console.log('[cl-diag][agent-sections]', {
323
- rawCount: allAgents.length,
324
- sectionCount: sections.length,
325
- sections: sections.map(function(s) {
326
- if (s.children && s.children.length > 0) {
327
- return s.title + '[' + s.children.map(function(c) { return c.title + ':' + c.agents.length; }).join(',') + ']';
328
- }
329
- return s.title + ':' + (s.agents ? s.agents.length : 0);
330
- }),
331
- });
332
- return sections;
333
- } catch (err) {
334
- console.warn('[openagent] fetchAgentSections error:', err);
335
- _setAgentBookError(err.message || 'Agent Book API error');
336
- return CL.agentSectionsCache || (_isMockEnabled() ? _MOCK_CATEGORIES.map(function(c) {
337
- return { title: c.name, children: [], agents: (_getMockAgentsForCategory(c.name) || []).map(mapAgent) };
338
- }) : []);
339
- }
340
- })();
341
-
342
- return CL._agentSectionsInflight.finally(function() {
343
- CL._agentSectionsInflight = null;
344
- });
345
- }
346
-
347
- /**
348
- * 按分类 ID 加载 agent 列表。
349
- * POST /api/agent-cards/search/by-category { category: [category_id], agentTypes: ['service'] }
350
- * @param {string} categoryId - 分类 ID(如 "cat_demo_chat")
351
- * @param {string} displayName - 分类显示名(用于 mock fallback 匹配)
352
- */
353
- async function fetchCategoryAgents(categoryId, displayName) {
354
- try {
355
- const res = await fetch(SEARCH_BY_CATEGORY_API, {
356
- method: 'POST',
357
- headers: { 'Content-Type': 'application/json' },
358
- body: JSON.stringify({
359
- category: [categoryId],
360
- agentTypes: ['service'],
361
- pageSize: 50,
362
- }),
363
- });
364
- if (!res.ok) {
365
- if (!_isMockEnabled()) return [];
366
- const mock = _getMockAgentsForCategory(displayName) || _getMockAgentsForCategory(categoryId);
367
- return mock.map(mapAgent);
368
- }
369
- const data = await res.json();
370
- // OASN 真实 API 用 camelCase(agentCards),mock 用 snake_case(agent_cards)
371
- let list = data.agentCards || data.agent_cards || [];
372
- if (!list.length && _isMockEnabled()) {
373
- list = _getMockAgentsForCategory(displayName) || _getMockAgentsForCategory(categoryId) || [];
374
- }
375
- return list.map(mapAgent);
376
- } catch (err) {
377
- console.warn('[openagent] fetchCategoryAgents(' + categoryId + ') error:', err);
378
- if (!_isMockEnabled()) return [];
379
- const mock = _getMockAgentsForCategory(displayName) || _getMockAgentsForCategory(categoryId);
380
- return mock.map(mapAgent);
381
- }
382
- }
383
-
384
- function _categoryId(cat) {
385
- return cat && (cat.categoryId || cat.category_id || cat.id || '');
386
- }
387
-
388
- function _agentCategoryIds(agent) {
389
- const categories = Array.isArray(agent && agent.category)
390
- ? agent.category
391
- : (agent && agent.category ? [agent.category] : []);
392
- return categories.map(function(value) { return String(value || '').trim(); }).filter(Boolean);
393
- }
394
-
395
- function _uniqueJobCategoryIds(jobs) {
396
- const seen = Object.create(null);
397
- const ids = [];
398
- jobs.forEach(function(job) {
399
- const id = _categoryId(job.cat);
400
- if (!id || seen[id]) return;
401
- seen[id] = true;
402
- ids.push(id);
403
- });
404
- return ids;
405
- }
406
-
407
- async function fetchCategoryAgentsBatch(jobs) {
408
- const categoryIds = _uniqueJobCategoryIds(jobs);
409
- if (categoryIds.length === 0) return [];
410
-
411
- try {
412
- const res = await fetch(SEARCH_BY_CATEGORY_API, {
413
- method: 'POST',
414
- headers: { 'Content-Type': 'application/json' },
415
- body: JSON.stringify({
416
- category: categoryIds,
417
- agentTypes: ['service'],
418
- pageSize: categoryIds.length * 50,
419
- }),
420
- });
421
- if (!res.ok) return null;
422
-
423
- const data = await res.json();
424
- let list = data.agentCards || data.agent_cards || [];
425
- if (!list.length && _isMockEnabled()) {
426
- return jobs.map(function(job) {
427
- const cat = job.cat;
428
- const mock = _getMockAgentsForCategory(cat.name) || _getMockAgentsForCategory(_categoryId(cat));
429
- return mock.map(mapAgent);
430
- });
431
- }
432
-
433
- return jobs.map(function(job) {
434
- const id = _categoryId(job.cat);
435
- const seen = Object.create(null);
436
- return list.filter(function(agent) {
437
- const agentId = agent && (agent.agentId || agent.agent_id || agent.id || '');
438
- if (agentId && seen[agentId]) return false;
439
- if (_agentCategoryIds(agent).indexOf(id) < 0) return false;
440
- if (agentId) seen[agentId] = true;
441
- return true;
442
- }).map(mapAgent);
443
- });
444
- } catch (err) {
445
- console.warn('[openagent] fetchCategoryAgentsBatch error:', err);
446
- return null;
447
- }
448
- }
449
-
450
- /**
451
- * Mock 分类树(OASN CategoryTreeResponse.categories 格式)
452
- * API 不可用时 fallback 到这份数据,确保 UI 始终有内容可渲染。
453
- */
454
- const _MOCK_CATEGORIES = Object.keys(_MOCK_AGENTS_BY_CATEGORY).map(function(key) {
455
- return {
456
- category_id: 'mock_cat_' + key.toLowerCase(),
457
- name: key,
458
- children: [],
459
- };
460
- });
461
-
462
- /**
463
- * Mock 搜索:在 _MOCK_AGENTS_ALL 中做大小写不敏感的子串匹配
464
- * (name / description / tag name / category)
465
- */
466
- function _mockSearch(q) {
467
- const needle = (q || '').toLowerCase();
468
- if (!needle) return _MOCK_AGENTS_ALL.slice();
469
- return _MOCK_AGENTS_ALL.filter(function(a) {
470
- if ((a.name || '').toLowerCase().indexOf(needle) >= 0) return true;
471
- if ((a.description || '').toLowerCase().indexOf(needle) >= 0) return true;
472
- if ((a.category || []).some(function(c) { return c.toLowerCase().indexOf(needle) >= 0; })) return true;
473
- if (Array.isArray(a.tags) && a.tags.some(function(t) {
474
- return (t && t.name || '').toLowerCase().indexOf(needle) >= 0;
475
- })) return true;
476
- return false;
477
- });
478
- }
479
-
480
- function _isMockEnabled() {
481
- if (typeof CL !== 'undefined' && CL.AGENT_BOOK_MOCK === true) return true;
482
- try {
483
- return window.localStorage && window.localStorage.getItem('openagent.agentBookMock') === '1';
484
- } catch {
485
- return false;
486
- }
487
- }
488
-
489
- /** 从 mock 数据中按分类名或 ID 提取 agents */
490
- // 叶子分类名 → 父分类 mock key 的映射
491
- const _CATEGORY_ALIAS = {
492
- 'Chat': 'Demo', 'Tool': 'Demo',
493
- 'Trip Planner': 'Travel', 'Booking': 'Travel',
494
- 'Code': 'Tool', 'Code Review': 'Tool',
495
- };
496
-
497
- function _getMockAgentsForCategory(nameOrId) {
498
- // 精确匹配
499
- if (_MOCK_AGENTS_BY_CATEGORY[nameOrId]) {
500
- return _MOCK_AGENTS_BY_CATEGORY[nameOrId];
501
- }
502
- // alias 匹配(叶子 → 父分类)
503
- const alias = _CATEGORY_ALIAS[nameOrId];
504
- if (alias && _MOCK_AGENTS_BY_CATEGORY[alias]) {
505
- return _MOCK_AGENTS_BY_CATEGORY[alias];
506
- }
507
- // 大小写不敏感匹配
508
- const key = Object.keys(_MOCK_AGENTS_BY_CATEGORY).find(function(k) {
509
- return k.toLowerCase() === nameOrId.toLowerCase();
510
- });
511
- return key ? _MOCK_AGENTS_BY_CATEGORY[key] : [];
512
- }
513
-
514
- /** 统一的 agent 数据映射(OASN AgentCardResponse 格式) */
515
- function _uniqCompact(list) {
516
- const seen = Object.create(null);
517
- const out = [];
518
- (list || []).forEach(item => {
519
- const value = String(item || '').trim();
520
- if (!value) return;
521
- const key = value.toLowerCase();
522
- if (seen[key]) return;
523
- seen[key] = true;
524
- out.push(value);
525
- });
526
- return out;
527
- }
528
-
529
- function _normalizeSkills(skills) {
530
- if (!Array.isArray(skills)) return [];
531
- return skills.map(s => ({
532
- id: s && (s.id || s.skill_id || s.skillId) || '',
533
- name: s && s.name || '',
534
- description: s && s.description || '',
535
- tags: Array.isArray(s && s.tags) ? s.tags.filter(Boolean) : []
536
- }));
537
- }
538
-
539
- /**
540
- * OASN AgentCardResponse → 前端 agent 对象
541
- *
542
- * AgentCardResponse 字段:
543
- * agent_id, agent_type, name, description, MOM,
544
- * tags: [{tag_id, name}], category: string[], avatar_url, visibility
545
- */
546
- function mapAgent(a, meta) {
547
- meta = meta || {};
548
- const agentId = a.agent_id || a.agentId || a.id || a.tag ||
549
- a.user_id || a.userId || a.identifier || a.tim_user_id || a.timUserId || '';
550
- const avatarFull = a.avatar_url || a.avatarUrl || a.avatar || null;
551
-
552
- // OASN tags: [{tag_id, name}] → 提取 name 列表
553
- const tagNames = Array.isArray(a.tags)
554
- ? a.tags.map(function(t) { return (typeof t === 'string') ? t : (t && t.name) || ''; }).filter(Boolean)
555
- : [];
556
-
557
- const skills = _normalizeSkills(a.skills);
558
- const skillTags = skills.reduce((acc, s) => acc.concat(s.tags || [], s.name || ''), []);
559
-
560
- // OASN category: string[] → 取第一个作为主分类
561
- const categoryArray = Array.isArray(a.category) ? a.category : (a.category ? [a.category] : []);
562
- const primaryCategory = categoryArray[0] || '';
563
-
564
- const tags = _uniqCompact([]
565
- .concat(tagNames)
566
- .concat(skillTags)
567
- .concat(categoryArray)
568
- .concat(a.group || '', a.scene || '', a.type || a.agent_type || a.agentType || ''));
569
-
570
- if (!agentId) {
571
- console.warn('[cl-diag][agent-map] missing identifier', {
572
- name: a.name,
573
- keys: Object.keys(a || {}),
574
- raw: a,
575
- });
576
- }
577
- const mapped = {
578
- id: agentId,
579
- agent_id: agentId,
580
- name: a.name || 'Unknown',
581
- tag: agentId,
582
- bio: a.description || a.MOM || '',
583
- skills: skills,
584
- specialties: skills.map(s => s.name).filter(Boolean).join(', ') || '',
585
- category: primaryCategory,
586
- type: a.agent_type || a.type || a.agentType || '',
587
- tags: tags,
588
- avatar: avatarFull,
589
- claws: a.stars || 0,
590
- credit: a.credit_per_1k || 0.3,
591
- calls: a.total_calls || 0,
592
- owner: a.provider ? (typeof a.provider === 'string' ? a.provider : a.provider.name) : '',
593
- provider: a.provider || null,
594
- version: a.version || '',
595
- score: typeof a.score === 'number' ? a.score : null,
596
- matchType: meta.matchType || a.match_type || '',
597
- searchQuery: meta.query || '',
598
- visibility: a.visibility || 'public',
599
- };
600
- if (CL && typeof CL.storeAgentIdentity === 'function') {
601
- CL.storeAgentIdentity(mapped);
602
- }
603
- return mapped;
604
- }
605
-
606
- // ── 工具函数 ──
607
-
608
- function formatNumber(n) {
609
- if (n == null) return '0';
610
- if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
611
- return String(n);
612
- }
613
-
614
- function avatarUrl(agent) {
615
- if (agent.avatar) {
616
- // Avatar paths from API are relative to auth upstream (e.g. /avatars/oc1.png).
617
- // Route through Gateway proxy: /plugins/openagent/avatars/oc1.png
618
- if (agent.avatar.startsWith('/')) return CL.AUTH_API + agent.avatar;
619
- if (agent.avatar.startsWith('http')) return agent.avatar;
620
- return CL.AUTH_API + '/' + agent.avatar;
621
- }
622
- return './icon.png';
623
- }
624
-
625
- const ESC_MAP = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
626
- function escHtml(s) {
627
- if (!s) return '';
628
- return String(s).replace(/[&<>"']/g, c => ESC_MAP[c]);
629
- }
630
-
631
- // DOM 构建工具(全局共用)
632
- function _el(tag, cls, styles) {
633
- const e = document.createElement(tag);
634
- if (cls) e.className = cls;
635
- if (styles) Object.assign(e.style, styles);
636
- return e;
637
- }
638
-
639
- function _text(tag, cls, text, styles) {
640
- const e = _el(tag, cls, styles);
641
- e.textContent = text;
642
- return e;
643
- }