opc-agent 4.1.24 → 4.2.0

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 (103) hide show
  1. package/CHANGELOG.md +59 -119
  2. package/COMPETITIVE-GAP.md +92 -92
  3. package/CONTRIBUTING.md +36 -36
  4. package/README.md +290 -290
  5. package/README.zh-CN.md +269 -269
  6. package/dist/channels/telegram.d.ts +0 -5
  7. package/dist/channels/telegram.d.ts.map +1 -1
  8. package/dist/channels/telegram.js +0 -108
  9. package/dist/channels/telegram.js.map +1 -1
  10. package/dist/channels/voice.d.ts +97 -71
  11. package/dist/channels/voice.d.ts.map +1 -1
  12. package/dist/channels/voice.js +347 -369
  13. package/dist/channels/voice.js.map +1 -1
  14. package/dist/channels/web.d.ts.map +1 -1
  15. package/dist/channels/web.js +2 -8
  16. package/dist/channels/web.js.map +1 -1
  17. package/dist/channels/wechat.js +6 -6
  18. package/dist/cli/chat.d.ts +1 -4
  19. package/dist/cli/chat.d.ts.map +1 -1
  20. package/dist/cli/chat.js +73 -680
  21. package/dist/cli/chat.js.map +1 -1
  22. package/dist/cli/setup.js +1 -1
  23. package/dist/cli/setup.js.map +1 -1
  24. package/dist/cli.js +280 -373
  25. package/dist/cli.js.map +1 -1
  26. package/dist/core/agent.d.ts +0 -1
  27. package/dist/core/agent.d.ts.map +1 -1
  28. package/dist/core/agent.js +0 -3
  29. package/dist/core/agent.js.map +1 -1
  30. package/dist/core/runtime.d.ts.map +1 -1
  31. package/dist/core/runtime.js +22 -192
  32. package/dist/core/runtime.js.map +1 -1
  33. package/dist/deploy/index.js +56 -56
  34. package/dist/doctor.d.ts +0 -1
  35. package/dist/doctor.d.ts.map +1 -1
  36. package/dist/doctor.js +10 -155
  37. package/dist/doctor.js.map +1 -1
  38. package/dist/index.d.ts +3 -4
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +9 -9
  41. package/dist/index.js.map +1 -1
  42. package/dist/memory/deepbrain.d.ts +1 -1
  43. package/dist/memory/deepbrain.d.ts.map +1 -1
  44. package/dist/memory/deepbrain.js +4 -95
  45. package/dist/memory/deepbrain.js.map +1 -1
  46. package/dist/memory/index.d.ts +0 -2
  47. package/dist/memory/index.d.ts.map +1 -1
  48. package/dist/memory/index.js +1 -3
  49. package/dist/memory/index.js.map +1 -1
  50. package/dist/memory/user-profiler.d.ts +0 -8
  51. package/dist/memory/user-profiler.d.ts.map +1 -1
  52. package/dist/memory/user-profiler.js +0 -89
  53. package/dist/memory/user-profiler.js.map +1 -1
  54. package/dist/scheduler/cron-engine.d.ts.map +1 -1
  55. package/dist/scheduler/cron-engine.js +36 -3
  56. package/dist/scheduler/cron-engine.js.map +1 -1
  57. package/dist/skills/auto-learn.d.ts.map +1 -1
  58. package/dist/skills/auto-learn.js +11 -65
  59. package/dist/skills/auto-learn.js.map +1 -1
  60. package/dist/skills/builtin/index.d.ts.map +1 -1
  61. package/dist/skills/builtin/index.js +30 -163
  62. package/dist/skills/builtin/index.js.map +1 -1
  63. package/dist/skills/types.d.ts +1 -1
  64. package/dist/skills/types.d.ts.map +1 -1
  65. package/dist/skills/types.js +0 -1
  66. package/dist/skills/types.js.map +1 -1
  67. package/dist/studio/server.d.ts +0 -1
  68. package/dist/studio/server.d.ts.map +1 -1
  69. package/dist/studio/server.js +12 -142
  70. package/dist/studio/server.js.map +1 -1
  71. package/dist/studio-ui/index.html +40 -359
  72. package/dist/ui/components.js +105 -105
  73. package/examples/README.md +22 -22
  74. package/examples/basic-agent.ts +90 -90
  75. package/examples/brain-integration.ts +71 -71
  76. package/examples/multi-channel.ts +74 -74
  77. package/install.ps1 +127 -127
  78. package/install.sh +154 -154
  79. package/models.json +164 -164
  80. package/package.json +63 -66
  81. package/scripts/install.ps1 +31 -31
  82. package/scripts/install.sh +40 -40
  83. package/templates/ecommerce-assistant/README.md +45 -45
  84. package/templates/ecommerce-assistant/oad.yaml +47 -47
  85. package/templates/tech-support/README.md +43 -43
  86. package/templates/tech-support/oad.yaml +45 -45
  87. package/.opc/memory.db +0 -0
  88. package/dist/core/model-recommender.d.ts +0 -40
  89. package/dist/core/model-recommender.d.ts.map +0 -1
  90. package/dist/core/model-recommender.js +0 -186
  91. package/dist/core/model-recommender.js.map +0 -1
  92. package/dist/memory/evolve-engine.d.ts +0 -113
  93. package/dist/memory/evolve-engine.d.ts.map +0 -1
  94. package/dist/memory/evolve-engine.js +0 -549
  95. package/dist/memory/evolve-engine.js.map +0 -1
  96. package/dist/memory/sqlite-store.d.ts +0 -40
  97. package/dist/memory/sqlite-store.d.ts.map +0 -1
  98. package/dist/memory/sqlite-store.js +0 -269
  99. package/dist/memory/sqlite-store.js.map +0 -1
  100. package/dist/scheduler/proactive.d.ts +0 -62
  101. package/dist/scheduler/proactive.d.ts.map +0 -1
  102. package/dist/scheduler/proactive.js +0 -185
  103. package/dist/scheduler/proactive.js.map +0 -1
