opc-agent 4.1.2 → 4.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics/index.d.ts.map +1 -0
- package/dist/analytics/index.js.map +1 -0
- package/dist/channels/dingtalk.d.ts.map +1 -0
- package/dist/channels/dingtalk.js.map +1 -0
- package/dist/channels/discord.d.ts.map +1 -0
- package/dist/channels/discord.js.map +1 -0
- package/dist/channels/email.d.ts.map +1 -0
- package/dist/channels/email.js.map +1 -0
- package/dist/channels/feishu.d.ts.map +1 -0
- package/dist/channels/feishu.js.map +1 -0
- package/dist/channels/googlechat.d.ts.map +1 -0
- package/dist/channels/googlechat.js.map +1 -0
- package/dist/channels/imessage.d.ts.map +1 -0
- package/dist/channels/imessage.js.map +1 -0
- package/dist/channels/index.d.ts.map +1 -0
- package/dist/channels/index.js.map +1 -0
- package/dist/channels/irc.d.ts.map +1 -0
- package/dist/channels/irc.js.map +1 -0
- package/dist/channels/line.d.ts.map +1 -0
- package/dist/channels/line.js.map +1 -0
- package/dist/channels/matrix.d.ts.map +1 -0
- package/dist/channels/matrix.js.map +1 -0
- package/dist/channels/mattermost.d.ts.map +1 -0
- package/dist/channels/mattermost.js.map +1 -0
- package/dist/channels/msteams.d.ts.map +1 -0
- package/dist/channels/msteams.js.map +1 -0
- package/dist/channels/nostr.d.ts.map +1 -0
- package/dist/channels/nostr.js.map +1 -0
- package/dist/channels/qq.d.ts.map +1 -0
- package/dist/channels/qq.js.map +1 -0
- package/dist/channels/signal.d.ts.map +1 -0
- package/dist/channels/signal.js.map +1 -0
- package/dist/channels/slack.d.ts.map +1 -0
- package/dist/channels/slack.js.map +1 -0
- package/dist/channels/sms.d.ts.map +1 -0
- package/dist/channels/sms.js.map +1 -0
- package/dist/channels/telegram.d.ts.map +1 -0
- package/dist/channels/telegram.js.map +1 -0
- package/dist/channels/twitch.d.ts.map +1 -0
- package/dist/channels/twitch.js.map +1 -0
- package/dist/channels/voice-call.d.ts.map +1 -0
- package/dist/channels/voice-call.js.map +1 -0
- package/dist/channels/voice.d.ts.map +1 -0
- package/dist/channels/voice.js.map +1 -0
- package/dist/channels/web.d.ts.map +1 -0
- package/dist/channels/web.js.map +1 -0
- package/dist/channels/webhook.d.ts.map +1 -0
- package/dist/channels/webhook.js.map +1 -0
- package/dist/channels/websocket.d.ts.map +1 -0
- package/dist/channels/websocket.js.map +1 -0
- package/dist/channels/wechat.d.ts.map +1 -0
- package/dist/channels/wechat.js.map +1 -0
- package/dist/channels/whatsapp.d.ts.map +1 -0
- package/dist/channels/whatsapp.js.map +1 -0
- package/dist/cli/chat.d.ts.map +1 -0
- package/dist/cli/chat.js.map +1 -0
- package/dist/cli/setup.d.ts.map +1 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +72 -11
- package/dist/cli.js.map +1 -0
- package/dist/core/a2a.d.ts.map +1 -0
- package/dist/core/a2a.js.map +1 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/analytics-engine.d.ts.map +1 -0
- package/dist/core/analytics-engine.js.map +1 -0
- package/dist/core/api-server.d.ts.map +1 -0
- package/dist/core/api-server.js.map +1 -0
- package/dist/core/audio.d.ts.map +1 -0
- package/dist/core/audio.js.map +1 -0
- package/dist/core/auth.d.ts.map +1 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/collaboration.d.ts.map +1 -0
- package/dist/core/collaboration.js.map +1 -0
- package/dist/core/compose.d.ts.map +1 -0
- package/dist/core/compose.js.map +1 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context-discovery.d.ts.map +1 -0
- package/dist/core/context-discovery.js.map +1 -0
- package/dist/core/context-refs.d.ts.map +1 -0
- package/dist/core/context-refs.js.map +1 -0
- package/dist/core/errors.d.ts.map +1 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/gateway.d.ts.map +1 -0
- package/dist/core/gateway.js.map +1 -0
- package/dist/core/heartbeat.d.ts.map +1 -0
- package/dist/core/heartbeat.js.map +1 -0
- package/dist/core/hitl.d.ts.map +1 -0
- package/dist/core/hitl.js.map +1 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/ide-bridge.d.ts.map +1 -0
- package/dist/core/ide-bridge.js.map +1 -0
- package/dist/core/knowledge.d.ts.map +1 -0
- package/dist/core/knowledge.js.map +1 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/node-network.d.ts.map +1 -0
- package/dist/core/node-network.js.map +1 -0
- package/dist/core/orchestrator.d.ts.map +1 -0
- package/dist/core/orchestrator.js.map +1 -0
- package/dist/core/performance.d.ts.map +1 -0
- package/dist/core/performance.js.map +1 -0
- package/dist/core/profiles.d.ts.map +1 -0
- package/dist/core/profiles.js.map +1 -0
- package/dist/core/rate-limiter.d.ts.map +1 -0
- package/dist/core/rate-limiter.js.map +1 -0
- package/dist/core/room.d.ts.map +1 -0
- package/dist/core/room.js.map +1 -0
- package/dist/core/runtime.d.ts.map +1 -0
- package/dist/core/runtime.js.map +1 -0
- package/dist/core/sandbox.d.ts.map +1 -0
- package/dist/core/sandbox.js.map +1 -0
- package/dist/core/scheduler.d.ts.map +1 -0
- package/dist/core/scheduler.js.map +1 -0
- package/dist/core/security.d.ts.map +1 -0
- package/dist/core/security.js.map +1 -0
- package/dist/core/session-manager.d.ts.map +1 -0
- package/dist/core/session-manager.js.map +1 -0
- package/dist/core/streaming.d.ts.map +1 -0
- package/dist/core/streaming.js.map +1 -0
- package/dist/core/subagent.d.ts.map +1 -0
- package/dist/core/subagent.js.map +1 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/versioning.d.ts.map +1 -0
- package/dist/core/versioning.js.map +1 -0
- package/dist/core/vision.d.ts.map +1 -0
- package/dist/core/vision.js.map +1 -0
- package/dist/core/watch.d.ts.map +1 -0
- package/dist/core/watch.js.map +1 -0
- package/dist/core/workflow-graph.d.ts.map +1 -0
- package/dist/core/workflow-graph.js.map +1 -0
- package/dist/core/workflow.d.ts.map +1 -0
- package/dist/core/workflow.js.map +1 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js.map +1 -0
- package/dist/deploy/hermes.d.ts.map +1 -0
- package/dist/deploy/hermes.js.map +1 -0
- package/dist/deploy/index.d.ts.map +1 -0
- package/dist/deploy/index.js.map +1 -0
- package/dist/deploy/openclaw.d.ts.map +1 -0
- package/dist/deploy/openclaw.js.map +1 -0
- package/dist/doctor.d.ts.map +1 -0
- package/dist/doctor.js.map +1 -0
- package/dist/eval/index.d.ts.map +1 -0
- package/dist/eval/index.js.map +1 -0
- package/dist/hub/brain-seed.d.ts.map +1 -0
- package/dist/hub/brain-seed.js.map +1 -0
- package/dist/hub/client.d.ts.map +1 -0
- package/dist/hub/client.js.map +1 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/servers/calculator-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/calculator-mcp.js.map +1 -0
- package/dist/mcp/servers/crypto-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/crypto-mcp.js.map +1 -0
- package/dist/mcp/servers/database-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/database-mcp.js.map +1 -0
- package/dist/mcp/servers/datetime-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/datetime-mcp.js.map +1 -0
- package/dist/mcp/servers/filesystem.d.ts.map +1 -0
- package/dist/mcp/servers/filesystem.js.map +1 -0
- package/dist/mcp/servers/github-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/github-mcp.js.map +1 -0
- package/dist/mcp/servers/index.d.ts.map +1 -0
- package/dist/mcp/servers/index.js.map +1 -0
- package/dist/mcp/servers/json-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/json-mcp.js.map +1 -0
- package/dist/mcp/servers/memory-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/memory-mcp.js.map +1 -0
- package/dist/mcp/servers/regex-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/regex-mcp.js.map +1 -0
- package/dist/mcp/servers/web-mcp.d.ts.map +1 -0
- package/dist/mcp/servers/web-mcp.js.map +1 -0
- package/dist/memory/context-compressor.d.ts.map +1 -0
- package/dist/memory/context-compressor.js.map +1 -0
- package/dist/memory/deepbrain.d.ts.map +1 -0
- package/dist/memory/deepbrain.js.map +1 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/seed-loader.d.ts.map +1 -0
- package/dist/memory/seed-loader.js.map +1 -0
- package/dist/memory/user-profiler.d.ts.map +1 -0
- package/dist/memory/user-profiler.js.map +1 -0
- package/dist/plugins/content-filter.d.ts.map +1 -0
- package/dist/plugins/content-filter.js.map +1 -0
- package/dist/plugins/index.d.ts.map +1 -0
- package/dist/plugins/index.js.map +1 -0
- package/dist/plugins/logger.d.ts.map +1 -0
- package/dist/plugins/logger.js.map +1 -0
- package/dist/plugins/rate-limiter.d.ts.map +1 -0
- package/dist/plugins/rate-limiter.js.map +1 -0
- package/dist/protocols/a2a/client.d.ts.map +1 -0
- package/dist/protocols/a2a/client.js.map +1 -0
- package/dist/protocols/a2a/index.d.ts.map +1 -0
- package/dist/protocols/a2a/index.js.map +1 -0
- package/dist/protocols/a2a/server.d.ts.map +1 -0
- package/dist/protocols/a2a/server.js.map +1 -0
- package/dist/protocols/a2a/types.d.ts.map +1 -0
- package/dist/protocols/a2a/types.js.map +1 -0
- package/dist/protocols/a2a/utils.d.ts.map +1 -0
- package/dist/protocols/a2a/utils.js.map +1 -0
- package/dist/protocols/agui/client.d.ts.map +1 -0
- package/dist/protocols/agui/client.js.map +1 -0
- package/dist/protocols/agui/index.d.ts.map +1 -0
- package/dist/protocols/agui/index.js.map +1 -0
- package/dist/protocols/agui/server.d.ts.map +1 -0
- package/dist/protocols/agui/server.js.map +1 -0
- package/dist/protocols/agui/types.d.ts.map +1 -0
- package/dist/protocols/agui/types.js.map +1 -0
- package/dist/protocols/index.d.ts.map +1 -0
- package/dist/protocols/index.js.map +1 -0
- package/dist/protocols/mcp/agent-tools.d.ts.map +1 -0
- package/dist/protocols/mcp/agent-tools.js.map +1 -0
- package/dist/protocols/mcp/index.d.ts.map +1 -0
- package/dist/protocols/mcp/index.js.map +1 -0
- package/dist/protocols/mcp/server.d.ts.map +1 -0
- package/dist/protocols/mcp/server.js.map +1 -0
- package/dist/protocols/mcp/types.d.ts.map +1 -0
- package/dist/protocols/mcp/types.js.map +1 -0
- package/dist/providers/index.d.ts.map +1 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/publish/index.d.ts.map +1 -0
- package/dist/publish/index.js.map +1 -0
- package/dist/scheduler/cron-engine.d.ts.map +1 -0
- package/dist/scheduler/cron-engine.js.map +1 -0
- package/dist/scheduler/index.d.ts.map +1 -0
- package/dist/scheduler/index.js.map +1 -0
- package/dist/schema/oad.d.ts.map +1 -0
- package/dist/schema/oad.js.map +1 -0
- package/dist/security/approval.d.ts.map +1 -0
- package/dist/security/approval.js.map +1 -0
- package/dist/security/approvals.d.ts.map +1 -0
- package/dist/security/approvals.js.map +1 -0
- package/dist/security/elevated.d.ts.map +1 -0
- package/dist/security/elevated.js.map +1 -0
- package/dist/security/guardrails.d.ts.map +1 -0
- package/dist/security/guardrails.js.map +1 -0
- package/dist/security/index.d.ts.map +1 -0
- package/dist/security/index.js.map +1 -0
- package/dist/security/keys.d.ts.map +1 -0
- package/dist/security/keys.js.map +1 -0
- package/dist/security/secrets.d.ts.map +1 -0
- package/dist/security/secrets.js.map +1 -0
- package/dist/skills/auto-learn.d.ts.map +1 -0
- package/dist/skills/auto-learn.js.map +1 -0
- package/dist/skills/base.d.ts.map +1 -0
- package/dist/skills/base.js.map +1 -0
- package/dist/skills/builtin/index.d.ts.map +1 -0
- package/dist/skills/builtin/index.js.map +1 -0
- package/dist/skills/document.d.ts.map +1 -0
- package/dist/skills/document.js.map +1 -0
- package/dist/skills/http.d.ts.map +1 -0
- package/dist/skills/http.js.map +1 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/marketplace.d.ts.map +1 -0
- package/dist/skills/marketplace.js.map +1 -0
- package/dist/skills/scheduler.d.ts.map +1 -0
- package/dist/skills/scheduler.js.map +1 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/skills/webhook-trigger.d.ts.map +1 -0
- package/dist/skills/webhook-trigger.js.map +1 -0
- package/dist/studio/server.d.ts.map +1 -0
- package/dist/studio/server.js.map +1 -0
- package/dist/studio/templates-data.d.ts.map +1 -0
- package/dist/studio/templates-data.js.map +1 -0
- package/dist/telemetry/index.d.ts.map +1 -0
- package/dist/telemetry/index.js.map +1 -0
- package/dist/templates/code-reviewer.d.ts.map +1 -0
- package/dist/templates/code-reviewer.js.map +1 -0
- package/dist/templates/content-writer.d.ts.map +1 -0
- package/dist/templates/content-writer.js.map +1 -0
- package/dist/templates/customer-service.d.ts.map +1 -0
- package/dist/templates/customer-service.js.map +1 -0
- package/dist/templates/data-analyst.d.ts.map +1 -0
- package/dist/templates/data-analyst.js.map +1 -0
- package/dist/templates/executive-assistant.d.ts.map +1 -0
- package/dist/templates/executive-assistant.js.map +1 -0
- package/dist/templates/financial-advisor.d.ts.map +1 -0
- package/dist/templates/financial-advisor.js.map +1 -0
- package/dist/templates/hr-recruiter.d.ts.map +1 -0
- package/dist/templates/hr-recruiter.js.map +1 -0
- package/dist/templates/knowledge-base.d.ts.map +1 -0
- package/dist/templates/knowledge-base.js.map +1 -0
- package/dist/templates/legal-assistant.d.ts.map +1 -0
- package/dist/templates/legal-assistant.js.map +1 -0
- package/dist/templates/project-manager.d.ts.map +1 -0
- package/dist/templates/project-manager.js.map +1 -0
- package/dist/templates/sales-assistant.d.ts.map +1 -0
- package/dist/templates/sales-assistant.js.map +1 -0
- package/dist/templates/teacher.d.ts.map +1 -0
- package/dist/templates/teacher.js.map +1 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tools/builtin/browser.d.ts.map +1 -0
- package/dist/tools/builtin/browser.js.map +1 -0
- package/dist/tools/builtin/datetime.d.ts.map +1 -0
- package/dist/tools/builtin/datetime.js.map +1 -0
- package/dist/tools/builtin/file.d.ts.map +1 -0
- package/dist/tools/builtin/file.js.map +1 -0
- package/dist/tools/builtin/home-assistant.d.ts.map +1 -0
- package/dist/tools/builtin/home-assistant.js.map +1 -0
- package/dist/tools/builtin/index.d.ts.map +1 -0
- package/dist/tools/builtin/index.js.map +1 -0
- package/dist/tools/builtin/rl-tools.d.ts.map +1 -0
- package/dist/tools/builtin/rl-tools.js.map +1 -0
- package/dist/tools/builtin/shell.d.ts.map +1 -0
- package/dist/tools/builtin/shell.js.map +1 -0
- package/dist/tools/builtin/vision.d.ts.map +1 -0
- package/dist/tools/builtin/vision.js.map +1 -0
- package/dist/tools/builtin/web-search.d.ts.map +1 -0
- package/dist/tools/builtin/web-search.js.map +1 -0
- package/dist/tools/builtin/web.d.ts.map +1 -0
- package/dist/tools/builtin/web.js.map +1 -0
- package/dist/tools/calculator.d.ts.map +1 -0
- package/dist/tools/calculator.js.map +1 -0
- package/dist/tools/datetime.d.ts.map +1 -0
- package/dist/tools/datetime.js.map +1 -0
- package/dist/tools/document-processor.d.ts.map +1 -0
- package/dist/tools/document-processor.js.map +1 -0
- package/dist/tools/gateway.d.ts.map +1 -0
- package/dist/tools/gateway.js.map +1 -0
- package/dist/tools/image-generator.d.ts.map +1 -0
- package/dist/tools/image-generator.js.map +1 -0
- package/dist/tools/integrations/calendar.d.ts.map +1 -0
- package/dist/tools/integrations/calendar.js.map +1 -0
- package/dist/tools/integrations/code-exec.d.ts.map +1 -0
- package/dist/tools/integrations/code-exec.js.map +1 -0
- package/dist/tools/integrations/csv-analyzer.d.ts.map +1 -0
- package/dist/tools/integrations/csv-analyzer.js.map +1 -0
- package/dist/tools/integrations/database.d.ts.map +1 -0
- package/dist/tools/integrations/database.js.map +1 -0
- package/dist/tools/integrations/email-send.d.ts.map +1 -0
- package/dist/tools/integrations/email-send.js.map +1 -0
- package/dist/tools/integrations/git-tool.d.ts.map +1 -0
- package/dist/tools/integrations/git-tool.js.map +1 -0
- package/dist/tools/integrations/github-tool.d.ts.map +1 -0
- package/dist/tools/integrations/github-tool.js.map +1 -0
- package/dist/tools/integrations/image-gen.d.ts.map +1 -0
- package/dist/tools/integrations/image-gen.js.map +1 -0
- package/dist/tools/integrations/index.d.ts.map +1 -0
- package/dist/tools/integrations/index.js.map +1 -0
- package/dist/tools/integrations/jira.d.ts.map +1 -0
- package/dist/tools/integrations/jira.js.map +1 -0
- package/dist/tools/integrations/notion.d.ts.map +1 -0
- package/dist/tools/integrations/notion.js.map +1 -0
- package/dist/tools/integrations/npm-tool.d.ts.map +1 -0
- package/dist/tools/integrations/npm-tool.js.map +1 -0
- package/dist/tools/integrations/pdf-reader.d.ts.map +1 -0
- package/dist/tools/integrations/pdf-reader.js.map +1 -0
- package/dist/tools/integrations/slack.d.ts.map +1 -0
- package/dist/tools/integrations/slack.js.map +1 -0
- package/dist/tools/integrations/summarizer.d.ts.map +1 -0
- package/dist/tools/integrations/summarizer.js.map +1 -0
- package/dist/tools/integrations/translator.d.ts.map +1 -0
- package/dist/tools/integrations/translator.js.map +1 -0
- package/dist/tools/integrations/trello.d.ts.map +1 -0
- package/dist/tools/integrations/trello.js.map +1 -0
- package/dist/tools/integrations/vector-search.d.ts.map +1 -0
- package/dist/tools/integrations/vector-search.js.map +1 -0
- package/dist/tools/integrations/web-scraper.d.ts.map +1 -0
- package/dist/tools/integrations/web-scraper.js.map +1 -0
- package/dist/tools/integrations/web-search.d.ts.map +1 -0
- package/dist/tools/integrations/web-search.js.map +1 -0
- package/dist/tools/integrations/webhook.d.ts.map +1 -0
- package/dist/tools/integrations/webhook.js.map +1 -0
- package/dist/tools/json-transform.d.ts.map +1 -0
- package/dist/tools/json-transform.js.map +1 -0
- package/dist/tools/mcp-client.d.ts.map +1 -0
- package/dist/tools/mcp-client.js.map +1 -0
- package/dist/tools/mcp.d.ts.map +1 -0
- package/dist/tools/mcp.js.map +1 -0
- package/dist/tools/text-analysis.d.ts.map +1 -0
- package/dist/tools/text-analysis.js.map +1 -0
- package/dist/tools/web-scraper.d.ts.map +1 -0
- package/dist/tools/web-scraper.js.map +1 -0
- package/dist/tools/web-search.d.ts.map +1 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/traces/index.d.ts.map +1 -0
- package/dist/traces/index.js.map +1 -0
- package/dist/ui/components.d.ts.map +1 -0
- package/dist/ui/components.js.map +1 -0
- package/package.json +1 -1
- package/.github/ISSUE_TEMPLATE/bug_report.md +0 -20
- package/.github/ISSUE_TEMPLATE/feature_request.md +0 -14
- package/.github/PULL_REQUEST_TEMPLATE.md +0 -13
- package/.github/workflows/ci.yml +0 -24
- package/USABILITY-ISSUES.md +0 -73
- package/docs/.vitepress/config.ts +0 -103
- package/docs/api/cli.md +0 -48
- package/docs/api/oad-schema.md +0 -64
- package/docs/api/sdk.md +0 -80
- package/docs/guide/concepts.md +0 -51
- package/docs/guide/configuration.md +0 -79
- package/docs/guide/deployment.md +0 -42
- package/docs/guide/getting-started.md +0 -44
- package/docs/guide/templates.md +0 -28
- package/docs/guide/testing.md +0 -84
- package/docs/index.md +0 -27
- package/docs/zh/api/cli.md +0 -54
- package/docs/zh/api/oad-schema.md +0 -87
- package/docs/zh/api/sdk.md +0 -102
- package/docs/zh/guide/concepts.md +0 -104
- package/docs/zh/guide/configuration.md +0 -135
- package/docs/zh/guide/deployment.md +0 -81
- package/docs/zh/guide/getting-started.md +0 -82
- package/docs/zh/guide/templates.md +0 -84
- package/docs/zh/guide/testing.md +0 -88
- package/docs/zh/index.md +0 -27
- package/fix-sidebar.mjs +0 -188
- package/serve-studio.js +0 -13
- package/serve-test.js +0 -25
- package/src/analytics/index.ts +0 -66
- package/src/channels/dingtalk.ts +0 -46
- package/src/channels/discord.ts +0 -192
- package/src/channels/email.ts +0 -351
- package/src/channels/feishu.ts +0 -349
- package/src/channels/googlechat.ts +0 -42
- package/src/channels/imessage.ts +0 -32
- package/src/channels/index.ts +0 -15
- package/src/channels/irc.ts +0 -82
- package/src/channels/line.ts +0 -33
- package/src/channels/matrix.ts +0 -34
- package/src/channels/mattermost.ts +0 -57
- package/src/channels/msteams.ts +0 -33
- package/src/channels/nostr.ts +0 -33
- package/src/channels/qq.ts +0 -34
- package/src/channels/signal.ts +0 -33
- package/src/channels/slack.ts +0 -217
- package/src/channels/sms.ts +0 -34
- package/src/channels/telegram.ts +0 -616
- package/src/channels/twitch.ts +0 -65
- package/src/channels/voice-call.ts +0 -100
- package/src/channels/voice.ts +0 -471
- package/src/channels/web.ts +0 -638
- package/src/channels/webhook.ts +0 -199
- package/src/channels/websocket.ts +0 -399
- package/src/channels/wechat.ts +0 -329
- package/src/channels/whatsapp.ts +0 -33
- package/src/cli/chat.ts +0 -99
- package/src/cli/setup.ts +0 -314
- package/src/cli.ts +0 -2826
- package/src/core/a2a.ts +0 -203
- package/src/core/agent.ts +0 -476
- package/src/core/analytics-engine.ts +0 -186
- package/src/core/api-server.ts +0 -277
- package/src/core/audio.ts +0 -98
- package/src/core/auth.ts +0 -57
- package/src/core/cache.ts +0 -141
- package/src/core/collaboration.ts +0 -275
- package/src/core/compose.ts +0 -77
- package/src/core/config.ts +0 -14
- package/src/core/context-discovery.ts +0 -85
- package/src/core/context-refs.ts +0 -140
- package/src/core/errors.ts +0 -148
- package/src/core/gateway.ts +0 -106
- package/src/core/heartbeat.ts +0 -51
- package/src/core/hitl.ts +0 -138
- package/src/core/hooks.ts +0 -105
- package/src/core/ide-bridge.ts +0 -133
- package/src/core/knowledge.ts +0 -255
- package/src/core/logger.ts +0 -57
- package/src/core/node-network.ts +0 -86
- package/src/core/orchestrator.ts +0 -215
- package/src/core/performance.ts +0 -187
- package/src/core/profiles.ts +0 -122
- package/src/core/rate-limiter.ts +0 -128
- package/src/core/room.ts +0 -109
- package/src/core/runtime.ts +0 -435
- package/src/core/sandbox.ts +0 -344
- package/src/core/scheduler.ts +0 -187
- package/src/core/security.ts +0 -171
- package/src/core/session-manager.ts +0 -137
- package/src/core/streaming.ts +0 -195
- package/src/core/subagent.ts +0 -98
- package/src/core/types.ts +0 -68
- package/src/core/versioning.ts +0 -106
- package/src/core/vision.ts +0 -180
- package/src/core/watch.ts +0 -178
- package/src/core/workflow-graph.ts +0 -365
- package/src/core/workflow.ts +0 -235
- package/src/daemon.ts +0 -96
- package/src/deploy/hermes.ts +0 -156
- package/src/deploy/index.ts +0 -255
- package/src/deploy/openclaw.ts +0 -190
- package/src/doctor.ts +0 -243
- package/src/eval/index.ts +0 -211
- package/src/eval/suites/basic.json +0 -16
- package/src/eval/suites/memory.json +0 -12
- package/src/eval/suites/safety.json +0 -14
- package/src/hub/brain-seed.ts +0 -54
- package/src/hub/client.ts +0 -60
- package/src/i18n/index.ts +0 -216
- package/src/index.ts +0 -283
- package/src/mcp/servers/calculator-mcp.ts +0 -65
- package/src/mcp/servers/crypto-mcp.ts +0 -73
- package/src/mcp/servers/database-mcp.ts +0 -72
- package/src/mcp/servers/datetime-mcp.ts +0 -69
- package/src/mcp/servers/filesystem.ts +0 -66
- package/src/mcp/servers/github-mcp.ts +0 -58
- package/src/mcp/servers/index.ts +0 -63
- package/src/mcp/servers/json-mcp.ts +0 -102
- package/src/mcp/servers/memory-mcp.ts +0 -56
- package/src/mcp/servers/regex-mcp.ts +0 -53
- package/src/mcp/servers/web-mcp.ts +0 -49
- package/src/memory/context-compressor.ts +0 -189
- package/src/memory/deepbrain.ts +0 -202
- package/src/memory/index.ts +0 -41
- package/src/memory/seed-loader.ts +0 -212
- package/src/memory/user-profiler.ts +0 -215
- package/src/plugins/content-filter.ts +0 -23
- package/src/plugins/index.ts +0 -339
- package/src/plugins/logger.ts +0 -18
- package/src/plugins/rate-limiter.ts +0 -38
- package/src/protocols/a2a/client.ts +0 -132
- package/src/protocols/a2a/index.ts +0 -8
- package/src/protocols/a2a/server.ts +0 -333
- package/src/protocols/a2a/types.ts +0 -88
- package/src/protocols/a2a/utils.ts +0 -50
- package/src/protocols/agui/client.ts +0 -83
- package/src/protocols/agui/index.ts +0 -4
- package/src/protocols/agui/server.ts +0 -218
- package/src/protocols/agui/types.ts +0 -153
- package/src/protocols/index.ts +0 -2
- package/src/protocols/mcp/agent-tools.ts +0 -134
- package/src/protocols/mcp/index.ts +0 -8
- package/src/protocols/mcp/server.ts +0 -262
- package/src/protocols/mcp/types.ts +0 -69
- package/src/providers/index.ts +0 -632
- package/src/publish/index.ts +0 -376
- package/src/scheduler/cron-engine.ts +0 -191
- package/src/scheduler/index.ts +0 -2
- package/src/schema/oad.ts +0 -217
- package/src/security/approval.ts +0 -131
- package/src/security/approvals.ts +0 -143
- package/src/security/elevated.ts +0 -105
- package/src/security/guardrails.ts +0 -248
- package/src/security/index.ts +0 -9
- package/src/security/keys.ts +0 -87
- package/src/security/secrets.ts +0 -129
- package/src/skills/auto-learn.ts +0 -262
- package/src/skills/base.ts +0 -16
- package/src/skills/builtin/index.ts +0 -408
- package/src/skills/document.ts +0 -100
- package/src/skills/http.ts +0 -35
- package/src/skills/index.ts +0 -27
- package/src/skills/marketplace.ts +0 -113
- package/src/skills/scheduler.ts +0 -80
- package/src/skills/types.ts +0 -42
- package/src/skills/webhook-trigger.ts +0 -59
- package/src/studio/server.ts +0 -1791
- package/src/studio/templates-data.ts +0 -178
- package/src/studio-ui/index.html +0 -3076
- package/src/telemetry/index.ts +0 -324
- package/src/templates/code-reviewer.ts +0 -30
- package/src/templates/content-writer.ts +0 -58
- package/src/templates/customer-service.ts +0 -76
- package/src/templates/data-analyst.ts +0 -66
- package/src/templates/executive-assistant.ts +0 -71
- package/src/templates/financial-advisor.ts +0 -60
- package/src/templates/hr-recruiter.ts +0 -58
- package/src/templates/knowledge-base.ts +0 -27
- package/src/templates/legal-assistant.ts +0 -71
- package/src/templates/project-manager.ts +0 -58
- package/src/templates/sales-assistant.ts +0 -75
- package/src/templates/teacher.ts +0 -75
- package/src/testing/index.ts +0 -181
- package/src/tools/builtin/browser.ts +0 -299
- package/src/tools/builtin/datetime.ts +0 -41
- package/src/tools/builtin/file.ts +0 -107
- package/src/tools/builtin/home-assistant.ts +0 -116
- package/src/tools/builtin/index.ts +0 -37
- package/src/tools/builtin/rl-tools.ts +0 -243
- package/src/tools/builtin/shell.ts +0 -43
- package/src/tools/builtin/vision.ts +0 -64
- package/src/tools/builtin/web-search.ts +0 -126
- package/src/tools/builtin/web.ts +0 -35
- package/src/tools/calculator.ts +0 -73
- package/src/tools/datetime.ts +0 -149
- package/src/tools/document-processor.ts +0 -213
- package/src/tools/gateway.ts +0 -220
- package/src/tools/image-generator.ts +0 -150
- package/src/tools/integrations/calendar.ts +0 -73
- package/src/tools/integrations/code-exec.ts +0 -39
- package/src/tools/integrations/csv-analyzer.ts +0 -92
- package/src/tools/integrations/database.ts +0 -44
- package/src/tools/integrations/email-send.ts +0 -76
- package/src/tools/integrations/git-tool.ts +0 -42
- package/src/tools/integrations/github-tool.ts +0 -76
- package/src/tools/integrations/image-gen.ts +0 -56
- package/src/tools/integrations/index.ts +0 -92
- package/src/tools/integrations/jira.ts +0 -83
- package/src/tools/integrations/notion.ts +0 -71
- package/src/tools/integrations/npm-tool.ts +0 -48
- package/src/tools/integrations/pdf-reader.ts +0 -58
- package/src/tools/integrations/slack.ts +0 -65
- package/src/tools/integrations/summarizer.ts +0 -49
- package/src/tools/integrations/translator.ts +0 -48
- package/src/tools/integrations/trello.ts +0 -60
- package/src/tools/integrations/vector-search.ts +0 -42
- package/src/tools/integrations/web-scraper.ts +0 -47
- package/src/tools/integrations/web-search.ts +0 -58
- package/src/tools/integrations/webhook.ts +0 -38
- package/src/tools/json-transform.ts +0 -187
- package/src/tools/mcp-client.ts +0 -131
- package/src/tools/mcp.ts +0 -76
- package/src/tools/text-analysis.ts +0 -116
- package/src/tools/web-scraper.ts +0 -179
- package/src/tools/web-search.ts +0 -180
- package/src/traces/index.ts +0 -132
- package/src/types/agent-workstation.d.ts +0 -2
- package/src/ui/components.ts +0 -127
- package/srv-err.txt +0 -0
- package/srv-out.txt +0 -1
- package/test-agent/Dockerfile +0 -9
- package/test-agent/README.md +0 -50
- package/test-agent/agent.yaml +0 -23
- package/test-agent/docker-compose.yml +0 -11
- package/test-agent/oad.yaml +0 -31
- package/test-agent/package-lock.json +0 -1492
- package/test-agent/package.json +0 -18
- package/test-agent/src/index.ts +0 -24
- package/test-agent/src/skills/echo.ts +0 -15
- package/test-agent/tsconfig.json +0 -25
- package/test-full.js +0 -43
- package/test-sidebar.js +0 -22
- package/test-studio3.js +0 -75
- package/test-studio4.js +0 -41
- package/tests/a2a-protocol.test.ts +0 -285
- package/tests/a2a.test.ts +0 -66
- package/tests/agent.test.ts +0 -72
- package/tests/agui-protocol.test.ts +0 -246
- package/tests/analytics.test.ts +0 -50
- package/tests/api-server.test.ts +0 -148
- package/tests/approvals.test.ts +0 -89
- package/tests/audio.test.ts +0 -40
- package/tests/auto-learn.test.ts +0 -105
- package/tests/brain-seed-extended.test.ts +0 -490
- package/tests/brain-seed.test.ts +0 -239
- package/tests/browser.test.ts +0 -179
- package/tests/builtin-tools.test.ts +0 -83
- package/tests/channel.test.ts +0 -39
- package/tests/channels/discord.test.ts +0 -79
- package/tests/channels/email.test.ts +0 -148
- package/tests/channels/feishu.test.ts +0 -123
- package/tests/channels/telegram.test.ts +0 -129
- package/tests/channels/websocket.test.ts +0 -53
- package/tests/channels/wechat.test.ts +0 -170
- package/tests/channels-extra.test.ts +0 -45
- package/tests/chat-cli.test.ts +0 -160
- package/tests/cli.test.ts +0 -46
- package/tests/collaboration.test.ts +0 -319
- package/tests/context-compressor.test.ts +0 -172
- package/tests/context-refs.test.ts +0 -121
- package/tests/cron-engine.test.ts +0 -101
- package/tests/daemon.test.ts +0 -135
- package/tests/deepbrain-wire.test.ts +0 -234
- package/tests/deploy-and-dag.test.ts +0 -196
- package/tests/doctor.test.ts +0 -38
- package/tests/document-processor.test.ts +0 -69
- package/tests/e2e-nocode.test.ts +0 -442
- package/tests/e2e.test.ts +0 -134
- package/tests/elevated.test.ts +0 -69
- package/tests/errors.test.ts +0 -83
- package/tests/eval.test.ts +0 -173
- package/tests/gateway.test.ts +0 -63
- package/tests/guardrails.test.ts +0 -177
- package/tests/hitl.test.ts +0 -71
- package/tests/home-assistant.test.ts +0 -40
- package/tests/hooks.test.ts +0 -79
- package/tests/i18n.test.ts +0 -41
- package/tests/ide-bridge.test.ts +0 -38
- package/tests/image-generator.test.ts +0 -84
- package/tests/init-role.test.ts +0 -124
- package/tests/integrations.test.ts +0 -249
- package/tests/mcp-client.test.ts +0 -92
- package/tests/mcp-server.test.ts +0 -178
- package/tests/mcp-servers.test.ts +0 -260
- package/tests/mcp.test.ts +0 -54
- package/tests/node-network.test.ts +0 -74
- package/tests/oad.test.ts +0 -68
- package/tests/performance.test.ts +0 -115
- package/tests/plugin-a2a-enhanced.test.ts +0 -230
- package/tests/plugin.test.ts +0 -74
- package/tests/profiles.test.ts +0 -61
- package/tests/publish.test.ts +0 -231
- package/tests/rl-tools.test.ts +0 -93
- package/tests/room.test.ts +0 -106
- package/tests/runtime.test.ts +0 -42
- package/tests/sandbox-manager.test.ts +0 -46
- package/tests/sandbox.test.ts +0 -46
- package/tests/scheduler.test.ts +0 -200
- package/tests/secrets.test.ts +0 -107
- package/tests/security-enhanced.test.ts +0 -233
- package/tests/security.test.ts +0 -60
- package/tests/settings-api.test.ts +0 -148
- package/tests/setup.test.ts +0 -73
- package/tests/skill-learner.test.ts +0 -161
- package/tests/streaming.test.ts +0 -109
- package/tests/studio.test.ts +0 -402
- package/tests/subagent.test.ts +0 -193
- package/tests/telegram-discord.test.ts +0 -60
- package/tests/telemetry.test.ts +0 -186
- package/tests/templates.test.ts +0 -77
- package/tests/tools/builtin-extended.test.ts +0 -138
- package/tests/user-profiler.test.ts +0 -169
- package/tests/v070.test.ts +0 -76
- package/tests/v090-features.test.ts +0 -254
- package/tests/versioning.test.ts +0 -75
- package/tests/vision.test.ts +0 -61
- package/tests/voice-call.test.ts +0 -47
- package/tests/voice-enhanced.test.ts +0 -169
- package/tests/voice-interaction.test.ts +0 -38
- package/tests/voice.test.ts +0 -61
- package/tests/web-search.test.ts +0 -155
- package/tests/webhook.test.ts +0 -29
- package/tests/workflow-graph.test.ts +0 -279
- package/tests/workflow.test.ts +0 -143
- package/tmp-js-test.js +0 -1532
- package/tmp-sc.js +0 -1716
- package/tutorial/customer-service-agent/README.md +0 -612
- package/tutorial/customer-service-agent/SOUL.md +0 -26
- package/tutorial/customer-service-agent/agent.yaml +0 -63
- package/tutorial/customer-service-agent/package.json +0 -19
- package/tutorial/customer-service-agent/src/index.ts +0 -69
- package/tutorial/customer-service-agent/src/skills/faq.ts +0 -27
- package/tutorial/customer-service-agent/src/skills/ticket.ts +0 -22
- package/tutorial/customer-service-agent/tsconfig.json +0 -14
- package/vitest.config.ts +0 -9
package/src/studio/server.ts
DELETED
|
@@ -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 };
|