openclaw-openagent 1.0.13 → 1.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/messaging/executor.d.ts +2 -3
- package/dist/src/messaging/executor.js +4 -31
- package/dist/src/plugin-ui/assets/openagent-override.js +4 -5
- package/dist/src/runtime/update-checker.d.ts +1 -1
- package/dist/src/runtime/update-checker.js +9 -46
- package/package.json +1 -3
- package/src/app/channel-tools.ts +0 -249
- package/src/app/discovery-tools.ts +0 -273
- package/src/app/download-file-tool.ts +0 -133
- package/src/app/hooks.ts +0 -144
- package/src/app/index.ts +0 -84
- package/src/app/messaging-tools.ts +0 -79
- package/src/app/ops-tools.ts +0 -155
- package/src/app/remote-agent-tool.ts +0 -762
- package/src/app/types.ts +0 -68
- package/src/app/upload-file-tool.ts +0 -411
- package/src/app/verbose-preflight.ts +0 -190
- package/src/auth/config.ts +0 -266
- package/src/auth/credential-manager.ts +0 -146
- package/src/auth/index.ts +0 -24
- package/src/auth/verify.ts +0 -99
- package/src/channel.ts +0 -566
- package/src/compat.ts +0 -94
- package/src/config/config-schema.ts +0 -45
- package/src/messaging/aggregator.ts +0 -120
- package/src/messaging/collector.ts +0 -89
- package/src/messaging/executor.ts +0 -72
- package/src/messaging/inbound.ts +0 -150
- package/src/messaging/index.ts +0 -11
- package/src/messaging/mention-protocol.ts +0 -94
- package/src/messaging/process-c2c-request.ts +0 -564
- package/src/messaging/process-message.ts +0 -373
- package/src/messaging/scheduler.ts +0 -55
- package/src/messaging/types.ts +0 -38
- package/src/plugin-ui/adapters/oc-2026-04.js +0 -103
- package/src/plugin-ui/adapters/oc-2026-05.js +0 -125
- package/src/plugin-ui/adapters/oc-2026-06.js +0 -125
- package/src/plugin-ui/adapters/oc-unknown.js +0 -48
- package/src/plugin-ui/assets/agentbook-icon.svg +0 -5
- package/src/plugin-ui/assets/bg.png +0 -0
- package/src/plugin-ui/assets/icon.png +0 -0
- package/src/plugin-ui/assets/magic.svg +0 -5
- package/src/plugin-ui/assets/openagent-override.js +0 -11263
- package/src/plugin-ui/build.cjs +0 -463
- package/src/plugin-ui/index.ts +0 -18
- package/src/plugin-ui/modules/agent-book/panel/agent-book.js +0 -570
- package/src/plugin-ui/modules/agent-book/panel/agent-card.js +0 -170
- package/src/plugin-ui/modules/agent-book/panel/agent-data.js +0 -643
- package/src/plugin-ui/modules/agent-book/panel/inject-ui.js +0 -665
- package/src/plugin-ui/modules/agent-book/panel/mention-state.js +0 -206
- package/src/plugin-ui/modules/agent-book/panel/styles.js +0 -832
- package/src/plugin-ui/modules/agent-book/panel/theme-adapter.js +0 -86
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/components-core.js +0 -295
- package/src/plugin-ui/modules/agent-book/remote-agent-tool/thought-chain-card.js +0 -211
- package/src/plugin-ui/modules/agent-book/scanner.js +0 -131
- package/src/plugin-ui/modules/agent-book/travelcard/travel-cards.js +0 -500
- package/src/plugin-ui/modules/agent-book/travelcard/travel-engine.js +0 -652
- package/src/plugin-ui/modules/agent-book/travelcard/travel-styles.js +0 -262
- package/src/plugin-ui/modules/loader/bootstrap.js +0 -133
- package/src/plugin-ui/modules/loader/shared-state.js +0 -838
- package/src/plugin-ui/modules/loader/ws-intercept.js +0 -199
- package/src/plugin-ui/modules/remote-agent/chunk-parser.js +0 -161
- package/src/plugin-ui/modules/remote-agent/execution-card.js +0 -530
- package/src/plugin-ui/modules/remote-agent/markdown-renderer.js +0 -256
- package/src/plugin-ui/modules/remote-agent/media-links.js +0 -151
- package/src/plugin-ui/modules/remote-agent/native-style-adapter.js +0 -134
- package/src/plugin-ui/modules/remote-agent/output-card.js +0 -342
- package/src/plugin-ui/modules/remote-agent/progress-store.js +0 -363
- package/src/plugin-ui/modules/remote-agent/render-hooks.js +0 -1700
- package/src/plugin-ui/modules/remote-agent/styles.js +0 -903
- package/src/plugin-ui/modules/remote-agent/tool-card-model.js +0 -130
- package/src/plugin-ui/postinstall-deploy.cjs +0 -52
- package/src/plugin-ui/ui-extension-loader/backup.ts +0 -92
- package/src/plugin-ui/ui-extension-loader/index.ts +0 -276
- package/src/plugin-ui/ui-extension-loader/locator.ts +0 -152
- package/src/plugin-ui/ui-extension-loader/manifest.ts +0 -57
- package/src/plugin-ui/ui-extension-loader/registry-regex.ts +0 -944
- package/src/plugin-ui/ui-extension-loader/removed-extensions.ts +0 -70
- package/src/plugin-ui/ui-extension-loader/types.ts +0 -72
- package/src/proxy/auth-proxy.ts +0 -414
- package/src/runtime/account.ts +0 -549
- package/src/runtime/index.ts +0 -7
- package/src/runtime/plugin-runtime.ts +0 -94
- package/src/runtime/registry.ts +0 -71
- package/src/runtime/update-checker.ts +0 -286
- package/src/sdk/CLASS_MAP.md +0 -143
- package/src/sdk/index.d.ts +0 -126
- package/src/sdk/index.js +0 -23990
- package/src/sdk/modules/cloud-search-module.js +0 -1117
- package/src/sdk/modules/follow-module.js +0 -1069
- package/src/sdk/modules/group-module.js +0 -7397
- package/src/sdk/modules/relationship-module.js +0 -2269
- package/src/sdk/modules/signaling-module.js +0 -1468
- package/src/sdk/modules/tim-upload-plugin.js +0 -730
- package/src/sdk/node-env/http-request.js +0 -90
- package/src/sdk/node-env/index.js +0 -57
- package/src/sdk/node-env/storage.js +0 -114
- package/src/sdk/package.json +0 -10
- package/src/sdk/tsconfig.json +0 -16
- package/src/state/pending-invocation-store.ts +0 -43
- package/src/state/store.ts +0 -756
- package/src/tim/c2c.ts +0 -451
- package/src/tim/channels.ts +0 -364
- package/src/tim/client.ts +0 -330
- package/src/tim/index.ts +0 -18
- package/src/tim/messages.ts +0 -166
- package/src/tim/sdk-logger-init.ts +0 -50
- package/src/tools.ts +0 -10
- package/src/transport/factory.ts +0 -95
- package/src/transport/oasn/index.ts +0 -17
- package/src/transport/oasn/oasn-agent-card.ts +0 -111
- package/src/transport/oasn/oasn-discovery.ts +0 -108
- package/src/transport/oasn/oasn-files.ts +0 -210
- package/src/transport/oasn/oasn-http.ts +0 -529
- package/src/transport/oasn/oasn-invocation.ts +0 -604
- package/src/transport/oasn/oasn-normalize.ts +0 -133
- package/src/transport/oasn/oasn-register.ts +0 -33
- package/src/transport/oasn/oasn-transport.ts +0 -318
- package/src/transport/oasn/oasn-types.ts +0 -404
- package/src/transport/tim/index.ts +0 -8
- package/src/transport/tim/tim-transport.ts +0 -515
- package/src/transport/types.ts +0 -538
- package/src/types/openclaw-plugin-sdk-media-store.d.ts +0 -9
- package/src/types/openclaw.d.ts +0 -97
- package/src/types/tencentcloud-chat.d.ts +0 -15
- package/src/util/http.ts +0 -113
- package/src/util/logger.ts +0 -131
- package/src/util/url-resolver.ts +0 -77
|
@@ -1,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 = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
|
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
|
-
}
|