@@ -388,9 +388,6 @@
388
388
  <div class="nav-item" data-page="global-models" onclick="navigate('global-models')">
389
389
  <span class="icon">🧠</span> Models
390
390
  </div>
391
- <div class="nav-item" data-page="global-channels" onclick="navigate('global-channels')">
392
- <span class="icon">📡</span> Channels
393
- </div>
394
391
  <div class="nav-item" data-page="global-memory" onclick="navigate('global-memory')">
395
392
  <span class="icon">💾</span> Memory
396
393
  </div>
@@ -422,14 +419,6 @@
422
419
  </div>
423
420
  <button class="btn btn-primary" onclick="navigate('create')">✨ Create New Agent</button>
424
421
  </div>
425
- <!-- Dashboard Stats -->
426
- <div class="card-grid" style="margin-bottom:24px;" id="dashboard-stats"></div>
427
- <!-- Quick Actions -->
428
- <div style="display:flex;gap:12px;flex-wrap:wrap;margin-bottom:24px;" id="dashboard-actions">
429
- <button class="btn btn-secondary" onclick="navigate('create')">✨ Create Agent</button>
430
- <button class="btn btn-secondary" onclick="navigate('global-models')">🧠 Configure Model</button>
431
- <button class="btn btn-secondary" onclick="navigate('templates')">📋 Browse Templates</button>
432
- </div>
433
422
  <!-- Health Status Section -->
434
423
  <div id="health-section" style="margin-bottom:24px;"></div>
435
424
  <div id="agents-list" class="card-grid"></div>
@@ -481,46 +470,31 @@
481
470
  <div class="agent-settings-content" id="agent-settings-content">
482
471
  <div class="agent-tab-panel active" id="atab-role">
483
472
  <h3>角色配置</h3>
484
- <div class="form-group"><label class="label">Agent 名称</label><input class="input" id="atab-role-name" placeholder="Agent name"></div>
485
- <div class="form-group"><label class="label">描述</label><textarea class="input" id="atab-role-desc" rows="2" placeholder="Brief description..."></textarea></div>
486
- <div class="form-group"><label class="label">System Prompt</label><textarea class="input" id="atab-role-prompt" rows="6" placeholder="You are a helpful assistant..."></textarea></div>
487
- <button class="btn btn-primary" onclick="saveAgentRole()">💾 保存</button>
488
- <span id="atab-role-status" style="margin-left:12px;font-size:18px;"></span>
473
+ <p style="color:var(--text-muted)">Agent 角色和人设配置(即将上线)</p>
489
474
  </div>
490
475
  <div class="agent-tab-panel" id="atab-models">
491
476
  <h3>模型配置</h3>
492
- <div class="form-group">
493
- <label style="display:flex;align-items:center;gap:8px;cursor:pointer;font-size:18px;"><input type="checkbox" id="atab-model-override"> 覆盖全局模型设置</label>
494
- </div>
495
- <div id="atab-model-fields" style="display:none;">
496
- <div class="form-group"><label class="label">Provider</label><select class="input" id="atab-model-provider"><option value="ollama">Ollama (Local)</option><option value="openai">OpenAI</option><option value="anthropic">Anthropic</option><option value="deepseek">DeepSeek</option></select></div>
497
- <div class="form-group"><label class="label">Model</label><input class="input" id="atab-model-name" placeholder="e.g. gpt-4o-mini"></div>
498
- <div class="form-group"><label class="label">Temperature</label><input class="input" id="atab-model-temp" type="number" min="0" max="2" step="0.1" value="0.7"></div>
499
- </div>
500
- <button class="btn btn-primary" onclick="saveAgentModel()">💾 保存</button>
501
- <span id="atab-model-status" style="margin-left:12px;font-size:18px;"></span>
477
+ <p style="color:var(--text-muted)">Agent 使用的模型配置(即将上线)</p>
502
478
  </div>
503
479
  <div class="agent-tab-panel" id="atab-channels">
504
480
  <h3>渠道配置</h3>
505
- <div id="atab-channels-list" style="font-size:18px;color:var(--text-muted);">加载中...</div>
506
- <button class="btn btn-primary" style="margin-top:16px;" onclick="saveAgentChannels()">💾 保存</button>
507
- <span id="atab-channels-status" style="margin-left:12px;font-size:18px;"></span>
481
+ <p style="color:var(--text-muted)">Agent 接入的渠道配置(即将上线)</p>
508
482
  </div>
509
483
  <div class="agent-tab-panel" id="atab-memory">
510
484
  <h3>记忆管理</h3>
511
- <div id="atab-memory-list" style="font-size:18px;color:var(--text-muted);">加载中...</div>
485
+ <p style="color:var(--text-muted)">Agent 记忆和知识库(即将上线)</p>
512
486
  </div>
