openclaw-openagent 1.0.12 → 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 (132) hide show
  1. package/dist/index.js +2 -0
  2. package/dist/src/config/config-schema.d.ts +9 -0
  3. package/dist/src/config/config-schema.js +6 -0
  4. package/dist/src/messaging/executor.d.ts +2 -3
  5. package/dist/src/messaging/executor.js +4 -31
  6. package/dist/src/plugin-ui/assets/openagent-override.js +124 -18
  7. package/dist/src/proxy/auth-proxy.js +5 -0
  8. package/dist/src/runtime/update-checker.d.ts +18 -0
  9. package/dist/src/runtime/update-checker.js +216 -0
  10. package/index.ts +3 -0
  11. package/package.json +1 -3
  12. package/src/app/channel-tools.ts +0 -249
  13. package/src/app/discovery-tools.ts +0 -273
  14. package/src/app/download-file-tool.ts +0 -133
  15. package/src/app/hooks.ts +0 -144
  16. package/src/app/index.ts +0 -84
  17. package/src/app/messaging-tools.ts +0 -79
  18. package/src/app/ops-tools.ts +0 -155
  19. package/src/app/remote-agent-tool.ts +0 -762
  20. package/src/app/types.ts +0 -68
  21. package/src/app/upload-file-tool.ts +0 -411
  22. package/src/app/verbose-preflight.ts +0 -190
  23. package/src/auth/config.ts +0 -266
  24. package/src/auth/credential-manager.ts +0 -146
  25. package/src/auth/index.ts +0 -24
  26. package/src/auth/verify.ts +0 -99
  27. package/src/channel.ts +0 -566
  28. package/src/compat.ts +0 -94
  29. package/src/config/config-schema.ts +0 -39
  30. package/src/messaging/aggregator.ts +0 -120
  31. package/src/messaging/collector.ts +0 -89
  32. package/src/messaging/executor.ts +0 -72
  33. package/src/messaging/inbound.ts +0 -150
  34. package/src/messaging/index.ts +0 -11
  35. package/src/messaging/mention-protocol.ts +0 -94
  36. package/src/messaging/process-c2c-request.ts +0 -564
  37. package/src/messaging/process-message.ts +0 -373
  38. package/src/messaging/scheduler.ts +0 -55
  39. package/src/messaging/types.ts +0 -38
  40. package/src/plugin-ui/adapters/oc-2026-04.js +0 -103
  41. package/src/plugin-ui/adapters/oc-2026-05.js +0 -125
  42. package/src/plugin-ui/adapters/oc-2026-06.js +0 -125
  43. package/src/plugin-ui/adapters/oc-unknown.js +0 -48
  44. package/src/plugin-ui/assets/agentbook-icon.svg +0 -5
  45. package/src/plugin-ui/assets/bg.png +0 -0
  46. package/src/plugin-ui/assets/icon.png +0 -0
  47. package/src/plugin-ui/assets/magic.svg +0 -5
  48. package/src/plugin-ui/assets/openagent-override.js +0 -11156
  49. package/src/plugin-ui/build.cjs +0 -463
  50. package/src/plugin-ui/index.ts +0 -18
  51. package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -570
  52. package/src/plugin-ui/modules/agent-book/panel/agent-card.js +0 -170
  53. package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -643
  54. package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +0 -665
  55. package/src/plugin-ui/modules/agent-book/panel/mention-state.js +0 -206
  56. package/src/plugin-ui/modules/agent-book/panel/styles.js +0 -833
  57. package/src/plugin-ui/modules/agent-book/panel/theme-adapter.js +0 -86
  58. package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +0 -295
  59. package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +0 -211
  60. package/src/plugin-ui/modules/agent-book/scanner.js +0 -131
  61. package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +0 -500
  62. package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +0 -652
  63. package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +0 -256
  64. package/src/plugin-ui/modules/loader/bootstrap.js +0 -38
  65. package/src/plugin-ui/modules/loader/shared-state.js +0 -838
  66. package/src/plugin-ui/modules/loader/ws-intercept.js +0 -199
  67. package/src/plugin-ui/modules/remote-agent/chunk-parser.js +0 -161
  68. package/src/plugin-ui/modules/remote-agent/execution-card.js +0 -530
  69. package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +0 -256
  70. package/src/plugin-ui/modules/remote-agent/media-links.js +0 -151
  71. package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +0 -134
  72. package/src/plugin-ui/modules/remote-agent/output-card.js +0 -342
  73. package/src/plugin-ui/modules/remote-agent/progress-store.js +0 -363
  74. package/src/plugin-ui/modules/remote-agent/render-hooks.js +0 -1700
  75. package/src/plugin-ui/modules/remote-agent/styles.js +0 -896
  76. package/src/plugin-ui/modules/remote-agent/tool-card-model.js +0 -130
  77. package/src/plugin-ui/postinstall-deploy.cjs +0 -52
  78. package/src/plugin-ui/ui-extension-loader/backup.ts +0 -92
  79. package/src/plugin-ui/ui-extension-loader/index.ts +0 -276
  80. package/src/plugin-ui/ui-extension-loader/locator.ts +0 -152
  81. package/src/plugin-ui/ui-extension-loader/manifest.ts +0 -57
  82. package/src/plugin-ui/ui-extension-loader/registry-regex.ts +0 -944
  83. package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +0 -70
  84. package/src/plugin-ui/ui-extension-loader/types.ts +0 -72
  85. package/src/proxy/auth-proxy.ts +0 -409
  86. package/src/runtime/account.ts +0 -549
  87. package/src/runtime/index.ts +0 -7
  88. package/src/runtime/plugin-runtime.ts +0 -94
  89. package/src/runtime/registry.ts +0 -71
  90. package/src/sdk/CLASS_MAP.md +0 -143
  91. package/src/sdk/index.d.ts +0 -126
  92. package/src/sdk/index.js +0 -23990
  93. package/src/sdk/modules/cloud-search-module.js +0 -1117
  94. package/src/sdk/modules/follow-module.js +0 -1069
  95. package/src/sdk/modules/group-module.js +0 -7397
  96. package/src/sdk/modules/relationship-module.js +0 -2269
  97. package/src/sdk/modules/signaling-module.js +0 -1468
  98. package/src/sdk/modules/tim-upload-plugin.js +0 -730
  99. package/src/sdk/node-env/http-request.js +0 -90
  100. package/src/sdk/node-env/index.js +0 -57
  101. package/src/sdk/node-env/storage.js +0 -114
  102. package/src/sdk/package.json +0 -10
  103. package/src/sdk/tsconfig.json +0 -16
  104. package/src/state/pending-invocation-store.ts +0 -43
  105. package/src/state/store.ts +0 -756
  106. package/src/tim/c2c.ts +0 -451
  107. package/src/tim/channels.ts +0 -364
  108. package/src/tim/client.ts +0 -330
  109. package/src/tim/index.ts +0 -18
  110. package/src/tim/messages.ts +0 -166
  111. package/src/tim/sdk-logger-init.ts +0 -50
  112. package/src/tools.ts +0 -10
  113. package/src/transport/factory.ts +0 -95
  114. package/src/transport/oasn/index.ts +0 -17
  115. package/src/transport/oasn/oasn-agent-card.ts +0 -111
  116. package/src/transport/oasn/oasn-discovery.ts +0 -108
  117. package/src/transport/oasn/oasn-files.ts +0 -210
  118. package/src/transport/oasn/oasn-http.ts +0 -529
  119. package/src/transport/oasn/oasn-invocation.ts +0 -604
  120. package/src/transport/oasn/oasn-normalize.ts +0 -133
  121. package/src/transport/oasn/oasn-register.ts +0 -33
  122. package/src/transport/oasn/oasn-transport.ts +0 -318
  123. package/src/transport/oasn/oasn-types.ts +0 -404
  124. package/src/transport/tim/index.ts +0 -8
  125. package/src/transport/tim/tim-transport.ts +0 -515
  126. package/src/transport/types.ts +0 -538
  127. package/src/types/openclaw-plugin-sdk-media-store.d.ts +0 -9
  128. package/src/types/openclaw.d.ts +0 -97
  129. package/src/types/tencentcloud-chat.d.ts +0 -15
  130. package/src/util/http.ts +0 -113
  131. package/src/util/logger.ts +0 -131
  132. 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
- }