opc-agent 4.2.3 → 4.2.4

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.
@@ -177,11 +177,11 @@
177
177
  <div class="app">
178
178
  <!-- Sidebar -->
179
179
  <nav class="sidebar" id="sidebar">
180
- <div class="sidebar-logo">ΓÜí OPC Studio</div>
180
+ <div class="sidebar-logo">⚡ OPC Studio</div>
181
181
 
182
182
  <div class="sidebar-section">
183
183
  <div class="sidebar-item active" onclick="navigate('assistant')" id="nav-assistant">
184
- <span>🧑‍💻</span><span>OPC 助手</span>
184
+ <span>🧑‍💻</span><span>OPC 助手</span>
185
185
  <span class="status-dot"></span>
186
186
  </div>
187
187
  </div>
@@ -189,32 +189,32 @@
189
189
  <div class="sidebar-divider"></div>
190
190
 
191
191
  <div class="sidebar-section">
192
- <div class="sidebar-label">🤖 OPC Agent</div>
192
+ <div class="sidebar-label">🤖 OPC Agent</div>
193
193
  <div id="agent-list"></div>
194
- <div class="sidebar-item action" onclick="navigate('new-agent')"><span>Γ₧ò</span><span>µû░σ╗║ Agent</span></div>
195
- <div class="sidebar-item action" onclick="showToast('群组功能即将推出')"><span>👥</span><span>新建群组</span></div>
196
- <div class="sidebar-item" onclick="navigate('channels')"><span>📡</span><span>渠道配置</span></div>
194
+ <div class="sidebar-item action" onclick="navigate('new-agent')"><span>➕</span><span>新建 Agent</span></div>
195
+ <div class="sidebar-item action" onclick="showToast('群组功能即将推出')"><span>👥</span><span>新建群组</span></div>
196
+ <div class="sidebar-item" onclick="navigate('channels')"><span>📡</span><span>渠道配置</span></div>
197
197
  </div>
198
198
 
199
199
  <div class="sidebar-divider"></div>
200
200
 
201
201
  <div class="sidebar-section">
202
- <div class="sidebar-label">🧩 AgentKits</div>
203
- <div class="sidebar-item" onclick="navigate('models')" id="nav-models"><span>🤖</span><span>模型配置</span></div>
202
+ <div class="sidebar-label">🧩 AgentKits</div>
203
+ <div class="sidebar-item" onclick="navigate('models')" id="nav-models"><span>🤖</span><span>模型配置</span></div>
204
204
  </div>
205
205
 
206
206
  <div class="sidebar-divider"></div>
207
207
 
208
208
  <div class="sidebar-section">
209
- <div class="sidebar-label">🧠 DeepBrain</div>
210
- <div class="sidebar-item" onclick="navigate('knowledge')" id="nav-knowledge"><span>📖</span><span>知识库浏览</span></div>
209
+ <div class="sidebar-label">🧠 DeepBrain</div>
210
+ <div class="sidebar-item" onclick="navigate('knowledge')" id="nav-knowledge"><span>📖</span><span>知识库浏览</span></div>
211
211
  </div>
212
212
 
213
213
  <div class="sidebar-divider"></div>
214
214
 
215
215
  <div class="sidebar-section">
216
- <div class="sidebar-label">🖥️ Workstation</div>
217
- <div class="sidebar-item" onclick="navigate('workstation')" id="nav-workstation"><span>📋</span><span>岗位模板库</span></div>
216
+ <div class="sidebar-label">🖥️ Workstation</div>
217
+ <div class="sidebar-item" onclick="navigate('workstation')" id="nav-workstation"><span>📋</span><span>岗位模板库</span></div>
218
218
  </div>
219
219
  </nav>
220
220
 
@@ -224,30 +224,30 @@
224
224
  <!-- Page: OPC Assistant Chat -->
225
225
  <div class="page active" id="page-assistant">
226
226
  <div class="page-header">
227
- <span>🧑‍💻</span> OPC 助手
227
+ <span>🧑‍💻</span> OPC 助手
228
228
  <span class="status"></span>
229
- <span class="status-text">在线</span>
229
+ <span class="status-text">在线</span>
230
230
  </div>
231
231
  <div class="chat-container">
232
232
  <div class="chat-main">
233
233
  <div class="chat-messages" id="assistant-messages">
234
234
  <div class="chat-msg agent">
235
235
  <div class="bubble">
236
- 👋 你好!我是 OPC 助手。<br><br>
237
- 我可以帮你:<br>
238
- • 直接聊天<br>
239
- • 创建 AI Agent<br>
240
- • 配置渠道(Telegram / 微信 / 飞书)<br>
241
- • 回答关于 OPC 的任何问题<br><br>
242
- 试试跟我说点什么吧!
236
+ 👋 Σ╜áσÑ╜!µêæµÿ» OPC 助手。<br><br>
237
+ 我可以帮你:<br>
238
+ 答疑解惑<br>
239
+ 创建 AI Agent<br>
240
+ Θàìτ╜«渠道(Telegram / 微信 / 飞书)<br>
241
+ 处理关于 OPC 的任何问题<br><br>
242
+ Φ»òΦ»òΦ╖ƒµêæΦ»┤τé╣Σ╗ÇΣ╣êσɺ!
243
243
  </div>
244
244
  </div>
245
245
  </div>
246
246
  <div class="chat-input-bar">
247
- <button class="icon-btn">📎</button>
248
- <button class="icon-btn">🎤</button>
249
- <input type="text" id="assistant-input" placeholder="输入消息..." onkeydown="if(event.key==='Enter')sendAssistantMsg()">
250
- <button class="send-btn" onclick="sendAssistantMsg()">发送</button>
247
+ <button class="icon-btn">📎</button>
248
+ <button class="icon-btn">🎤</button>
249
+ <input type="text" id="assistant-input" placeholder="输入消息..." onkeydown="if(event.key==='Enter')sendAssistantMsg()">
250
+ <button class="send-btn" onclick="sendAssistantMsg()">发送</button>
251
251
  </div>
252
252
  </div>
253
253
  </div>
@@ -256,29 +256,29 @@
256
256
  <!-- Page: Agent Chat -->
257
257
  <div class="page" id="page-agent-chat">
258
258
  <div class="page-header">
259
- <span id="agent-chat-icon">🤖</span>
259
+ <span id="agent-chat-icon">🤖</span>
260
260
  <span id="agent-chat-name">Agent</span>
261
261
  <span class="status"></span>