513
487
  <div class="agent-tab-panel" id="atab-skills">
514
488
  <h3>技能配置</h3>
515
- <div id="atab-skills-list" style="font-size:18px;color:var(--text-muted);">加载中...</div>
489
+ <p style="color:var(--text-muted)">Agent 已安装的技能(即将上线)</p>
516
490
  </div>
517
491
  <div class="agent-tab-panel" id="atab-schedules">
518
492
  <h3>定时任务</h3>
519
- <div id="atab-schedules-list" style="font-size:18px;color:var(--text-muted);">加载中...</div>
493
+ <p style="color:var(--text-muted)">Agent 定时任务配置(即将上线)</p>
520
494
  </div>
521
495
  <div class="agent-tab-panel" id="atab-usage">
522
496
  <h3>用量统计</h3>
523
- <div id="atab-usage-content" style="font-size:18px;color:var(--text-muted);">加载中...</div>
497
+ <p style="color:var(--text-muted)">Agent 使用量和成本(即将上线)</p>
524
498
  </div>
525
499
  </div>
526
500
  </div>
@@ -633,42 +607,22 @@
633
607
  <label class="label">Company / Business Description</label>
634
608
  <textarea class="input" id="agent-desc" rows="3" placeholder="Brief description of your business so the agent can better help you..."></textarea>
635
609
  </div>
636
-
637
- <!-- AI Prompt Generator -->
638
- <div class="form-group">
639
- <label class="label">What should this agent do? <span style="color:var(--text-dim);font-size:13px;">(Describe in plain words, AI generates the prompt)</span></label>
640
- <textarea class="input" id="agent-task-desc" rows="2" placeholder="e.g. Help me answer customer questions about our products, be friendly and professional..."></textarea>
641
- <button class="btn btn-sm" style="margin-top:8px;background:var(--accent-light);color:var(--accent);border:1px solid var(--border);" onclick="generatePrompt()">✨ AI Generate Prompt</button>
642
- <textarea class="input" id="agent-prompt" rows="4" placeholder="System prompt will appear here (or write your own)..." style="margin-top:8px;display:none;"></textarea>
643
- </div>
644
-
645
610
  <div class="form-group">
646
611
  <label class="label">AI Model</label>
647
612
  <select class="input" id="agent-model">
648
- <option value="auto">🤖 Auto-detect (Ollama local first)</option>
649
- <option value="ollama/qwen2.5:7b">🏠 Ollama: Qwen 2.5 7B (Free, Local)</option>
650
- <option value="ollama/llama3.1:8b">🏠 Ollama: Llama 3.1 8B (Free, Local)</option>
651
- <option value="ollama/qwen2.5:0.5b">🏠 Ollama: Qwen 2.5 0.5B (Ultra-fast)</option>
652
- <option value="gpt-4o-mini">☁️ GPT-4o Mini (Fast & Affordable)</option>
653
- <option value="gpt-4o">☁️ GPT-4o (Most Capable)</option>
654
- <option value="claude-sonnet-4">☁️ Claude Sonnet (Balanced)</option>
655
- <option value="deepseek-v3">☁️ DeepSeek V3 (Affordable)</option>
656
- <option value="gemini-2.0-flash">☁️ Gemini Flash (Google)</option>
613
+ <option value="gpt-4o-mini">GPT-4o Mini (Fast & Affordable) ⭐ Recommended</option>
614
+ <option value="gpt-4o">GPT-4o (Most Capable)</option>
615
+ <option value="claude-sonnet-4">Claude Sonnet (Balanced)</option>
616
+ <option value="claude-haiku">Claude Haiku (Fast)</option>
617
+ <option value="gemini-2.0-flash">Gemini 2.0 Flash (Google)</option>
618
+ <option value="deepseek-v3">DeepSeek V3 (Open Source)</option>
657
619
  </select>
658
- <p style="color:var(--text-dim);font-size:12px;margin-top:4px;">🏠 = runs locally, free forever. ☁️ = needs API key.</p>
659
620
  </div>
660
-
661
- <!-- Skill Toggles -->
662
- <div class="form-group">
663
- <label class="label">Enable Skills <span style="color:var(--text-dim);font-size:13px;">(What can your agent do?)</span></label>
664
- <div id="skill-toggles" style="display:grid;grid-template-columns:repeat(auto-fill,minmax(200px,1fr));gap:8px;max-height:200px;overflow-y:auto;padding:4px;"></div>
665
- </div>
666
-
667
621
  <div class="form-group">
668
622
  <label class="label">Language Preference</label>
669
623
  <select class="input" id="agent-lang">
670
- <option value="zh">中文</option>
671
624
  <option value="en">English</option>
625
+ <option value="zh">中文</option>
672
626
  <option value="auto">Auto-detect</option>
673
627
  </select>
674
628
  </div>
@@ -781,10 +735,6 @@
781
735
  <label class="label">Description</label>
782
736
  <textarea class="input" id="sched-desc" rows="2" placeholder="e.g. Send a news summary every morning at 8am"></textarea>
783
737
  </div>
784
- <div class="form-group">
785
- <label class="label">Agent</label>
786
- <select class="input" id="sched-agent"></select>
787
- </div>
788
738
  <div class="form-group">
789
739
  <label class="label">Output Channel</label>
790
740
  <select class="input" id="sched-channel">
@@ -811,8 +761,17 @@
811
761
  </div>
812
762
  </div>
