opc-agent 4.1.1 → 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 (744) 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 +8 -2
  47. package/dist/channels/web.js.map +1 -0
  48. package/dist/channels/webhook.d.ts.map +1 -0
  49. package/dist/channels/webhook.js.map +1 -0
  50. package/dist/channels/websocket.d.ts.map +1 -0
  51. package/dist/channels/websocket.js.map +1 -0
  52. package/dist/channels/wechat.d.ts.map +1 -0
  53. package/dist/channels/wechat.js.map +1 -0
  54. package/dist/channels/whatsapp.d.ts.map +1 -0
  55. package/dist/channels/whatsapp.js.map +1 -0
  56. package/dist/cli/chat.d.ts.map +1 -0
  57. package/dist/cli/chat.js.map +1 -0
  58. package/dist/cli/setup.d.ts.map +1 -0
  59. package/dist/cli/setup.js.map +1 -0
  60. package/dist/cli.d.ts.map +1 -0
  61. package/dist/cli.js +261 -85
  62. package/dist/cli.js.map +1 -0
  63. package/dist/core/a2a.d.ts.map +1 -0
  64. package/dist/core/a2a.js.map +1 -0
  65. package/dist/core/agent.d.ts.map +1 -0
  66. package/dist/core/agent.js.map +1 -0
  67. package/dist/core/analytics-engine.d.ts.map +1 -0
  68. package/dist/core/analytics-engine.js.map +1 -0
  69. package/dist/core/api-server.d.ts.map +1 -0
  70. package/dist/core/api-server.js.map +1 -0
  71. package/dist/core/audio.d.ts.map +1 -0
  72. package/dist/core/audio.js.map +1 -0
  73. package/dist/core/auth.d.ts.map +1 -0
  74. package/dist/core/auth.js.map +1 -0
  75. package/dist/core/cache.d.ts.map +1 -0
  76. package/dist/core/cache.js.map +1 -0
  77. package/dist/core/collaboration.d.ts.map +1 -0
  78. package/dist/core/collaboration.js.map +1 -0
  79. package/dist/core/compose.d.ts.map +1 -0
  80. package/dist/core/compose.js.map +1 -0
  81. package/dist/core/config.d.ts.map +1 -0
  82. package/dist/core/config.js.map +1 -0
  83. package/dist/core/context-discovery.d.ts.map +1 -0
  84. package/dist/core/context-discovery.js.map +1 -0
  85. package/dist/core/context-refs.d.ts.map +1 -0
  86. package/dist/core/context-refs.js.map +1 -0
  87. package/dist/core/errors.d.ts.map +1 -0
  88. package/dist/core/errors.js.map +1 -0
  89. package/dist/core/gateway.d.ts.map +1 -0
  90. package/dist/core/gateway.js.map +1 -0
  91. package/dist/core/heartbeat.d.ts.map +1 -0
  92. package/dist/core/heartbeat.js.map +1 -0
  93. package/dist/core/hitl.d.ts.map +1 -0
  94. package/dist/core/hitl.js.map +1 -0
  95. package/dist/core/hooks.d.ts.map +1 -0
  96. package/dist/core/hooks.js.map +1 -0
  97. package/dist/core/ide-bridge.d.ts.map +1 -0
  98. package/dist/core/ide-bridge.js.map +1 -0
  99. package/dist/core/knowledge.d.ts.map +1 -0
  100. package/dist/core/knowledge.js.map +1 -0
  101. package/dist/core/logger.d.ts.map +1 -0
  102. package/dist/core/logger.js.map +1 -0
  103. package/dist/core/node-network.d.ts.map +1 -0
  104. package/dist/core/node-network.js.map +1 -0
  105. package/dist/core/orchestrator.d.ts.map +1 -0
  106. package/dist/core/orchestrator.js.map +1 -0
  107. package/dist/core/performance.d.ts.map +1 -0
  108. package/dist/core/performance.js.map +1 -0
  109. package/dist/core/profiles.d.ts.map +1 -0
  110. package/dist/core/profiles.js.map +1 -0
  111. package/dist/core/rate-limiter.d.ts.map +1 -0
  112. package/dist/core/rate-limiter.js.map +1 -0
  113. package/dist/core/room.d.ts.map +1 -0
  114. package/dist/core/room.js.map +1 -0
  115. package/dist/core/runtime.d.ts.map +1 -0
  116. package/dist/core/runtime.js +37 -15
  117. package/dist/core/runtime.js.map +1 -0
  118. package/dist/core/sandbox.d.ts.map +1 -0
  119. package/dist/core/sandbox.js.map +1 -0
  120. package/dist/core/scheduler.d.ts.map +1 -0
  121. package/dist/core/scheduler.js.map +1 -0
  122. package/dist/core/security.d.ts.map +1 -0
  123. package/dist/core/security.js.map +1 -0
  124. package/dist/core/session-manager.d.ts.map +1 -0
  125. package/dist/core/session-manager.js.map +1 -0
  126. package/dist/core/streaming.d.ts.map +1 -0
  127. package/dist/core/streaming.js.map +1 -0
  128. package/dist/core/subagent.d.ts.map +1 -0
  129. package/dist/core/subagent.js.map +1 -0
  130. package/dist/core/types.d.ts.map +1 -0
  131. package/dist/core/types.js.map +1 -0
  132. package/dist/core/versioning.d.ts.map +1 -0
  133. package/dist/core/versioning.js.map +1 -0
  134. package/dist/core/vision.d.ts.map +1 -0
  135. package/dist/core/vision.js.map +1 -0
  136. package/dist/core/watch.d.ts.map +1 -0
  137. package/dist/core/watch.js.map +1 -0
  138. package/dist/core/workflow-graph.d.ts.map +1 -0
  139. package/dist/core/workflow-graph.js.map +1 -0
  140. package/dist/core/workflow.d.ts.map +1 -0
  141. package/dist/core/workflow.js.map +1 -0
  142. package/dist/daemon.d.ts.map +1 -0
  143. package/dist/daemon.js.map +1 -0
  144. package/dist/deploy/hermes.d.ts.map +1 -0
  145. package/dist/deploy/hermes.js.map +1 -0
  146. package/dist/deploy/index.d.ts.map +1 -0
  147. package/dist/deploy/index.js.map +1 -0
  148. package/dist/deploy/openclaw.d.ts.map +1 -0
  149. package/dist/deploy/openclaw.js.map +1 -0
  150. package/dist/doctor.d.ts +1 -0
  151. package/dist/doctor.d.ts.map +1 -0
  152. package/dist/doctor.js +105 -10
  153. package/dist/doctor.js.map +1 -0
  154. package/dist/eval/index.d.ts.map +1 -0
  155. package/dist/eval/index.js.map +1 -0
  156. package/dist/hub/brain-seed.d.ts.map +1 -0
  157. package/dist/hub/brain-seed.js.map +1 -0
  158. package/dist/hub/client.d.ts.map +1 -0
  159. package/dist/hub/client.js.map +1 -0
  160. package/dist/i18n/index.d.ts.map +1 -0
  161. package/dist/i18n/index.js.map +1 -0
  162. package/dist/index.d.ts.map +1 -0
  163. package/dist/index.js.map +1 -0
  164. package/dist/mcp/servers/calculator-mcp.d.ts.map +1 -0
  165. package/dist/mcp/servers/calculator-mcp.js.map +1 -0
  166. package/dist/mcp/servers/crypto-mcp.d.ts.map +1 -0
  167. package/dist/mcp/servers/crypto-mcp.js.map +1 -0
  168. package/dist/mcp/servers/database-mcp.d.ts.map +1 -0
  169. package/dist/mcp/servers/database-mcp.js.map +1 -0
  170. package/dist/mcp/servers/datetime-mcp.d.ts.map +1 -0
  171. package/dist/mcp/servers/datetime-mcp.js.map +1 -0
  172. package/dist/mcp/servers/filesystem.d.ts.map +1 -0
  173. package/dist/mcp/servers/filesystem.js.map +1 -0
  174. package/dist/mcp/servers/github-mcp.d.ts.map +1 -0
  175. package/dist/mcp/servers/github-mcp.js.map +1 -0
  176. package/dist/mcp/servers/index.d.ts.map +1 -0
  177. package/dist/mcp/servers/index.js.map +1 -0
  178. package/dist/mcp/servers/json-mcp.d.ts.map +1 -0
  179. package/dist/mcp/servers/json-mcp.js.map +1 -0
  180. package/dist/mcp/servers/memory-mcp.d.ts.map +1 -0
  181. package/dist/mcp/servers/memory-mcp.js.map +1 -0
  182. package/dist/mcp/servers/regex-mcp.d.ts.map +1 -0
  183. package/dist/mcp/servers/regex-mcp.js.map +1 -0
  184. package/dist/mcp/servers/web-mcp.d.ts.map +1 -0
  185. package/dist/mcp/servers/web-mcp.js.map +1 -0
  186. package/dist/memory/context-compressor.d.ts.map +1 -0
  187. package/dist/memory/context-compressor.js.map +1 -0
  188. package/dist/memory/deepbrain.d.ts +1 -1
  189. package/dist/memory/deepbrain.d.ts.map +1 -0
  190. package/dist/memory/deepbrain.js +95 -4
  191. package/dist/memory/deepbrain.js.map +1 -0
  192. package/dist/memory/index.d.ts.map +1 -0
  193. package/dist/memory/index.js.map +1 -0
  194. package/dist/memory/seed-loader.d.ts.map +1 -0
  195. package/dist/memory/seed-loader.js.map +1 -0
  196. package/dist/memory/user-profiler.d.ts.map +1 -0
  197. package/dist/memory/user-profiler.js.map +1 -0
  198. package/dist/plugins/content-filter.d.ts.map +1 -0
  199. package/dist/plugins/content-filter.js.map +1 -0
  200. package/dist/plugins/index.d.ts.map +1 -0
  201. package/dist/plugins/index.js.map +1 -0
  202. package/dist/plugins/logger.d.ts.map +1 -0
  203. package/dist/plugins/logger.js.map +1 -0
  204. package/dist/plugins/rate-limiter.d.ts.map +1 -0
  205. package/dist/plugins/rate-limiter.js.map +1 -0
  206. package/dist/protocols/a2a/client.d.ts.map +1 -0
  207. package/dist/protocols/a2a/client.js.map +1 -0
  208. package/dist/protocols/a2a/index.d.ts.map +1 -0
  209. package/dist/protocols/a2a/index.js.map +1 -0
  210. package/dist/protocols/a2a/server.d.ts.map +1 -0
  211. package/dist/protocols/a2a/server.js.map +1 -0
  212. package/dist/protocols/a2a/types.d.ts.map +1 -0
  213. package/dist/protocols/a2a/types.js.map +1 -0
  214. package/dist/protocols/a2a/utils.d.ts.map +1 -0
  215. package/dist/protocols/a2a/utils.js.map +1 -0
  216. package/dist/protocols/agui/client.d.ts.map +1 -0
  217. package/dist/protocols/agui/client.js.map +1 -0
  218. package/dist/protocols/agui/index.d.ts.map +1 -0
  219. package/dist/protocols/agui/index.js.map +1 -0
  220. package/dist/protocols/agui/server.d.ts.map +1 -0
  221. package/dist/protocols/agui/server.js.map +1 -0
  222. package/dist/protocols/agui/types.d.ts.map +1 -0
  223. package/dist/protocols/agui/types.js.map +1 -0
  224. package/dist/protocols/index.d.ts.map +1 -0
  225. package/dist/protocols/index.js.map +1 -0
  226. package/dist/protocols/mcp/agent-tools.d.ts.map +1 -0
  227. package/dist/protocols/mcp/agent-tools.js.map +1 -0
  228. package/dist/protocols/mcp/index.d.ts.map +1 -0
  229. package/dist/protocols/mcp/index.js.map +1 -0
  230. package/dist/protocols/mcp/server.d.ts.map +1 -0
  231. package/dist/protocols/mcp/server.js.map +1 -0
  232. package/dist/protocols/mcp/types.d.ts.map +1 -0
  233. package/dist/protocols/mcp/types.js.map +1 -0
  234. package/dist/providers/index.d.ts.map +1 -0
  235. package/dist/providers/index.js.map +1 -0
  236. package/dist/publish/index.d.ts.map +1 -0
  237. package/dist/publish/index.js.map +1 -0
  238. package/dist/scheduler/cron-engine.d.ts.map +1 -0
  239. package/dist/scheduler/cron-engine.js +3 -36
  240. package/dist/scheduler/cron-engine.js.map +1 -0
  241. package/dist/scheduler/index.d.ts.map +1 -0
  242. package/dist/scheduler/index.js.map +1 -0
  243. package/dist/schema/oad.d.ts.map +1 -0
  244. package/dist/schema/oad.js.map +1 -0
  245. package/dist/security/approval.d.ts.map +1 -0
  246. package/dist/security/approval.js.map +1 -0
  247. package/dist/security/approvals.d.ts.map +1 -0
  248. package/dist/security/approvals.js.map +1 -0
  249. package/dist/security/elevated.d.ts.map +1 -0
  250. package/dist/security/elevated.js.map +1 -0
  251. package/dist/security/guardrails.d.ts.map +1 -0
  252. package/dist/security/guardrails.js.map +1 -0
  253. package/dist/security/index.d.ts.map +1 -0
  254. package/dist/security/index.js.map +1 -0
  255. package/dist/security/keys.d.ts.map +1 -0
  256. package/dist/security/keys.js.map +1 -0
  257. package/dist/security/secrets.d.ts.map +1 -0
  258. package/dist/security/secrets.js.map +1 -0
  259. package/dist/skills/auto-learn.d.ts.map +1 -0
  260. package/dist/skills/auto-learn.js.map +1 -0
  261. package/dist/skills/base.d.ts.map +1 -0
  262. package/dist/skills/base.js.map +1 -0
  263. package/dist/skills/builtin/index.d.ts.map +1 -0
  264. package/dist/skills/builtin/index.js.map +1 -0
  265. package/dist/skills/document.d.ts.map +1 -0
  266. package/dist/skills/document.js.map +1 -0
  267. package/dist/skills/http.d.ts.map +1 -0
  268. package/dist/skills/http.js.map +1 -0
  269. package/dist/skills/index.d.ts.map +1 -0
  270. package/dist/skills/index.js.map +1 -0
  271. package/dist/skills/marketplace.d.ts.map +1 -0
  272. package/dist/skills/marketplace.js.map +1 -0
  273. package/dist/skills/scheduler.d.ts.map +1 -0
  274. package/dist/skills/scheduler.js.map +1 -0
  275. package/dist/skills/types.d.ts.map +1 -0
  276. package/dist/skills/types.js.map +1 -0
  277. package/dist/skills/webhook-trigger.d.ts.map +1 -0
  278. package/dist/skills/webhook-trigger.js.map +1 -0
  279. package/dist/studio/server.d.ts.map +1 -0
  280. package/dist/studio/server.js.map +1 -0
  281. package/dist/studio/templates-data.d.ts.map +1 -0
  282. package/dist/studio/templates-data.js.map +1 -0
  283. package/dist/telemetry/index.d.ts.map +1 -0
  284. package/dist/telemetry/index.js.map +1 -0
  285. package/dist/templates/code-reviewer.d.ts.map +1 -0
  286. package/dist/templates/code-reviewer.js.map +1 -0
  287. package/dist/templates/content-writer.d.ts.map +1 -0
  288. package/dist/templates/content-writer.js.map +1 -0
  289. package/dist/templates/customer-service.d.ts.map +1 -0
  290. package/dist/templates/customer-service.js.map +1 -0
  291. package/dist/templates/data-analyst.d.ts.map +1 -0
  292. package/dist/templates/data-analyst.js.map +1 -0
  293. package/dist/templates/executive-assistant.d.ts.map +1 -0
  294. package/dist/templates/executive-assistant.js.map +1 -0
  295. package/dist/templates/financial-advisor.d.ts.map +1 -0
  296. package/dist/templates/financial-advisor.js.map +1 -0
  297. package/dist/templates/hr-recruiter.d.ts.map +1 -0
  298. package/dist/templates/hr-recruiter.js.map +1 -0
  299. package/dist/templates/knowledge-base.d.ts.map +1 -0
  300. package/dist/templates/knowledge-base.js.map +1 -0
  301. package/dist/templates/legal-assistant.d.ts.map +1 -0
  302. package/dist/templates/legal-assistant.js.map +1 -0
  303. package/dist/templates/project-manager.d.ts.map +1 -0
  304. package/dist/templates/project-manager.js.map +1 -0
  305. package/dist/templates/sales-assistant.d.ts.map +1 -0
  306. package/dist/templates/sales-assistant.js.map +1 -0
  307. package/dist/templates/teacher.d.ts.map +1 -0
  308. package/dist/templates/teacher.js.map +1 -0
  309. package/dist/testing/index.d.ts.map +1 -0
  310. package/dist/testing/index.js.map +1 -0
  311. package/dist/tools/builtin/browser.d.ts.map +1 -0
  312. package/dist/tools/builtin/browser.js.map +1 -0
  313. package/dist/tools/builtin/datetime.d.ts.map +1 -0
  314. package/dist/tools/builtin/datetime.js.map +1 -0
  315. package/dist/tools/builtin/file.d.ts.map +1 -0
  316. package/dist/tools/builtin/file.js.map +1 -0
  317. package/dist/tools/builtin/home-assistant.d.ts.map +1 -0
  318. package/dist/tools/builtin/home-assistant.js.map +1 -0
  319. package/dist/tools/builtin/index.d.ts.map +1 -0
  320. package/dist/tools/builtin/index.js.map +1 -0
  321. package/dist/tools/builtin/rl-tools.d.ts.map +1 -0
  322. package/dist/tools/builtin/rl-tools.js.map +1 -0
  323. package/dist/tools/builtin/shell.d.ts.map +1 -0
  324. package/dist/tools/builtin/shell.js.map +1 -0
  325. package/dist/tools/builtin/vision.d.ts.map +1 -0
  326. package/dist/tools/builtin/vision.js.map +1 -0
  327. package/dist/tools/builtin/web-search.d.ts.map +1 -0
  328. package/dist/tools/builtin/web-search.js.map +1 -0
  329. package/dist/tools/builtin/web.d.ts.map +1 -0
  330. package/dist/tools/builtin/web.js.map +1 -0
  331. package/dist/tools/calculator.d.ts.map +1 -0
  332. package/dist/tools/calculator.js.map +1 -0
  333. package/dist/tools/datetime.d.ts.map +1 -0
  334. package/dist/tools/datetime.js.map +1 -0
  335. package/dist/tools/document-processor.d.ts.map +1 -0
  336. package/dist/tools/document-processor.js.map +1 -0
  337. package/dist/tools/gateway.d.ts.map +1 -0
  338. package/dist/tools/gateway.js.map +1 -0
  339. package/dist/tools/image-generator.d.ts.map +1 -0
  340. package/dist/tools/image-generator.js.map +1 -0
  341. package/dist/tools/integrations/calendar.d.ts.map +1 -0
  342. package/dist/tools/integrations/calendar.js.map +1 -0
  343. package/dist/tools/integrations/code-exec.d.ts.map +1 -0
  344. package/dist/tools/integrations/code-exec.js.map +1 -0
  345. package/dist/tools/integrations/csv-analyzer.d.ts.map +1 -0
  346. package/dist/tools/integrations/csv-analyzer.js.map +1 -0
  347. package/dist/tools/integrations/database.d.ts.map +1 -0
  348. package/dist/tools/integrations/database.js.map +1 -0
  349. package/dist/tools/integrations/email-send.d.ts.map +1 -0
  350. package/dist/tools/integrations/email-send.js.map +1 -0
  351. package/dist/tools/integrations/git-tool.d.ts.map +1 -0
  352. package/dist/tools/integrations/git-tool.js.map +1 -0
  353. package/dist/tools/integrations/github-tool.d.ts.map +1 -0
  354. package/dist/tools/integrations/github-tool.js.map +1 -0
  355. package/dist/tools/integrations/image-gen.d.ts.map +1 -0
  356. package/dist/tools/integrations/image-gen.js.map +1 -0
  357. package/dist/tools/integrations/index.d.ts.map +1 -0
  358. package/dist/tools/integrations/index.js.map +1 -0
  359. package/dist/tools/integrations/jira.d.ts.map +1 -0
  360. package/dist/tools/integrations/jira.js.map +1 -0
  361. package/dist/tools/integrations/notion.d.ts.map +1 -0
  362. package/dist/tools/integrations/notion.js.map +1 -0
  363. package/dist/tools/integrations/npm-tool.d.ts.map +1 -0
  364. package/dist/tools/integrations/npm-tool.js.map +1 -0
  365. package/dist/tools/integrations/pdf-reader.d.ts.map +1 -0
  366. package/dist/tools/integrations/pdf-reader.js.map +1 -0
  367. package/dist/tools/integrations/slack.d.ts.map +1 -0
  368. package/dist/tools/integrations/slack.js.map +1 -0
  369. package/dist/tools/integrations/summarizer.d.ts.map +1 -0
  370. package/dist/tools/integrations/summarizer.js.map +1 -0
  371. package/dist/tools/integrations/translator.d.ts.map +1 -0
  372. package/dist/tools/integrations/translator.js.map +1 -0
  373. package/dist/tools/integrations/trello.d.ts.map +1 -0
  374. package/dist/tools/integrations/trello.js.map +1 -0
  375. package/dist/tools/integrations/vector-search.d.ts.map +1 -0
  376. package/dist/tools/integrations/vector-search.js.map +1 -0
  377. package/dist/tools/integrations/web-scraper.d.ts.map +1 -0
  378. package/dist/tools/integrations/web-scraper.js.map +1 -0
  379. package/dist/tools/integrations/web-search.d.ts.map +1 -0
  380. package/dist/tools/integrations/web-search.js.map +1 -0
  381. package/dist/tools/integrations/webhook.d.ts.map +1 -0
  382. package/dist/tools/integrations/webhook.js.map +1 -0
  383. package/dist/tools/json-transform.d.ts.map +1 -0
  384. package/dist/tools/json-transform.js.map +1 -0
  385. package/dist/tools/mcp-client.d.ts.map +1 -0
  386. package/dist/tools/mcp-client.js.map +1 -0
  387. package/dist/tools/mcp.d.ts.map +1 -0
  388. package/dist/tools/mcp.js.map +1 -0
  389. package/dist/tools/text-analysis.d.ts.map +1 -0
  390. package/dist/tools/text-analysis.js.map +1 -0
  391. package/dist/tools/web-scraper.d.ts.map +1 -0
  392. package/dist/tools/web-scraper.js.map +1 -0
  393. package/dist/tools/web-search.d.ts.map +1 -0
  394. package/dist/tools/web-search.js.map +1 -0
  395. package/dist/traces/index.d.ts.map +1 -0
  396. package/dist/traces/index.js.map +1 -0
  397. package/dist/ui/components.d.ts.map +1 -0
  398. package/dist/ui/components.js.map +1 -0
  399. package/package.json +1 -1
  400. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
  401. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
  402. package/.github/PULL_REQUEST_TEMPLATE.md +0 -13
  403. package/.github/workflows/ci.yml +0 -24
  404. package/docs/.vitepress/config.ts +0 -103
  405. package/docs/api/cli.md +0 -48
  406. package/docs/api/oad-schema.md +0 -64
  407. package/docs/api/sdk.md +0 -80
  408. package/docs/guide/concepts.md +0 -51
  409. package/docs/guide/configuration.md +0 -79
  410. package/docs/guide/deployment.md +0 -42
  411. package/docs/guide/getting-started.md +0 -44
  412. package/docs/guide/templates.md +0 -28
  413. package/docs/guide/testing.md +0 -84
  414. package/docs/index.md +0 -27
  415. package/docs/zh/api/cli.md +0 -54
  416. package/docs/zh/api/oad-schema.md +0 -87
  417. package/docs/zh/api/sdk.md +0 -102
  418. package/docs/zh/guide/concepts.md +0 -104
  419. package/docs/zh/guide/configuration.md +0 -135
  420. package/docs/zh/guide/deployment.md +0 -81
  421. package/docs/zh/guide/getting-started.md +0 -82
  422. package/docs/zh/guide/templates.md +0 -84
  423. package/docs/zh/guide/testing.md +0 -88
  424. package/docs/zh/index.md +0 -27
  425. package/fix-sidebar.mjs +0 -188
  426. package/serve-studio.js +0 -13
  427. package/serve-test.js +0 -25
  428. package/src/analytics/index.ts +0 -66
  429. package/src/channels/dingtalk.ts +0 -46
  430. package/src/channels/discord.ts +0 -192
  431. package/src/channels/email.ts +0 -351
  432. package/src/channels/feishu.ts +0 -349
  433. package/src/channels/googlechat.ts +0 -42
  434. package/src/channels/imessage.ts +0 -32
  435. package/src/channels/index.ts +0 -15
  436. package/src/channels/irc.ts +0 -82
  437. package/src/channels/line.ts +0 -33
  438. package/src/channels/matrix.ts +0 -34
  439. package/src/channels/mattermost.ts +0 -57
  440. package/src/channels/msteams.ts +0 -33
  441. package/src/channels/nostr.ts +0 -33
  442. package/src/channels/qq.ts +0 -34
  443. package/src/channels/signal.ts +0 -33
  444. package/src/channels/slack.ts +0 -217
  445. package/src/channels/sms.ts +0 -34
  446. package/src/channels/telegram.ts +0 -616
  447. package/src/channels/twitch.ts +0 -65
  448. package/src/channels/voice-call.ts +0 -100
  449. package/src/channels/voice.ts +0 -471
  450. package/src/channels/web.ts +0 -632
  451. package/src/channels/webhook.ts +0 -199
  452. package/src/channels/websocket.ts +0 -399
  453. package/src/channels/wechat.ts +0 -329
  454. package/src/channels/whatsapp.ts +0 -33
  455. package/src/cli/chat.ts +0 -99
  456. package/src/cli/setup.ts +0 -314
  457. package/src/cli.ts +0 -2723
  458. package/src/core/a2a.ts +0 -203
  459. package/src/core/agent.ts +0 -476
  460. package/src/core/analytics-engine.ts +0 -186
  461. package/src/core/api-server.ts +0 -277
  462. package/src/core/audio.ts +0 -98
  463. package/src/core/auth.ts +0 -57
  464. package/src/core/cache.ts +0 -141
  465. package/src/core/collaboration.ts +0 -275
  466. package/src/core/compose.ts +0 -77
  467. package/src/core/config.ts +0 -14
  468. package/src/core/context-discovery.ts +0 -85
  469. package/src/core/context-refs.ts +0 -140
  470. package/src/core/errors.ts +0 -148
  471. package/src/core/gateway.ts +0 -106
  472. package/src/core/heartbeat.ts +0 -51
  473. package/src/core/hitl.ts +0 -138
  474. package/src/core/hooks.ts +0 -105
  475. package/src/core/ide-bridge.ts +0 -133
  476. package/src/core/knowledge.ts +0 -255
  477. package/src/core/logger.ts +0 -57
  478. package/src/core/node-network.ts +0 -86
  479. package/src/core/orchestrator.ts +0 -215
  480. package/src/core/performance.ts +0 -187
  481. package/src/core/profiles.ts +0 -122
  482. package/src/core/rate-limiter.ts +0 -128
  483. package/src/core/room.ts +0 -109
  484. package/src/core/runtime.ts +0 -410
  485. package/src/core/sandbox.ts +0 -344
  486. package/src/core/scheduler.ts +0 -187
  487. package/src/core/security.ts +0 -171
  488. package/src/core/session-manager.ts +0 -137
  489. package/src/core/streaming.ts +0 -195
  490. package/src/core/subagent.ts +0 -98
  491. package/src/core/types.ts +0 -68
  492. package/src/core/versioning.ts +0 -106
  493. package/src/core/vision.ts +0 -180
  494. package/src/core/watch.ts +0 -178
  495. package/src/core/workflow-graph.ts +0 -365
  496. package/src/core/workflow.ts +0 -235
  497. package/src/daemon.ts +0 -96
  498. package/src/deploy/hermes.ts +0 -156
  499. package/src/deploy/index.ts +0 -255
  500. package/src/deploy/openclaw.ts +0 -190
  501. package/src/doctor.ts +0 -156
  502. package/src/eval/index.ts +0 -211
  503. package/src/eval/suites/basic.json +0 -16
  504. package/src/eval/suites/memory.json +0 -12
  505. package/src/eval/suites/safety.json +0 -14
  506. package/src/hub/brain-seed.ts +0 -54
  507. package/src/hub/client.ts +0 -60
  508. package/src/i18n/index.ts +0 -216
  509. package/src/index.ts +0 -283
  510. package/src/mcp/servers/calculator-mcp.ts +0 -65
  511. package/src/mcp/servers/crypto-mcp.ts +0 -73
  512. package/src/mcp/servers/database-mcp.ts +0 -72
  513. package/src/mcp/servers/datetime-mcp.ts +0 -69
  514. package/src/mcp/servers/filesystem.ts +0 -66
  515. package/src/mcp/servers/github-mcp.ts +0 -58
  516. package/src/mcp/servers/index.ts +0 -63
  517. package/src/mcp/servers/json-mcp.ts +0 -102
  518. package/src/mcp/servers/memory-mcp.ts +0 -56
  519. package/src/mcp/servers/regex-mcp.ts +0 -53
  520. package/src/mcp/servers/web-mcp.ts +0 -49
  521. package/src/memory/context-compressor.ts +0 -189
  522. package/src/memory/deepbrain.ts +0 -108
  523. package/src/memory/index.ts +0 -41
  524. package/src/memory/seed-loader.ts +0 -212
  525. package/src/memory/user-profiler.ts +0 -215
  526. package/src/plugins/content-filter.ts +0 -23
  527. package/src/plugins/index.ts +0 -339
  528. package/src/plugins/logger.ts +0 -18
  529. package/src/plugins/rate-limiter.ts +0 -38
  530. package/src/protocols/a2a/client.ts +0 -132
  531. package/src/protocols/a2a/index.ts +0 -8
  532. package/src/protocols/a2a/server.ts +0 -333
  533. package/src/protocols/a2a/types.ts +0 -88
  534. package/src/protocols/a2a/utils.ts +0 -50
  535. package/src/protocols/agui/client.ts +0 -83
  536. package/src/protocols/agui/index.ts +0 -4
  537. package/src/protocols/agui/server.ts +0 -218
  538. package/src/protocols/agui/types.ts +0 -153
  539. package/src/protocols/index.ts +0 -2
  540. package/src/protocols/mcp/agent-tools.ts +0 -134
  541. package/src/protocols/mcp/index.ts +0 -8
  542. package/src/protocols/mcp/server.ts +0 -262
  543. package/src/protocols/mcp/types.ts +0 -69
  544. package/src/providers/index.ts +0 -632
  545. package/src/publish/index.ts +0 -376
  546. package/src/scheduler/cron-engine.ts +0 -191
  547. package/src/scheduler/index.ts +0 -2
  548. package/src/schema/oad.ts +0 -217
  549. package/src/security/approval.ts +0 -131
  550. package/src/security/approvals.ts +0 -143
  551. package/src/security/elevated.ts +0 -105
  552. package/src/security/guardrails.ts +0 -248
  553. package/src/security/index.ts +0 -9
  554. package/src/security/keys.ts +0 -87
  555. package/src/security/secrets.ts +0 -129
  556. package/src/skills/auto-learn.ts +0 -262
  557. package/src/skills/base.ts +0 -16
  558. package/src/skills/builtin/index.ts +0 -408
  559. package/src/skills/document.ts +0 -100
  560. package/src/skills/http.ts +0 -35
  561. package/src/skills/index.ts +0 -27
  562. package/src/skills/marketplace.ts +0 -113
  563. package/src/skills/scheduler.ts +0 -80
  564. package/src/skills/types.ts +0 -42
  565. package/src/skills/webhook-trigger.ts +0 -59
  566. package/src/studio/server.ts +0 -1791
  567. package/src/studio/templates-data.ts +0 -178
  568. package/src/studio-ui/index.html +0 -3076
  569. package/src/telemetry/index.ts +0 -324
  570. package/src/templates/code-reviewer.ts +0 -30
  571. package/src/templates/content-writer.ts +0 -58
  572. package/src/templates/customer-service.ts +0 -76
  573. package/src/templates/data-analyst.ts +0 -66
  574. package/src/templates/executive-assistant.ts +0 -71
  575. package/src/templates/financial-advisor.ts +0 -60
  576. package/src/templates/hr-recruiter.ts +0 -58
  577. package/src/templates/knowledge-base.ts +0 -27
  578. package/src/templates/legal-assistant.ts +0 -71
  579. package/src/templates/project-manager.ts +0 -58
  580. package/src/templates/sales-assistant.ts +0 -75
  581. package/src/templates/teacher.ts +0 -75
  582. package/src/testing/index.ts +0 -181
  583. package/src/tools/builtin/browser.ts +0 -299
  584. package/src/tools/builtin/datetime.ts +0 -41
  585. package/src/tools/builtin/file.ts +0 -107
  586. package/src/tools/builtin/home-assistant.ts +0 -116
  587. package/src/tools/builtin/index.ts +0 -37
  588. package/src/tools/builtin/rl-tools.ts +0 -243
  589. package/src/tools/builtin/shell.ts +0 -43
  590. package/src/tools/builtin/vision.ts +0 -64
  591. package/src/tools/builtin/web-search.ts +0 -126
  592. package/src/tools/builtin/web.ts +0 -35
  593. package/src/tools/calculator.ts +0 -73
  594. package/src/tools/datetime.ts +0 -149
  595. package/src/tools/document-processor.ts +0 -213
  596. package/src/tools/gateway.ts +0 -220
  597. package/src/tools/image-generator.ts +0 -150
  598. package/src/tools/integrations/calendar.ts +0 -73
  599. package/src/tools/integrations/code-exec.ts +0 -39
  600. package/src/tools/integrations/csv-analyzer.ts +0 -92
  601. package/src/tools/integrations/database.ts +0 -44
  602. package/src/tools/integrations/email-send.ts +0 -76
  603. package/src/tools/integrations/git-tool.ts +0 -42
  604. package/src/tools/integrations/github-tool.ts +0 -76
  605. package/src/tools/integrations/image-gen.ts +0 -56
  606. package/src/tools/integrations/index.ts +0 -92
  607. package/src/tools/integrations/jira.ts +0 -83
  608. package/src/tools/integrations/notion.ts +0 -71
  609. package/src/tools/integrations/npm-tool.ts +0 -48
  610. package/src/tools/integrations/pdf-reader.ts +0 -58
  611. package/src/tools/integrations/slack.ts +0 -65
  612. package/src/tools/integrations/summarizer.ts +0 -49
  613. package/src/tools/integrations/translator.ts +0 -48
  614. package/src/tools/integrations/trello.ts +0 -60
  615. package/src/tools/integrations/vector-search.ts +0 -42
  616. package/src/tools/integrations/web-scraper.ts +0 -47
  617. package/src/tools/integrations/web-search.ts +0 -58
  618. package/src/tools/integrations/webhook.ts +0 -38
  619. package/src/tools/json-transform.ts +0 -187
  620. package/src/tools/mcp-client.ts +0 -131
  621. package/src/tools/mcp.ts +0 -76
  622. package/src/tools/text-analysis.ts +0 -116
  623. package/src/tools/web-scraper.ts +0 -179
  624. package/src/tools/web-search.ts +0 -180
  625. package/src/traces/index.ts +0 -132
  626. package/src/types/agent-workstation.d.ts +0 -2
  627. package/src/ui/components.ts +0 -127
  628. package/srv-err.txt +0 -0
  629. package/srv-out.txt +0 -1
  630. package/test-agent/Dockerfile +0 -9
  631. package/test-agent/README.md +0 -50
  632. package/test-agent/agent.yaml +0 -23
  633. package/test-agent/docker-compose.yml +0 -11
  634. package/test-agent/oad.yaml +0 -31
  635. package/test-agent/package-lock.json +0 -1492
  636. package/test-agent/package.json +0 -18
  637. package/test-agent/src/index.ts +0 -24
  638. package/test-agent/src/skills/echo.ts +0 -15
  639. package/test-agent/tsconfig.json +0 -25
  640. package/test-full.js +0 -43
  641. package/test-sidebar.js +0 -22
  642. package/test-studio3.js +0 -75
  643. package/test-studio4.js +0 -41
  644. package/tests/a2a-protocol.test.ts +0 -285
  645. package/tests/a2a.test.ts +0 -66
  646. package/tests/agent.test.ts +0 -72
  647. package/tests/agui-protocol.test.ts +0 -246
  648. package/tests/analytics.test.ts +0 -50
  649. package/tests/api-server.test.ts +0 -148
  650. package/tests/approvals.test.ts +0 -89
  651. package/tests/audio.test.ts +0 -40
  652. package/tests/auto-learn.test.ts +0 -105
  653. package/tests/brain-seed-extended.test.ts +0 -490
  654. package/tests/brain-seed.test.ts +0 -239
  655. package/tests/browser.test.ts +0 -179
  656. package/tests/builtin-tools.test.ts +0 -83
  657. package/tests/channel.test.ts +0 -39
  658. package/tests/channels/discord.test.ts +0 -79
  659. package/tests/channels/email.test.ts +0 -148
  660. package/tests/channels/feishu.test.ts +0 -123
  661. package/tests/channels/telegram.test.ts +0 -129
  662. package/tests/channels/websocket.test.ts +0 -53
  663. package/tests/channels/wechat.test.ts +0 -170
  664. package/tests/channels-extra.test.ts +0 -45
  665. package/tests/chat-cli.test.ts +0 -160
  666. package/tests/cli.test.ts +0 -46
  667. package/tests/collaboration.test.ts +0 -319
  668. package/tests/context-compressor.test.ts +0 -172
  669. package/tests/context-refs.test.ts +0 -121
  670. package/tests/cron-engine.test.ts +0 -101
  671. package/tests/daemon.test.ts +0 -135
  672. package/tests/deepbrain-wire.test.ts +0 -234
  673. package/tests/deploy-and-dag.test.ts +0 -196
  674. package/tests/doctor.test.ts +0 -38
  675. package/tests/document-processor.test.ts +0 -69
  676. package/tests/e2e-nocode.test.ts +0 -442
  677. package/tests/e2e.test.ts +0 -134
  678. package/tests/elevated.test.ts +0 -69
  679. package/tests/errors.test.ts +0 -83
  680. package/tests/eval.test.ts +0 -173
  681. package/tests/gateway.test.ts +0 -63
  682. package/tests/guardrails.test.ts +0 -177
  683. package/tests/hitl.test.ts +0 -71
  684. package/tests/home-assistant.test.ts +0 -40
  685. package/tests/hooks.test.ts +0 -79
  686. package/tests/i18n.test.ts +0 -41
  687. package/tests/ide-bridge.test.ts +0 -38
  688. package/tests/image-generator.test.ts +0 -84
  689. package/tests/init-role.test.ts +0 -124
  690. package/tests/integrations.test.ts +0 -249
  691. package/tests/mcp-client.test.ts +0 -92
  692. package/tests/mcp-server.test.ts +0 -178
  693. package/tests/mcp-servers.test.ts +0 -260
  694. package/tests/mcp.test.ts +0 -54
  695. package/tests/node-network.test.ts +0 -74
  696. package/tests/oad.test.ts +0 -68
  697. package/tests/performance.test.ts +0 -115
  698. package/tests/plugin-a2a-enhanced.test.ts +0 -230
  699. package/tests/plugin.test.ts +0 -74
  700. package/tests/profiles.test.ts +0 -61
  701. package/tests/publish.test.ts +0 -231
  702. package/tests/rl-tools.test.ts +0 -93
  703. package/tests/room.test.ts +0 -106
  704. package/tests/runtime.test.ts +0 -42
  705. package/tests/sandbox-manager.test.ts +0 -46
  706. package/tests/sandbox.test.ts +0 -46
  707. package/tests/scheduler.test.ts +0 -200
  708. package/tests/secrets.test.ts +0 -107
  709. package/tests/security-enhanced.test.ts +0 -233
  710. package/tests/security.test.ts +0 -60
  711. package/tests/settings-api.test.ts +0 -148
  712. package/tests/setup.test.ts +0 -73
  713. package/tests/skill-learner.test.ts +0 -161
  714. package/tests/streaming.test.ts +0 -109
  715. package/tests/studio.test.ts +0 -402
  716. package/tests/subagent.test.ts +0 -193
  717. package/tests/telegram-discord.test.ts +0 -60
  718. package/tests/telemetry.test.ts +0 -186
  719. package/tests/templates.test.ts +0 -77
  720. package/tests/tools/builtin-extended.test.ts +0 -138
  721. package/tests/user-profiler.test.ts +0 -169
  722. package/tests/v070.test.ts +0 -76
  723. package/tests/v090-features.test.ts +0 -254
  724. package/tests/versioning.test.ts +0 -75
  725. package/tests/vision.test.ts +0 -61
  726. package/tests/voice-call.test.ts +0 -47
  727. package/tests/voice-enhanced.test.ts +0 -169
  728. package/tests/voice-interaction.test.ts +0 -38
  729. package/tests/voice.test.ts +0 -61
  730. package/tests/web-search.test.ts +0 -155
  731. package/tests/webhook.test.ts +0 -29
  732. package/tests/workflow-graph.test.ts +0 -279
  733. package/tests/workflow.test.ts +0 -143
  734. package/tmp-js-test.js +0 -1532
  735. package/tmp-sc.js +0 -1716
  736. package/tutorial/customer-service-agent/README.md +0 -612
  737. package/tutorial/customer-service-agent/SOUL.md +0 -26
  738. package/tutorial/customer-service-agent/agent.yaml +0 -63
  739. package/tutorial/customer-service-agent/package.json +0 -19
  740. package/tutorial/customer-service-agent/src/index.ts +0 -69
  741. package/tutorial/customer-service-agent/src/skills/faq.ts +0 -27
  742. package/tutorial/customer-service-agent/src/skills/ticket.ts +0 -22
  743. package/tutorial/customer-service-agent/tsconfig.json +0 -14
  744. 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 };