262
- <span class="status-text">在线</span>
263
- <button class="settings-btn" onclick="toggleSettings()">⚙️</button>
262
+ <span class="status-text">在线</span>
263
+ <button class="settings-btn" onclick="toggleSettings()">⚙️</button>
264
264
  </div>
265
265
  <div class="chat-container">
266
266
  <div class="chat-main">
267
267
  <div class="chat-messages" id="agent-messages"></div>
268
268
  <div class="chat-input-bar">
269
- <button class="icon-btn">📎</button>
270
- <button class="icon-btn">🎤</button>
271
- <input type="text" id="agent-input" placeholder="输入消息..." onkeydown="if(event.key==='Enter')sendAgentMsg()">
272
- <button class="send-btn" onclick="sendAgentMsg()">发送</button>
269
+ <button class="icon-btn">📎</button>
270
+ <button class="icon-btn">🎤</button>
271
+ <input type="text" id="agent-input" placeholder="输入消息..." onkeydown="if(event.key==='Enter')sendAgentMsg()">
272
+ <button class="send-btn" onclick="sendAgentMsg()">发送</button>
273
273
  </div>
274
274
  </div>
275
275
  <div class="settings-panel" id="agent-settings">
276
276
  <div class="settings-tabs" id="settings-tabs">
277
- <div class="settings-tab active" onclick="switchSettingsTab('role')">角色</div>
278
- <div class="settings-tab" onclick="switchSettingsTab('model')">模型</div>
279
- <div class="settings-tab" onclick="switchSettingsTab('channel')">渠道</div>
280
- <div class="settings-tab" onclick="switchSettingsTab('memory')">记忆</div>
281
- <div class="settings-tab" onclick="switchSettingsTab('skills')">技能</div>
277
+ <div class="settings-tab active" onclick="switchSettingsTab('role')">角色</div>
278
+ <div class="settings-tab" onclick="switchSettingsTab('model')">模型</div>
279
+ <div class="settings-tab" onclick="switchSettingsTab('channel')">渠道</div>
280
+ <div class="settings-tab" onclick="switchSettingsTab('memory')">记忆</div>
281
+ <div class="settings-tab" onclick="switchSettingsTab('skills')">技能</div>
282
282
  </div>
283
283
  <div class="settings-content" id="settings-content">
284
284
  <!-- Filled by JS -->
@@ -289,106 +289,106 @@
289
289
 
290
290
  <!-- Page: Models Config (AgentKits) -->
291
291
  <div class="page" id="page-models">
292
- <div class="page-header"><span>🧩</span> AgentKits — 模型配置</div>
292
+ <div class="page-header"><span>🧩</span> AgentKits 模型配置</div>
293
293
  <div class="page-body" id="models-body">
294
294
  <div style="background:var(--yellow-light);border:1px solid var(--yellow);border-radius:var(--radius-sm);padding:12px 16px;margin-bottom:16px;font-size:14px;">
295
- <strong style="color:var(--yellow);">⚠️ 规则:</strong>没有配通 API Key 的 Provider,其模型不会出现在 Agent 的模型选择列表中。
295
+ <strong style="color:var(--yellow);">⚠️ ΦºäσêÖ:</strong>µ▓íµ£ë配通 API Key τÜä Provider,σà╢模型Σ╕ìΣ╝Üσç║τÄ░在 Agent τÜä模型ΘÇëµï⌐σêùΦí¿Σ╕¡。
296
296
  </div>
297
- <div id="models-content">加载中...</div>
297
+ <div id="models-content">加载中...</div>
298
298
  </div>
299
299
  </div>
300
300
 
301
301
  <!-- Page: Knowledge (DeepBrain) -->
302
302
  <div class="page" id="page-knowledge">
303
- <div class="page-header"><span>🧠</span> DeepBrain — 知识库</div>
303
+ <div class="page-header"><span>🧠</span> DeepBrain τƒÑΦ»åσ║ô</div>
304
304
  <div class="page-body">
305
305
  <div class="upload-zone" onclick="document.getElementById('file-upload').click()">
306
- <div class="icon">📂</div>
307
- <div class="title">拖入文档,自动分类</div>
308
- <div class="desc">支持 PDF · Word · TXT · Markdown · 网页链接</div>
309
- <div style="font-size:12px;color:var(--text-dim);margin-top:8px;">DeepBrain 自动分析内容,归入行业 / 岗位 / 工位层</div>
306
+ <div class="icon">📂</div>
307
+ <div class="title">µïûσàѵûçµíú,Φç¬σè¿σêåτ▒╗</div>
308
+ <div class="desc">支持 PDF · Word · TXT · Markdown · 网页链接</div>
309
+ <div style="font-size:12px;color:var(--text-dim);margin-top:8px;">DeepBrain Φç¬σè¿σêåµ₧Éσåàσ«╣,σ╜ÆσàÑΦíîΣ╕Ü / 岗位 / σ╖ÑΣ╜ìσ▒é</div>
310
310
  <input type="file" id="file-upload" style="display:none" multiple accept=".pdf,.doc,.docx,.txt,.md">
311
311
  </div>
312
312
 
313
313
  <div class="stat-row">
314
- <div class="stat-card" style="background:var(--blue-light);"><div class="num" style="color:var(--blue);" id="kb-total">0</div><div class="label">知识条目</div></div>
315
- <div class="stat-card" style="background:var(--green-light);"><div class="num" style="color:var(--green);" id="kb-evolve">0</div><div class="label">进化次数</div></div>
316
- <div class="stat-card" style="background:var(--yellow-light);"><div class="num" style="color:var(--yellow);" id="kb-docs">0</div><div class="label">文档已导入</div></div>
314
+ <div class="stat-card" style="background:var(--blue-light);"><div class="num" style="color:var(--blue);" id="kb-total">0</div><div class="label">知识条目</div></div>
315
+ <div class="stat-card" style="background:var(--green-light);"><div class="num" style="color:var(--green);" id="kb-evolve">0</div><div class="label">进化次数</div></div>
316
+ <div class="stat-card" style="background:var(--yellow-light);"><div class="num" style="color:var(--yellow);" id="kb-docs">0</div><div class="label">文档已导入</div></div>
317
317
  </div>
318
318
 
319
- <input type="text" class="search-input" placeholder="🔍 搜索知识..." oninput="searchKnowledge(this.value)">
319
+ <input type="text" class="search-input" placeholder="🔍 搜索知识..." oninput="searchKnowledge(this.value)">
320
320
 