813
763
 
814
- <!-- Settings Page -->
815
- <div class="page" id="page-settings">
764
+ <!-- Channel Config Dialog -->
765
+ <div class="dialog-overlay" id="channel-dialog">
766
+ <div class="dialog" style="max-width:480px;width:92%;">
767
+ <div class="dialog-title" id="channel-dialog-title">配置渠道</div>
768
+ <div id="channel-dialog-body" style="margin-bottom:4px;"></div>
769
+ <div class="dialog-actions">
770
+ <button class="btn btn-secondary btn-sm" onclick="closeChannelDialog()">取消</button>
771
+ <button class="btn btn-primary btn-sm" onclick="saveCurrentChannel()">💾 保存</button>
772
+ </div>
773
+ <!-- Settings Page -->
774
+ <div class="page" id="page-settings">
816
775
  <div class="settings-layout">
817
776
  <div class="settings-nav">
818
777
  <div class="settings-nav-item active" data-settings="models" onclick="showSettings('models')">🤖 模型配置</div>
@@ -1030,6 +989,9 @@
1030
989
  </div>
1031
990
  </div>
1032
991
 
992
+ </div>
993
+ </div>
994
+
1033
995
  <!-- Delete Confirm Dialog -->
1034
996
  <div class="dialog-overlay" id="delete-dialog">
1035
997
  <div class="dialog">
@@ -1165,7 +1127,6 @@
1165
1127
  async function init() {
1166
1128
  await Promise.all([loadTemplates(), loadAgents(), loadSidebarAgents()]);
1167
1129
  loadSidebarGroups();
1168
- loadDashboardStats();
1169
1130
  handleRoute();
1170
1131
  window.addEventListener('popstate', handleRoute);
1171
1132
  checkFirstRun();
@@ -1306,7 +1267,7 @@
1306
1267
  document.getElementById('agent-chat-view').style.display = '';
1307
1268
  document.getElementById('agent-settings-view').style.display = 'none';
1308
1269
  document.getElementById('agent-detail-toggle').classList.remove('active');
1309
- const welcomeEl = document.querySelector('.agent-chat-welcome'); document.getElementById('agent-chat-messages').innerHTML = welcomeEl ? welcomeEl.outerHTML : '<div class="agent-chat-welcome"><div style="font-size:48px;margin-bottom:16px">💬</div><div style="font-size:18px;font-weight:600;margin-bottom:8px">开始对话</div><div style="color:var(--text-muted);font-size:14px">向你的 Agent 发送第一条消息</div></div>';
1270
+ document.getElementById('agent-chat-messages').innerHTML = document.querySelector('.agent-chat-welcome').outerHTML || '<div class="agent-chat-welcome"><div style="font-size:48px;margin-bottom:16px">💬</div><div style="font-size:18px;font-weight:600;margin-bottom:8px">开始对话</div><div style="color:var(--text-muted);font-size:14px">向你的 Agent 发送第一条消息</div></div>';
1310
1271
  document.getElementById('agent-chat-input').value = '';
1311
1272
 
1312
1273
  // Show agent detail page
@@ -1331,7 +1292,6 @@
1331
1292
  document.querySelector(`.agent-tab[data-atab="${tab}"]`)?.classList.add('active');
1332
1293
  document.querySelectorAll('.agent-tab-panel').forEach(p => p.classList.remove('active'));
1333
1294
  document.getElementById(`atab-${tab}`)?.classList.add('active');
1334
- if (typeof loadAgentTabData === 'function') loadAgentTabData(tab);
1335
1295
  }
1336
1296
 
1337
1297
  let agentChatHistory = [];
@@ -1430,12 +1390,11 @@
1430
1390
  const navItem = document.querySelector(`.nav-item[data-page="${page}"]`);
1431
1391
  if (navItem) navItem.classList.add('active');
1432
1392
 
1433
- if (page === 'dashboard') { loadAgents(); loadHealthDashboard(); loadSidebarAgents(); loadDashboardStats(); }
1393
+ if (page === 'dashboard') { loadAgents(); loadHealthDashboard(); loadSidebarAgents(); }
1434
1394
  if (page === 'create') { renderWizard(); renderWizardTemplates(); }
1435
1395
  if (page === 'settings') { showSettings(currentSettingsTab || 'models'); }
1436
1396
  if (page === 'global-runtime') { currentSettingsTab='status'; showSettings('status'); showPage('settings'); return; }
1437
1397
  if (page === 'global-models') { currentSettingsTab='models'; showSettings('models'); showPage('settings'); return; }
1438
- if (page === 'global-channels') { currentSettingsTab='channels'; showSettings('channels'); showPage('settings'); return; }
1439
1398
  if (page === 'global-memory') { currentSettingsTab='memory'; showSettings('memory'); showPage('settings'); return; }
1440
1399
  if (page === 'global-templates') { navigate('templates'); return; }
1441
1400
  if (page === 'create-group') { loadGroupAgentSelect(); }
@@ -1646,112 +1605,13 @@
1646
1605
  }
1647
1606
  if (wizardStep === 2 && selectedTemplate) {
1648
1607
  document.getElementById('agent-name').placeholder = selectedTemplate.name;
1649
- document.getElementById('agent-model').value = selectedTemplate.suggestedModel || 'auto';
1650
- renderSkillToggles();
1608
+ document.getElementById('agent-model').value = selectedTemplate.suggestedModel;
1651
1609
  }
