opc-agent 4.1.2 → 4.1.3

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 (738) hide show
  1. package/dist/analytics/index.d.ts.map +1 -0
  2. package/dist/analytics/index.js.map +1 -0
  3. package/dist/channels/dingtalk.d.ts.map +1 -0
  4. package/dist/channels/dingtalk.js.map +1 -0
  5. package/dist/channels/discord.d.ts.map +1 -0
  6. package/dist/channels/discord.js.map +1 -0
  7. package/dist/channels/email.d.ts.map +1 -0
  8. package/dist/channels/email.js.map +1 -0
  9. package/dist/channels/feishu.d.ts.map +1 -0
  10. package/dist/channels/feishu.js.map +1 -0
  11. package/dist/channels/googlechat.d.ts.map +1 -0
  12. package/dist/channels/googlechat.js.map +1 -0
  13. package/dist/channels/imessage.d.ts.map +1 -0
  14. package/dist/channels/imessage.js.map +1 -0
  15. package/dist/channels/index.d.ts.map +1 -0
  16. package/dist/channels/index.js.map +1 -0
  17. package/dist/channels/irc.d.ts.map +1 -0
  18. package/dist/channels/irc.js.map +1 -0
  19. package/dist/channels/line.d.ts.map +1 -0
  20. package/dist/channels/line.js.map +1 -0
  21. package/dist/channels/matrix.d.ts.map +1 -0
  22. package/dist/channels/matrix.js.map +1 -0
  23. package/dist/channels/mattermost.d.ts.map +1 -0
  24. package/dist/channels/mattermost.js.map +1 -0
  25. package/dist/channels/msteams.d.ts.map +1 -0
  26. package/dist/channels/msteams.js.map +1 -0
  27. package/dist/channels/nostr.d.ts.map +1 -0
  28. package/dist/channels/nostr.js.map +1 -0
  29. package/dist/channels/qq.d.ts.map +1 -0
  30. package/dist/channels/qq.js.map +1 -0
  31. package/dist/channels/signal.d.ts.map +1 -0
  32. package/dist/channels/signal.js.map +1 -0
  33. package/dist/channels/slack.d.ts.map +1 -0
  34. package/dist/channels/slack.js.map +1 -0
  35. package/dist/channels/sms.d.ts.map +1 -0
  36. package/dist/channels/sms.js.map +1 -0
  37. package/dist/channels/telegram.d.ts.map +1 -0
  38. package/dist/channels/telegram.js.map +1 -0
  39. package/dist/channels/twitch.d.ts.map +1 -0
  40. package/dist/channels/twitch.js.map +1 -0
  41. package/dist/channels/voice-call.d.ts.map +1 -0
  42. package/dist/channels/voice-call.js.map +1 -0
  43. package/dist/channels/voice.d.ts.map +1 -0
  44. package/dist/channels/voice.js.map +1 -0
  45. package/dist/channels/web.d.ts.map +1 -0
  46. package/dist/channels/web.js.map +1 -0
  47. package/dist/channels/webhook.d.ts.map +1 -0
  48. package/dist/channels/webhook.js.map +1 -0
  49. package/dist/channels/websocket.d.ts.map +1 -0
  50. package/dist/channels/websocket.js.map +1 -0
  51. package/dist/channels/wechat.d.ts.map +1 -0
  52. package/dist/channels/wechat.js.map +1 -0
  53. package/dist/channels/whatsapp.d.ts.map +1 -0
  54. package/dist/channels/whatsapp.js.map +1 -0
  55. package/dist/cli/chat.d.ts.map +1 -0
  56. package/dist/cli/chat.js.map +1 -0
  57. package/dist/cli/setup.d.ts.map +1 -0
  58. package/dist/cli/setup.js.map +1 -0
  59. package/dist/cli.d.ts.map +1 -0
  60. package/dist/cli.js +72 -11
  61. package/dist/cli.js.map +1 -0
  62. package/dist/core/a2a.d.ts.map +1 -0
  63. package/dist/core/a2a.js.map +1 -0
  64. package/dist/core/agent.d.ts.map +1 -0
  65. package/dist/core/agent.js.map +1 -0
  66. package/dist/core/analytics-engine.d.ts.map +1 -0
  67. package/dist/core/analytics-engine.js.map +1 -0
  68. package/dist/core/api-server.d.ts.map +1 -0
  69. package/dist/core/api-server.js.map +1 -0
  70. package/dist/core/audio.d.ts.map +1 -0
  71. package/dist/core/audio.js.map +1 -0
  72. package/dist/core/auth.d.ts.map +1 -0
  73. package/dist/core/auth.js.map +1 -0
  74. package/dist/core/cache.d.ts.map +1 -0
  75. package/dist/core/cache.js.map +1 -0
  76. package/dist/core/collaboration.d.ts.map +1 -0
  77. package/dist/core/collaboration.js.map +1 -0
  78. package/dist/core/compose.d.ts.map +1 -0
  79. package/dist/core/compose.js.map +1 -0
  80. package/dist/core/config.d.ts.map +1 -0
  81. package/dist/core/config.js.map +1 -0
  82. package/dist/core/context-discovery.d.ts.map +1 -0
  83. package/dist/core/context-discovery.js.map +1 -0
  84. package/dist/core/context-refs.d.ts.map +1 -0
  85. package/dist/core/context-refs.js.map +1 -0
  86. package/dist/core/errors.d.ts.map +1 -0
  87. package/dist/core/errors.js.map +1 -0
  88. package/dist/core/gateway.d.ts.map +1 -0
  89. package/dist/core/gateway.js.map +1 -0
  90. package/dist/core/heartbeat.d.ts.map +1 -0
  91. package/dist/core/heartbeat.js.map +1 -0
  92. package/dist/core/hitl.d.ts.map +1 -0
  93. package/dist/core/hitl.js.map +1 -0
  94. package/dist/core/hooks.d.ts.map +1 -0
  95. package/dist/core/hooks.js.map +1 -0
  96. package/dist/core/ide-bridge.d.ts.map +1 -0
  97. package/dist/core/ide-bridge.js.map +1 -0
  98. package/dist/core/knowledge.d.ts.map +1 -0
  99. package/dist/core/knowledge.js.map +1 -0
  100. package/dist/core/logger.d.ts.map +1 -0
  101. package/dist/core/logger.js.map +1 -0
  102. package/dist/core/node-network.d.ts.map +1 -0
  103. package/dist/core/node-network.js.map +1 -0
  104. package/dist/core/orchestrator.d.ts.map +1 -0
  105. package/dist/core/orchestrator.js.map +1 -0
  106. package/dist/core/performance.d.ts.map +1 -0
  107. package/dist/core/performance.js.map +1 -0
  108. package/dist/core/profiles.d.ts.map +1 -0
  109. package/dist/core/profiles.js.map +1 -0
  110. package/dist/core/rate-limiter.d.ts.map +1 -0
  111. package/dist/core/rate-limiter.js.map +1 -0
  112. package/dist/core/room.d.ts.map +1 -0
  113. package/dist/core/room.js.map +1 -0
  114. package/dist/core/runtime.d.ts.map +1 -0
  115. package/dist/core/runtime.js.map +1 -0
  116. package/dist/core/sandbox.d.ts.map +1 -0
  117. package/dist/core/sandbox.js.map +1 -0
  118. package/dist/core/scheduler.d.ts.map +1 -0
  119. package/dist/core/scheduler.js.map +1 -0
  120. package/dist/core/security.d.ts.map +1 -0
  121. package/dist/core/security.js.map +1 -0
  122. package/dist/core/session-manager.d.ts.map +1 -0
  123. package/dist/core/session-manager.js.map +1 -0
  124. package/dist/core/streaming.d.ts.map +1 -0
  125. package/dist/core/streaming.js.map +1 -0
  126. package/dist/core/subagent.d.ts.map +1 -0
  127. package/dist/core/subagent.js.map +1 -0
  128. package/dist/core/types.d.ts.map +1 -0
  129. package/dist/core/types.js.map +1 -0
  130. package/dist/core/versioning.d.ts.map +1 -0
  131. package/dist/core/versioning.js.map +1 -0
  132. package/dist/core/vision.d.ts.map +1 -0
  133. package/dist/core/vision.js.map +1 -0
  134. package/dist/core/watch.d.ts.map +1 -0
  135. package/dist/core/watch.js.map +1 -0
  136. package/dist/core/workflow-graph.d.ts.map +1 -0
  137. package/dist/core/workflow-graph.js.map +1 -0
  138. package/dist/core/workflow.d.ts.map +1 -0
  139. package/dist/core/workflow.js.map +1 -0
  140. package/dist/daemon.d.ts.map +1 -0
  141. package/dist/daemon.js.map +1 -0
  142. package/dist/deploy/hermes.d.ts.map +1 -0
  143. package/dist/deploy/hermes.js.map +1 -0
  144. package/dist/deploy/index.d.ts.map +1 -0
  145. package/dist/deploy/index.js.map +1 -0
  146. package/dist/deploy/openclaw.d.ts.map +1 -0
  147. package/dist/deploy/openclaw.js.map +1 -0
  148. package/dist/doctor.d.ts.map +1 -0
  149. package/dist/doctor.js.map +1 -0
  150. package/dist/eval/index.d.ts.map +1 -0
  151. package/dist/eval/index.js.map +1 -0
  152. package/dist/hub/brain-seed.d.ts.map +1 -0
  153. package/dist/hub/brain-seed.js.map +1 -0
  154. package/dist/hub/client.d.ts.map +1 -0
  155. package/dist/hub/client.js.map +1 -0
  156. package/dist/i18n/index.d.ts.map +1 -0
  157. package/dist/i18n/index.js.map +1 -0
  158. package/dist/index.d.ts.map +1 -0
  159. package/dist/index.js.map +1 -0
  160. package/dist/mcp/servers/calculator-mcp.d.ts.map +1 -0
  161. package/dist/mcp/servers/calculator-mcp.js.map +1 -0
  162. package/dist/mcp/servers/crypto-mcp.d.ts.map +1 -0
  163. package/dist/mcp/servers/crypto-mcp.js.map +1 -0
  164. package/dist/mcp/servers/database-mcp.d.ts.map +1 -0
  165. package/dist/mcp/servers/database-mcp.js.map +1 -0
  166. package/dist/mcp/servers/datetime-mcp.d.ts.map +1 -0
  167. package/dist/mcp/servers/datetime-mcp.js.map +1 -0
  168. package/dist/mcp/servers/filesystem.d.ts.map +1 -0
  169. package/dist/mcp/servers/filesystem.js.map +1 -0
  170. package/dist/mcp/servers/github-mcp.d.ts.map +1 -0
  171. package/dist/mcp/servers/github-mcp.js.map +1 -0
  172. package/dist/mcp/servers/index.d.ts.map +1 -0
  173. package/dist/mcp/servers/index.js.map +1 -0
  174. package/dist/mcp/servers/json-mcp.d.ts.map +1 -0
  175. package/dist/mcp/servers/json-mcp.js.map +1 -0
  176. package/dist/mcp/servers/memory-mcp.d.ts.map +1 -0
  177. package/dist/mcp/servers/memory-mcp.js.map +1 -0
  178. package/dist/mcp/servers/regex-mcp.d.ts.map +1 -0
  179. package/dist/mcp/servers/regex-mcp.js.map +1 -0
  180. package/dist/mcp/servers/web-mcp.d.ts.map +1 -0
  181. package/dist/mcp/servers/web-mcp.js.map +1 -0
  182. package/dist/memory/context-compressor.d.ts.map +1 -0
  183. package/dist/memory/context-compressor.js.map +1 -0
  184. package/dist/memory/deepbrain.d.ts.map +1 -0
  185. package/dist/memory/deepbrain.js.map +1 -0
  186. package/dist/memory/index.d.ts.map +1 -0
  187. package/dist/memory/index.js.map +1 -0
  188. package/dist/memory/seed-loader.d.ts.map +1 -0
  189. package/dist/memory/seed-loader.js.map +1 -0
  190. package/dist/memory/user-profiler.d.ts.map +1 -0
  191. package/dist/memory/user-profiler.js.map +1 -0
  192. package/dist/plugins/content-filter.d.ts.map +1 -0
  193. package/dist/plugins/content-filter.js.map +1 -0
  194. package/dist/plugins/index.d.ts.map +1 -0
  195. package/dist/plugins/index.js.map +1 -0
  196. package/dist/plugins/logger.d.ts.map +1 -0
  197. package/dist/plugins/logger.js.map +1 -0
  198. package/dist/plugins/rate-limiter.d.ts.map +1 -0
  199. package/dist/plugins/rate-limiter.js.map +1 -0
  200. package/dist/protocols/a2a/client.d.ts.map +1 -0
  201. package/dist/protocols/a2a/client.js.map +1 -0
  202. package/dist/protocols/a2a/index.d.ts.map +1 -0
  203. package/dist/protocols/a2a/index.js.map +1 -0
  204. package/dist/protocols/a2a/server.d.ts.map +1 -0
  205. package/dist/protocols/a2a/server.js.map +1 -0
  206. package/dist/protocols/a2a/types.d.ts.map +1 -0
  207. package/dist/protocols/a2a/types.js.map +1 -0
  208. package/dist/protocols/a2a/utils.d.ts.map +1 -0
  209. package/dist/protocols/a2a/utils.js.map +1 -0
  210. package/dist/protocols/agui/client.d.ts.map +1 -0
  211. package/dist/protocols/agui/client.js.map +1 -0
  212. package/dist/protocols/agui/index.d.ts.map +1 -0
  213. package/dist/protocols/agui/index.js.map +1 -0
  214. package/dist/protocols/agui/server.d.ts.map +1 -0
  215. package/dist/protocols/agui/server.js.map +1 -0
  216. package/dist/protocols/agui/types.d.ts.map +1 -0
  217. package/dist/protocols/agui/types.js.map +1 -0
  218. package/dist/protocols/index.d.ts.map +1 -0
  219. package/dist/protocols/index.js.map +1 -0
  220. package/dist/protocols/mcp/agent-tools.d.ts.map +1 -0
  221. package/dist/protocols/mcp/agent-tools.js.map +1 -0
  222. package/dist/protocols/mcp/index.d.ts.map +1 -0
  223. package/dist/protocols/mcp/index.js.map +1 -0
  224. package/dist/protocols/mcp/server.d.ts.map +1 -0
  225. package/dist/protocols/mcp/server.js.map +1 -0
  226. package/dist/protocols/mcp/types.d.ts.map +1 -0
  227. package/dist/protocols/mcp/types.js.map +1 -0
  228. package/dist/providers/index.d.ts.map +1 -0
  229. package/dist/providers/index.js.map +1 -0
  230. package/dist/publish/index.d.ts.map +1 -0
  231. package/dist/publish/index.js.map +1 -0
  232. package/dist/scheduler/cron-engine.d.ts.map +1 -0
  233. package/dist/scheduler/cron-engine.js.map +1 -0
  234. package/dist/scheduler/index.d.ts.map +1 -0
  235. package/dist/scheduler/index.js.map +1 -0
  236. package/dist/schema/oad.d.ts.map +1 -0
  237. package/dist/schema/oad.js.map +1 -0
  238. package/dist/security/approval.d.ts.map +1 -0
  239. package/dist/security/approval.js.map +1 -0
  240. package/dist/security/approvals.d.ts.map +1 -0
  241. package/dist/security/approvals.js.map +1 -0
  242. package/dist/security/elevated.d.ts.map +1 -0
  243. package/dist/security/elevated.js.map +1 -0
  244. package/dist/security/guardrails.d.ts.map +1 -0
  245. package/dist/security/guardrails.js.map +1 -0
  246. package/dist/security/index.d.ts.map +1 -0
  247. package/dist/security/index.js.map +1 -0
  248. package/dist/security/keys.d.ts.map +1 -0
  249. package/dist/security/keys.js.map +1 -0
  250. package/dist/security/secrets.d.ts.map +1 -0
  251. package/dist/security/secrets.js.map +1 -0
  252. package/dist/skills/auto-learn.d.ts.map +1 -0
  253. package/dist/skills/auto-learn.js.map +1 -0
  254. package/dist/skills/base.d.ts.map +1 -0
  255. package/dist/skills/base.js.map +1 -0
  256. package/dist/skills/builtin/index.d.ts.map +1 -0
  257. package/dist/skills/builtin/index.js.map +1 -0
  258. package/dist/skills/document.d.ts.map +1 -0
  259. package/dist/skills/document.js.map +1 -0
  260. package/dist/skills/http.d.ts.map +1 -0
  261. package/dist/skills/http.js.map +1 -0
  262. package/dist/skills/index.d.ts.map +1 -0
  263. package/dist/skills/index.js.map +1 -0
  264. package/dist/skills/marketplace.d.ts.map +1 -0
  265. package/dist/skills/marketplace.js.map +1 -0
  266. package/dist/skills/scheduler.d.ts.map +1 -0
  267. package/dist/skills/scheduler.js.map +1 -0
  268. package/dist/skills/types.d.ts.map +1 -0
  269. package/dist/skills/types.js.map +1 -0
  270. package/dist/skills/webhook-trigger.d.ts.map +1 -0
  271. package/dist/skills/webhook-trigger.js.map +1 -0
  272. package/dist/studio/server.d.ts.map +1 -0
  273. package/dist/studio/server.js.map +1 -0
  274. package/dist/studio/templates-data.d.ts.map +1 -0
  275. package/dist/studio/templates-data.js.map +1 -0
  276. package/dist/telemetry/index.d.ts.map +1 -0
  277. package/dist/telemetry/index.js.map +1 -0
  278. package/dist/templates/code-reviewer.d.ts.map +1 -0
  279. package/dist/templates/code-reviewer.js.map +1 -0
  280. package/dist/templates/content-writer.d.ts.map +1 -0
  281. package/dist/templates/content-writer.js.map +1 -0
  282. package/dist/templates/customer-service.d.ts.map +1 -0
  283. package/dist/templates/customer-service.js.map +1 -0
  284. package/dist/templates/data-analyst.d.ts.map +1 -0
  285. package/dist/templates/data-analyst.js.map +1 -0
  286. package/dist/templates/executive-assistant.d.ts.map +1 -0
  287. package/dist/templates/executive-assistant.js.map +1 -0
  288. package/dist/templates/financial-advisor.d.ts.map +1 -0
  289. package/dist/templates/financial-advisor.js.map +1 -0
  290. package/dist/templates/hr-recruiter.d.ts.map +1 -0
  291. package/dist/templates/hr-recruiter.js.map +1 -0
  292. package/dist/templates/knowledge-base.d.ts.map +1 -0
  293. package/dist/templates/knowledge-base.js.map +1 -0
  294. package/dist/templates/legal-assistant.d.ts.map +1 -0
  295. package/dist/templates/legal-assistant.js.map +1 -0
  296. package/dist/templates/project-manager.d.ts.map +1 -0
  297. package/dist/templates/project-manager.js.map +1 -0
  298. package/dist/templates/sales-assistant.d.ts.map +1 -0
  299. package/dist/templates/sales-assistant.js.map +1 -0
  300. package/dist/templates/teacher.d.ts.map +1 -0
  301. package/dist/templates/teacher.js.map +1 -0
  302. package/dist/testing/index.d.ts.map +1 -0
  303. package/dist/testing/index.js.map +1 -0
  304. package/dist/tools/builtin/browser.d.ts.map +1 -0
  305. package/dist/tools/builtin/browser.js.map +1 -0
  306. package/dist/tools/builtin/datetime.d.ts.map +1 -0
  307. package/dist/tools/builtin/datetime.js.map +1 -0
  308. package/dist/tools/builtin/file.d.ts.map +1 -0
  309. package/dist/tools/builtin/file.js.map +1 -0
  310. package/dist/tools/builtin/home-assistant.d.ts.map +1 -0
  311. package/dist/tools/builtin/home-assistant.js.map +1 -0
  312. package/dist/tools/builtin/index.d.ts.map +1 -0
  313. package/dist/tools/builtin/index.js.map +1 -0
  314. package/dist/tools/builtin/rl-tools.d.ts.map +1 -0
  315. package/dist/tools/builtin/rl-tools.js.map +1 -0
  316. package/dist/tools/builtin/shell.d.ts.map +1 -0
  317. package/dist/tools/builtin/shell.js.map +1 -0
  318. package/dist/tools/builtin/vision.d.ts.map +1 -0
  319. package/dist/tools/builtin/vision.js.map +1 -0
  320. package/dist/tools/builtin/web-search.d.ts.map +1 -0
  321. package/dist/tools/builtin/web-search.js.map +1 -0
  322. package/dist/tools/builtin/web.d.ts.map +1 -0
  323. package/dist/tools/builtin/web.js.map +1 -0
  324. package/dist/tools/calculator.d.ts.map +1 -0
  325. package/dist/tools/calculator.js.map +1 -0
  326. package/dist/tools/datetime.d.ts.map +1 -0
  327. package/dist/tools/datetime.js.map +1 -0
  328. package/dist/tools/document-processor.d.ts.map +1 -0
  329. package/dist/tools/document-processor.js.map +1 -0
  330. package/dist/tools/gateway.d.ts.map +1 -0
  331. package/dist/tools/gateway.js.map +1 -0
  332. package/dist/tools/image-generator.d.ts.map +1 -0
  333. package/dist/tools/image-generator.js.map +1 -0
  334. package/dist/tools/integrations/calendar.d.ts.map +1 -0
  335. package/dist/tools/integrations/calendar.js.map +1 -0
  336. package/dist/tools/integrations/code-exec.d.ts.map +1 -0
  337. package/dist/tools/integrations/code-exec.js.map +1 -0
  338. package/dist/tools/integrations/csv-analyzer.d.ts.map +1 -0
  339. package/dist/tools/integrations/csv-analyzer.js.map +1 -0
  340. package/dist/tools/integrations/database.d.ts.map +1 -0
  341. package/dist/tools/integrations/database.js.map +1 -0
  342. package/dist/tools/integrations/email-send.d.ts.map +1 -0
  343. package/dist/tools/integrations/email-send.js.map +1 -0
  344. package/dist/tools/integrations/git-tool.d.ts.map +1 -0
  345. package/dist/tools/integrations/git-tool.js.map +1 -0
  346. package/dist/tools/integrations/github-tool.d.ts.map +1 -0
  347. package/dist/tools/integrations/github-tool.js.map +1 -0
  348. package/dist/tools/integrations/image-gen.d.ts.map +1 -0
  349. package/dist/tools/integrations/image-gen.js.map +1 -0
  350. package/dist/tools/integrations/index.d.ts.map +1 -0
  351. package/dist/tools/integrations/index.js.map +1 -0
  352. package/dist/tools/integrations/jira.d.ts.map +1 -0
  353. package/dist/tools/integrations/jira.js.map +1 -0
  354. package/dist/tools/integrations/notion.d.ts.map +1 -0
  355. package/dist/tools/integrations/notion.js.map +1 -0
  356. package/dist/tools/integrations/npm-tool.d.ts.map +1 -0
  357. package/dist/tools/integrations/npm-tool.js.map +1 -0
  358. package/dist/tools/integrations/pdf-reader.d.ts.map +1 -0
  359. package/dist/tools/integrations/pdf-reader.js.map +1 -0
  360. package/dist/tools/integrations/slack.d.ts.map +1 -0
  361. package/dist/tools/integrations/slack.js.map +1 -0
  362. package/dist/tools/integrations/summarizer.d.ts.map +1 -0
  363. package/dist/tools/integrations/summarizer.js.map +1 -0
  364. package/dist/tools/integrations/translator.d.ts.map +1 -0
  365. package/dist/tools/integrations/translator.js.map +1 -0
  366. package/dist/tools/integrations/trello.d.ts.map +1 -0
  367. package/dist/tools/integrations/trello.js.map +1 -0
  368. package/dist/tools/integrations/vector-search.d.ts.map +1 -0
  369. package/dist/tools/integrations/vector-search.js.map +1 -0
  370. package/dist/tools/integrations/web-scraper.d.ts.map +1 -0
  371. package/dist/tools/integrations/web-scraper.js.map +1 -0
  372. package/dist/tools/integrations/web-search.d.ts.map +1 -0
  373. package/dist/tools/integrations/web-search.js.map +1 -0
  374. package/dist/tools/integrations/webhook.d.ts.map +1 -0
  375. package/dist/tools/integrations/webhook.js.map +1 -0
  376. package/dist/tools/json-transform.d.ts.map +1 -0
  377. package/dist/tools/json-transform.js.map +1 -0
  378. package/dist/tools/mcp-client.d.ts.map +1 -0
  379. package/dist/tools/mcp-client.js.map +1 -0
  380. package/dist/tools/mcp.d.ts.map +1 -0
  381. package/dist/tools/mcp.js.map +1 -0
  382. package/dist/tools/text-analysis.d.ts.map +1 -0
  383. package/dist/tools/text-analysis.js.map +1 -0
  384. package/dist/tools/web-scraper.d.ts.map +1 -0
  385. package/dist/tools/web-scraper.js.map +1 -0
  386. package/dist/tools/web-search.d.ts.map +1 -0
  387. package/dist/tools/web-search.js.map +1 -0
  388. package/dist/traces/index.d.ts.map +1 -0
  389. package/dist/traces/index.js.map +1 -0
  390. package/dist/ui/components.d.ts.map +1 -0
  391. package/dist/ui/components.js.map +1 -0
  392. package/package.json +1 -1
  393. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
  394. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
  395. package/.github/PULL_REQUEST_TEMPLATE.md +0 -13
  396. package/.github/workflows/ci.yml +0 -24
  397. package/USABILITY-ISSUES.md +0 -73
  398. package/docs/.vitepress/config.ts +0 -103
  399. package/docs/api/cli.md +0 -48
  400. package/docs/api/oad-schema.md +0 -64
  401. package/docs/api/sdk.md +0 -80
  402. package/docs/guide/concepts.md +0 -51
  403. package/docs/guide/configuration.md +0 -79
  404. package/docs/guide/deployment.md +0 -42
  405. package/docs/guide/getting-started.md +0 -44
  406. package/docs/guide/templates.md +0 -28
  407. package/docs/guide/testing.md +0 -84
  408. package/docs/index.md +0 -27
  409. package/docs/zh/api/cli.md +0 -54
  410. package/docs/zh/api/oad-schema.md +0 -87
  411. package/docs/zh/api/sdk.md +0 -102
  412. package/docs/zh/guide/concepts.md +0 -104
  413. package/docs/zh/guide/configuration.md +0 -135
  414. package/docs/zh/guide/deployment.md +0 -81
  415. package/docs/zh/guide/getting-started.md +0 -82
  416. package/docs/zh/guide/templates.md +0 -84
  417. package/docs/zh/guide/testing.md +0 -88
  418. package/docs/zh/index.md +0 -27
  419. package/fix-sidebar.mjs +0 -188
  420. package/serve-studio.js +0 -13
  421. package/serve-test.js +0 -25
  422. package/src/analytics/index.ts +0 -66
  423. package/src/channels/dingtalk.ts +0 -46
  424. package/src/channels/discord.ts +0 -192
  425. package/src/channels/email.ts +0 -351
  426. package/src/channels/feishu.ts +0 -349
  427. package/src/channels/googlechat.ts +0 -42
  428. package/src/channels/imessage.ts +0 -32
  429. package/src/channels/index.ts +0 -15
  430. package/src/channels/irc.ts +0 -82
  431. package/src/channels/line.ts +0 -33
  432. package/src/channels/matrix.ts +0 -34
  433. package/src/channels/mattermost.ts +0 -57
  434. package/src/channels/msteams.ts +0 -33
  435. package/src/channels/nostr.ts +0 -33
  436. package/src/channels/qq.ts +0 -34
  437. package/src/channels/signal.ts +0 -33
  438. package/src/channels/slack.ts +0 -217
  439. package/src/channels/sms.ts +0 -34
  440. package/src/channels/telegram.ts +0 -616
  441. package/src/channels/twitch.ts +0 -65
  442. package/src/channels/voice-call.ts +0 -100
  443. package/src/channels/voice.ts +0 -471
  444. package/src/channels/web.ts +0 -638
  445. package/src/channels/webhook.ts +0 -199
  446. package/src/channels/websocket.ts +0 -399
  447. package/src/channels/wechat.ts +0 -329
  448. package/src/channels/whatsapp.ts +0 -33
  449. package/src/cli/chat.ts +0 -99
  450. package/src/cli/setup.ts +0 -314
  451. package/src/cli.ts +0 -2826
  452. package/src/core/a2a.ts +0 -203
  453. package/src/core/agent.ts +0 -476
  454. package/src/core/analytics-engine.ts +0 -186
  455. package/src/core/api-server.ts +0 -277
  456. package/src/core/audio.ts +0 -98
  457. package/src/core/auth.ts +0 -57
  458. package/src/core/cache.ts +0 -141
  459. package/src/core/collaboration.ts +0 -275
  460. package/src/core/compose.ts +0 -77
  461. package/src/core/config.ts +0 -14
  462. package/src/core/context-discovery.ts +0 -85
  463. package/src/core/context-refs.ts +0 -140
  464. package/src/core/errors.ts +0 -148
  465. package/src/core/gateway.ts +0 -106
  466. package/src/core/heartbeat.ts +0 -51
  467. package/src/core/hitl.ts +0 -138
  468. package/src/core/hooks.ts +0 -105
  469. package/src/core/ide-bridge.ts +0 -133
  470. package/src/core/knowledge.ts +0 -255
  471. package/src/core/logger.ts +0 -57
  472. package/src/core/node-network.ts +0 -86
  473. package/src/core/orchestrator.ts +0 -215
  474. package/src/core/performance.ts +0 -187
  475. package/src/core/profiles.ts +0 -122
  476. package/src/core/rate-limiter.ts +0 -128
  477. package/src/core/room.ts +0 -109
  478. package/src/core/runtime.ts +0 -435
  479. package/src/core/sandbox.ts +0 -344
  480. package/src/core/scheduler.ts +0 -187
  481. package/src/core/security.ts +0 -171
  482. package/src/core/session-manager.ts +0 -137
  483. package/src/core/streaming.ts +0 -195
  484. package/src/core/subagent.ts +0 -98
  485. package/src/core/types.ts +0 -68
  486. package/src/core/versioning.ts +0 -106
  487. package/src/core/vision.ts +0 -180
  488. package/src/core/watch.ts +0 -178
  489. package/src/core/workflow-graph.ts +0 -365
  490. package/src/core/workflow.ts +0 -235
  491. package/src/daemon.ts +0 -96
  492. package/src/deploy/hermes.ts +0 -156
  493. package/src/deploy/index.ts +0 -255
  494. package/src/deploy/openclaw.ts +0 -190
  495. package/src/doctor.ts +0 -243
  496. package/src/eval/index.ts +0 -211
  497. package/src/eval/suites/basic.json +0 -16
  498. package/src/eval/suites/memory.json +0 -12
  499. package/src/eval/suites/safety.json +0 -14
  500. package/src/hub/brain-seed.ts +0 -54
  501. package/src/hub/client.ts +0 -60
  502. package/src/i18n/index.ts +0 -216
  503. package/src/index.ts +0 -283
  504. package/src/mcp/servers/calculator-mcp.ts +0 -65
  505. package/src/mcp/servers/crypto-mcp.ts +0 -73
  506. package/src/mcp/servers/database-mcp.ts +0 -72
  507. package/src/mcp/servers/datetime-mcp.ts +0 -69
  508. package/src/mcp/servers/filesystem.ts +0 -66
  509. package/src/mcp/servers/github-mcp.ts +0 -58
  510. package/src/mcp/servers/index.ts +0 -63
  511. package/src/mcp/servers/json-mcp.ts +0 -102
  512. package/src/mcp/servers/memory-mcp.ts +0 -56
  513. package/src/mcp/servers/regex-mcp.ts +0 -53
  514. package/src/mcp/servers/web-mcp.ts +0 -49
  515. package/src/memory/context-compressor.ts +0 -189
  516. package/src/memory/deepbrain.ts +0 -202
  517. package/src/memory/index.ts +0 -41
  518. package/src/memory/seed-loader.ts +0 -212
  519. package/src/memory/user-profiler.ts +0 -215
  520. package/src/plugins/content-filter.ts +0 -23
  521. package/src/plugins/index.ts +0 -339
  522. package/src/plugins/logger.ts +0 -18
  523. package/src/plugins/rate-limiter.ts +0 -38
  524. package/src/protocols/a2a/client.ts +0 -132
  525. package/src/protocols/a2a/index.ts +0 -8
  526. package/src/protocols/a2a/server.ts +0 -333
  527. package/src/protocols/a2a/types.ts +0 -88
  528. package/src/protocols/a2a/utils.ts +0 -50
  529. package/src/protocols/agui/client.ts +0 -83
  530. package/src/protocols/agui/index.ts +0 -4
  531. package/src/protocols/agui/server.ts +0 -218
  532. package/src/protocols/agui/types.ts +0 -153
  533. package/src/protocols/index.ts +0 -2
  534. package/src/protocols/mcp/agent-tools.ts +0 -134
  535. package/src/protocols/mcp/index.ts +0 -8
  536. package/src/protocols/mcp/server.ts +0 -262
  537. package/src/protocols/mcp/types.ts +0 -69
  538. package/src/providers/index.ts +0 -632
  539. package/src/publish/index.ts +0 -376
  540. package/src/scheduler/cron-engine.ts +0 -191
  541. package/src/scheduler/index.ts +0 -2
  542. package/src/schema/oad.ts +0 -217
  543. package/src/security/approval.ts +0 -131
  544. package/src/security/approvals.ts +0 -143
  545. package/src/security/elevated.ts +0 -105
  546. package/src/security/guardrails.ts +0 -248
  547. package/src/security/index.ts +0 -9
  548. package/src/security/keys.ts +0 -87
  549. package/src/security/secrets.ts +0 -129
  550. package/src/skills/auto-learn.ts +0 -262
  551. package/src/skills/base.ts +0 -16
  552. package/src/skills/builtin/index.ts +0 -408
  553. package/src/skills/document.ts +0 -100
  554. package/src/skills/http.ts +0 -35
  555. package/src/skills/index.ts +0 -27
  556. package/src/skills/marketplace.ts +0 -113
  557. package/src/skills/scheduler.ts +0 -80
  558. package/src/skills/types.ts +0 -42
  559. package/src/skills/webhook-trigger.ts +0 -59
  560. package/src/studio/server.ts +0 -1791
  561. package/src/studio/templates-data.ts +0 -178
  562. package/src/studio-ui/index.html +0 -3076
  563. package/src/telemetry/index.ts +0 -324
  564. package/src/templates/code-reviewer.ts +0 -30
  565. package/src/templates/content-writer.ts +0 -58
  566. package/src/templates/customer-service.ts +0 -76
  567. package/src/templates/data-analyst.ts +0 -66
  568. package/src/templates/executive-assistant.ts +0 -71
  569. package/src/templates/financial-advisor.ts +0 -60
  570. package/src/templates/hr-recruiter.ts +0 -58
  571. package/src/templates/knowledge-base.ts +0 -27
  572. package/src/templates/legal-assistant.ts +0 -71
  573. package/src/templates/project-manager.ts +0 -58
  574. package/src/templates/sales-assistant.ts +0 -75
  575. package/src/templates/teacher.ts +0 -75
  576. package/src/testing/index.ts +0 -181
  577. package/src/tools/builtin/browser.ts +0 -299
  578. package/src/tools/builtin/datetime.ts +0 -41
  579. package/src/tools/builtin/file.ts +0 -107
  580. package/src/tools/builtin/home-assistant.ts +0 -116
  581. package/src/tools/builtin/index.ts +0 -37
  582. package/src/tools/builtin/rl-tools.ts +0 -243
  583. package/src/tools/builtin/shell.ts +0 -43
  584. package/src/tools/builtin/vision.ts +0 -64
  585. package/src/tools/builtin/web-search.ts +0 -126
  586. package/src/tools/builtin/web.ts +0 -35
  587. package/src/tools/calculator.ts +0 -73
  588. package/src/tools/datetime.ts +0 -149
  589. package/src/tools/document-processor.ts +0 -213
  590. package/src/tools/gateway.ts +0 -220
  591. package/src/tools/image-generator.ts +0 -150
  592. package/src/tools/integrations/calendar.ts +0 -73
  593. package/src/tools/integrations/code-exec.ts +0 -39
  594. package/src/tools/integrations/csv-analyzer.ts +0 -92
  595. package/src/tools/integrations/database.ts +0 -44
  596. package/src/tools/integrations/email-send.ts +0 -76
  597. package/src/tools/integrations/git-tool.ts +0 -42
  598. package/src/tools/integrations/github-tool.ts +0 -76
  599. package/src/tools/integrations/image-gen.ts +0 -56
  600. package/src/tools/integrations/index.ts +0 -92
  601. package/src/tools/integrations/jira.ts +0 -83
  602. package/src/tools/integrations/notion.ts +0 -71
  603. package/src/tools/integrations/npm-tool.ts +0 -48
  604. package/src/tools/integrations/pdf-reader.ts +0 -58
  605. package/src/tools/integrations/slack.ts +0 -65
  606. package/src/tools/integrations/summarizer.ts +0 -49
  607. package/src/tools/integrations/translator.ts +0 -48
  608. package/src/tools/integrations/trello.ts +0 -60
  609. package/src/tools/integrations/vector-search.ts +0 -42
  610. package/src/tools/integrations/web-scraper.ts +0 -47
  611. package/src/tools/integrations/web-search.ts +0 -58
  612. package/src/tools/integrations/webhook.ts +0 -38
  613. package/src/tools/json-transform.ts +0 -187
  614. package/src/tools/mcp-client.ts +0 -131
  615. package/src/tools/mcp.ts +0 -76
  616. package/src/tools/text-analysis.ts +0 -116
  617. package/src/tools/web-scraper.ts +0 -179
  618. package/src/tools/web-search.ts +0 -180
  619. package/src/traces/index.ts +0 -132
  620. package/src/types/agent-workstation.d.ts +0 -2
  621. package/src/ui/components.ts +0 -127
  622. package/srv-err.txt +0 -0
  623. package/srv-out.txt +0 -1
  624. package/test-agent/Dockerfile +0 -9
  625. package/test-agent/README.md +0 -50
  626. package/test-agent/agent.yaml +0 -23
  627. package/test-agent/docker-compose.yml +0 -11
  628. package/test-agent/oad.yaml +0 -31
  629. package/test-agent/package-lock.json +0 -1492
  630. package/test-agent/package.json +0 -18
  631. package/test-agent/src/index.ts +0 -24
  632. package/test-agent/src/skills/echo.ts +0 -15
  633. package/test-agent/tsconfig.json +0 -25
  634. package/test-full.js +0 -43
  635. package/test-sidebar.js +0 -22
  636. package/test-studio3.js +0 -75
  637. package/test-studio4.js +0 -41
  638. package/tests/a2a-protocol.test.ts +0 -285
  639. package/tests/a2a.test.ts +0 -66
  640. package/tests/agent.test.ts +0 -72
  641. package/tests/agui-protocol.test.ts +0 -246
  642. package/tests/analytics.test.ts +0 -50
  643. package/tests/api-server.test.ts +0 -148
  644. package/tests/approvals.test.ts +0 -89
  645. package/tests/audio.test.ts +0 -40
  646. package/tests/auto-learn.test.ts +0 -105
  647. package/tests/brain-seed-extended.test.ts +0 -490
  648. package/tests/brain-seed.test.ts +0 -239
  649. package/tests/browser.test.ts +0 -179
  650. package/tests/builtin-tools.test.ts +0 -83
  651. package/tests/channel.test.ts +0 -39
  652. package/tests/channels/discord.test.ts +0 -79
  653. package/tests/channels/email.test.ts +0 -148
  654. package/tests/channels/feishu.test.ts +0 -123
  655. package/tests/channels/telegram.test.ts +0 -129
  656. package/tests/channels/websocket.test.ts +0 -53
  657. package/tests/channels/wechat.test.ts +0 -170
  658. package/tests/channels-extra.test.ts +0 -45
  659. package/tests/chat-cli.test.ts +0 -160
  660. package/tests/cli.test.ts +0 -46
  661. package/tests/collaboration.test.ts +0 -319
  662. package/tests/context-compressor.test.ts +0 -172
  663. package/tests/context-refs.test.ts +0 -121
  664. package/tests/cron-engine.test.ts +0 -101
  665. package/tests/daemon.test.ts +0 -135
  666. package/tests/deepbrain-wire.test.ts +0 -234
  667. package/tests/deploy-and-dag.test.ts +0 -196
  668. package/tests/doctor.test.ts +0 -38
  669. package/tests/document-processor.test.ts +0 -69
  670. package/tests/e2e-nocode.test.ts +0 -442
  671. package/tests/e2e.test.ts +0 -134
  672. package/tests/elevated.test.ts +0 -69
  673. package/tests/errors.test.ts +0 -83
  674. package/tests/eval.test.ts +0 -173
  675. package/tests/gateway.test.ts +0 -63
  676. package/tests/guardrails.test.ts +0 -177
  677. package/tests/hitl.test.ts +0 -71
  678. package/tests/home-assistant.test.ts +0 -40
  679. package/tests/hooks.test.ts +0 -79
  680. package/tests/i18n.test.ts +0 -41
  681. package/tests/ide-bridge.test.ts +0 -38
  682. package/tests/image-generator.test.ts +0 -84
  683. package/tests/init-role.test.ts +0 -124
  684. package/tests/integrations.test.ts +0 -249
  685. package/tests/mcp-client.test.ts +0 -92
  686. package/tests/mcp-server.test.ts +0 -178
  687. package/tests/mcp-servers.test.ts +0 -260
  688. package/tests/mcp.test.ts +0 -54
  689. package/tests/node-network.test.ts +0 -74
  690. package/tests/oad.test.ts +0 -68
  691. package/tests/performance.test.ts +0 -115
  692. package/tests/plugin-a2a-enhanced.test.ts +0 -230
  693. package/tests/plugin.test.ts +0 -74
  694. package/tests/profiles.test.ts +0 -61
  695. package/tests/publish.test.ts +0 -231
  696. package/tests/rl-tools.test.ts +0 -93
  697. package/tests/room.test.ts +0 -106
  698. package/tests/runtime.test.ts +0 -42
  699. package/tests/sandbox-manager.test.ts +0 -46
  700. package/tests/sandbox.test.ts +0 -46
  701. package/tests/scheduler.test.ts +0 -200
  702. package/tests/secrets.test.ts +0 -107
  703. package/tests/security-enhanced.test.ts +0 -233
  704. package/tests/security.test.ts +0 -60
  705. package/tests/settings-api.test.ts +0 -148
  706. package/tests/setup.test.ts +0 -73
  707. package/tests/skill-learner.test.ts +0 -161
  708. package/tests/streaming.test.ts +0 -109
  709. package/tests/studio.test.ts +0 -402
  710. package/tests/subagent.test.ts +0 -193
  711. package/tests/telegram-discord.test.ts +0 -60
  712. package/tests/telemetry.test.ts +0 -186
  713. package/tests/templates.test.ts +0 -77
  714. package/tests/tools/builtin-extended.test.ts +0 -138
  715. package/tests/user-profiler.test.ts +0 -169
  716. package/tests/v070.test.ts +0 -76
  717. package/tests/v090-features.test.ts +0 -254
  718. package/tests/versioning.test.ts +0 -75
  719. package/tests/vision.test.ts +0 -61
  720. package/tests/voice-call.test.ts +0 -47
  721. package/tests/voice-enhanced.test.ts +0 -169
  722. package/tests/voice-interaction.test.ts +0 -38
  723. package/tests/voice.test.ts +0 -61
  724. package/tests/web-search.test.ts +0 -155
  725. package/tests/webhook.test.ts +0 -29
  726. package/tests/workflow-graph.test.ts +0 -279
  727. package/tests/workflow.test.ts +0 -143
  728. package/tmp-js-test.js +0 -1532
  729. package/tmp-sc.js +0 -1716
  730. package/tutorial/customer-service-agent/README.md +0 -612
  731. package/tutorial/customer-service-agent/SOUL.md +0 -26
  732. package/tutorial/customer-service-agent/agent.yaml +0 -63
  733. package/tutorial/customer-service-agent/package.json +0 -19
  734. package/tutorial/customer-service-agent/src/index.ts +0 -69
  735. package/tutorial/customer-service-agent/src/skills/faq.ts +0 -27
  736. package/tutorial/customer-service-agent/src/skills/ticket.ts +0 -22
  737. package/tutorial/customer-service-agent/tsconfig.json +0 -14
  738. package/vitest.config.ts +0 -9