321
321
  <div id="knowledge-layers">
322
322
  <div class="knowledge-card industry">
323
- <div style="font-weight:600;margin-bottom:4px;">🏢 行业知识</div>
324
- <div style="font-size:13px;color:var(--text-muted);">加载中...</div>
323
+ <div style="font-weight:600;margin-bottom:4px;">🏢 行业知识</div>
324
+ <div style="font-size:13px;color:var(--text-muted);">加载中...</div>
325
325
  </div>
326
326
  <div class="knowledge-card job">
327
- <div style="font-weight:600;margin-bottom:4px;">👔 岗位知识</div>
328
- <div style="font-size:13px;color:var(--text-muted);">加载中...</div>
327
+ <div style="font-weight:600;margin-bottom:4px;">👨 岗位知识</div>
328
+ <div style="font-size:13px;color:var(--text-muted);">加载中...</div>
329
329
  </div>
330
330
  <div class="knowledge-card station">
331
- <div style="font-weight:600;margin-bottom:4px;">🖥️ 工位知识</div>
332
- <div style="font-size:13px;color:var(--text-muted);">加载中...</div>
331
+ <div style="font-weight:600;margin-bottom:4px;">🖥️ 工位知识</div>
332
+ <div style="font-size:13px;color:var(--text-muted);">加载中...</div>
333
333
  </div>
334
334
  </div>
335
335
 
336
336
  <div style="font-size:12px;color:var(--text-dim);margin-top:16px;text-align:center;">
337
- 💡 所有 Agent 自动从知识库 recall 相关知识,无需手动分配
337
+ 💡 µëǵ£ë Agent Φç¬σè¿Σ╗ÄτƒÑΦ»åσ║ô recall τ¢╕σà│τƒÑΦ»å,µùáΘ£Çµëïσè¿σêåΘàì
338
338
  </div>
339
339
  </div>
340
340
  </div>
341
341
 
342
342
  <!-- Page: Workstation -->
343
343
  <div class="page" id="page-workstation">
344
- <div class="page-header"><span>🖥️</span> Workstation — 岗位模板库</div>
344
+ <div class="page-header"><span>🖥️</span> Workstation 岗位模板库</div>
345
345
  <div class="page-body">
346
- <input type="text" class="search-input" placeholder="🔍 搜索模板..." oninput="searchTemplates(this.value)">
346
+ <input type="text" class="search-input" placeholder="🔍 搜索模板..." oninput="searchTemplates(this.value)">
347
347
  <div class="breadcrumb" id="ws-breadcrumb">
348
- <a onclick="wsNavigate('root')">全部行业</a>
348
+ <a onclick="wsNavigate('root')">全部行业</a>
349
349
  </div>
350
- <div id="ws-content">加载中...</div>
350
+ <div id="ws-content">加载中...</div>
351
351
  </div>
352
352
  </div>
353
353
 
354
354
  <!-- Page: Channels -->
355
355
  <div class="page" id="page-channels">
356
- <div class="page-header"><span>📡</span> 渠道配置</div>
356
+ <div class="page-header"><span>📡</span> 渠道配置</div>
357
357
  <div class="page-body" id="channels-body">
358
- <div id="channels-content">加载中...</div>
358
+ <div id="channels-content">加载中...</div>
359
359
  </div>
360
360
  </div>
361
361
 
362
362
  <!-- Page: New Agent -->
363
363
  <div class="page" id="page-new-agent">
364
- <div class="page-header"><span>Γ₧ò</span> µû░σ╗║ Agent</div>
364
+ <div class="page-header"><span>➕</span> 新建 Agent</div>
365
365
  <div class="page-body">
366
366
  <div class="card" style="max-width:600px;">
367
367
  <div class="form-group">
368
- <label class="form-label">名称</label>
369
- <input class="form-input" id="new-agent-name" placeholder="给你的 Agent 起个名字">
368
+ <label class="form-label">名称</label>
369
+ <input class="form-input" id="new-agent-name" placeholder="给你的 Agent 取个名字">
370
370
  </div>
371
371
  <div class="form-group">
372
- <label class="form-label">描述</label>
373
- <input class="form-input" id="new-agent-desc" placeholder="这个 Agent 做什么?">
372
+ <label class="form-label">描述</label>
373
+ <input class="form-input" id="new-agent-desc" placeholder="这个 Agent 做什么?">
374
374
  </div>
375
375
  <div class="form-group">
376
- <label class="form-label">图标</label>
377
- <input class="form-input" id="new-agent-icon" placeholder="🤖" value="🤖" style="width:60px;">
376
+ <label class="form-label">图标</label>
377
+ <input class="form-input" id="new-agent-icon" placeholder="🤖" value="🤖" style="width:60px;">
378
378
  </div>
379
379
  <div class="form-group">
380
380
  <label class="form-label">System Prompt</label>
381
- <textarea class="form-input form-textarea" id="new-agent-prompt" placeholder="描述 Agent 的角色和行为..."></textarea>
381
+ <textarea class="form-input form-textarea" id="new-agent-prompt" placeholder="描述 Agent 的角色和行为..."></textarea>
382
382
  </div>
383
383
  <div class="form-group">
384
- <label class="form-label">模型</label>
384
+ <label class="form-label">模型</label>
385
385
  <select class="form-input" id="new-agent-model">
386
- <option value="">使用全局默认</option>
386
+ <option value="">使用全局默认</option>
387
387
  </select>
388
388
  </div>
389
389
  <div style="display:flex;gap:8px;margin-top:16px;">
390
- <button class="btn-primary" onclick="createAgent()">创建 Agent</button>
391
- <button class="btn-secondary" onclick="navigate('assistant')">取消</button>
390
+ <button class="btn-primary" onclick="createAgent()">创建 Agent</button>
391
+ <button class="btn-secondary" onclick="navigate('assistant')">取消</button>
392
392
  </div>
393
393
  </div>
394
394
  </div>