1652
1610
  if (wizardStep === 3) {
1653
1611
  renderConfirmCard();
1654
1612
  }
1655
1613
  }
1656
1614
 
1657
- // --- Skill toggle rendering ---
1658
- const WIZARD_SKILL_CATEGORIES = {
1659
- productivity: { icon: '📋', label: 'Productivity' },
1660
- knowledge: { icon: '📚', label: 'Knowledge' },
1661
- creative: { icon: '✍️', label: 'Creative' },
1662
- developer: { icon: '💻', label: 'Developer' },
1663
- lifestyle: { icon: '🏠', label: 'Lifestyle' },
1664
- business: { icon: '💼', label: 'Business' },
1665
- education: { icon: '🎓', label: 'Education' },
1666
- };
1667
- const PRESET_SKILLS = [
1668
- { id: 'note-assistant', name: '📝 Notes', cat: 'productivity', default: true },
1669
- { id: 'todo-manager', name: '✅ Todo', cat: 'productivity', default: true },
1670
- { id: 'reminder', name: '🔔 Reminder', cat: 'productivity', default: true },
1671
- { id: 'reading-summary', name: '📚 Summarize', cat: 'knowledge', default: true },
1672
- { id: 'knowledge-search', name: '🔍 Search', cat: 'knowledge', default: true },
1673
- { id: 'dictionary-translator', name: '📖 Translate', cat: 'knowledge', default: false },
1674
- { id: 'calculator', name: '🧮 Calculate', cat: 'knowledge', default: false },
1675
- { id: 'writing-assistant', name: '✍️ Writing', cat: 'creative', default: true },
1676
- { id: 'social-media', name: '📱 Social', cat: 'creative', default: false },
1677
- { id: 'code-assistant', name: '💻 Code', cat: 'developer', default: false },
1678
- { id: 'data-analysis', name: '📊 Data', cat: 'knowledge', default: false },
1679
- { id: 'customer-followup', name: '🤝 CRM', cat: 'business', default: false },
1680
- { id: 'weather-query', name: '🌤 Weather', cat: 'lifestyle', default: false },
1681
- { id: 'language-tutor', name: '🗣 Language', cat: 'education', default: false },
1682
- { id: 'meeting-summarizer', name: '📋 Meeting', cat: 'productivity', default: false },
1683
- { id: 'brainstorm', name: '💡 Brainstorm', cat: 'creative', default: false },
1684
- ];
1685
- let selectedSkills = new Set(PRESET_SKILLS.filter(s => s.default).map(s => s.id));
1686
-
1687
- function renderSkillToggles() {
1688
- const grid = document.getElementById('skill-toggles');
1689
- if (!grid) return;
1690
- grid.innerHTML = PRESET_SKILLS.map(s => `
1691
- <label style="display:flex;align-items:center;gap:8px;padding:8px 12px;border-radius:10px;border:1px solid ${selectedSkills.has(s.id) ? 'var(--accent)' : 'var(--border)'};background:${selectedSkills.has(s.id) ? 'var(--accent-light)' : 'transparent'};cursor:pointer;font-size:14px;transition:all 0.2s;" onclick="toggleSkill('${s.id}',this)">
1692
- <input type="checkbox" ${selectedSkills.has(s.id) ? 'checked' : ''} style="display:none;">
1693
- <span>${s.name}</span>
1694
- </label>
1695
- `).join('');
1696
- }
1697
-
1698
- function toggleSkill(id, el) {
1699
- if (selectedSkills.has(id)) { selectedSkills.delete(id); } else { selectedSkills.add(id); }
1700
- renderSkillToggles();
1701
- }
1702
-
1703
- // --- AI Prompt Generator ---
1704
- async function generatePrompt() {
1705
- const taskDesc = document.getElementById('agent-task-desc').value.trim();
1706
- const tplName = selectedTemplate?.name || '';
1707
- const agentName = document.getElementById('agent-name').value.trim();
1708
- const bizDesc = document.getElementById('agent-desc').value.trim();
1709
-
1710
- if (!taskDesc && !tplName) { alert('Please describe what your agent should do'); return; }
1711
-
1712
- const promptArea = document.getElementById('agent-prompt');
1713
- promptArea.style.display = 'block';
1714
- promptArea.value = '✨ Generating prompt...';
1715
-
1716
- // Build the meta-prompt
1717
- const context = [
1718
- tplName ? `Role template: ${tplName}` : '',
1719
- agentName ? `Agent name: ${agentName}` : '',
1720
- bizDesc ? `Business: ${bizDesc}` : '',
1721
- taskDesc ? `User request: ${taskDesc}` : '',
1722
- `Enabled skills: ${[...selectedSkills].join(', ')}`,
1723
- ].filter(Boolean).join('\n');
1724
-
1725
- const metaPrompt = `Generate a system prompt for an AI agent with these requirements:\n${context}\n\nRules:\n- Be specific and actionable\n- Include personality traits\n- Mention the skills it can use\n- Keep it under 300 words\n- Write in the same language as the user's request\n\nOutput ONLY the system prompt, no explanation.`;
1726
-
1727
- try {
1728
- const res = await fetch(`${API}/api/agents/generate-prompt`, {
1729
- method: 'POST',
1730
- headers: { 'Content-Type': 'application/json' },
1731
- body: JSON.stringify({ prompt: metaPrompt }),
1732
- });
1733
- if (res.ok) {
1734
- const data = await res.json();
1735
- promptArea.value = data.prompt || data.text || 'Failed to generate. Try writing manually.';
1736
- } else {
1737
- // Fallback: generate a simple prompt locally
1738
- promptArea.value = generateLocalPrompt(tplName, taskDesc, bizDesc);
1739
- }
1740
- } catch {
1741
- // Offline fallback
1742
- promptArea.value = generateLocalPrompt(tplName, taskDesc, bizDesc);
1743
- }
1744
- }
1745
-
1746
- function generateLocalPrompt(role, task, biz) {
1747
- const parts = [`You are ${role || 'an AI assistant'}.`];
1748
- if (biz) parts.push(`You work for: ${biz}.`);
1749
- if (task) parts.push(`Your main job: ${task}.`);
1750
- parts.push('Be helpful, professional, and friendly. Ask clarifying questions when needed.');
1751
- if (selectedSkills.size > 0) parts.push(`You have access to these skills: ${[...selectedSkills].join(', ')}.`);
1752
- return parts.join('\n');
1753
- }
1754
-
1755
1615
  function wizardNext() {
1756
1616
  if (wizardStep === 1 && !selectedTemplate) { alert('Please select a template first'); return; }
1757
1617
  if (wizardStep < 3) { wizardStep++; renderWizard(); }
@@ -2604,31 +2464,8 @@
2604
2464
  let frCreatedAgentId = null;
2605
2465
 
2606
2466
  async function checkFirstRun() {
2607
- try {
2608
- const res = await fetch(`${API}/api/first-run/status`);
2609
- const data = await res.json();
2610
- if (data.completed) return; // already configured
2611
- // Check if models are configured — if so, skip
2612
- const modelRes = await fetch(`${API}/api/settings/models`);
2613
- const modelData = await modelRes.json();
2614
- const hasCloudKey = modelData.providers && Object.values(modelData.providers).some(p => p && p.apiKey);
2615
- if (hasCloudKey) return; // user already has API keys
2616
- // Check if Ollama is running with models
2617
- const ollamaRes = await fetch(`${API}/api/settings/models/local`);
2618
- const ollamaData = await ollamaRes.json();
2619
- if (ollamaData.running && ollamaData.models?.length > 0) {
2620
- // Ollama ready — auto-set local mode and skip wizard
2621
- await fetch(`${API}/api/settings/models`, {
2622
- method: 'PUT', headers: {'Content-Type':'application/json'},
2623
- body: JSON.stringify({ mode: 'local', provider: 'ollama', chatModel: ollamaData.models[0]?.name || 'qwen2.5:7b' })
2624
- });
2625
- return;
2626
- }
2627
- // Nothing configured — show wizard
2628
- showFirstRunWizard({ ollamaDetected: ollamaData.running, ollamaModels: ollamaData.models });
2629
- } catch {
2630
- // API not ready, skip
2631
- }
2467
+ // Skip first-run wizard — agents are configured via init
2468
+ return;
2632
2469
  }
2633
2470
 
2634
2471
  function showFirstRunWizard(data) {
@@ -2759,158 +2596,6 @@
2759
2596
  });