@@ -1,1791 +0,0 @@
1
- import { createServer, IncomingMessage, ServerResponse, request as httpRequest } from 'http';
2
- import { readFileSync, existsSync, writeFileSync, mkdirSync, readdirSync, unlinkSync } from 'fs';
3
- import { join, extname } from 'path';
4
- import * as os from 'os';
5
- import * as net from 'net';
6
- import { Tracer } from '../telemetry';
7
- import { TEMPLATES, INDUSTRIES, AgentTemplate } from './templates-data';
8
- import { SkillMarketplace } from '../skills/marketplace';
9
- import { CronEngine } from '../scheduler/cron-engine';
10
- import { ImageGenerator } from '../tools/image-generator';
11
- import { DocumentProcessor, ProcessedDocument } from '../tools/document-processor';
12
-
13
- export interface WorkflowNode {
14
- id: string;
15
- type: 'agent' | 'tool' | 'condition' | 'loop' | 'parallel' | 'input' | 'output';
16
- name: string;
17
- x: number;
18
- y: number;
19
- config: Record<string, any>;
20
- }
21
-
22
- export interface WorkflowEdge {
23
- id: string;
24
- from: string;
25
- to: string;
26
- fromPort: string;
27
- toPort: string;
28
- }
29
-
30
- export interface WorkflowDefinition {
31
- id: string;
32
- name: string;
33
- nodes: WorkflowNode[];
34
- edges: WorkflowEdge[];
35
- created: string;
36
- updated: string;
37
- }
38
-
39
- interface StudioConfig {
40
- port: number;
41
- agentDir: string;
42
- staticDir: string;
43
- }
44
-
45
- interface ModuleInfo {
46
- name: string;
47
- path: string;
48
- port: number;
49
- icon: string;
50
- }
51
-
52
- const MODULE_REGISTRY: ModuleInfo[] = [
53
- { name: 'DeepBrain', path: 'brain', port: 4001, icon: '🧠' },
54
- { name: 'AgentKits', path: 'kits', port: 4002, icon: '📊' },
55
- { name: 'Workstation', path: 'workstation', port: 4003, icon: '👤' },
56
- ];
57
-
58
- // Settings config helpers
59
- function getSettingsConfigPath(): string {
60
- const dir = join(os.homedir(), '.opc');
61
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
62
- return join(dir, 'config.json');
63
- }
64
-
65
- function loadSettingsConfig(): any {
66
- const p = getSettingsConfigPath();
67
- if (existsSync(p)) {
68
- try { return JSON.parse(readFileSync(p, 'utf-8')); } catch { return {}; }
69
- }
70
- return {};
71
- }
72
-
73
- function saveSettingsConfig(config: any): void {
74
- writeFileSync(getSettingsConfigPath(), JSON.stringify(config, null, 2));
75
- }
76
-
77
- class StudioServer {
78
- private server: any;
79
- private config: StudioConfig;
80
- private tracer?: Tracer;
81
- private skillMarketplace: SkillMarketplace;
82
- private cronEngine: CronEngine;
83
- private imageGenerator: ImageGenerator;
84
-
85
- constructor(config: Partial<StudioConfig> = {}) {
86
- this.config = {
87
- port: config.port || 4000,
88
- agentDir: config.agentDir || process.cwd(),
89
- staticDir: config.staticDir || join(__dirname, '../studio-ui'),
90
- };
91
- this.cronEngine = new CronEngine();
92
- this.imageGenerator = new ImageGenerator();
93
- this.skillMarketplace = new SkillMarketplace();
94
- }
95
-
96
- setTracer(tracer: Tracer): void {
97
- this.tracer = tracer;
98
- }
99
-
100
- getTracer(): Tracer | undefined {
101
- return this.tracer;
102
- }
103
-
104
- getConfig(): StudioConfig {
105
- return { ...this.config };
106
- }
107
-
108
- async start(): Promise<void> {
109
- const opcDir = join(os.homedir(), '.opc');
110
- if (!existsSync(opcDir)) mkdirSync(opcDir, { recursive: true });
111
- const cfgPath = join(opcDir, 'config.json');
112
- if (!existsSync(cfgPath)) writeFileSync(cfgPath, JSON.stringify({}, null, 2));
113
-
114
- this.server = createServer((req, res) => this.handleRequest(req, res));
115
- this.server.listen(this.config.port, '0.0.0.0');
116
- this.cronEngine.start();
117
- console.log(`🎨 OPC Studio: http://localhost:${this.config.port}`);
118
- }
119
-
120
- async stop(): Promise<void> {
121
- this.cronEngine.stop();
122
- return new Promise((resolve) => {
123
- if (this.server) {
124
- this.server.close(() => resolve());
125
- } else {
126
- resolve();
127
- }
128
- });
129
- }
130
-
131
- async handleRequest(req: IncomingMessage, res: ServerResponse) {
132
- const url = new URL(req.url || '/', `http://localhost`);
133
-
134
- // Handle CORS preflight
135
- if (req.method === 'OPTIONS') {
136
- res.writeHead(204, {
137
- 'Access-Control-Allow-Origin': '*',
138
- 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
139
- 'Access-Control-Allow-Headers': 'Content-Type',
140
- });
141
- res.end();
142
- return;
143
- }
144
-
145
- // API routes
146
- if (url.pathname.startsWith('/api/')) {
147
- return this.handleAPI(req, res, url);
148
- }
149
-
150
- // Module proxy routes
151
- for (const mod of MODULE_REGISTRY) {
152
- if (url.pathname.startsWith(`/${mod.path}/`) || url.pathname === `/${mod.path}`) {
153
- return this.proxyToModule(req, res, mod, url);
154
- }
155
- }
156
-
157
- // Static files
158
- return this.serveStatic(req, res, url);
159
- }
160
-
161
- private async handleAPI(req: IncomingMessage, res: ServerResponse, url: URL) {
162
- const route = url.pathname.replace('/api/', '');
163
-
164
- try {
165
- let data: any;
166
-
167
- // Dynamic agent routes
168
- if (route === 'agents' && req.method === 'POST') {
169
- data = await this.createAgent(req);
170
- res.writeHead(201, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
171
- res.end(JSON.stringify(data));
172
- return;
173
- }
174
- if (route === 'agents' && req.method === 'GET') {
175
- data = this.listAgents();
176
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
177
- res.end(JSON.stringify(data));
178
- return;
179
- }
180
- if (route === 'templates' && req.method === 'GET') {
181
- const industry = url.searchParams.get('industry') || '';
182
- const search = url.searchParams.get('q') || '';
183
- data = this.getTemplates(industry, search);
184
- // Merge with real workstation templates
185
- try {
186
- const ws = require('agent-workstation');
187
- const categories = ws.getCategories();
188
- const wsTemplates: any[] = [];
189
- for (const cat of categories) {
190
- for (const roleName of cat.roles) {
191
- const role = ws.getRole(cat.name, roleName);
192
- if (!role) continue;
193
- let oad: any = {};
194
- try {
195
- if (role.files?.['oad.yaml']) {
196
- const yaml = require('js-yaml');
197
- oad = yaml.load(role.files['oad.yaml']) || {};
198
- }
199
- } catch {}
200
- const tpl = {
201
- id: `ws-${cat.name}-${roleName}`,
202
- name: oad.name || roleName.replace(/-/g, ' ').replace(/\b\w/g, (c: string) => c.toUpperCase()),
203
- nameZh: oad.nameZh || '',
204
- icon: oad.icon || '🤖',
205
- description: oad.description || '',
206
- descriptionZh: oad.descriptionZh || '',
207
- industry: cat.name,
208
- industryZh: cat.name,
209
- tags: [cat.name, 'workstation'],
210
- suggestedModel: 'auto',
211
- systemPrompt: oad.systemPrompt || role.files?.['brain-seed.md'] || '',
212
- source: 'workstation',
213
- ego: oad.ego || null,
214
- mission: oad.mission || null,
215
- skills: oad.skills || [],
216
- };
217
- if (!search || tpl.name.toLowerCase().includes(search.toLowerCase()) || tpl.nameZh.includes(search)) {
218
- if (!industry || tpl.industry === industry) {
219
- wsTemplates.push(tpl);
220
- }
221
- }
222
- }
223
- }
224
- data.templates = [...data.templates, ...wsTemplates];
225
- // Add workstation industries to list
226
- const existingIds = new Set(data.industries.map((i: any) => i.id));
227
- for (const cat of categories) {
228
- if (!existingIds.has(cat.name)) {
229
- data.industries.push({ id: cat.name, name: cat.name, nameZh: cat.name });
230
- }
231
- }
232
- } catch (wsErr: any) {
233
- // workstation not available, use built-in templates only
234
- }
235
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
236
- res.end(JSON.stringify(data));
237
- return;
238
- }
239
- if (route.match(/^templates\/[^/]+$/) && req.method === 'GET') {
240
- const tplId = route.split('/')[1];
241
- // Check workstation first
242
- if (tplId.startsWith('ws-')) {
243
- const parts = tplId.replace('ws-', '').split('-');
244
- const catName = parts[0];
245
- const roleName = parts.slice(1).join('-');
246
- try {
247
- const ws = require('agent-workstation');
248
- const role = ws.getRole(catName, roleName);
249
- if (role) {
250
- let oad: any = {};
251
- try {
252
- if (role.files?.['oad.yaml']) {
253
- const yaml = require('js-yaml');
254
- oad = yaml.load(role.files['oad.yaml']) || {};
255
- }
256
- } catch {}
257
- data = {
258
- id: tplId, name: oad.name || roleName, source: 'workstation',
259
- category: catName, role: roleName, files: role.files,
260
- ego: oad.ego, mission: oad.mission, skills: oad.skills,
261
- systemPrompt: oad.systemPrompt || role.files?.['brain-seed.md'] || '',
262
- };
263
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
264
- res.end(JSON.stringify(data));
265
- return;
266
- }
267
- } catch {}
268
- }
269
- data = this.getTemplateById(tplId);
270
- res.writeHead(data.error ? 404 : 200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
271
- res.end(JSON.stringify(data));
272
- return;
273
- }
274
- if (route.match(/^agents\/[^/]+\/memory$/) && req.method === 'GET') {
275
- const agentId = route.split('/')[1];
276
- data = this.getAgentMemory(agentId);
277
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
278
- res.end(JSON.stringify(data));
279
- return;
280
- }
281
- if (route.match(/^agents\/[^/]+\/chat$/) && req.method === 'POST') {
282
- const agentId = route.split('/')[1];
283
- return this.handleAgentChat(req, res, agentId);
284
- }
285
- if (route.match(/^agents\/[^/]+$/) && req.method === 'GET') {
286
- const agentId = route.split('/')[1];
287
- data = this.getAgentById(agentId);
288
- res.writeHead(data.error ? 404 : 200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
289
- res.end(JSON.stringify(data));
290
- return;
291
- }
292
- if (route.match(/^agents\/[^/]+$/) && req.method === 'PUT') {
293
- const agentId = route.split('/')[1];
294
- data = await this.updateAgent(agentId, req);
295
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
296
- res.end(JSON.stringify(data));
297
- return;
298
- }
299
- if (route.match(/^agents\/[^/]+$/) && req.method === 'DELETE') {
300
- const agentId = route.split('/')[1];
301
- data = this.deleteAgent(agentId);
302
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
303
- res.end(JSON.stringify(data));
304
- return;
305
- }
306
-
307
- // --- Document upload routes ---
308
- if (route.match(/^agents\/[^/]+\/upload$/) && req.method === 'POST') {
309
- const agentId = route.split('/')[1];
310
- return this.handleDocumentUpload(req, res, agentId);
311
- }
312
- if (route.match(/^agents\/[^/]+\/documents$/) && req.method === 'GET') {
313
- const agentId = route.split('/')[1];
314
- data = this.getDocumentList(agentId);
315
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
316
- res.end(JSON.stringify(data));
317
- return;
318
- }
319
- if (route.match(/^agents\/[^/]+\/documents\/[^/]+$/) && req.method === 'DELETE') {
320
- const parts = route.split('/');
321
- const agentId = parts[1];
322
- const docId = parts[3];
323
- data = this.deleteDocument(agentId, docId);
324
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
325
- res.end(JSON.stringify(data));
326
- return;
327
- }
328
-
329
- // --- Settings API routes ---
330
- if (route === 'settings/models' && req.method === 'GET') {
331
- const cfg = loadSettingsConfig();
332
- data = cfg.models || { mode: 'local', provider: 'ollama', chatModel: 'qwen2.5:7b', embeddingModel: 'nomic-embed-text', providers: {} };
333
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
334
- res.end(JSON.stringify(data));
335
- return;
336
- }
337
- if (route === 'settings/models' && req.method === 'PUT') {
338
- const body = JSON.parse(await this.readBody(req));
339
- const cfg = loadSettingsConfig();
340
- cfg.models = { ...(cfg.models || {}), ...body };
341
- saveSettingsConfig(cfg);
342
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
343
- res.end(JSON.stringify({ success: true, models: cfg.models }));
344
- return;
345
- }
346
- if (route === 'settings/models/test' && req.method === 'POST') {
347
- const body = JSON.parse(await this.readBody(req));
348
- const { provider, apiKey, baseUrl } = body;
349
- data = await this.testModelConnection(provider, apiKey, baseUrl);
350
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
351
- res.end(JSON.stringify(data));
352
- return;
353
- }
354
- if (route === 'settings/models/local' && req.method === 'GET') {
355
- data = await this.detectLocalOllama();
356
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
357
- res.end(JSON.stringify(data));
358
- return;
359
- }
360
- if (route === 'settings/channels' && req.method === 'GET') {
361
- const cfg = loadSettingsConfig();
362
- data = cfg.channels || {};
363
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
364
- res.end(JSON.stringify(data));
365
- return;
366
- }
367
- if (route.match(/^settings\/channels\/[^/]+$/) && req.method === 'PUT') {
368
- const channelName = route.split('/')[2];
369
- const body = JSON.parse(await this.readBody(req));
370
- const cfg = loadSettingsConfig();
371
- if (!cfg.channels) cfg.channels = {};
372
- cfg.channels[channelName] = { ...(cfg.channels[channelName] || {}), ...body, updated: new Date().toISOString() };
373
- saveSettingsConfig(cfg);
374
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
375
- res.end(JSON.stringify({ success: true, channel: cfg.channels[channelName] }));
376
- return;
377
- }
378
- // Web Search settings
379
- if (route === 'settings/search' && req.method === 'GET') {
380
- const cfg = loadSettingsConfig();
381
- data = cfg.webSearch || { defaultEngine: 'duckduckgo', enabled: true, engines: { duckduckgo: { enabled: true } } };
382
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
383
- res.end(JSON.stringify(data));
384
- return;
385
- }
386
- if (route === 'settings/search' && req.method === 'PUT') {
387
- const body = JSON.parse(await this.readBody(req));
388
- const cfg = loadSettingsConfig();
389
- cfg.webSearch = { ...(cfg.webSearch || {}), ...body, updated: new Date().toISOString() };
390
- saveSettingsConfig(cfg);
391
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
392
- res.end(JSON.stringify({ success: true, config: cfg.webSearch }));
393
- return;
394
- }
395
- if (route === 'settings/search/test' && req.method === 'POST') {
396
- try {
397
- const { webSearch: doSearch } = require('../tools/web-search');
398
- const body = JSON.parse(await this.readBody(req));
399
- const query = body.query || 'test search';
400
- const cfg = loadSettingsConfig();
401
- const searchCfg = { ...(cfg.webSearch || { defaultEngine: 'duckduckgo', enabled: true, engines: { duckduckgo: { enabled: true } } }), ...body.config };
402
- const results = await doSearch(query, searchCfg, { maxResults: 3 });
403
- data = { success: true, results, engine: searchCfg.defaultEngine };
404
- } catch (e: any) {
405
- data = { success: false, error: e.message };
406
- }
407
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
408
- res.end(JSON.stringify(data));
409
- return;
410
- }
411
- if (route === 'settings/status' && req.method === 'GET') {
412
- data = await this.getSettingsStatus();
413
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
414
- res.end(JSON.stringify(data));
415
- return;
416
- }
417
- if (route === 'settings/status/start' && req.method === 'POST') {
418
- data = { success: true, status: 'running', message: 'Agent started' };
419
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
420
- res.end(JSON.stringify(data));
421
- return;
422
- }
423
- if (route === 'settings/status/stop' && req.method === 'POST') {
424
- data = { success: true, status: 'stopped', message: 'Agent stopped' };
425
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
426
- res.end(JSON.stringify(data));
427
- return;
428
- }
429
- if (route === 'settings/usage' && req.method === 'GET') {
430
- data = await this.getUsageStats();
431
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
432
- res.end(JSON.stringify(data));
433
- return;
434
- }
435
-
436
- // Dynamic workflow routes (parameterized)
437
- if (route.match(/^workflows\/[^/]+\/run$/) && req.method === 'POST') {
438
- const wfId = route.split('/')[1];
439
- data = await this.runWorkflow(wfId);
440
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
441
- res.end(JSON.stringify(data));
442
- return;
443
- }
444
- if (route.match(/^workflows\/[^/]+$/) && req.method === 'GET') {
445
- const wfId = route.split('/')[1];
446
- data = this.getWorkflowById(wfId);
447
- res.writeHead(data.error ? 404 : 200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
448
- res.end(JSON.stringify(data));
449
- return;
450
- }
451
- if (route.match(/^workflows\/[^/]+$/) && req.method === 'DELETE') {
452
- const wfId = route.split('/')[1];
453
- data = this.deleteWorkflow(wfId);
454
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
455
- res.end(JSON.stringify(data));
456
- return;
457
- }
458
-
459
- // --- Schedules API ---
460
- if (route === 'schedules' && req.method === 'GET') {
461
- data = this.cronEngine.listTasks();
462
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
463
- res.end(JSON.stringify(data));
464
- return;
465
- }
466
- if (route === 'schedules' && req.method === 'POST') {
467
- const body = JSON.parse(await this.readBody(req));
468
- data = this.cronEngine.createTask(body);
469
- res.writeHead(201, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
470
- res.end(JSON.stringify(data));
471
- return;
472
- }
473
- if (route.match(/^schedules\/[^/]+$/) && req.method === 'PUT') {
474
- const id = route.split('/')[1];
475
- const body = JSON.parse(await this.readBody(req));
476
- data = this.cronEngine.updateTask(id, body);
477
- res.writeHead(data ? 200 : 404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
478
- res.end(JSON.stringify(data || { error: 'Schedule not found' }));
479
- return;
480
- }
481
- if (route.match(/^schedules\/[^/]+$/) && req.method === 'DELETE') {
482
- const id = route.split('/')[1];
483
- const success = this.cronEngine.deleteTask(id);
484
- res.writeHead(success ? 200 : 404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
485
- res.end(JSON.stringify({ success }));
486
- return;
487
- }
488
- if (route.match(/^schedules\/[^/]+\/run$/) && req.method === 'POST') {
489
- const id = route.split('/')[1];
490
- const success = await this.cronEngine.runTask(id);
491
- res.writeHead(success ? 200 : 404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
492
- res.end(JSON.stringify({ success }));
493
- return;
494
- }
495
-
496
- // --- Image Generation API ---
497
- if (route === 'image-gen/status' && req.method === 'GET') {
498
- data = this.imageGenerator.getStatus();
499
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
500
- res.end(JSON.stringify(data));
501
- return;
502
- }
503
- if (route === 'image-gen/generate' && req.method === 'POST') {
504
- const body = JSON.parse(await this.readBody(req));
505
- data = await this.imageGenerator.generate(body.prompt, body);
506
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
507
- res.end(JSON.stringify(data));
508
- return;
509
- }
510
- if (route === 'image-gen/config' && req.method === 'PUT') {
511
- const body = JSON.parse(await this.readBody(req));
512
- const cfg = loadSettingsConfig();
513
- cfg.imageGen = { ...(cfg.imageGen || {}), ...body };
514
- saveSettingsConfig(cfg);
515
- this.imageGenerator = new ImageGenerator({
516
- openaiApiKey: body.openaiApiKey,
517
- replicateApiKey: body.replicateApiKey,
518
- sdApiUrl: body.sdApiUrl,
519
- });
520
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
521
- res.end(JSON.stringify({ success: true }));
522
- return;
523
- }
524
-
525
- if (route === 'first-run/status' && req.method === 'GET') {
526
- data = await this.getFirstRunStatus();
527
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
528
- res.end(JSON.stringify(data));
529
- return;
530
- }
531
- if (route === 'first-run/complete' && req.method === 'POST') {
532
- const body = JSON.parse(await this.readBody(req));
533
- data = await this.completeFirstRun(body);
534
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
535
- res.end(JSON.stringify(data));
536
- return;
537
- }
538
-
539
- // === Skill Marketplace API ===
540
- if (route === 'skills/marketplace' && req.method === 'GET') {
541
- const category = url.searchParams.get('category') || undefined;
542
- const search = url.searchParams.get('q') || undefined;
543
- data = this.skillMarketplace.listAll(category, search);
544
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
545
- res.end(JSON.stringify(data));
546
- return;
547
- }
548
- if (route === 'skills/installed' && req.method === 'GET') {
549
- data = this.skillMarketplace.getInstalled();
550
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
551
- res.end(JSON.stringify(data));
552
- return;
553
- }
554
- if (route.match(/^skills\/marketplace\/[^/]+$/) && req.method === 'GET') {
555
- const skillId = route.split('/')[2];
556
- data = this.skillMarketplace.getSkill(skillId);
557
- res.writeHead(data ? 200 : 404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
558
- res.end(JSON.stringify(data || { error: 'Skill not found' }));
559
- return;
560
- }
561
- if (route.match(/^skills\/marketplace\/[^/]+\/install$/) && req.method === 'POST') {
562
- const skillId = route.split('/')[2];
563
- data = this.skillMarketplace.install(skillId);
564
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
565
- res.end(JSON.stringify(data));
566
- return;
567
- }
568
- if (route.match(/^skills\/marketplace\/[^/]+\/uninstall$/) && req.method === 'DELETE') {
569
- const skillId = route.split('/')[2];
570
- data = this.skillMarketplace.uninstall(skillId);
571
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
572
- res.end(JSON.stringify(data));
573
- return;
574
- }
575
-
576
- // === Global config API (reads/writes ~/.opc/config.json) ===
577
- if (route === 'config' && req.method === 'GET') {
578
- data = loadSettingsConfig();
579
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
580
- res.end(JSON.stringify(data));
581
- return;
582
- }
583
- if (route === 'config' && req.method === 'PUT') {
584
- const body = JSON.parse(await this.readBody(req));
585
- const cfg = loadSettingsConfig();
586
- Object.assign(cfg, body);
587
- saveSettingsConfig(cfg);
588
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
589
- res.end(JSON.stringify({ success: true, config: cfg }));
590
- return;
591
- }
592
-
593
- // === Models API (real agentkits integration) ===
594
- if (route === 'models' && req.method === 'GET') {
595
- try {
596
- const ak = await import('agentkits');
597
- const providers = ak.listLLMProviders();
598
- data = { providers };
599
- } catch (e: any) {
600
- data = { providers: [], error: 'agentkits not available: ' + e.message };
601
- }
602
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
603
- res.end(JSON.stringify(data));
604
- return;
605
- }
606
-
607
- // === Memory stats API (real deepbrain integration) ===
608
- if (route === 'memory/stats' && req.method === 'GET') {
609
- try {
610
- const { Brain } = require('deepbrain');
611
- const oad = this.loadOAD();
612
- const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
613
- const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
614
- await brain.connect();
615
- const stats = await brain.stats();
616
- await brain.disconnect();
617
- data = { connected: true, ...stats };
618
- } catch {
619
- data = { connected: false, pages: 0, chunks: 0, error: 'DeepBrain not installed or not configured. Install with: npm i deepbrain' };
620
- }
621
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
622
- res.end(JSON.stringify(data));
623
- return;
624
- }
625
- if (route.match(/^memory\/[^/]+$/) && req.method === 'GET') {
626
- const agentId = route.split('/')[1];
627
- if (agentId !== 'stats' && agentId !== 'list' && agentId !== 'search') {
628
- data = this.getAgentMemory(agentId);
629
- res.writeHead(200, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
630
- res.end(JSON.stringify(data));
631
- return;
632
- }
633
- }
634
-
635
- switch (route) {
636
- case 'modules':
637
- data = await this.getModulesStatus();
638
- break;
639
- case 'agent/info':
640
- data = await this.getAgentInfo();
641
- break;
642
- case 'agent/config':
643
- if (req.method === 'GET') data = await this.getAgentConfig();
644
- else if (req.method === 'PUT') data = await this.saveConfig(req);
645
- break;
646
- case 'agent/chat':
647
- data = await this.handleChat(req);
648
- break;
649
- case 'memory/list':
650
- data = await this.getMemoryList();
651
- break;
652
- case 'memory/search':
653
- data = await this.searchMemory(url.searchParams.get('q') || '');
654
- break;
655
- case 'memory/stats':
656
- data = await this.getMemoryStats();
657
- break;
658
- case 'skills/list':
659
- data = await this.getSkills();
660
- break;
661
- case 'tools/list':
662
- data = await this.getTools();
663
- break;
664
- case 'workflows/list':
665
- data = this.listWorkflows();
666
- break;
667
- case 'workflows':
668
- if (req.method === 'POST') data = await this.saveWorkflow(req);
669
- else if (req.method === 'GET') data = this.listWorkflows();
670
- else { res.writeHead(405); res.end(); return; }
671
- break;
672
- case 'jobs/list':
673
- data = await this.getJobs();
674
- break;
675
- case 'logs/recent':
676
- data = await this.getRecentLogs();
677
- break;
678
- case 'analytics/overview':
679
- data = await this.getAnalytics();
680
- break;
681
- case 'doctor/check':
682
- data = await this.runDoctor();
683
- break;
684
- case 'channels/list':
685
- data = await this.getChannels();
686
- break;
687
- case 'plugins/list':
688
- data = await this.getPlugins();
689
- break;
690
- case 'security/approvals':
691
- data = await this.getPendingApprovals();
692
- break;
693
- case 'eval/suites':
694
- data = await this.getEvalSuites();
695
- break;
696
- case 'eval/run':
697
- if (req.method === 'POST') data = await this.runEvalSuite(req);
698
- else { res.writeHead(405); res.end(); return; }
699
- break;
700
- case 'a2a/card':
701
- data = this.getA2ACard();
702
- break;
703
- case 'a2a/tasks':
704
- data = this.getA2ATasks();
705
- break;
706
- case 'a2a/discover':
707
- if (req.method === 'POST') data = await this.discoverA2AAgent(req);
708
- else { res.writeHead(405); res.end(); return; }
709
- break;
710
- case 'protocols':
711
- data = await this.getProtocols();
712
- break;
713
- case 'protocols/mcp':
714
- data = this.getMCPServerStatus();
715
- break;
716
- case 'eval/reports':
717
- data = await this.getEvalReports();
718
- break;
719
- case 'telemetry/stats':
720
- data = this.tracer ? this.tracer.getStats() : { error: 'Telemetry not enabled' };
721
- break;
722
- case 'telemetry/traces':
723
- data = this.getTelemetryTraces(url);
724
- break;
725
- case 'telemetry/metrics':
726
- data = this.tracer ? this.tracer.getMetrics() : [];
727
- break;
728
- case 'playground/chat':
729
- if (req.method === 'POST') {
730
- return this.handlePlaygroundChat(req, res);
731
- }
732
- res.writeHead(405); res.end(); return;
733
- case 'playground/models':
734
- data = { models: ['gpt-4o', 'gpt-4o-mini', 'claude-sonnet-4', 'claude-haiku', 'gemini-2.0-flash', 'deepseek-v3'] };
735
- break;
736
- default:
737
- res.writeHead(404, { 'Content-Type': 'application/json' });
738
- res.end(JSON.stringify({ error: 'Not found' }));
739
- return;
740
- }
741
-
742
- res.writeHead(200, {
743
- 'Content-Type': 'application/json',
744
- 'Access-Control-Allow-Origin': '*',
745
- });
746
- res.end(JSON.stringify(data));
747
- } catch (e: any) {
748
- res.writeHead(500, { 'Content-Type': 'application/json' });
749
- res.end(JSON.stringify({ error: e.message }));
750
- }
751
- }
752
-
753
- // --- Agent CRUD & Templates ---
754
-
755
- private getAgentsDir(): string {
756
- const dir = join(os.homedir(), '.opc', 'agents');
757
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
758
- return dir;
759
- }
760
-
761
- private async createAgent(req: IncomingMessage): Promise<any> {
762
- const body = await this.readBody(req);
763
- const { name, templateId, description, model, language } = JSON.parse(body);
764
- const template = TEMPLATES.find(t => t.id === templateId);
765
- const id = `agent-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
766
- const agent = {
767
- id,
768
- name: name || template?.name || 'My Agent',
769
- templateId: templateId || null,
770
- templateName: template?.name || 'Custom',
771
- templateIcon: template?.icon || '🤖',
772
- description: description || template?.description || '',
773
- model: model || template?.suggestedModel || 'gpt-4o-mini',
774
- language: language || 'en',
775
- systemPrompt: template?.systemPrompt || 'You are a helpful assistant.',
776
- industry: template?.industry || 'general',
777
- created: new Date().toISOString(),
778
- updated: new Date().toISOString(),
779
- messageCount: 0,
780
- lastActive: new Date().toISOString(),
781
- };
782
- const filePath = join(this.getAgentsDir(), `${id}.json`);
783
- writeFileSync(filePath, JSON.stringify(agent, null, 2));
784
- return agent;
785
- }
786
-
787
- private listAgents(): { agents: any[] } {
788
- // 1. Load Studio-created agents from ~/.opc/agents/*.json
789
- const dir = this.getAgentsDir();
790
- const files = readdirSync(dir).filter(f => f.endsWith('.json'));
791
- const agents = files.map(f => {
792
- try { return JSON.parse(readFileSync(join(dir, f), 'utf-8')); } catch { return null; }
793
- }).filter(Boolean);
794
-
795
- // 2. Also detect current working directory agent (oad.yaml)
796
- const seenIds = new Set(agents.map((a: any) => a.id));
797
- const oadPath = join(this.config.agentDir, 'oad.yaml');
798
- if (existsSync(oadPath)) {
799
- try {
800
- const oadRaw = readFileSync(oadPath, 'utf-8');
801
- const yamlMod = require('js-yaml');
802
- const oad = yamlMod.load(oadRaw) as any;
803
- const name = oad?.name || oad?.metadata?.name || 'My Agent';
804
- const id = oad?.id || name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '');
805
- if (!seenIds.has(id)) {
806
- agents.push({
807
- id,
808
- name,
809
- description: oad?.description || oad?.spec?.description || '',
810
- icon: oad?.icon || '🤖',
811
- emoji: oad?.icon || '🤖',
812
- status: 'running',
813
- source: 'oad.yaml',
814
- model: oad?.spec?.model || oad?.spec?.provider?.model || 'auto',
815
- created: new Date().toISOString(),
816
- updated: new Date().toISOString(),
817
- });
818
- }
819
- } catch { /* ignore parse errors */ }
820
- }
821
-
822
- agents.sort((a: any, b: any) => new Date(b.updated).getTime() - new Date(a.updated).getTime());
823
- return { agents };
824
- }
825
-
826
- private getAgentById(id: string): any {
827
- const filePath = join(this.getAgentsDir(), `${id}.json`);
828
- if (!existsSync(filePath)) return { error: 'Agent not found' };
829
- return JSON.parse(readFileSync(filePath, 'utf-8'));
830
- }
831
-
832
- private async updateAgent(id: string, req: IncomingMessage): Promise<any> {
833
- const filePath = join(this.getAgentsDir(), `${id}.json`);
834
- if (!existsSync(filePath)) return { error: 'Agent not found' };
835
- const existing = JSON.parse(readFileSync(filePath, 'utf-8'));
836
- const body = await this.readBody(req);
837
- const updates = JSON.parse(body);
838
- const updated = { ...existing, ...updates, id, updated: new Date().toISOString() };
839
- writeFileSync(filePath, JSON.stringify(updated, null, 2));
840
- return updated;
841
- }
842
-
843
- private deleteAgent(id: string): { success: boolean } {
844
- const filePath = join(this.getAgentsDir(), `${id}.json`);
845
- if (existsSync(filePath)) unlinkSync(filePath);
846
- return { success: true };
847
- }
848
-
849
- private getTemplates(industry: string, search: string): { templates: AgentTemplate[]; industries: typeof INDUSTRIES } {
850
- let filtered = TEMPLATES;
851
- if (industry) filtered = filtered.filter(t => t.industry === industry);
852
- if (search) {
853
- const q = search.toLowerCase();
854
- filtered = filtered.filter(t =>
855
- t.name.toLowerCase().includes(q) || t.nameZh.includes(q) ||
856
- t.description.toLowerCase().includes(q) || t.descriptionZh.includes(q) ||
857
- t.tags.some(tag => tag.includes(q))
858
- );
859
- }
860
- return { templates: filtered, industries: INDUSTRIES };
861
- }
862
-
863
- private getTemplateById(id: string): AgentTemplate | { error: string } {
864
- const tpl = TEMPLATES.find(t => t.id === id);
865
- return tpl || { error: 'Template not found' };
866
- }
867
-
868
- private getAgentMemory(agentId: string): any {
869
- const memDir = join(this.getAgentsDir(), agentId + '-memory');
870
- if (!existsSync(memDir)) return { entries: [], timeline: [] };
871
- const files = readdirSync(memDir).filter(f => f.endsWith('.json'));
872
- const entries = files.map(f => {
873
- try { return JSON.parse(readFileSync(join(memDir, f), 'utf-8')); } catch { return null; }
874
- }).filter(Boolean).sort((a: any, b: any) => new Date(b.timestamp).getTime() - new Date(a.timestamp).getTime());
875
- return { entries, timeline: entries.map((e: any) => ({ date: e.timestamp, summary: e.summary || e.content?.slice(0, 100) })) };
876
- }
877
-
878
- private async handleAgentChat(req: IncomingMessage, res: ServerResponse, agentId: string): Promise<void> {
879
- let body: any;
880
- try {
881
- body = JSON.parse(await this.readBody(req));
882
- } catch {
883
- res.writeHead(400, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
884
- res.end(JSON.stringify({ error: 'Invalid JSON body' }));
885
- return;
886
- }
887
-
888
- // Accept both { messages: [...] } and { message: "...", history: [...] }
889
- let messages: any[] = body.messages || [];
890
- if (body.message) {
891
- // Frontend sends { message, history }
892
- messages = [...(body.history || []), { role: 'user', content: body.message }];
893
- }
894
-
895
- const agent = this.getAgentById(agentId);
896
- if (agent.error) {
897
- res.writeHead(404, { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' });
898
- res.end(JSON.stringify(agent));
899
- return;
900
- }
901
-
902
- // Update message count
903
- agent.messageCount = (agent.messageCount || 0) + 1;
904
- agent.lastActive = new Date().toISOString();
905
- agent.updated = new Date().toISOString();
906
- const agentFilePath = join(this.getAgentsDir(), `${agentId}.json`);
907
- writeFileSync(agentFilePath, JSON.stringify(agent, null, 2));
908
-
909
- // SSE streaming response
910
- res.writeHead(200, {
911
- 'Content-Type': 'text/event-stream',
912
- 'Cache-Control': 'no-cache',
913
- 'Connection': 'keep-alive',
914
- 'Access-Control-Allow-Origin': '*',
915
- });
916
-
917
- // Use createProvider directly to call LLM
918
- try {
919
- const { createProvider } = require('../providers');
920
- // Determine provider: agent config > OAD yaml > env > auto
921
- let providerName = agent.provider || process.env.OPC_LLM_PROVIDER;
922
- if (!providerName) {
923
- try {
924
- for (const fname of ['oad.yaml', 'agent.yaml']) {
925
- const oadPath = join(this.config.agentDir, fname);
926
- if (existsSync(oadPath)) {
927
- const yaml = require('js-yaml');
928
- const oad = yaml.load(readFileSync(oadPath, 'utf-8'));
929
- providerName = oad?.spec?.provider?.default;
930
- if (providerName) break;
931
- }
932
- }
933
- } catch {}
934
- }
935
- providerName = providerName || 'auto';
936
- const provider = createProvider(providerName, agent.model);
937
-
938
- let fullText = '';
939
- try {
940
- for await (const chunk of provider.chatStream(messages, agent.systemPrompt)) {
941
- const sseData = JSON.stringify({
942
- choices: [{ delta: { content: chunk }, index: 0 }],
943
- });
944
- res.write(`data: ${sseData}\n\n`);
945
- fullText += chunk;
946
- }
947
- } catch (streamErr: any) {
948
- if (!fullText) {
949
- const errData = JSON.stringify({
950
- choices: [{ delta: { content: `⚠️ LLM Error: ${streamErr.message}` }, index: 0 }],
951
- });
952
- res.write(`data: ${errData}\n\n`);
953
- }
954
- }
955
- res.write('data: [DONE]\n\n');
956
- res.end();
957
- } catch (err: any) {
958
- // Provider creation failed — send error as SSE so frontend can display it
959
- const errData = JSON.stringify({
960
- choices: [{ delta: { content: `⚠️ Provider error: ${err.message}\n\nTip: Install Claude CLI (npm i -g @anthropic-ai/claude-code) or set OPENAI_API_KEY.` }, index: 0 }],
961
- });
962
- res.write(`data: ${errData}\n\n`);
963
- res.write('data: [DONE]\n\n');
964
- res.end();
965
- }
966
- }
967
-
968
- private sendSimulatedResponse(res: ServerResponse, lastMsg: string, agent: any): void {
969
- const response = `Hello! I'm ${agent.name}. You said: "${lastMsg}"\n\nI'm ready to help you. (Note: Connect a model provider for real AI responses)`;
970
- const words = response.split(' ');
971
- let i = 0;
972
- const interval = setInterval(() => {
973
- if (i >= words.length) {
974
- res.write('data: [DONE]\n\n');
975
- res.end();
976
- clearInterval(interval);
977
- return;
978
- }
979
- const chunk = (i === 0 ? '' : ' ') + words[i];
980
- res.write(`data: ${JSON.stringify({ choices: [{ delta: { content: chunk } }] })}\n\n`);
981
- i++;
982
- }, 50);
983
- }
984
-
985
- // --- Settings Implementations ---
986
-
987
- private async detectLocalOllama(): Promise<any> {
988
- return new Promise((resolve) => {
989
- const req = httpRequest({ hostname: 'localhost', port: 11434, path: '/api/tags', method: 'GET', timeout: 3000 }, (res) => {
990
- let body = '';
991
- res.on('data', (c: any) => body += c);
992
- res.on('end', () => {
993
- try {
994
- const data = JSON.parse(body);
995
- const models = (data.models || []).map((m: any) => ({
996
- name: m.name, size: m.size, modified: m.modified_at,
997
- details: m.details || {},
998
- }));
999
- resolve({ running: true, models });
1000
- } catch { resolve({ running: true, models: [] }); }
1001
- });
1002
- });
1003
- req.on('error', () => resolve({ running: false, models: [] }));
1004
- req.on('timeout', () => { req.destroy(); resolve({ running: false, models: [] }); });
1005
- req.end();
1006
- });
1007
- }
1008
-
1009
- private async testModelConnection(provider: string, apiKey: string, baseUrl?: string): Promise<any> {
1010
- const endpoints: Record<string, { url: string; path: string }> = {
1011
- openai: { url: 'api.openai.com', path: '/v1/models' },
1012
- deepseek: { url: 'api.deepseek.com', path: '/v1/models' },
1013
- anthropic: { url: 'api.anthropic.com', path: '/v1/models' },
1014
- openrouter: { url: 'openrouter.ai', path: '/api/v1/models' },
1015
- };
1016
- const ep = endpoints[provider];
1017
- if (!ep && !baseUrl) return { success: false, error: 'Unknown provider' };
1018
-
1019
- const hostname = baseUrl ? new URL(baseUrl).hostname : ep.url;
1020
- const path = baseUrl ? '/v1/models' : ep.path;
1021
- const headers: Record<string, string> = { 'Authorization': `Bearer ${apiKey}` };
1022
- if (provider === 'anthropic') {
1023
- headers['x-api-key'] = apiKey;
1024
- headers['anthropic-version'] = '2023-06-01';
1025
- delete headers['Authorization'];
1026
- }
1027
-
1028
- return new Promise((resolve) => {
1029
- const https = require('https');
1030
- const req = https.request({ hostname, path, method: 'GET', headers, timeout: 10000 }, (res: any) => {
1031
- resolve({ success: res.statusCode === 200, statusCode: res.statusCode });
1032
- });
1033
- req.on('error', (e: any) => resolve({ success: false, error: e.message }));
1034
- req.on('timeout', () => { req.destroy(); resolve({ success: false, error: 'Timeout' }); });
1035
- req.end();
1036
- });
1037
- }
1038
-
1039
- private async getSettingsStatus(): Promise<any> {
1040
- const uptime = process.uptime();
1041
- const mem = process.memoryUsage();
1042
- const modules = await this.getModulesStatus();
1043
- const logPath = join(this.config.agentDir, '.opc', 'agent.log');
1044
- let recentLogs: string[] = [];
1045
- if (existsSync(logPath)) {
1046
- const content = readFileSync(logPath, 'utf-8');
1047
- recentLogs = content.split('\n').slice(-50);
1048
- }
1049
- return {
1050
- status: 'running',
1051
- uptime,
1052
- memory: { rss: mem.rss, heapUsed: mem.heapUsed, heapTotal: mem.heapTotal },
1053
- cpu: os.loadavg(),
1054
- modules: modules.modules,
1055
- logs: recentLogs,
1056
- startedAt: new Date(Date.now() - uptime * 1000).toISOString(),
1057
- };
1058
- }
1059
-
1060
- private async getUsageStats(): Promise<any> {
1061
- const cfg = loadSettingsConfig();
1062
- const usage = cfg.usage || { totalTokens: 0, totalCost: 0, daily: [], byModel: {} };
1063
- return usage;
1064
- }
1065
-
1066
- // --- API Implementations ---
1067
-
1068
- private async getAgentInfo() {
1069
- const oad = this.loadOAD();
1070
- const pkg = this.loadPackageJson();
1071
- return {
1072
- name: oad?.metadata?.name || pkg?.name || 'unknown',
1073
- version: oad?.metadata?.version || pkg?.version || '0.0.0',
1074
- description: oad?.metadata?.description || pkg?.description || '',
1075
- model: oad?.spec?.model || 'unknown',
1076
- provider: oad?.spec?.provider?.default || 'unknown',
1077
- channels: oad?.spec?.channels?.map((c: any) => c.type) || [],
1078
- skills: oad?.spec?.skills?.map((s: any) => s.name) || [],
1079
- status: 'running',
1080
- };
1081
- }
1082
-
1083
- private async getAgentConfig() {
1084
- const yamlPath = join(this.config.agentDir, 'agent.yaml');
1085
- if (existsSync(yamlPath)) {
1086
- return { content: readFileSync(yamlPath, 'utf-8') };
1087
- }
1088
- return { content: '', error: 'agent.yaml not found' };
1089
- }
1090
-
1091
- private async saveConfig(req: IncomingMessage) {
1092
- const body = await this.readBody(req);
1093
- const { content } = JSON.parse(body);
1094
- const yamlPath = join(this.config.agentDir, 'agent.yaml');
1095
- const { writeFileSync } = require('fs');
1096
- writeFileSync(yamlPath, content, 'utf-8');
1097
- return { success: true };
1098
- }
1099
-
1100
- private async handleChat(req: IncomingMessage) {
1101
- const body = await this.readBody(req);
1102
- const { message, sessionId } = JSON.parse(body);
1103
- try {
1104
- const { BaseAgent, InMemoryStore } = require('../index');
1105
- const oad = this.loadOAD();
1106
- const agent = new BaseAgent({
1107
- name: oad?.metadata?.name || 'studio-agent',
1108
- systemPrompt: oad?.spec?.systemPrompt || 'You are a helpful assistant.',
1109
- provider: oad?.spec?.provider?.default || 'ollama',
1110
- model: oad?.spec?.model || 'qwen2.5',
1111
- memory: new InMemoryStore(),
1112
- });
1113
- await agent.init();
1114
- const response = await agent.handleMessage({
1115
- id: String(Date.now()),
1116
- content: message,
1117
- sender: 'studio-user',
1118
- channel: 'studio',
1119
- sessionId: sessionId || 'studio-session',
1120
- timestamp: new Date(),
1121
- });
1122
- return { response: response.content };
1123
- } catch (e: any) {
1124
- return { response: `Error: ${e.message}` };
1125
- }
1126
- }
1127
-
1128
- private async getMemoryList() {
1129
- try {
1130
- const { Brain } = require('deepbrain');
1131
- const oad = this.loadOAD();
1132
- const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
1133
- const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
1134
- await brain.connect();
1135
- const pages = await brain.list({ limit: 50 });
1136
- await brain.disconnect();
1137
- return { pages };
1138
- } catch {
1139
- return { pages: [], error: 'DeepBrain not available' };
1140
- }
1141
- }
1142
-
1143
- private async searchMemory(query: string) {
1144
- try {
1145
- const { Brain } = require('deepbrain');
1146
- const oad = this.loadOAD();
1147
- const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
1148
- const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
1149
- await brain.connect();
1150
- const results = await brain.search(query);
1151
- await brain.disconnect();
1152
- return { results };
1153
- } catch {
1154
- return { results: [], error: 'Search failed' };
1155
- }
1156
- }
1157
-
1158
- private async getMemoryStats() {
1159
- try {
1160
- const { Brain } = require('deepbrain');
1161
- const oad = this.loadOAD();
1162
- const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
1163
- const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
1164
- await brain.connect();
1165
- const stats = await brain.stats();
1166
- await brain.disconnect();
1167
- return stats;
1168
- } catch {
1169
- return { pages: 0, chunks: 0, error: 'Stats unavailable' };
1170
- }
1171
- }
1172
-
1173
- private async getSkills() {
1174
- try {
1175
- const { SkillLearner } = require('../index');
1176
- const learner = new SkillLearner('.opc/skills');
1177
- const skills = learner.loadSkills();
1178
- return { skills };
1179
- } catch {
1180
- return { skills: [] };
1181
- }
1182
- }
1183
-
1184
- private async getTools() {
1185
- try {
1186
- const { getBuiltinTools } = require('../index');
1187
- const tools = getBuiltinTools(this.config.agentDir);
1188
- return { tools: tools.map((t: any) => ({ name: t.definition.name, description: t.definition.description })) };
1189
- } catch {
1190
- return { tools: [] };
1191
- }
1192
- }
1193
-
1194
- private getWorkflowsDir(): string {
1195
- const dir = join(this.config.agentDir, '.opc', 'workflows');
1196
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
1197
- return dir;
1198
- }
1199
-
1200
- private listWorkflows(): { workflows: WorkflowDefinition[] } {
1201
- const dir = this.getWorkflowsDir();
1202
- const files = require('fs').readdirSync(dir).filter((f: string) => f.endsWith('.json'));
1203
- const workflows = files.map((f: string) => {
1204
- try { return JSON.parse(readFileSync(join(dir, f), 'utf-8')); } catch { return null; }
1205
- }).filter(Boolean);
1206
- // Also include OAD-defined workflows
1207
- const oad = this.loadOAD();
1208
- const oadWorkflows = (oad?.spec?.workflows || []).map((w: any, i: number) => ({
1209
- id: `oad-${i}`,
1210
- name: w.name || `Workflow ${i + 1}`,
1211
- nodes: [],
1212
- edges: [],
1213
- steps: w.steps,
1214
- source: 'oad',
1215
- }));
1216
- return { workflows: [...workflows, ...oadWorkflows] };
1217
- }
1218
-
1219
- private getWorkflowById(id: string): WorkflowDefinition | { error: string } {
1220
- const filePath = join(this.getWorkflowsDir(), `${id}.json`);
1221
- if (!existsSync(filePath)) return { error: 'Workflow not found' };
1222
- return JSON.parse(readFileSync(filePath, 'utf-8'));
1223
- }
1224
-
1225
- private async saveWorkflow(req: IncomingMessage): Promise<{ success: boolean; id: string }> {
1226
- const body = await this.readBody(req);
1227
- const workflow = JSON.parse(body) as WorkflowDefinition;
1228
- if (!workflow.id) workflow.id = `wf-${Date.now()}`;
1229
- workflow.updated = new Date().toISOString();
1230
- if (!workflow.created) workflow.created = workflow.updated;
1231
- const filePath = join(this.getWorkflowsDir(), `${workflow.id}.json`);
1232
- writeFileSync(filePath, JSON.stringify(workflow, null, 2));
1233
- return { success: true, id: workflow.id };
1234
- }
1235
-
1236
- private deleteWorkflow(id: string): { success: boolean } {
1237
- const filePath = join(this.getWorkflowsDir(), `${id}.json`);
1238
- if (existsSync(filePath)) require('fs').unlinkSync(filePath);
1239
- return { success: true };
1240
- }
1241
-
1242
- private async runWorkflow(id: string): Promise<any> {
1243
- const wf = this.getWorkflowById(id);
1244
- if ('error' in wf) return wf;
1245
- // Basic topological execution simulation
1246
- const results: Record<string, any> = {};
1247
- const sorted = this.topoSort(wf.nodes, wf.edges);
1248
- for (const node of sorted) {
1249
- results[node.id] = { type: node.type, name: node.name, status: 'completed', output: `[simulated output for ${node.name}]` };
1250
- }
1251
- return { workflowId: id, status: 'completed', results };
1252
- }
1253
-
1254
- private topoSort(nodes: WorkflowNode[], edges: WorkflowEdge[]): WorkflowNode[] {
1255
- const nodeMap = new Map(nodes.map(n => [n.id, n]));
1256
- const inDegree = new Map<string, number>();
1257
- const adj = new Map<string, string[]>();
1258
- for (const n of nodes) { inDegree.set(n.id, 0); adj.set(n.id, []); }
1259
- for (const e of edges) { adj.get(e.from)?.push(e.to); inDegree.set(e.to, (inDegree.get(e.to) || 0) + 1); }
1260
- const queue = nodes.filter(n => (inDegree.get(n.id) || 0) === 0);
1261
- const result: WorkflowNode[] = [];
1262
- while (queue.length > 0) {
1263
- const node = queue.shift()!;
1264
- result.push(node);
1265
- for (const next of (adj.get(node.id) || [])) {
1266
- const d = (inDegree.get(next) || 1) - 1;
1267
- inDegree.set(next, d);
1268
- if (d === 0) queue.push(nodeMap.get(next)!);
1269
- }
1270
- }
1271
- return result;
1272
- }
1273
-
1274
- private async getJobs() {
1275
- const oad = this.loadOAD();
1276
- return { jobs: oad?.spec?.scheduler?.jobs || [] };
1277
- }
1278
-
1279
- private async getRecentLogs() {
1280
- const logPath = join(this.config.agentDir, '.opc', 'agent.log');
1281
- if (existsSync(logPath)) {
1282
- const content = readFileSync(logPath, 'utf-8');
1283
- const lines = content.split('\n').slice(-100);
1284
- return { lines };
1285
- }
1286
- return { lines: [] };
1287
- }
1288
-
1289
- private async getAnalytics() {
1290
- return {
1291
- totalMessages: 0,
1292
- totalSessions: 0,
1293
- avgResponseTime: 0,
1294
- topSkills: [],
1295
- note: 'Analytics tracking starts when agent is running via opc run/start',
1296
- };
1297
- }
1298
-
1299
- private async runDoctor() {
1300
- try {
1301
- const { runDoctor } = require('../doctor');
1302
- const results = await runDoctor();
1303
- return results;
1304
- } catch {
1305
- return { error: 'Doctor not available' };
1306
- }
1307
- }
1308
-
1309
- private async getChannels() {
1310
- const oad = this.loadOAD();
1311
- return { channels: oad?.spec?.channels || [] };
1312
- }
1313
-
1314
- private async getPlugins() {
1315
- const oad = this.loadOAD();
1316
- return { plugins: oad?.spec?.plugins || [] };
1317
- }
1318
-
1319
- private async getProtocols() {
1320
- const oad = this.loadOAD();
1321
- const protocols = (oad?.spec as any)?.protocols || {};
1322
- return {
1323
- protocols: [
1324
- { name: 'a2a', description: 'Agent-to-Agent', enabled: !!protocols.a2a?.enabled, config: protocols.a2a || {} },
1325
- { name: 'agui', description: 'AG-UI — Agent-User Interaction (SSE)', enabled: !!protocols.agui?.enabled, config: protocols.agui || {} },
1326
- { name: 'mcp', description: 'MCP Server — Expose as MCP tools', enabled: !!protocols.mcp?.enabled, config: protocols.mcp || {} },
1327
- ],
1328
- };
1329
- }
1330
-
1331
- private async getPendingApprovals() {
1332
- return { approvals: [] };
1333
- }
1334
-
1335
- private getMCPServerStatus() {
1336
- const oad = this.loadOAD();
1337
- const mcpConfig = (oad?.spec as any)?.protocols?.mcp;
1338
- const { agentToMCPTools } = require('../protocols/mcp/agent-tools');
1339
- const agentName = oad?.metadata?.name || 'opc-agent';
1340
- const tools = agentToMCPTools({ name: agentName });
1341
- return {
1342
- enabled: !!mcpConfig?.enabled,
1343
- mode: mcpConfig?.mode || 'stdio',
1344
- port: mcpConfig?.port || 3002,
1345
- tools: tools.map((t: any) => ({ name: t.name, description: t.description })),
1346
- toolCount: tools.length,
1347
- exposedTools: mcpConfig?.exposedTools || tools.map((t: any) => t.name),
1348
- };
1349
- }
1350
-
1351
- private getTelemetryTraces(url: URL) {
1352
- if (!this.tracer) return { traces: [] };
1353
- const traceId = url.searchParams.get('id');
1354
- if (traceId) {
1355
- return { spans: this.tracer.getTrace(traceId) };
1356
- }
1357
- const limit = parseInt(url.searchParams.get('limit') || '50');
1358
- const spans = this.tracer.getSpans({ limit });
1359
- // Group by traceId for trace list
1360
- const traceMap = new Map<string, { traceId: string; rootSpan: string; startTime: number; spanCount: number; status: string }>();
1361
- for (const s of spans) {
1362
- if (!traceMap.has(s.traceId)) {
1363
- traceMap.set(s.traceId, { traceId: s.traceId, rootSpan: s.name, startTime: s.startTime, spanCount: 0, status: s.status });
1364
- }
1365
- traceMap.get(s.traceId)!.spanCount++;
1366
- }
1367
- return { traces: Array.from(traceMap.values()) };
1368
- }
1369
-
1370
- private async getEvalSuites() {
1371
- const { AgentEvaluator } = require('../eval');
1372
- return { suites: AgentEvaluator.builtinSuites() };
1373
- }
1374
-
1375
- private async runEvalSuite(req: IncomingMessage): Promise<any> {
1376
- const body = await this.readBody(req);
1377
- const { suite: suiteName } = JSON.parse(body || '{}');
1378
- const { AgentEvaluator } = require('../eval');
1379
- const suite = AgentEvaluator.loadBuiltinSuite(suiteName || 'basic');
1380
- // Use a mock agent for studio eval (no real agent loaded)
1381
- const mockAgent = { chat: async (input: string) => `[mock response to: ${input}]` };
1382
- const evaluator = new AgentEvaluator(mockAgent);
1383
- const report = await evaluator.evalSuite(suite);
1384
- // Save report
1385
- const reportsDir = join(this.config.agentDir, '.eval-reports');
1386
- const reportPath = join(reportsDir, `${suiteName || 'basic'}-${Date.now()}.json`);
1387
- AgentEvaluator.saveReport(report, reportPath);
1388
- return report;
1389
- }
1390
-
1391
- private async getEvalReports() {
1392
- const reportsDir = join(this.config.agentDir, '.eval-reports');
1393
- if (!existsSync(reportsDir)) return { reports: [] };
1394
- const files = require('fs').readdirSync(reportsDir).filter((f: string) => f.endsWith('.json'));
1395
- return {
1396
- reports: files.map((f: string) => {
1397
- try {
1398
- return JSON.parse(readFileSync(join(reportsDir, f), 'utf-8'));
1399
- } catch { return null; }
1400
- }).filter(Boolean)
1401
- };
1402
- }
1403
-
1404
- // --- A2A Protocol ---
1405
-
1406
- private getA2ACard() {
1407
- try {
1408
- const { oadToAgentCard } = require('../protocols/a2a');
1409
- const yaml = require('js-yaml');
1410
- for (const name of ['agent.yaml', 'agent.yml']) {
1411
- const p = join(this.config.agentDir, name);
1412
- if (existsSync(p)) {
1413
- const oad = yaml.load(readFileSync(p, 'utf-8'));
1414
- return oadToAgentCard(oad, `http://localhost:${this.config.port}`);
1415
- }
1416
- }
1417
- return { error: 'No agent.yaml found' };
1418
- } catch { return { error: 'Failed to generate agent card' }; }
1419
- }
1420
-
1421
- private getA2ATasks() {
1422
- // In-memory tasks from A2A server if running
1423
- return { tasks: [] };
1424
- }
1425
-
1426
- private async discoverA2AAgent(req: IncomingMessage): Promise<any> {
1427
- const body = await this.readBody(req);
1428
- const { url } = JSON.parse(body || '{}');
1429
- if (!url) return { error: 'url required' };
1430
- try {
1431
- const { A2AClient } = require('../protocols/a2a');
1432
- const client = new A2AClient(url);
1433
- return await client.getAgentCard();
1434
- } catch (err: any) {
1435
- return { error: err.message };
1436
- }
1437
- }
1438
-
1439
- private async getFirstRunStatus(): Promise<any> {
1440
- const configPath = join(os.homedir(), '.opc', 'config.json');
1441
- const ollamaStatus = await this.detectLocalOllama();
1442
- if (!existsSync(configPath)) {
1443
- return { firstRun: true, ollamaDetected: ollamaStatus.running, ollamaModels: ollamaStatus.models || [] };
1444
- }
1445
- try {
1446
- const config = JSON.parse(readFileSync(configPath, 'utf-8'));
1447
- return { firstRun: !config.firstRunComplete, ollamaDetected: ollamaStatus.running, ollamaModels: ollamaStatus.models || [] };
1448
- } catch {
1449
- return { firstRun: true, ollamaDetected: ollamaStatus.running, ollamaModels: ollamaStatus.models || [] };
1450
- }
1451
- }
1452
-
1453
- private async completeFirstRun(choices: any): Promise<any> {
1454
- const cfg = loadSettingsConfig();
1455
- cfg.firstRunComplete = true;
1456
- if (choices) {
1457
- if (choices.templateId) cfg.firstRunTemplate = choices.templateId;
1458
- if (choices.model) cfg.models = { ...(cfg.models || {}), chatModel: choices.model };
1459
- }
1460
- saveSettingsConfig(cfg);
1461
- return { success: true };
1462
- }
1463
-
1464
- // --- Module Proxy & Health ---
1465
-
1466
- private proxyToModule(req: IncomingMessage, res: ServerResponse, mod: ModuleInfo, url: URL) {
1467
- const targetPath = url.pathname.slice(`/${mod.path}`.length) || '/';
1468
- const proxyReq = httpRequest(
1469
- {
1470
- hostname: 'localhost',
1471
- port: mod.port,
1472
- path: targetPath + (url.search || ''),
1473
- method: req.method,
1474
- headers: { ...req.headers, host: `localhost:${mod.port}` },
1475
- },
1476
- (proxyRes) => {
1477
- res.writeHead(proxyRes.statusCode || 502, proxyRes.headers);
1478
- proxyRes.pipe(res, { end: true });
1479
- },
1480
- );
1481
- proxyReq.on('error', () => {
1482
- res.writeHead(502, { 'Content-Type': 'text/html' });
1483
- res.end(`<html><body style="font-family:system-ui;padding:40px;color:#999;background:#1a1a2e;text-align:center"><h2>${mod.icon} ${mod.name}</h2><p>Module not running on port ${mod.port}</p></body></html>`);
1484
- });
1485
- req.pipe(proxyReq, { end: true });
1486
- }
1487
-
1488
- private checkPort(port: number): Promise<boolean> {
1489
- return new Promise((resolve) => {
1490
- const sock = new net.Socket();
1491
- sock.setTimeout(500);
1492
- sock.once('connect', () => { sock.destroy(); resolve(true); });
1493
- sock.once('error', () => { sock.destroy(); resolve(false); });
1494
- sock.once('timeout', () => { sock.destroy(); resolve(false); });
1495
- sock.connect(port, 'localhost');
1496
- });
1497
- }
1498
-
1499
- async getModulesStatus() {
1500
- const modules = await Promise.all(
1501
- MODULE_REGISTRY.map(async (mod) => ({
1502
- name: mod.name,
1503
- path: `/${mod.path}/`,
1504
- port: mod.port,
1505
- icon: mod.icon,
1506
- running: await this.checkPort(mod.port),
1507
- })),
1508
- );
1509
- return { modules };
1510
- }
1511
-
1512
- // --- Helpers ---
1513
-
1514
- private loadOAD(): any {
1515
- try {
1516
- const yamlPath = join(this.config.agentDir, 'agent.yaml');
1517
- if (!existsSync(yamlPath)) return null;
1518
- const content = readFileSync(yamlPath, 'utf-8');
1519
- try {
1520
- const { loadOAD } = require('../index');
1521
- return loadOAD(yamlPath);
1522
- } catch {
1523
- // Fallback: simple yaml parse
1524
- const yaml = require('js-yaml');
1525
- return yaml.load(content);
1526
- }
1527
- } catch {
1528
- return null;
1529
- }
1530
- }
1531
-
1532
- private loadPackageJson(): any {
1533
- try {
1534
- const pkgPath = join(this.config.agentDir, 'package.json');
1535
- if (!existsSync(pkgPath)) return null;
1536
- return JSON.parse(readFileSync(pkgPath, 'utf-8'));
1537
- } catch {
1538
- return null;
1539
- }
1540
- }
1541
-
1542
- serveStatic(req: IncomingMessage, res: ServerResponse, url: URL) {
1543
- let filePath = url.pathname === '/' ? '/index.html' : url.pathname;
1544
- const fullPath = join(this.config.staticDir, filePath);
1545
-
1546
- if (!existsSync(fullPath)) {
1547
- // SPA fallback
1548
- const indexPath = join(this.config.staticDir, 'index.html');
1549
- if (existsSync(indexPath)) {
1550
- const content = readFileSync(indexPath, 'utf-8');
1551
- res.writeHead(200, { 'Content-Type': 'text/html', 'Cache-Control': 'no-cache, no-store, must-revalidate' });
1552
- res.end(content);
1553
- return;
1554
- }
1555
- res.writeHead(404);
1556
- res.end('Not found');
1557
- return;
1558
- }
1559
-
1560
- const mimeTypes: Record<string, string> = {
1561
- '.html': 'text/html',
1562
- '.css': 'text/css',
1563
- '.js': 'application/javascript',
1564
- '.json': 'application/json',
1565
- '.png': 'image/png',
1566
- '.svg': 'image/svg+xml',
1567
- '.ico': 'image/x-icon',
1568
- };
1569
- const ext = extname(fullPath);
1570
- const contentType = mimeTypes[ext] || 'application/octet-stream';
1571
-
1572
- const content = readFileSync(fullPath);
1573
- res.writeHead(200, { 'Content-Type': contentType });
1574
- res.end(content);
1575
- }
1576
-
1577
- private async handlePlaygroundChat(req: IncomingMessage, res: ServerResponse): Promise<void> {
1578
- const body = JSON.parse(await this.readBody(req));
1579
- const { messages = [], model = 'gpt-4o', temperature = 0.7, systemPrompt } = body;
1580
-
1581
- res.writeHead(200, {
1582
- 'Content-Type': 'text/event-stream',
1583
- 'Cache-Control': 'no-cache',
1584
- 'Connection': 'keep-alive',
1585
- 'Access-Control-Allow-Origin': '*',
1586
- });
1587
-
1588
- // Simulated streaming response for playground demo
1589
- const allMsgs = systemPrompt ? [{ role: 'system', content: systemPrompt }, ...messages] : messages;
1590
- const lastMsg = allMsgs[allMsgs.length - 1]?.content || '';
1591
- const response = `This is a playground demo response to: "${lastMsg}"\n\nModel: ${model}, Temperature: ${temperature}\nMessages in context: ${allMsgs.length}`;
1592
-
1593
- const words = response.split(' ');
1594
- for (let i = 0; i < words.length; i++) {
1595
- const chunk = (i === 0 ? '' : ' ') + words[i];
1596
- res.write(`data: ${JSON.stringify({ content: chunk })}\n\n`);
1597
- }
1598
- res.write('data: [DONE]\n\n');
1599
- res.end();
1600
- }
1601
-
1602
- // --- Document upload handlers ---
1603
-
1604
- private getDocumentsDir(agentId: string): string {
1605
- const dir = join(this.getAgentsDir(), agentId + '-documents');
1606
- if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
1607
- return dir;
1608
- }
1609
-
1610
- private async handleDocumentUpload(req: IncomingMessage, res: ServerResponse, agentId: string): Promise<void> {
1611
- const corsHeaders = { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' };
1612
-
1613
- try {
1614
- // Parse multipart form data manually
1615
- const { buffer, filename } = await this.parseMultipart(req);
1616
-
1617
- if (!filename) {
1618
- res.writeHead(400, corsHeaders);
1619
- res.end(JSON.stringify({ error: 'No file uploaded' }));
1620
- return;
1621
- }
1622
-
1623
- if (buffer.length > 50 * 1024 * 1024) {
1624
- res.writeHead(413, corsHeaders);
1625
- res.end(JSON.stringify({ error: 'File too large (max 50MB)' }));
1626
- return;
1627
- }
1628
-
1629
- // Process document
1630
- const processor = new DocumentProcessor();
1631
- const doc = await processor.process(buffer, filename);
1632
-
1633
- // Store chunks via DeepBrain learn()
1634
- let learnedCount = 0;
1635
- try {
1636
- const { Brain } = require('deepbrain');
1637
- const oad = this.loadOAD();
1638
- const dbPath = oad?.spec?.memory?.longTerm?.database || './data/brain.db';
1639
- const brain = new Brain({ database: dbPath, embedding_provider: 'ollama' });
1640
- await brain.connect();
1641
-
1642
- for (const chunk of doc.chunks) {
1643
- const content = `[Source: ${filename}] ${chunk.title}\n\n${chunk.content}`;
1644
- if (typeof brain.store === 'function') {
1645
- await brain.store('documents', `${doc.id}-${chunk.metadata.chunkIndex}`, content, {
1646
- source: filename,
1647
- docId: doc.id,
1648
- chunkIndex: chunk.metadata.chunkIndex,
1649
- tags: ['document-upload', filename],
1650
- });
1651
- } else if (typeof brain.learn === 'function') {
1652
- await brain.learn(content, {
1653
- tags: ['document-upload', filename],
1654
- slug: `${doc.id}-${chunk.metadata.chunkIndex}`,
1655
- });
1656
- }
1657
- learnedCount++;
1658
- }
1659
-
1660
- await brain.disconnect();
1661
- } catch {
1662
- // If DeepBrain is not available, store in local memory files
1663
- const memDir = join(this.getAgentsDir(), agentId + '-memory');
1664
- if (!existsSync(memDir)) mkdirSync(memDir, { recursive: true });
1665
-
1666
- for (const chunk of doc.chunks) {
1667
- const entry = {
1668
- id: `${doc.id}-${chunk.metadata.chunkIndex}`,
1669
- content: chunk.content,
1670
- summary: `[${filename}] ${chunk.title}`,
1671
- timestamp: new Date().toISOString(),
1672
- source: filename,
1673
- docId: doc.id,
1674
- tags: ['document-upload'],
1675
- };
1676
- writeFileSync(join(memDir, `${entry.id}.json`), JSON.stringify(entry, null, 2));
1677
- learnedCount++;
1678
- }
1679
- }
1680
-
1681
- // Save document metadata
1682
- const docsDir = this.getDocumentsDir(agentId);
1683
- const docMeta = {
1684
- id: doc.id,
1685
- filename: doc.filename,
1686
- format: doc.format,
1687
- size: doc.size,
1688
- chunks: doc.chunks.length,
1689
- processedAt: doc.processedAt,
1690
- };
1691
- writeFileSync(join(docsDir, `${doc.id}.json`), JSON.stringify(docMeta, null, 2));
1692
-
1693
- res.writeHead(200, corsHeaders);
1694
- res.end(JSON.stringify({ success: true, document: docMeta, learnedCount }));
1695
- } catch (e: any) {
1696
- res.writeHead(500, corsHeaders);
1697
- res.end(JSON.stringify({ error: e.message || 'Upload failed' }));
1698
- }
1699
- }
1700
-
1701
- private async parseMultipart(req: IncomingMessage): Promise<{ buffer: Buffer; filename: string }> {
1702
- return new Promise((resolve, reject) => {
1703
- const contentType = req.headers['content-type'] || '';
1704
- const boundaryMatch = contentType.match(/boundary=(.+)/);
1705
-
1706
- if (!boundaryMatch) {
1707
- reject(new Error('Missing multipart boundary'));
1708
- return;
1709
- }
1710
-
1711
- const boundary = boundaryMatch[1];
1712
- const chunks: Buffer[] = [];
1713
-
1714
- req.on('data', (chunk: Buffer) => chunks.push(chunk));
1715
- req.on('error', reject);
1716
- req.on('end', () => {
1717
- const body = Buffer.concat(chunks);
1718
- const bodyStr = body.toString('latin1');
1719
- const parts = bodyStr.split('--' + boundary).filter(p => p.trim() && p.trim() !== '--');
1720
-
1721
- for (const part of parts) {
1722
- const headerEnd = part.indexOf('\r\n\r\n');
1723
- if (headerEnd === -1) continue;
1724
-
1725
- const headers = part.slice(0, headerEnd);
1726
- const filenameMatch = headers.match(/filename="([^"]+)"/);
1727
- if (!filenameMatch) continue;
1728
-
1729
- const filename = filenameMatch[1];
1730
- // Extract binary content properly
1731
- const contentStart = body.indexOf('\r\n\r\n', body.indexOf(Buffer.from(headers.slice(0, 40), 'latin1'))) + 4;
1732
- const nextBoundary = body.indexOf(Buffer.from('\r\n--' + boundary, 'latin1'), contentStart);
1733
- const fileBuffer = body.slice(contentStart, nextBoundary);
1734
-
1735
- resolve({ buffer: fileBuffer, filename });
1736
- return;
1737
- }
1738
-
1739
- reject(new Error('No file found in upload'));
1740
- });
1741
- });
1742
- }
1743
-
1744
- private getDocumentList(agentId: string): any {
1745
- const docsDir = this.getDocumentsDir(agentId);
1746
- const files = readdirSync(docsDir).filter(f => f.endsWith('.json'));
1747
- const documents = files.map(f => {
1748
- try { return JSON.parse(readFileSync(join(docsDir, f), 'utf-8')); } catch { return null; }
1749
- }).filter(Boolean).sort((a: any, b: any) =>
1750
- new Date(b.processedAt).getTime() - new Date(a.processedAt).getTime()
1751
- );
1752
- return { documents };
1753
- }
1754
-
1755
- private deleteDocument(agentId: string, docId: string): any {
1756
- const docsDir = this.getDocumentsDir(agentId);
1757
- const docPath = join(docsDir, `${docId}.json`);
1758
-
1759
- if (!existsSync(docPath)) {
1760
- return { error: 'Document not found' };
1761
- }
1762
-
1763
- // Delete document metadata
1764
- unlinkSync(docPath);
1765
-
1766
- // Try to delete from DeepBrain
1767
- try {
1768
- // Remove memory entries with this docId
1769
- const memDir = join(this.getAgentsDir(), agentId + '-memory');
1770
- if (existsSync(memDir)) {
1771
- const files = readdirSync(memDir).filter(f => f.startsWith(docId));
1772
- for (const f of files) {
1773
- unlinkSync(join(memDir, f));
1774
- }
1775
- }
1776
- } catch { /* best effort */ }
1777
-
1778
- return { success: true, deleted: docId };
1779
- }
1780
-
1781
- private readBody(req: IncomingMessage): Promise<string> {
1782
- return new Promise((resolve, reject) => {
1783
- let body = '';
1784
- req.on('data', (chunk: any) => (body += chunk));
1785
- req.on('end', () => resolve(body));
1786
- req.on('error', reject);
1787
- });
1788
- }
1789
- }
1790
-
1791
- export { StudioServer, StudioConfig };