@@ -421,7 +421,7 @@
421
421
  } else if (page === 'agent' && data) {
422
422
  currentAgentId = data.id;
423
423
  document.getElementById('page-agent-chat').classList.add('active');
424
- document.getElementById('agent-chat-icon').textContent = data.icon || '🤖';
424
+ document.getElementById('agent-chat-icon').textContent = data.icon || '🤖';
425
425
  document.getElementById('agent-chat-name').textContent = data.name || data.id;
426
426
  const navItem = document.querySelector(`[data-agent-id="${data.id}"]`);
427
427
  if (navItem) navItem.classList.add('active');
@@ -462,12 +462,12 @@
462
462
  function renderAgentList() {
463
463
  const el = document.getElementById('agent-list');
464
464
  if (!agents.length) {
465
- el.innerHTML = '<div style="padding:4px 12px;font-size:12px;color:var(--text-dim);font-style:italic;">还没有 Agent</div>';
465
+ el.innerHTML = '<div style="padding:4px 12px;font-size:12px;color:var(--text-dim);font-style:italic;">还没有 Agent</div>';
466
466
  return;
467
467
  }
468
468
  el.innerHTML = agents.map(a => `
469
469
  <div class="sidebar-item${currentAgentId === a.id ? ' active' : ''}" data-agent-id="${a.id}" onclick="navigate('agent', ${JSON.stringify(a).replace(/"/g, '&quot;')})">
470
- <span>${a.icon || '🤖'}</span><span>${a.name || a.id}</span>
470
+ <span>${a.icon || '🤖'}</span><span>${a.name || a.id}</span>
471
471
  </div>
472
472
  `).join('');
473
473
  }
@@ -564,7 +564,7 @@
564
564
  }
565
565
  }
566
566
  }
567
- if (!fullText) bubble.innerHTML = '<em style="color:var(--text-dim);">(无响应)</em>';
567
+ if (!fullText) bubble.innerHTML = '<em style="color:var(--text-dim);">(无响应)</em>';
568
568
  } else {
569
569
  // JSON response
570
570
  const data = await res.json();
@@ -583,7 +583,7 @@
583
583
  if (ti) ti.remove();
584
584
  const errDiv = document.createElement('div');
585
585
  errDiv.className = 'chat-msg agent';
586
- errDiv.innerHTML = `<div class="bubble" style="color:var(--red);">⚠️ 发送失败: ${escapeHtml(e.message)}</div>`;
586
+ errDiv.innerHTML = `<div class="bubble" style="color:var(--red);">⚠️ 发送失败: ${escapeHtml(e.message)}</div>`;
587
587
  messagesEl.appendChild(errDiv);
588
588
  messagesEl.scrollTop = messagesEl.scrollHeight;
589
589
  }
@@ -600,7 +600,7 @@
600
600
  `<div class="chat-msg ${m.role === 'user' ? 'user' : 'agent'}"><div class="bubble">${m.role === 'user' ? escapeHtml(m.content) : m.content}</div></div>`
601
601
  ).join('');
602
602
  } else {
603
- el.innerHTML = `<div class="chat-msg agent"><div class="bubble">你好!有什么可以帮你的吗?</div></div>`;
603
+ el.innerHTML = `<div class="chat-msg agent"><div class="bubble">你好!有什么可以帮你的吗?</div></div>`;
604
604
  }
605
605
  el.scrollTop = el.scrollHeight;
606
606
  }
@@ -635,28 +635,28 @@
635
635
 
636
636
  if (tab === 'role') {
637
637
  el.innerHTML = `
638
- <div class="form-group"><label class="form-label">名称</label><input class="form-input" id="s-name" value="${escapeAttr(cfg.name || agent.name || '')}"></div>
639
- <div class="form-group"><label class="form-label">描述</label><input class="form-input" id="s-desc" value="${escapeAttr(cfg.description || '')}"></div>
640
- <div class="form-group"><label class="form-label">图标</label><input class="form-input" id="s-icon" value="${escapeAttr(cfg.icon || agent.icon || '🤖')}" style="width:60px"></div>
638
+ <div class="form-group"><label class="form-label">名称</label><input class="form-input" id="s-name" value="${escapeAttr(cfg.name || agent.name || '')}"></div>
639
+ <div class="form-group"><label class="form-label">描述</label><input class="form-input" id="s-desc" value="${escapeAttr(cfg.description || '')}"></div>
640
+ <div class="form-group"><label class="form-label">图标</label><input class="form-input" id="s-icon" value="${escapeAttr(cfg.icon || agent.icon || '🤖')}" style="width:60px"></div>
641
641
  <div class="form-group"><label class="form-label">System Prompt</label><textarea class="form-input form-textarea" id="s-prompt">${escapeHtml(cfg.systemPrompt || '')}</textarea></div>
642
- <button class="btn-primary" onclick="saveAgentSettings()">保存</button>
642
+ <button class="btn-primary" onclick="saveAgentSettings()">保存</button>
643
643
  `;
644
644
  } else if (tab === 'model') {
645
- el.innerHTML = '<div style="color:var(--text-dim);">加载可用模型...</div>';
645
+ el.innerHTML = '<div style="color:var(--text-dim);">加载可用模型...</div>';
646
646
  loadModelTab(agent);
647
647
  } else if (tab === 'memory') {
648
- el.innerHTML = '<div style="color:var(--text-dim);">加载记忆...</div>';
648
+ el.innerHTML = '<div style="color:var(--text-dim);">加载记忆...</div>';
649
649
  loadMemoryTab(agent.id || currentAgentId);
650
650
  } else if (tab === 'skills') {
651
651
  const skills = cfg.skills || [];
652
652
  el.innerHTML = `
653
- <div class="form-label">已安装技能</div>
654
- ${skills.length ? skills.map(s => `<div class="tag tag-blue">${s}</div>`).join(' ') : '<div style="color:var(--text-dim);font-size:13px;">暂无技能</div>'}
653
+ <div class="form-label">已安装技能</div>
654
+ ${skills.length ? skills.map(s => `<div class="tag tag-blue">${s}</div>`).join(' ') : '<div style="color:var(--text-dim);font-size:13px;">暂无技能</div>'}
655
655
  `;
656
656
  } else if (tab === 'channel') {
657
657
  el.innerHTML = `
658
- <div class="form-label">Agent 渠道</div>
659
- <div style="color:var(--text-dim);font-size:13px;">渠道在全局配置中管理 → <a style="color:var(--blue);cursor:pointer;" onclick="navigate('channels')">前往渠道配置</a></div>
658
+ <div class="form-label">Agent 渠道</div>
659
+ <div style="color:var(--text-dim);font-size:13px;">渠道在全局配置中管理 <a style="color:var(--blue);cursor:pointer;" onclick="navigate('channels')">前往渠道配置</a></div>
660
660
  `;
661
661
  }
662
662
  }
@@ -671,7 +671,7 @@
671
671
  const models = await modelsRes.json();