2760
2597
  }
2761
2598
 
2762
- // === Dashboard Stats ===
2763
- async function loadDashboardStats() {
2764
- const el = document.getElementById('dashboard-stats');
2765
- if (!el) return;
2766
- try {
2767
- const [agentsRes, modelsRes] = await Promise.all([
2768
- fetch('/api/agents').then(r=>r.json()).catch(()=>({})),
2769
- fetch('/api/settings/models').then(r=>r.json()).catch(()=>({})),
2770
- ]);
2771
- const agentList = agentsRes.agents || [];
2772
- const currentModel = modelsRes.chatModel || 'Not configured';
2773
- el.innerHTML = `
2774
- <div class="card stat-card"><div class="stat-value">${agentList.length}</div><div class="stat-label">Agents</div></div>
2775
- <div class="card stat-card"><div class="stat-value" style="font-size:18px;">${currentModel}</div><div class="stat-label">Current Model</div></div>
2776
- <div class="card stat-card"><div class="stat-value">${agentList.filter(a=>(a.status||'').toLowerCase()==='online').length}</div><div class="stat-label">Online</div></div>
2777
- `;
2778
- } catch { el.innerHTML = ''; }
2779
- }
2780
-
2781
- // === Agent Detail Settings Tab Logic ===
2782
-
2783
- async function loadAgentTabData(tab) {
2784
- if (!selectedAgentId) return;
2785
- const id = selectedAgentId;
2786
- try {
2787
- if (tab === 'role') {
2788
- const res = await fetch(`/api/agents/${id}`);
2789
- const a = await res.json();
2790
- document.getElementById('atab-role-name').value = a.name || '';
2791
- document.getElementById('atab-role-desc').value = a.description || '';
2792
- document.getElementById('atab-role-prompt').value = a.systemPrompt || a.prompt || '';
2793
- } else if (tab === 'models') {
2794
- const res = await fetch(`/api/agents/${id}`);
2795
- const a = await res.json();
2796
- const ov = document.getElementById('atab-model-override');
2797
- const fields = document.getElementById('atab-model-fields');
2798
- ov.checked = !!a.modelOverride;
2799
- fields.style.display = ov.checked ? '' : 'none';
2800
- ov.onchange = () => { fields.style.display = ov.checked ? '' : 'none'; };
2801
- if (a.modelOverride) {
2802
- document.getElementById('atab-model-provider').value = a.provider || 'ollama';
2803
- document.getElementById('atab-model-name').value = a.model || '';
2804
- document.getElementById('atab-model-temp').value = a.temperature ?? 0.7;
2805
- }
2806
- } else if (tab === 'channels') {
2807
- const chList = ['web','telegram','discord','slack','feishu','email','whatsapp'];
2808
- const res = await fetch(`/api/agents/${id}`);
2809
- const a = await res.json();
2810
- const enabled = a.channels || ['web'];
2811
- document.getElementById('atab-channels-list').innerHTML = chList.map(ch =>
2812
- `<label style="display:flex;align-items:center;gap:10px;padding:8px 0;font-size:18px;cursor:pointer;">
2813
- <input type="checkbox" class="atab-ch-cb" value="${ch}" ${enabled.includes(ch)?'checked':''}>
2814
- ${ch.charAt(0).toUpperCase()+ch.slice(1)}
2815
- </label>`
2816
- ).join('');
2817
- } else if (tab === 'memory') {
2818
- const el = document.getElementById('atab-memory-list');
2819
- el.innerHTML = '<span style="color:var(--text-muted);">⏳ Loading...</span>';
2820
- try {
2821
- const res = await fetch(`/api/agents/${id}/memory`);
2822
- const data = await res.json();
2823
- const entries = data.entries || [];
2824
- if (!entries.length) { el.innerHTML = '<p style="color:var(--text-muted);">No memories yet.</p>'; return; }
2825
- el.innerHTML = '<div class="timeline">' + entries.map(e =>
2826
- `<div class="timeline-item"><div class="timeline-date">${new Date(e.timestamp).toLocaleString()}</div><div class="timeline-content">${esc(e.summary||e.content||'')}</div></div>`
2827
- ).join('') + '</div>';
2828
- } catch { el.innerHTML = '<p style="color:var(--text-muted);">Failed to load memories.</p>'; }
2829
- } else if (tab === 'skills') {
2830
- const el = document.getElementById('atab-skills-list');
2831
- el.innerHTML = '<span style="color:var(--text-muted);">⏳ Loading...</span>';
2832
- try {
2833
- const res = await fetch(`/api/agents/${id}`);
2834
- const a = await res.json();
2835
- const skills = a.skills || [];
2836
- if (!skills.length) { el.innerHTML = '<p style="color:var(--text-muted);">No skills installed.</p>'; return; }
2837
- el.innerHTML = skills.map(s => `<div class="card" style="margin-bottom:8px;padding:12px;"><span style="font-size:18px;font-weight:600;">${s.name||s}</span></div>`).join('');
2838
- } catch { el.innerHTML = '<p style="color:var(--text-muted);">Failed to load skills.</p>'; }
2839
- } else if (tab === 'schedules') {
2840
- const el = document.getElementById('atab-schedules-list');
2841
- el.innerHTML = '<span style="color:var(--text-muted);">⏳ Loading...</span>';
2842
- try {
2843
- const res = await fetch('/api/schedules');
2844
- const all = await res.json();
2845
- const tasks = (Array.isArray(all)?all:[]).filter(t => t.agentId === id);
2846
- if (!tasks.length) { el.innerHTML = '<p style="color:var(--text-muted);">No schedules for this agent.</p>'; return; }
2847
- el.innerHTML = tasks.map(t => `<div class="card" style="margin-bottom:8px;padding:12px;display:flex;align-items:center;gap:12px;">
2848
- <span>⏰</span><div style="flex:1;"><div style="font-weight:600;font-size:18px;">${esc(t.name)}</div><div style="font-size:18px;color:var(--text-dim);">${esc(t.schedule||t.frequency||'')}</div></div>
2849
- <span style="font-size:18px;color:${t.enabled?'var(--green)':'var(--text-dim)'};">${t.enabled?'Active':'Paused'}</span>
2850
- </div>`).join('');
2851
- } catch { el.innerHTML = '<p style="color:var(--text-muted);">Failed to load schedules.</p>'; }
2852
- } else if (tab === 'usage') {
2853
- const el = document.getElementById('atab-usage-content');
2854
- el.innerHTML = '<span style="color:var(--text-muted);">⏳ Loading...</span>';
2855
- try {
2856
- const res = await fetch('/api/settings/usage');
2857
- const data = await res.json();
2858
- const tokens = data.totalTokens || 0;
2859
- const cost = data.totalCost || 0;
2860
- el.innerHTML = `<div class="card-grid"><div class="card stat-card"><div class="stat-value">${tokens>1000?(tokens/1000).toFixed(1)+'K':tokens}</div><div class="stat-label">Total Tokens</div></div><div class="card stat-card"><div class="stat-value">$${cost.toFixed(4)}</div><div class="stat-label">Est. Cost</div></div></div>`;
2861
- } catch { el.innerHTML = '<p style="color:var(--text-muted);">Failed to load usage data.</p>'; }
2862
- }
2863
- } catch(e) { console.error('loadAgentTabData error:', e); }
2864
- }
2865
-
2866
- async function saveAgentRole() {
2867
- if (!selectedAgentId) return;
2868
- const st = document.getElementById('atab-role-status');
2869
- try {
2870
- await fetch(`/api/agents/${selectedAgentId}`, { method:'PUT', headers:{'Content-Type':'application/json'}, body:JSON.stringify({
2871
- name: document.getElementById('atab-role-name').value.trim(),
2872
- description: document.getElementById('atab-role-desc').value.trim(),
2873
- systemPrompt: document.getElementById('atab-role-prompt').value.trim(),
2874
- })});
2875
- st.textContent = '✅ Saved'; st.style.color = 'var(--green)';
2876
- loadSidebarAgents();
2877
- } catch { st.textContent = '❌ Failed'; st.style.color = 'var(--red)'; }
2878
- }
2879
-
2880
- async function saveAgentModel() {
2881
- if (!selectedAgentId) return;
2882
- const st = document.getElementById('atab-model-status');
2883
- const ov = document.getElementById('atab-model-override').checked;
2884
- const body = { modelOverride: ov };
2885
- if (ov) { body.provider = document.getElementById('atab-model-provider').value; body.model = document.getElementById('atab-model-name').value; body.temperature = parseFloat(document.getElementById('atab-model-temp').value); }
2886
- try {
2887
- await fetch(`/api/agents/${selectedAgentId}`, { method:'PUT', headers:{'Content-Type':'application/json'}, body:JSON.stringify(body) });
2888
- st.textContent = '✅ Saved'; st.style.color = 'var(--green)';
2889
- } catch { st.textContent = '❌ Failed'; st.style.color = 'var(--red)'; }
2890
- }
2891
-
2892
- async function saveAgentChannels() {
2893
- if (!selectedAgentId) return;
2894
- const st = document.getElementById('atab-channels-status');
2895
- const channels = [...document.querySelectorAll('.atab-ch-cb:checked')].map(cb => cb.value);
2896
- try {
2897
- await fetch(`/api/agents/${selectedAgentId}`, { method:'PUT', headers:{'Content-Type':'application/json'}, body:JSON.stringify({ channels }) });
2898
- st.textContent = '✅ Saved'; st.style.color = 'var(--green)';
2899
- } catch { st.textContent = '❌ Failed'; st.style.color = 'var(--red)'; }
2900
- }
2901
-
2902
- // === Populate schedule form agent select ===
2903
- async function populateSchedAgentSelect() {
2904
- const sel = document.getElementById('sched-agent');
2905
- if (!sel) return;
2906
- try {
2907
- const res = await fetch('/api/agents');
2908
- const data = await res.json();
2909
- const list = data.agents || [];
2910
- sel.innerHTML = list.map(a => `<option value="${a.id}">${a.name||a.id}</option>`).join('');
2911
- } catch { sel.innerHTML = '<option value="">No agents</option>'; }
2912
- }
2913
-
2914
2599
  // === Start ===