672
672
  const ollama = ollamaRes ? await ollamaRes.json() : { available: false, models: [] };
673
673
 
674
- let options = '<option value="">使用全局默认</option>';
674
+ let options = '<option value="">使用全局默认</option>';
675
675
  if (ollama.available && ollama.models) {
676
676
  ollama.models.filter(m => !m.name?.includes('embed')).forEach(m => {
677
677
  options += `<option value="ollama:${m.name}" ${agent.model === `ollama:${m.name}` ? 'selected' : ''}>${m.name} (Ollama)</option>`;
@@ -690,13 +690,13 @@
690
690
 
691
691
  el.innerHTML = `
692
692
  <div class="form-group">
693
- <label class="form-label">聊天模型</label>
693
+ <label class="form-label">选择模型</label>
694
694
  <select class="form-input" id="s-model">${options}</select>
695
695
  </div>
696
- <button class="btn-primary" onclick="saveAgentSettings()">保存</button>
696
+ <button class="btn-primary" onclick="saveAgentSettings()">保存</button>
697
697
  `;
698
698
  } catch (e) {
699
- el.innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
699
+ el.innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
700
700
  }
701
701
  }
702
702
 
@@ -707,13 +707,13 @@
707
707
  const data = await res.json();
708
708
  const items = data.memories || data.items || [];
709
709
  el.innerHTML = `
710
- <div class="form-label">Agent 记忆 (${items.length} 条)</div>
710
+ <div class="form-label">Agent 记忆 (${items.length} )</div>
711
711
  ${items.length ? items.slice(0, 20).map(m =>
712
712
  `<div style="background:var(--white);border:1px solid var(--border);border-radius:6px;padding:8px;margin:4px 0;font-size:12px;">${escapeHtml(typeof m === 'string' ? m : m.content || JSON.stringify(m))}</div>`
713
- ).join('') : '<div style="color:var(--text-dim);font-size:13px;">暂无记忆</div>'}
713
+ ).join('') : '<div style="color:var(--text-dim);font-size:13px;">暂无记忆</div>'}
714
714
  `;
715
715
  } catch (e) {
716
- el.innerHTML = `<div style="color:var(--text-dim);font-size:13px;">暂无记忆数据</div>`;
716
+ el.innerHTML = `<div style="color:var(--text-dim);font-size:13px;">暂无记忆数据</div>`;
717
717
  }
718
718
  }
719
719
 
@@ -736,9 +736,9 @@
736
736
  method: 'PUT', headers: { 'Content-Type': 'application/json' },
737
737
  body: JSON.stringify(body)
738
738
  });
739
- showToast('✅ 已保存');
739
+ showToast(' 已保存');
740
740
  loadAgents();
741
- } catch (e) { showToast('❌ 保存失败: ' + e.message); }
741
+ } catch (e) { showToast(' 保存失败: ' + e.message); }
742
742
  }
743
743
 
744
744
  // ======================== Models Config ========================
@@ -757,27 +757,27 @@
757
757
  // Ollama
758
758
  html += `<div class="card">
759
759
  <div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
760
- <span style="font-size:20px;">🦙</span><strong>本地模型(Ollama)</strong>
761
- ${ollama.available ? '<span class="status-dot" style="width:8px;height:8px;border-radius:50%;background:var(--green);display:inline-block;"></span><span style="font-size:12px;color:var(--green);">自动检测 · 无需 Key</span>' : '<span style="font-size:12px;color:var(--red);">未检测到</span>'}
760
+ <span style="font-size:20px;">🦙</span><strong>µ£¼σ£░模型(Ollama)</strong>
761
+ ${ollama.available ? '<span class="status-dot" style="width:8px;height:8px;border-radius:50%;background:var(--green);display:inline-block;"></span><span style="font-size:12px;color:var(--green);">Φç¬σ迵úǵ╡ï · µùá需 Key</span>' : '<span style="font-size:12px;color:var(--red);">未检测到</span>'}
762
762
  </div>
763
763
  ${ollama.available && ollama.models?.length ? `<table style="width:100%;font-size:13px;border-collapse:collapse;">
764
- <tr><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">模型</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">大小</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">状态</th></tr>
765
- ${ollama.models.map(m => `<tr><td style="padding:6px;">${m.name}</td><td style="padding:6px;">${formatSize(m.size)}</td><td style="padding:6px;color:var(--green);">✅ 可用</td></tr>`).join('')}
766
- </table>` : '<div style="font-size:13px;color:var(--text-muted);">请安装 Ollama 并拉取模型</div>'}
764
+ <tr><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">模型</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">大小</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">状态</th></tr>
765
+ ${ollama.models.map(m => `<tr><td style="padding:6px;">${m.name}</td><td style="padding:6px;">${formatSize(m.size)}</td><td style="padding:6px;color:var(--green);">✅ 可用</td></tr>`).join('')}
766
+ </table>` : '<div style="font-size:13px;color:var(--text-muted);">请安装 Ollama 并拉取模型</div>'}
767
767
  </div>`;
768
768
 
769
769
  // Cloud providers
770
770
  const cloudProviders = [
771
- { id: 'openai', name: 'OpenAI', models: 'GPT-4o ┬╖ GPT-4o-mini ┬╖ o1 ┬╖ o3' },
772
- { id: 'deepseek', name: 'DeepSeek', models: 'DeepSeek-V3 ┬╖ DeepSeek-R1' },
773
- { id: 'anthropic', name: 'Anthropic', models: 'Claude Opus ┬╖ Sonnet ┬╖ Haiku' },
774
- { id: 'google', name: 'Google Gemini', models: 'Gemini Pro ┬╖ Flash ┬╖ Ultra' },
771
+ { id: 'openai', name: 'OpenAI', models: 'GPT-4o · GPT-4o-mini · o1 · o3' },
772
+ { id: 'deepseek', name: 'DeepSeek', models: 'DeepSeek-V3 · DeepSeek-R1' },
773
+ { id: 'anthropic', name: 'Anthropic', models: 'Claude Opus · Sonnet · Haiku' },
774
+ { id: 'google', name: 'Google Gemini', models: 'Gemini Pro · Flash · Ultra' },
775
775
  ];
776
776
  const providers = modelsConfig.providers || {};
777
777
 
778
778
  html += `<div class="card">
779
779
  <div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
780
- <span style="font-size:20px;">☁️</span><strong>云端 API — 填 Key → 验证 → 解锁模型</strong>
780
+ <span style="font-size:20px;">Γÿü∩╕Å</span><strong>云端 API Key 验证 解锁模型</strong>
781
781
  </div>
782
782
  <div class="card-grid">
783
783
  ${cloudProviders.map(p => {
@@ -785,11 +785,11 @@
785
785
  const verified = cfg.verified;
786
786
  return `<div class="provider-card${verified ? ' verified' : ''}">
787
787
  <div class="provider-name">${p.name} <span style="width:8px;height:8px;border-radius:50%;background:${verified ? 'var(--green)' : 'var(--red)'};display:inline-block;"></span></div>
788
- <div class="provider-status" style="color:${verified ? 'var(--green)' : 'var(--red)'};">${verified ? '✅ 已验证' : '❌ 未配置'}</div>
789
- <div class="provider-models">${verified ? '解锁:' : ''}${p.models}${verified ? '' : '(需配 Key)'}</div>
788
+ <div class="provider-status" style="color:${verified ? 'var(--green)' : 'var(--red)'};">${verified ? ' 已验证' : ' 未配置'}</div>
789
+ <div class="provider-models">${verified ? '解锁:' : ''}${p.models}${verified ? '' : '(需配 Key'}</div>
790
790
  <div class="key-row">
791
- <input class="key-input" id="key-${p.id}" type="password" placeholder="输入 API Key..." value="${cfg.apiKey ? '••••••••' : ''}">
792
- <button class="verify-btn" onclick="verifyProvider('${p.id}')">验证</button>
791
+ <input class="key-input" id="key-${p.id}" type="password" placeholder="输入 API Key..." value="${cfg.apiKey ? '••••••••' : ''}">
792
+ <button class="verify-btn" onclick="verifyProvider('${p.id}')">验证</button>
793
793
  </div>
794
794
  </div>`;
795
795
  }).join('')}
@@ -799,27 +799,27 @@
799
799
  // Agent model assignment
800
800
  html += `<div class="card">
801
801
  <div style="display:flex;align-items:center;gap:8px;margin-bottom:12px;">
802
- <span style="font-size:20px;">🤖</span><strong>Agent 模型分配</strong>
803
- <span style="font-size:12px;color:var(--text-muted);">(只显示已配通的模型)</span>
802
+ <span style="font-size:20px;">🤖</span><strong>Agent 模型分配</strong>
803
+ <span style="font-size:12px;color:var(--text-muted);">(σŬµÿ╛τñ║σ╖▓配通τÜä模型)</span>
804
804
  </div>
805
805
  ${agents.length ? `<table style="width:100%;font-size:13px;border-collapse:collapse;">
806
- <tr><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">Agent</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">模型</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">来源</th></tr>
807
- ${agents.map(a => `<tr><td style="padding:6px;">${a.icon || '🤖'} ${a.name || a.id}</td><td style="padding:6px;">${a.model || modelsConfig.chatModel || 'auto'}</td><td style="padding:6px;"><span class="tag ${a.model ? 'tag-green' : 'tag-blue'}">${a.model ? 'Agent 覆盖' : '全局默认'}</span></td></tr>`).join('')}
808
- </table>` : '<div style="font-size:13px;color:var(--text-dim);">暂无 Agent</div>'}
806
+ <tr><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">Agent</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">模型</th><th style="text-align:left;padding:6px;border-bottom:1px solid var(--border);">来源</th></tr>
807
+ ${agents.map(a => `<tr><td style="padding:6px;">${a.icon || '🤖'} ${a.name || a.id}</td><td style="padding:6px;">${a.model || modelsConfig.chatModel || 'auto'}</td><td style="padding:6px;"><span class="tag ${a.model ? 'tag-green' : 'tag-blue'}">${a.model ? 'Agent 覆盖' : '全局默认'}</span></td></tr>`).join('')}
808
+ </table>` : '<div style="font-size:13px;color:var(--text-dim);">暂无 Agent</div>'}
809
809
  </div>`;
810
810
 
811
811
  el.innerHTML = html;
812
812
  } catch (e) {
813
- el.innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
813
+ el.innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
814
814
  }
815
815
  }
816
816
 
817
817
  async function verifyProvider(providerId) {
818
818
  const keyInput = document.getElementById(`key-${providerId}`);
819
819
  const apiKey = keyInput.value;
820
- if (!apiKey || apiKey === '••••••••') { showToast('请输入 API Key'); return; }
820
+ if (!apiKey || apiKey === '••••••••') { showToast('请输入 API Key'); return; }
821
821
 
822
- showToast('验证中...');
822
+ showToast('验证中...');
823
823
  try {
824
824
  const res = await fetch(`${API}/api/settings/models/test`, {
825
825
  method: 'POST', headers: { 'Content-Type': 'application/json' },
@@ -832,12 +832,12 @@
832
832
  method: 'PUT', headers: { 'Content-Type': 'application/json' },
833
833
  body: JSON.stringify({ providers: { ...modelsConfig.providers, [providerId]: { apiKey, verified: true, models: data.models || [] } } })
834
834
  });
835
- showToast(`✅ ${providerId} 验证成功`);
835
+ showToast(`✅ ${providerId} 验证成功`);
836
836
  loadModelsConfig();
837
837
  } else {
838
- showToast(`❌ 验证失败: ${data.error || '无效的 API Key'}`);
838
+ showToast(`❌ 验证失败: ${data.error || '无效的 API Key'}`);
839
839
  }
840
- } catch (e) { showToast(`❌ 验证失败: ${e.message}`); }
840
+ } catch (e) { showToast(`❌ 验证失败: ${e.message}`); }
841
841
  }
842
842
 
843
843
  // ======================== Knowledge ========================
@@ -861,7 +861,7 @@
861
861
  const data = await res.json();
862
862
  renderWorkstation(data);
863
863
  } catch (e) {
864
- document.getElementById('ws-content').innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
864
+ document.getElementById('ws-content').innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
865
865
  }
866
866
  }
867
867
 
@@ -879,12 +879,12 @@
879
879
  const industries = data.industries || [];
880
880
 
881
881
  // Breadcrumb
882
- let bcHtml = '<a onclick="wsNavigate(\'root\')">全部行业</a>';
882
+ let bcHtml = '<a onclick="wsNavigate(\'root\')">全部行业</a>';
883
883
  if (wsState.industry) {
884
- bcHtml += `<span class="sep">›</span><a onclick="wsNavigate('industry','${wsState.industry}')">${wsState.industry}</a>`;
884
+ bcHtml += `<span class="sep">›</span><a onclick="wsNavigate('industry','${wsState.industry}')">${wsState.industry}</a>`;
885
885
  }
886
886
  if (wsState.job) {
887
- bcHtml += `<span class="sep">›</span><span style="color:var(--text);font-weight:500;">${wsState.job}</span>`;
887
+ bcHtml += `<span class="sep">›</span><span style="color:var(--text);font-weight:500;">${wsState.job}</span>`;
888
888
  }
889
889
  bc.innerHTML = bcHtml;
890
890
 
@@ -895,24 +895,24 @@
895
895
 
896
896
  el.innerHTML = `