2915
2600
  init();
2916
2601
 
@@ -2977,9 +2662,6 @@
2977
2662
  document.getElementById('sched-desc').value = task ? task.description : '';
2978
2663
  document.getElementById('sched-channel').value = task ? task.outputChannel : 'web';
2979
2664
  onSchedFreqChange();
2980
- populateSchedAgentSelect().then(() => {
2981
- if (task?.agentId) document.getElementById('sched-agent').value = task.agentId;
2982
- });
2983
2665
  }
2984
2666
 
2985
2667
  function hideScheduleForm() {
@@ -3000,7 +2682,6 @@
3000
2682
  time: document.getElementById('sched-time').value,
3001
2683
  schedule: document.getElementById('sched-frequency').value === 'custom' ? document.getElementById('sched-cron').value.trim() : '',
3002
2684
  description: document.getElementById('sched-desc').value.trim(),
3003
- agentId: document.getElementById('sched-agent').value,
3004
2685
  outputChannel: document.getElementById('sched-channel').value,
3005
2686
  enabled: true,
3006
2687
  };
@@ -3156,17 +2837,17 @@
3156
2837
  // =============================================
3157
2838
  async function saveImageGenConfig() {
3158
2839
  const data = {
3159
- openaiApiKey: document.getElementById('ig-openai-key')?.value?.trim() || '',
3160
- sdApiUrl: document.getElementById('ig-sd-url')?.value?.trim() || '',
3161
- replicateApiKey: document.getElementById('ig-replicate-key')?.value?.trim() || '',
2840
+ openaiApiKey: document.getElementById('ig-openai-key').value.trim(),
2841
+ sdApiUrl: document.getElementById('ig-sd-url').value.trim(),
2842
+ replicateApiKey: document.getElementById('ig-replicate-key').value.trim(),
3162
2843
  };
3163
2844
  try {
3164
2845
  await fetch('/api/image-gen/config', { method: 'PUT', headers: {'Content-Type':'application/json'}, body: JSON.stringify(data) });
3165
- const st = document.getElementById('ig-status');
3166
- if (st) { st.textContent = '✅ Configuration saved'; st.style.color = 'var(--green)'; }
2846
+ document.getElementById('ig-status').textContent = '✅ Configuration saved!';
2847
+ document.getElementById('ig-status').style.color = 'var(--green)';
3167
2848
  } catch(e) {
3168
- const st = document.getElementById('ig-status');
3169
- if (st) { st.textContent = '❌ Failed: ' + e.message; st.style.color = 'var(--red)'; }
2849
+ document.getElementById('ig-status').textContent = '❌ Failed: ' + e.message;
2850
+ document.getElementById('ig-status').style.color = 'var(--red)';
3170
2851
  }
3171
2852
  }
3172
2853