897
897
  <div class="card" style="border-left:4px solid var(--blue);">
898
- <div style="font-weight:600;margin-bottom:12px;">🏢 选择行业</div>
898
+ <div style="font-weight:600;margin-bottom:12px;">🏢 选择行业</div>
899
899
  <div class="filter-row">
900
900
  ${uniqueIndustries.map(i => `<div class="filter-tag" onclick="wsNavigate('industry','${i}')">${i}</div>`).join('')}
901
- ${!uniqueIndustries.length ? '<div style="color:var(--text-dim);font-size:13px;">暂无模板</div>' : ''}
901
+ ${!uniqueIndustries.length ? '<div style="color:var(--text-dim);font-size:13px;">暂无模板</div>' : ''}
902
902
  </div>
903
903
  </div>
904
904
  `;
905
905
  } else if (wsState.level === 'industry') {
906
906
  // Show jobs for selected industry
907
907
  const filtered = templates.filter(t => (t.industry || t.industryZh) === wsState.industry);
908
- const jobs = [...new Set(filtered.map(t => t.tags?.[1] || t.function || 'ΘÇÜτö¿').filter(Boolean))];
908
+ const jobs = [...new Set(filtered.map(t => t.tags?.[1] || t.function || '通用').filter(Boolean))];
909
909
 
910
910
  el.innerHTML = `
911
911
  <div class="card" style="border-left:4px solid var(--green);">
912
- <div style="font-weight:600;margin-bottom:12px;">👔 ${wsState.industry} — 选择岗位</div>
912
+ <div style="font-weight:600;margin-bottom:12px;">👨 ${wsState.industry} 选择岗位</div>
913
913
  <div class="filter-row">
914
914
  ${jobs.map(j => `<div class="filter-tag" onclick="wsNavigate('job','${j}')">${j}</div>`).join('')}
915
- ${!jobs.length ? '<div style="color:var(--text-dim);font-size:13px;">暂无岗位</div>' : ''}
915
+ ${!jobs.length ? '<div style="color:var(--text-dim);font-size:13px;">暂无岗位</div>' : ''}
916
916
  </div>
917
917
  </div>
918
918
  <div class="card-grid">
@@ -923,18 +923,18 @@
923
923
  // Show specific templates
924
924
  const filtered = templates.filter(t =>
925
925
  (t.industry || t.industryZh) === wsState.industry &&
926
- (t.tags?.[1] || t.function || 'ΘÇÜτö¿') === wsState.job
926
+ (t.tags?.[1] || t.function || '通用') === wsState.job
927
927
  );
928
928
  el.innerHTML = `
929
929
  <div class="card" style="border-left:4px solid var(--yellow);">
930
- <div style="font-weight:600;margin-bottom:12px;">🖥️ ${wsState.industry} › ${wsState.job} — 工位模板</div>
930
+ <div style="font-weight:600;margin-bottom:12px;">🖥️ ${wsState.industry} ${wsState.job} 工位模板</div>
931
931
  <div class="card-grid" style="margin:0;">
932
932
  ${filtered.map(t => renderTemplateCard(t)).join('')}
933
- ${!filtered.length ? '<div style="color:var(--text-dim);font-size:13px;">暂无模板</div>' : ''}
933
+ ${!filtered.length ? '<div style="color:var(--text-dim);font-size:13px;">暂无模板</div>' : ''}
934
934
  </div>
935
935
  </div>
936
936
  <div style="background:var(--blue-light);border:1px solid var(--blue);border-radius:var(--radius-sm);padding:16px;margin-top:16px;font-size:13px;">
937
- <strong style="color:var(--blue);">💡 Skill 自动叠加:</strong>选择工位模板后,Agent 自动获得行业 + 岗位 + 工位三层 Skill。
937
+ <strong style="color:var(--blue);">💡 Skill Φç¬σè¿σÅáσèá:</strong>ΘÇëµï⌐工位模板σÉÄ,Agent Φç¬σè¿ΦÄ╖σ╛ùΦíîΣ╕Ü + 岗位 + σ╖ÑΣ╜ìΣ╕ëσ▒é Skill
938
938
  </div>
939
939
  `;
940
940
  }
@@ -943,11 +943,11 @@
943
943
  function renderTemplateCard(t) {
944
944
  const skills = t.skills || [];
945
945
  return `<div class="card" style="cursor:pointer;" onclick="useTemplate('${t.id}')">
946
- <div style="font-size:24px;margin-bottom:8px;">${t.icon || '🤖'}</div>
946
+ <div style="font-size:24px;margin-bottom:8px;">${t.icon || '🤖'}</div>
947
947
  <div style="font-weight:600;">${t.nameZh || t.name}</div>
948
948
  <div style="font-size:12px;color:var(--text-muted);margin:4px 0;">${t.descriptionZh || t.description || ''}</div>
949
949
  ${skills.length ? `<div style="margin:4px 0;">${skills.slice(0, 3).map(s => `<span class="tag tag-yellow">${s}</span>`).join('')}</div>` : ''}
950
- <button class="btn-primary" style="width:100%;margin-top:8px;font-size:12px;" onclick="event.stopPropagation();useTemplate('${t.id}')">使用模板</button>
950
+ <button class="btn-primary" style="width:100%;margin-top:8px;font-size:12px;" onclick="event.stopPropagation();useTemplate('${t.id}')">使用模板</button>
951
951
  </div>`;
952
952
  }
953
953
 
@@ -958,11 +958,11 @@
958
958
  // Pre-fill new agent form
959
959
  document.getElementById('new-agent-name').value = tpl.nameZh || tpl.name || '';
960
960
  document.getElementById('new-agent-desc').value = tpl.descriptionZh || tpl.description || '';
961
- document.getElementById('new-agent-icon').value = tpl.icon || '🤖';
961
+ document.getElementById('new-agent-icon').value = tpl.icon || '🤖';
962
962
  document.getElementById('new-agent-prompt').value = tpl.systemPrompt || '';
963
963
  navigate('new-agent');
964
- showToast(`已加载模板: ${tpl.nameZh || tpl.name}`);
965
- } catch (e) { showToast('❌ 加载模板失败: ' + e.message); }
964
+ showToast(`已加载模板: ${tpl.nameZh || tpl.name}`);
965
+ } catch (e) { showToast(' 加载模板失败: ' + e.message); }
966
966
  }
967
967
 
968
968
  function searchTemplates(query) { /* TODO: search filter */ }
@@ -975,12 +975,12 @@
975
975
  const channels = await res.json();
976
976
 
977
977
  const channelDefs = [
978
- { id: 'telegram', name: 'Telegram', icon: '📱', fields: [{ key: 'token', label: 'Bot Token', placeholder: '123456:ABC-DEF...' }] },
979
- { id: 'wechat', name: '微信', icon: '💬', fields: [{ key: 'appId', label: 'App ID' }, { key: 'appSecret', label: 'App Secret' }] },
980
- { id: 'feishu', name: '飞书', icon: '🐦', fields: [{ key: 'appId', label: 'App ID' }, { key: 'appSecret', label: 'App Secret' }] },
981
- { id: 'slack', name: 'Slack', icon: '💼', fields: [{ key: 'token', label: 'Bot Token' }] },
982
- { id: 'discord', name: 'Discord', icon: '🎮', fields: [{ key: 'token', label: 'Bot Token' }] },
983
- { id: 'email', name: 'Email', icon: '📧', fields: [{ key: 'smtp', label: 'SMTP 地址' }, { key: 'password', label: '密码' }] },
978
+ { id: 'telegram', name: 'Telegram', icon: '📱', fields: [{ key: 'token', label: 'Bot Token', placeholder: '123456:ABC-DEF...' }] },
979
+ { id: 'wechat', name: '微信', icon: '💬', fields: [{ key: 'appId', label: 'App ID' }, { key: 'appSecret', label: 'App Secret' }] },
980
+ { id: 'feishu', name: '飞书', icon: '🐦', fields: [{ key: 'appId', label: 'App ID' }, { key: 'appSecret', label: 'App Secret' }] },
981
+ { id: 'slack', name: 'Slack', icon: '💼', fields: [{ key: 'token', label: 'Bot Token' }] },
982
+ { id: 'discord', name: 'Discord', icon: '🎮', fields: [{ key: 'token', label: 'Bot Token' }] },
983
+ { id: 'email', name: 'Email', icon: '📧', fields: [{ key: 'smtp', label: 'SMTP 地址' }, { key: 'password', label: '密码' }] },
984
984
  ];
985
985
 
986
986
  el.innerHTML = `<div class="card-grid">${channelDefs.map(ch => {
@@ -998,11 +998,11 @@
998
998
  <input class="form-input" style="font-size:13px;" id="ch-${ch.id}-${f.key}" type="password" placeholder="${f.placeholder || ''}" value="${cfg[f.key] || ''}">
999
999
  </div>
1000
1000
  `).join('')}
1001
- <button class="btn-primary" style="font-size:12px;" onclick="saveChannel('${ch.id}', [${ch.fields.map(f => `'${f.key}'`).join(',')}])">保存</button>
1001
+ <button class="btn-primary" style="font-size:12px;" onclick="saveChannel('${ch.id}', [${ch.fields.map(f => `'${f.key}'`).join(',')}])">保存</button>
1002
1002
  </div>`;
1003
1003
  }).join('')}</div>`;
1004
1004
  } catch (e) {
1005
- el.innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
1005
+ el.innerHTML = `<div style="color:var(--red);">加载失败: ${e.message}</div>`;
1006
1006
  }
1007
1007
  }
1008
1008
 
@@ -1014,19 +1014,19 @@
1014
1014
  method: 'PUT', headers: { 'Content-Type': 'application/json' },
1015
1015
  body: JSON.stringify(body)
1016
1016
  });
1017
- showToast(`✅ ${channelId} 已保存`);
1018
- } catch (e) { showToast('❌ 保存失败: ' + e.message); }
1017
+ showToast(`✅ ${channelId} 已保存`);
1018
+ } catch (e) { showToast(' 保存失败: ' + e.message); }
1019
1019
  }
1020
1020
 
1021
1021
  // ======================== Create Agent ========================
1022
1022
  async function createAgent() {
1023
1023
  const name = document.getElementById('new-agent-name').value.trim();
1024
- if (!name) { showToast('请输入名称'); return; }
1024
+ if (!name) { showToast('请输入名称'); return; }
1025
1025
 
1026
1026
  const body = {
1027
1027
  name,
1028
1028
  description: document.getElementById('new-agent-desc').value,
1029
- icon: document.getElementById('new-agent-icon').value || '🤖',
1029
+ icon: document.getElementById('new-agent-icon').value || '🤖',
1030
1030
  systemPrompt: document.getElementById('new-agent-prompt').value,
1031
1031
  model: document.getElementById('new-agent-model').value,
1032
1032
  };
@@ -1037,15 +1037,15 @@
1037
1037
  body: JSON.stringify(body)
1038
1038
  });
1039
1039
  const data = await res.json();
1040
- showToast(`✅ Agent "${name}" 已创建`);
1040
+ showToast(`✅ Agent "${name}" 已创建`);
1041
1041
  await loadAgents();
1042
1042
  navigate('agent', { id: data.id || name.toLowerCase().replace(/\s+/g, '-'), name, icon: body.icon });
1043
- } catch (e) { showToast('❌ 创建失败: ' + e.message); }
1043
+ } catch (e) { showToast(' 创建失败: ' + e.message); }
1044
1044
  }
1045
1045
 
1046
1046
  async function loadAvailableModels() {
1047
1047
  const sel = document.getElementById('new-agent-model');
1048
- sel.innerHTML = '<option value="">使用全局默认</option>';
1048
+ sel.innerHTML = '<option value="">使用全局默认</option>';
1049
1049
  try {
1050
1050
  const [modelsRes, ollamaRes] = await Promise.all([
1051
1051
  fetch(`${API}/api/settings/models`),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opc-agent",
3
- "version": "4.2.3",
3
+ "version": "4.2.4",
4
4
  "description": "Open Agent Framework — Build, test, and run AI Agents for business workstations",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",