profclaw 2.0.0 → 2.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +14 -2
- package/CHANGELOG.md +37 -0
- package/CONTRIBUTING.md +20 -0
- package/Dockerfile +39 -23
- package/README.md +174 -40
- package/dist/agents/agent-summary.d.ts +44 -0
- package/dist/agents/agent-summary.js +176 -0
- package/dist/agents/auto-memory.d.ts +59 -0
- package/dist/agents/auto-memory.js +310 -0
- package/dist/agents/checkpoint-manager.d.ts +76 -0
- package/dist/agents/checkpoint-manager.js +156 -0
- package/dist/agents/circuit-breaker.d.ts +54 -0
- package/dist/agents/circuit-breaker.js +153 -0
- package/dist/agents/context-compactor.d.ts +70 -0
- package/dist/agents/context-compactor.js +361 -0
- package/dist/agents/conversation-branch.d.ts +55 -0
- package/dist/agents/conversation-branch.js +115 -0
- package/dist/agents/error-recovery.d.ts +44 -0
- package/dist/agents/error-recovery.js +197 -0
- package/dist/agents/events.d.ts +76 -0
- package/dist/agents/events.js +8 -0
- package/dist/agents/executor.d.ts +35 -1
- package/dist/agents/executor.js +573 -124
- package/dist/agents/file-snapshots.d.ts +72 -0
- package/dist/agents/file-snapshots.js +182 -0
- package/dist/agents/index.d.ts +2 -0
- package/dist/agents/orchestrator.d.ts +183 -0
- package/dist/agents/orchestrator.js +495 -0
- package/dist/agents/permissions.d.ts +63 -0
- package/dist/agents/permissions.js +138 -0
- package/dist/agents/plan-mode.d.ts +71 -0
- package/dist/agents/plan-mode.js +186 -0
- package/dist/agents/prompt-suggestions.d.ts +33 -0
- package/dist/agents/prompt-suggestions.js +208 -0
- package/dist/agents/rate-limit-monitor.d.ts +56 -0
- package/dist/agents/rate-limit-monitor.js +224 -0
- package/dist/agents/result-store.d.ts +37 -0
- package/dist/agents/result-store.js +104 -0
- package/dist/agents/session-diff.d.ts +43 -0
- package/dist/agents/session-diff.js +258 -0
- package/dist/agents/tool-loader.d.ts +65 -0
- package/dist/agents/tool-loader.js +273 -0
- package/dist/agents/transcript.d.ts +96 -0
- package/dist/agents/transcript.js +267 -0
- package/dist/agents/worktree-manager.d.ts +80 -0
- package/dist/agents/worktree-manager.js +203 -0
- package/dist/auth/middleware.js +14 -0
- package/dist/chat/agentic-executor.d.ts +7 -0
- package/dist/chat/agentic-executor.js +253 -30
- package/dist/chat/conversations.d.ts +2 -0
- package/dist/chat/conversations.js +8 -0
- package/dist/chat/execution/executor.d.ts +8 -0
- package/dist/chat/execution/executor.js +157 -103
- package/dist/chat/execution/index.js +5 -1
- package/dist/chat/execution/tool-router.js +40 -14
- package/dist/chat/execution/tools/canvas.d.ts +2 -2
- package/dist/chat/execution/tools/code-tools.d.ts +66 -0
- package/dist/chat/execution/tools/code-tools.js +353 -0
- package/dist/chat/execution/tools/complete-task.d.ts +2 -2
- package/dist/chat/execution/tools/cron-tool.d.ts +26 -10
- package/dist/chat/execution/tools/cron-tool.js +48 -3
- package/dist/chat/execution/tools/decompose-task.d.ts +58 -0
- package/dist/chat/execution/tools/decompose-task.js +166 -0
- package/dist/chat/execution/tools/exec.d.ts +5 -2
- package/dist/chat/execution/tools/exec.js +294 -155
- package/dist/chat/execution/tools/feed-tools.d.ts +77 -0
- package/dist/chat/execution/tools/feed-tools.js +142 -0
- package/dist/chat/execution/tools/file-ops.d.ts +1 -1
- package/dist/chat/execution/tools/github.d.ts +2 -2
- package/dist/chat/execution/tools/index.d.ts +14 -2
- package/dist/chat/execution/tools/index.js +86 -12
- package/dist/chat/execution/tools/integrations.d.ts +8 -8
- package/dist/chat/execution/tools/multi-patch.d.ts +53 -0
- package/dist/chat/execution/tools/multi-patch.js +373 -0
- package/dist/chat/execution/tools/openai-image-gen.d.ts +2 -2
- package/dist/chat/execution/tools/plan-tools.d.ts +80 -0
- package/dist/chat/execution/tools/plan-tools.js +134 -0
- package/dist/chat/execution/tools/profclaw-ops.d.ts +6 -6
- package/dist/chat/execution/tools/repl-tool.d.ts +46 -0
- package/dist/chat/execution/tools/repl-tool.js +207 -0
- package/dist/chat/execution/tools/sessions-send.d.ts +2 -2
- package/dist/chat/execution/tools/slack-actions.d.ts +2 -2
- package/dist/chat/execution/tools/system.d.ts +4 -4
- package/dist/chat/execution/tools/todo-tool.d.ts +72 -0
- package/dist/chat/execution/tools/todo-tool.js +152 -0
- package/dist/chat/execution/tools/tool-search.d.ts +50 -0
- package/dist/chat/execution/tools/tool-search.js +155 -0
- package/dist/chat/execution/types.d.ts +21 -14
- package/dist/chat/execution/workflows/executor.d.ts +11 -0
- package/dist/chat/execution/workflows/executor.js +99 -1
- package/dist/chat/execution/workflows/types.d.ts +35 -2
- package/dist/chat/format/index.d.ts +1 -0
- package/dist/chat/format/index.js +1 -0
- package/dist/chat/format/markdown-convert.d.ts +23 -0
- package/dist/chat/format/markdown-convert.js +149 -0
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +1 -1
- package/dist/chat/message-handler.js +58 -6
- package/dist/chat/proactive/index.d.ts +62 -0
- package/dist/chat/proactive/index.js +147 -0
- package/dist/chat/prompt-adapter.js +2 -0
- package/dist/chat/providers/irc/index.d.ts +2 -2
- package/dist/chat/providers/telegram/index.d.ts +2 -0
- package/dist/chat/providers/telegram/index.js +21 -2
- package/dist/chat/system-prompts.d.ts +3 -3
- package/dist/chat/system-prompts.js +116 -61
- package/dist/chat/tools.d.ts +6 -6
- package/dist/cli/commands/auth.js +64 -1
- package/dist/cli/commands/chat.js +1327 -138
- package/dist/cli/commands/doctor.js +222 -16
- package/dist/cli/commands/history.d.ts +3 -0
- package/dist/cli/commands/history.js +138 -0
- package/dist/cli/commands/import.d.ts +44 -0
- package/dist/cli/commands/import.js +526 -0
- package/dist/cli/commands/init.d.ts +13 -0
- package/dist/cli/commands/init.js +381 -0
- package/dist/cli/commands/onboard.js +210 -30
- package/dist/cli/commands/plan.d.ts +13 -0
- package/dist/cli/commands/plan.js +184 -0
- package/dist/cli/commands/serve.d.ts +7 -0
- package/dist/cli/commands/serve.js +77 -18
- package/dist/cli/commands/setup.js +84 -3
- package/dist/cli/commands/status.js +54 -0
- package/dist/cli/commands/tools.js +13 -13
- package/dist/cli/commands/tui.js +26 -1
- package/dist/cli/index.js +19 -0
- package/dist/cli/ink/App.d.ts +13 -0
- package/dist/cli/ink/App.js +6 -0
- package/dist/cli/ink/ChatApp.d.ts +60 -0
- package/dist/cli/ink/ChatApp.js +325 -0
- package/dist/cli/ink/DashboardApp.d.ts +3 -0
- package/dist/cli/ink/DashboardApp.js +143 -0
- package/dist/cli/ink/components/AgentStatus.d.ts +17 -0
- package/dist/cli/ink/components/AgentStatus.js +33 -0
- package/dist/cli/ink/components/ChannelList.d.ts +17 -0
- package/dist/cli/ink/components/ChannelList.js +33 -0
- package/dist/cli/ink/components/ConnectionStatus.d.ts +19 -0
- package/dist/cli/ink/components/ConnectionStatus.js +50 -0
- package/dist/cli/ink/components/CostBar.d.ts +19 -0
- package/dist/cli/ink/components/CostBar.js +35 -0
- package/dist/cli/ink/components/HookStatus.d.ts +15 -0
- package/dist/cli/ink/components/HookStatus.js +7 -0
- package/dist/cli/ink/components/PermissionPrompt.d.ts +21 -0
- package/dist/cli/ink/components/PermissionPrompt.js +51 -0
- package/dist/cli/ink/components/PlanView.d.ts +23 -0
- package/dist/cli/ink/components/PlanView.js +26 -0
- package/dist/cli/ink/components/ProviderList.d.ts +16 -0
- package/dist/cli/ink/components/ProviderList.js +16 -0
- package/dist/cli/ink/components/SessionHeader.d.ts +15 -0
- package/dist/cli/ink/components/SessionHeader.js +15 -0
- package/dist/cli/ink/components/StreamingMessage.d.ts +20 -0
- package/dist/cli/ink/components/StreamingMessage.js +27 -0
- package/dist/cli/ink/components/SuggestionBar.d.ts +15 -0
- package/dist/cli/ink/components/SuggestionBar.js +28 -0
- package/dist/cli/ink/components/SystemHealth.d.ts +20 -0
- package/dist/cli/ink/components/SystemHealth.js +39 -0
- package/dist/cli/ink/components/TaskList.d.ts +17 -0
- package/dist/cli/ink/components/TaskList.js +59 -0
- package/dist/cli/ink/components/ToolCall.d.ts +17 -0
- package/dist/cli/ink/components/ToolCall.js +43 -0
- package/dist/cli/ink/index.d.ts +23 -0
- package/dist/cli/ink/index.js +15 -0
- package/dist/cli/ink/keybindings.d.ts +35 -0
- package/dist/cli/ink/keybindings.js +105 -0
- package/dist/cli/ink/markdown-renderer.d.ts +47 -0
- package/dist/cli/ink/markdown-renderer.js +380 -0
- package/dist/cli/ink/output-styles.d.ts +39 -0
- package/dist/cli/ink/output-styles.js +119 -0
- package/dist/cli/interactive/auto-serve.d.ts +38 -0
- package/dist/cli/interactive/auto-serve.js +209 -0
- package/dist/cli/interactive/index.d.ts +25 -0
- package/dist/cli/interactive/index.js +23 -0
- package/dist/cli/interactive/picker.d.ts +28 -0
- package/dist/cli/interactive/picker.js +153 -0
- package/dist/cli/interactive/renderer.d.ts +26 -0
- package/dist/cli/interactive/renderer.js +555 -0
- package/dist/cli/interactive/repl.d.ts +14 -0
- package/dist/cli/interactive/repl.js +1516 -0
- package/dist/cli/interactive/stream-client.d.ts +59 -0
- package/dist/cli/interactive/stream-client.js +506 -0
- package/dist/cli/interactive/types.d.ts +121 -0
- package/dist/cli/interactive/types.js +10 -0
- package/dist/cli/utils/api.d.ts +9 -0
- package/dist/cli/utils/api.js +58 -2
- package/dist/cron/natural-language.d.ts +54 -0
- package/dist/cron/natural-language.js +569 -0
- package/dist/cron/scheduler.d.ts +34 -4
- package/dist/cron/scheduler.js +141 -9
- package/dist/cron/templates.d.ts +1 -1
- package/dist/cron/templates.js +219 -0
- package/dist/feeds/feed-engine.d.ts +149 -0
- package/dist/feeds/feed-engine.js +600 -0
- package/dist/feeds/index.d.ts +9 -0
- package/dist/feeds/index.js +8 -0
- package/dist/gateway/router.js +6 -1
- package/dist/hooks/built-in/audit-log.d.ts +11 -0
- package/dist/hooks/built-in/audit-log.js +84 -0
- package/dist/hooks/built-in/cost-warning.d.ts +10 -0
- package/dist/hooks/built-in/cost-warning.js +59 -0
- package/dist/hooks/built-in/dangerous-tool.d.ts +32 -0
- package/dist/hooks/built-in/dangerous-tool.js +80 -0
- package/dist/hooks/built-in/index.d.ts +14 -0
- package/dist/hooks/built-in/index.js +20 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.js +6 -0
- package/dist/hooks/loader.d.ts +17 -0
- package/dist/hooks/loader.js +142 -0
- package/dist/hooks/registry.d.ts +62 -0
- package/dist/hooks/registry.js +127 -0
- package/dist/integrations/web-search.js +6 -3
- package/dist/memory/index.d.ts +1 -0
- package/dist/memory/index.js +2 -0
- package/dist/memory/memory-service.js +14 -13
- package/dist/memory/observational.d.ts +62 -0
- package/dist/memory/observational.js +396 -0
- package/dist/middleware/content-filter.d.ts +22 -0
- package/dist/middleware/content-filter.js +69 -0
- package/dist/middleware/request-validator.d.ts +159 -0
- package/dist/middleware/request-validator.js +93 -0
- package/dist/plugins/sdk.d.ts +22 -0
- package/dist/plugins/sdk.js +17 -1
- package/dist/projects/types.d.ts +10 -10
- package/dist/providers/ai-sdk.d.ts +11 -0
- package/dist/providers/ai-sdk.js +78 -19
- package/dist/providers/core/models.js +67 -1
- package/dist/providers/core/types.d.ts +3 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/smart-router.d.ts +118 -0
- package/dist/providers/smart-router.js +685 -0
- package/dist/providers/types.d.ts +16 -16
- package/dist/routes/agents.js +50 -0
- package/dist/routes/auth.js +8 -1
- package/dist/routes/chat.js +259 -14
- package/dist/routes/costs.js +32 -0
- package/dist/routes/cron.js +80 -5
- package/dist/routes/feeds.d.ts +10 -0
- package/dist/routes/feeds.js +168 -0
- package/dist/routes/mcp.js +21 -0
- package/dist/routes/memory.js +130 -0
- package/dist/routes/skills.js +129 -0
- package/dist/routes/teams.d.ts +9 -0
- package/dist/routes/teams.js +210 -0
- package/dist/routes/tools.js +14 -0
- package/dist/routes/users.js +2 -0
- package/dist/server/route-loader.js +3 -1
- package/dist/server/stream-bridge.d.ts +19 -0
- package/dist/server/stream-bridge.js +38 -0
- package/dist/server.js +310 -36
- package/dist/skills/marketplace.d.ts +87 -0
- package/dist/skills/marketplace.js +268 -0
- package/dist/storage/index.d.ts +14 -0
- package/dist/storage/index.js +64 -3
- package/dist/storage/schema.d.ts +4 -4
- package/dist/storage/schema.js +1 -1
- package/dist/teams/index.d.ts +110 -0
- package/dist/teams/index.js +365 -0
- package/dist/tickets/types.d.ts +39 -39
- package/dist/types/summary.d.ts +5 -5
- package/dist/utils/auto-update.d.ts +23 -0
- package/dist/utils/auto-update.js +157 -0
- package/dist/utils/offline-detect.d.ts +55 -0
- package/dist/utils/offline-detect.js +121 -0
- package/dist/utils/pid-file.d.ts +36 -0
- package/dist/utils/pid-file.js +125 -0
- package/dist/utils/prevent-sleep.d.ts +27 -0
- package/dist/utils/prevent-sleep.js +95 -0
- package/dist/utils/sanitizer.d.ts +57 -0
- package/dist/utils/sanitizer.js +174 -0
- package/docker-compose.yml +13 -137
- package/package.json +31 -6
- package/skills/deploy-cloudflare/SKILL.md +62 -0
- package/skills/deploy-vercel/SKILL.md +67 -0
- package/skills/docker-deploy/SKILL.md +158 -0
- package/skills/full-stack-builder/SKILL.md +92 -0
- package/skills/humanizer/SKILL.md +488 -0
- package/skills/profclaw-assistant/SKILL.md +85 -56
- package/ui/dist/assets/ActivityView-Da6HQ8ws.js +1 -0
- package/ui/dist/assets/AgentList-H58R0kX3.js +1 -0
- package/ui/dist/assets/AnalyticsDashboard-B28AeRsc.js +1 -0
- package/ui/dist/assets/AreaChart-DwLzeAQ8.js +1 -0
- package/ui/dist/assets/CartesianChart-piKQsTAR.js +36 -0
- package/ui/dist/assets/ChatView-Dbj8rxU5.js +10 -0
- package/ui/dist/assets/CostsDashboard-C6F5df0F.js +1 -0
- package/ui/dist/assets/EstimateSelect-wga0rUKX.js +1 -0
- package/ui/dist/assets/FeedDashboard-Ef6FEzEf.js +1 -0
- package/ui/dist/assets/FloatingChatbot-0yhkUeCq.js +2 -0
- package/ui/dist/assets/InviteCodeManagement-tUXfx4Bc.js +2 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/ui/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/ui/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/ui/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/ui/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/ui/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/ui/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/ui/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/ui/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/ui/dist/assets/MarketplacePage-DGrLtolR.js +1 -0
- package/ui/dist/assets/{ProjectDetail--gPfvATB.js → ProjectDetail-BgWvA6UP.js} +2 -2
- package/ui/dist/assets/ProjectIcon-TDuliqwg.js +1 -0
- package/ui/dist/assets/ProjectList-DXgM4187.js +1 -0
- package/ui/dist/assets/{Settings-1kaf7VHE.js → Settings-xA8Zhi3p.js} +3 -3
- package/ui/dist/assets/StatusIndicator-B8vfFAxg.js +1 -0
- package/ui/dist/assets/{SummaryDetail-DV3AmONk.js → SummaryDetail-eedRfTtF.js} +2 -2
- package/ui/dist/assets/SummaryList-CLNX2P84.js +1 -0
- package/ui/dist/assets/TaskDetail-BtWclNiR.js +1 -0
- package/ui/dist/assets/TaskList-JjODAgSc.js +1 -0
- package/ui/dist/assets/TeamsPage-CBK5iAyx.js +1 -0
- package/ui/dist/assets/TicketBoard-C9aJNNYp.js +1 -0
- package/ui/dist/assets/TicketDetail-CV5JmL31.js +1 -0
- package/ui/dist/assets/TicketList-68V4lzUz.js +1 -0
- package/ui/dist/assets/UserManagement-DKTb6UpE.js +2 -0
- package/ui/dist/assets/ViewSwitcher-BvdQht2Y.js +1 -0
- package/ui/dist/assets/alert-dialog-O6qBOv_f.js +1 -0
- package/ui/dist/assets/{archive-BsLa7brF.js → archive-CX7UvZpf.js} +1 -1
- package/ui/dist/assets/badge-BbfnwDJP.js +1 -0
- package/ui/dist/assets/{bug-CmZI7jqM.js → bug-3WX0394-.js} +1 -1
- package/ui/dist/assets/{calendar-Bf0t2B82.js → calendar-buq77TaS.js} +1 -1
- package/ui/dist/assets/{chevron-up-CoUsOvZj.js → chevron-up-4ymsBJRo.js} +1 -1
- package/ui/dist/assets/{circle-x-Dgw11LgT.js → circle-x-ByXtwR6Y.js} +1 -1
- package/ui/dist/assets/constants-CVdDh7p0.js +1 -0
- package/ui/dist/assets/{cpu-DiPMQICV.js → cpu-CiuoCeDY.js} +1 -1
- package/ui/dist/assets/{database-BwTfupDi.js → database-BWXSBg5a.js} +1 -1
- package/ui/dist/assets/dialog-lDg4NvMV.js +1 -0
- package/ui/dist/assets/dollar-sign-Dmijd6DP.js +1 -0
- package/ui/dist/assets/{ellipsis-UJx4Xnf6.js → ellipsis-vT-5SVIp.js} +1 -1
- package/ui/dist/assets/{ellipsis-vertical-DoULYEKn.js → ellipsis-vertical-B4tAX_bL.js} +1 -1
- package/ui/dist/assets/feature-markdown-DBo5Q7uq.js +289 -0
- package/ui/dist/assets/{file-code-B2UrJLwi.js → file-code-ChOWdKXf.js} +1 -1
- package/ui/dist/assets/{folder-open-BJi577JH.js → folder-open-CkOUbIiP.js} +1 -1
- package/ui/dist/assets/{funnel-PkaD_HSR.js → funnel-uZkoSPP-.js} +1 -1
- package/ui/dist/assets/{git-branch-C_K30am0.js → git-branch-CwvUxj7C.js} +1 -1
- package/ui/dist/assets/{git-commit-horizontal-IT6ecxWQ.js → git-commit-horizontal-lxPzCvhD.js} +1 -1
- package/ui/dist/assets/{globe-f-jjCa_g.js → globe-D_WpJdsj.js} +1 -1
- package/ui/dist/assets/{hash-DNEv8Elo.js → hash-CA0hJ7vh.js} +1 -1
- package/ui/dist/assets/{history-BQSBo_1Q.js → history-CEWMLELs.js} +1 -1
- package/ui/dist/assets/inbox-ehtOptTV.js +1 -0
- package/ui/dist/assets/{index-nS3EErDg.js → index-C1rhbml4.js} +3 -3
- package/ui/dist/assets/index-CR8gfCHv.js +1 -0
- package/ui/dist/assets/index-DVXMpWai.js +1 -0
- package/ui/dist/assets/index-DaDJMM2v.js +1 -0
- package/ui/dist/assets/index-Djdq_0xu.js +1 -0
- package/ui/dist/assets/index-M46Gcb8K.css +1 -0
- package/ui/dist/assets/index-sEBN7w8J.js +109 -0
- package/ui/dist/assets/layers-C6Mhf8Nk.js +1 -0
- package/ui/dist/assets/{layout-dashboard-CcKt1hXw.js → layout-dashboard-BRUM0kpT.js} +1 -1
- package/ui/dist/assets/{lightbulb-Jhp7FvbU.js → lightbulb-CN2q1O5l.js} +1 -1
- package/ui/dist/assets/{link-2-DdO7ostF.js → link-2-CC4E28yJ.js} +1 -1
- package/ui/dist/assets/markdown-renderer-C6ENbB0u.js +10 -0
- package/ui/dist/assets/markdown-renderer-CfVKi3_s.css +1 -0
- package/ui/dist/assets/{message-square-CBgH65X7.js → message-square-Bbb241am.js} +1 -1
- package/ui/dist/assets/package-CwT3IzFx.js +1 -0
- package/ui/dist/assets/{pencil-CYXCEPQh.js → pencil-CDmiHzoj.js} +1 -1
- package/ui/dist/assets/{play-d1ONaH0-.js → play-tjy5jMQX.js} +1 -1
- package/ui/dist/assets/popover-CFHZf3pE.js +1 -0
- package/ui/dist/assets/progress-BboUHuLf.js +1 -0
- package/ui/dist/assets/{rocket-DhvUetsk.js → rocket--8ZHgdXJ.js} +1 -1
- package/ui/dist/assets/select-n108rXny.js +1 -0
- package/ui/dist/assets/{send-P0r5D7td.js → send-Cu7MR2Qh.js} +1 -1
- package/ui/dist/assets/server-DmodxZp-.js +1 -0
- package/ui/dist/assets/{settings-2-ocj5uHGx.js → settings-2-CkRNqkxj.js} +1 -1
- package/ui/dist/assets/sheet-7aUJkyzU.js +1 -0
- package/ui/dist/assets/{shield-check-DfVdE34l.js → shield-check-ViI3nMKE.js} +1 -1
- package/ui/dist/assets/{shield-off-8l0J6R-8.js → shield-off-DN3tagkn.js} +1 -1
- package/ui/dist/assets/skeleton-C0E1Nfro.js +1 -0
- package/ui/dist/assets/{smartphone-77_g3SQn.js → smartphone-5FghiXpA.js} +1 -1
- package/ui/dist/assets/{square-Ckzsr3Rn.js → square-DiNSx8K7.js} +1 -1
- package/ui/dist/assets/star-DhdFVidS.js +1 -0
- package/ui/dist/assets/switch-CIgVbZqQ.js +1 -0
- package/ui/dist/assets/table-BC56FVMV.js +1 -0
- package/ui/dist/assets/{tag-C35mgoEv.js → tag-CH_vQliw.js} +1 -1
- package/ui/dist/assets/textarea-CxDiKFXZ.js +1 -0
- package/ui/dist/assets/{timer-DHJBS2w1.js → timer-CdGVTb60.js} +1 -1
- package/ui/dist/assets/tooltip-BuW9A5UO.js +1 -0
- package/ui/dist/assets/{trash-2-keO5tKPE.js → trash-2-CucZJL0N.js} +1 -1
- package/ui/dist/assets/trending-down-BCezC1z2.js +1 -0
- package/ui/dist/assets/{trending-up-BBv8KbrY.js → trending-up-C5OYX2k2.js} +1 -1
- package/ui/dist/assets/vendor-query-C0p7b53x.js +4 -0
- package/ui/dist/assets/vendor-react-Mc5_kfYG.js +12 -0
- package/ui/dist/assets/vendor-ui-CXPAUBFv.js +51 -0
- package/ui/dist/assets/{wand-sparkles-BusQ52ZK.js → wand-sparkles-BaH6pJnc.js} +1 -1
- package/ui/dist/assets/{wrench-02YaOSiK.js → wrench-CjxjP6ok.js} +1 -1
- package/ui/dist/index.html +5 -2
- package/ui/dist/assets/ActivityView-BeshZXmE.js +0 -1
- package/ui/dist/assets/AgentList-QVHeldPi.js +0 -1
- package/ui/dist/assets/AnalyticsDashboard-C9R97dXE.js +0 -1
- package/ui/dist/assets/AreaChart-B73gaiVQ.js +0 -1
- package/ui/dist/assets/CartesianChart-CXYL2R-A.js +0 -36
- package/ui/dist/assets/ChatView-qjZErlrp.js +0 -10
- package/ui/dist/assets/CostsDashboard-O4DCLy1i.js +0 -1
- package/ui/dist/assets/EstimateSelect-1hQf4Osk.js +0 -1
- package/ui/dist/assets/FloatingChatbot-BZBzrJxd.js +0 -2
- package/ui/dist/assets/InviteCodeManagement-LEoGqYeA.js +0 -2
- package/ui/dist/assets/ProjectIcon-Chd_ofsw.js +0 -1
- package/ui/dist/assets/ProjectList-BvUfVB6c.js +0 -4
- package/ui/dist/assets/StatusIndicator-pRfkNcdV.js +0 -1
- package/ui/dist/assets/SummaryList-B6kXiTxL.js +0 -1
- package/ui/dist/assets/TaskDetail-CV6CzbOS.js +0 -1
- package/ui/dist/assets/TaskList-DL7brQKd.js +0 -1
- package/ui/dist/assets/TicketBoard-CrkkFj7C.js +0 -1
- package/ui/dist/assets/TicketDetail-hnnYclpD.js +0 -1
- package/ui/dist/assets/TicketList-CsDAyQCL.js +0 -1
- package/ui/dist/assets/UserManagement-BGFQyTSr.js +0 -2
- package/ui/dist/assets/ViewSwitcher-CnL0OqA8.js +0 -1
- package/ui/dist/assets/alert-dialog-SKM6Gjz4.js +0 -7
- package/ui/dist/assets/badge-CVHH1a-v.js +0 -1
- package/ui/dist/assets/brain-6o_RHVpe.js +0 -1
- package/ui/dist/assets/constants-Q5Zivl-a.js +0 -1
- package/ui/dist/assets/dialog-BUqN9Psj.js +0 -1
- package/ui/dist/assets/index-BUmnwPQr.js +0 -1
- package/ui/dist/assets/index-BfF5G4Cw.js +0 -1
- package/ui/dist/assets/index-C8N375c2.js +0 -1
- package/ui/dist/assets/index-CuxnqVVz.css +0 -1
- package/ui/dist/assets/index-CzMM3QOk.js +0 -1
- package/ui/dist/assets/index-lJlNPFVJ.js +0 -67
- package/ui/dist/assets/layers-jFqVrWMD.js +0 -1
- package/ui/dist/assets/markdown-renderer-n1ToC4XQ.js +0 -36
- package/ui/dist/assets/popover-CrmZgoWu.js +0 -1
- package/ui/dist/assets/progress-uv4SPkL5.js +0 -1
- package/ui/dist/assets/select-CeQ8AHGy.js +0 -1
- package/ui/dist/assets/server-CVHTZB72.js +0 -1
- package/ui/dist/assets/sheet-DuQExSho.js +0 -1
- package/ui/dist/assets/skeleton-TFiFJ3nB.js +0 -1
- package/ui/dist/assets/switch-CAePkd6k.js +0 -1
- package/ui/dist/assets/table-ZjAZ7hkt.js +0 -1
- package/ui/dist/assets/textarea-DsVPnSgR.js +0 -1
- package/ui/dist/assets/tooltip-BYmQ331W.js +0 -1
|
@@ -238,7 +238,7 @@ export declare const ChatMessageSchema: z.ZodObject<{
|
|
|
238
238
|
id: string;
|
|
239
239
|
timestamp: string;
|
|
240
240
|
content: string;
|
|
241
|
-
role: "user" | "system" | "
|
|
241
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
242
242
|
name?: string | undefined;
|
|
243
243
|
tokensUsed?: number | undefined;
|
|
244
244
|
toolCallId?: string | undefined;
|
|
@@ -247,7 +247,7 @@ export declare const ChatMessageSchema: z.ZodObject<{
|
|
|
247
247
|
id: string;
|
|
248
248
|
timestamp: string;
|
|
249
249
|
content: string;
|
|
250
|
-
role: "user" | "system" | "
|
|
250
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
251
251
|
name?: string | undefined;
|
|
252
252
|
tokensUsed?: number | undefined;
|
|
253
253
|
toolCallId?: string | undefined;
|
|
@@ -270,7 +270,7 @@ export declare const ChatCompletionRequestSchema: z.ZodObject<{
|
|
|
270
270
|
id: string;
|
|
271
271
|
timestamp: string;
|
|
272
272
|
content: string;
|
|
273
|
-
role: "user" | "system" | "
|
|
273
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
274
274
|
name?: string | undefined;
|
|
275
275
|
tokensUsed?: number | undefined;
|
|
276
276
|
toolCallId?: string | undefined;
|
|
@@ -279,7 +279,7 @@ export declare const ChatCompletionRequestSchema: z.ZodObject<{
|
|
|
279
279
|
id: string;
|
|
280
280
|
timestamp: string;
|
|
281
281
|
content: string;
|
|
282
|
-
role: "user" | "system" | "
|
|
282
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
283
283
|
name?: string | undefined;
|
|
284
284
|
tokensUsed?: number | undefined;
|
|
285
285
|
toolCallId?: string | undefined;
|
|
@@ -311,7 +311,7 @@ export declare const ChatCompletionRequestSchema: z.ZodObject<{
|
|
|
311
311
|
id: string;
|
|
312
312
|
timestamp: string;
|
|
313
313
|
content: string;
|
|
314
|
-
role: "user" | "system" | "
|
|
314
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
315
315
|
name?: string | undefined;
|
|
316
316
|
tokensUsed?: number | undefined;
|
|
317
317
|
toolCallId?: string | undefined;
|
|
@@ -328,14 +328,14 @@ export declare const ChatCompletionRequestSchema: z.ZodObject<{
|
|
|
328
328
|
description: string;
|
|
329
329
|
parameters: Record<string, unknown>;
|
|
330
330
|
}[] | undefined;
|
|
331
|
-
systemPrompt?: string | undefined;
|
|
332
331
|
maxTokens?: number | undefined;
|
|
332
|
+
systemPrompt?: string | undefined;
|
|
333
333
|
}, {
|
|
334
334
|
messages: {
|
|
335
335
|
id: string;
|
|
336
336
|
timestamp: string;
|
|
337
337
|
content: string;
|
|
338
|
-
role: "user" | "system" | "
|
|
338
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
339
339
|
name?: string | undefined;
|
|
340
340
|
tokensUsed?: number | undefined;
|
|
341
341
|
toolCallId?: string | undefined;
|
|
@@ -352,9 +352,9 @@ export declare const ChatCompletionRequestSchema: z.ZodObject<{
|
|
|
352
352
|
description: string;
|
|
353
353
|
parameters: Record<string, unknown>;
|
|
354
354
|
}[] | undefined;
|
|
355
|
+
maxTokens?: number | undefined;
|
|
355
356
|
systemPrompt?: string | undefined;
|
|
356
357
|
temperature?: number | undefined;
|
|
357
|
-
maxTokens?: number | undefined;
|
|
358
358
|
}>;
|
|
359
359
|
export type ChatCompletionRequest = z.infer<typeof ChatCompletionRequestSchema>;
|
|
360
360
|
export declare const ChatCompletionResponseSchema: z.ZodObject<{
|
|
@@ -374,7 +374,7 @@ export declare const ChatCompletionResponseSchema: z.ZodObject<{
|
|
|
374
374
|
id: string;
|
|
375
375
|
timestamp: string;
|
|
376
376
|
content: string;
|
|
377
|
-
role: "user" | "system" | "
|
|
377
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
378
378
|
name?: string | undefined;
|
|
379
379
|
tokensUsed?: number | undefined;
|
|
380
380
|
toolCallId?: string | undefined;
|
|
@@ -383,7 +383,7 @@ export declare const ChatCompletionResponseSchema: z.ZodObject<{
|
|
|
383
383
|
id: string;
|
|
384
384
|
timestamp: string;
|
|
385
385
|
content: string;
|
|
386
|
-
role: "user" | "system" | "
|
|
386
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
387
387
|
name?: string | undefined;
|
|
388
388
|
tokensUsed?: number | undefined;
|
|
389
389
|
toolCallId?: string | undefined;
|
|
@@ -425,7 +425,7 @@ export declare const ChatCompletionResponseSchema: z.ZodObject<{
|
|
|
425
425
|
id: string;
|
|
426
426
|
timestamp: string;
|
|
427
427
|
content: string;
|
|
428
|
-
role: "user" | "system" | "
|
|
428
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
429
429
|
name?: string | undefined;
|
|
430
430
|
tokensUsed?: number | undefined;
|
|
431
431
|
toolCallId?: string | undefined;
|
|
@@ -452,7 +452,7 @@ export declare const ChatCompletionResponseSchema: z.ZodObject<{
|
|
|
452
452
|
id: string;
|
|
453
453
|
timestamp: string;
|
|
454
454
|
content: string;
|
|
455
|
-
role: "user" | "system" | "
|
|
455
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
456
456
|
name?: string | undefined;
|
|
457
457
|
tokensUsed?: number | undefined;
|
|
458
458
|
toolCallId?: string | undefined;
|
|
@@ -494,7 +494,7 @@ export declare const ConversationSchema: z.ZodObject<{
|
|
|
494
494
|
id: string;
|
|
495
495
|
timestamp: string;
|
|
496
496
|
content: string;
|
|
497
|
-
role: "user" | "system" | "
|
|
497
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
498
498
|
name?: string | undefined;
|
|
499
499
|
tokensUsed?: number | undefined;
|
|
500
500
|
toolCallId?: string | undefined;
|
|
@@ -503,7 +503,7 @@ export declare const ConversationSchema: z.ZodObject<{
|
|
|
503
503
|
id: string;
|
|
504
504
|
timestamp: string;
|
|
505
505
|
content: string;
|
|
506
|
-
role: "user" | "system" | "
|
|
506
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
507
507
|
name?: string | undefined;
|
|
508
508
|
tokensUsed?: number | undefined;
|
|
509
509
|
toolCallId?: string | undefined;
|
|
@@ -530,7 +530,7 @@ export declare const ConversationSchema: z.ZodObject<{
|
|
|
530
530
|
id: string;
|
|
531
531
|
timestamp: string;
|
|
532
532
|
content: string;
|
|
533
|
-
role: "user" | "system" | "
|
|
533
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
534
534
|
name?: string | undefined;
|
|
535
535
|
tokensUsed?: number | undefined;
|
|
536
536
|
toolCallId?: string | undefined;
|
|
@@ -552,7 +552,7 @@ export declare const ConversationSchema: z.ZodObject<{
|
|
|
552
552
|
id: string;
|
|
553
553
|
timestamp: string;
|
|
554
554
|
content: string;
|
|
555
|
-
role: "user" | "system" | "
|
|
555
|
+
role: "user" | "system" | "tool" | "assistant";
|
|
556
556
|
name?: string | undefined;
|
|
557
557
|
tokensUsed?: number | undefined;
|
|
558
558
|
toolCallId?: string | undefined;
|
package/dist/routes/agents.js
CHANGED
|
@@ -43,5 +43,55 @@ agents.get('/types', (c) => {
|
|
|
43
43
|
types: registry.getAdapterTypes(),
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
|
+
// --- Multi-Agent Orchestration ---
|
|
47
|
+
import { z } from 'zod';
|
|
48
|
+
import { orchestrate, cancelOrchestration, listActiveOrchestrations } from '../agents/orchestrator.js';
|
|
49
|
+
const subAgentSchema = z.object({
|
|
50
|
+
id: z.string().optional(),
|
|
51
|
+
name: z.string(),
|
|
52
|
+
prompt: z.string(),
|
|
53
|
+
systemPrompt: z.string().optional(),
|
|
54
|
+
model: z.string().optional(),
|
|
55
|
+
maxTokens: z.number().optional(),
|
|
56
|
+
timeoutMs: z.number().optional(),
|
|
57
|
+
allowedTools: z.array(z.string()).optional(),
|
|
58
|
+
effort: z.enum(['low', 'medium', 'high']).optional(),
|
|
59
|
+
});
|
|
60
|
+
const orchestrateSchema = z.object({
|
|
61
|
+
name: z.string().min(1).max(200),
|
|
62
|
+
pattern: z.enum(['fan_out', 'pipeline', 'debate', 'custom']),
|
|
63
|
+
agents: z.array(subAgentSchema).min(1).max(10),
|
|
64
|
+
synthesizerPrompt: z.string().optional(),
|
|
65
|
+
judgePrompt: z.string().optional(),
|
|
66
|
+
timeoutMs: z.number().optional(),
|
|
67
|
+
failFast: z.boolean().optional(),
|
|
68
|
+
});
|
|
69
|
+
/** Execute a multi-agent orchestration */
|
|
70
|
+
agents.post('/orchestrate', async (c) => {
|
|
71
|
+
const body = await c.req.json();
|
|
72
|
+
const parsed = orchestrateSchema.safeParse(body);
|
|
73
|
+
if (!parsed.success) {
|
|
74
|
+
return c.json({ success: false, error: { code: 'VALIDATION_ERROR', message: parsed.error.message } }, 400);
|
|
75
|
+
}
|
|
76
|
+
const config = {
|
|
77
|
+
id: crypto.randomUUID(),
|
|
78
|
+
...parsed.data,
|
|
79
|
+
agents: parsed.data.agents.map((a, i) => ({
|
|
80
|
+
...a,
|
|
81
|
+
id: a.id || `agent-${i}`,
|
|
82
|
+
})),
|
|
83
|
+
};
|
|
84
|
+
const result = await orchestrate(config);
|
|
85
|
+
return c.json({ success: result.success, data: result });
|
|
86
|
+
});
|
|
87
|
+
/** Cancel a running orchestration */
|
|
88
|
+
agents.post('/orchestrate/:id/cancel', (c) => {
|
|
89
|
+
const cancelled = cancelOrchestration(c.req.param('id'));
|
|
90
|
+
return c.json({ success: cancelled });
|
|
91
|
+
});
|
|
92
|
+
/** List active orchestrations */
|
|
93
|
+
agents.get('/orchestrate/active', (c) => {
|
|
94
|
+
return c.json({ success: true, data: listActiveOrchestrations() });
|
|
95
|
+
});
|
|
46
96
|
export { agents as agentsRoutes };
|
|
47
97
|
//# sourceMappingURL=agents.js.map
|
package/dist/routes/auth.js
CHANGED
|
@@ -99,8 +99,15 @@ authRoutes.post('/signup', signupLimiter, async (c) => {
|
|
|
99
99
|
// Check registration mode
|
|
100
100
|
const settings = await getSettingsRaw();
|
|
101
101
|
const mode = settings.system.registrationMode;
|
|
102
|
+
// Allow first user signup without invite code (bootstrap admin)
|
|
103
|
+
const db = getDb();
|
|
104
|
+
let isFirstUser = false;
|
|
105
|
+
if (db) {
|
|
106
|
+
const existingUsers = await db.select({ id: users.id }).from(users).limit(1);
|
|
107
|
+
isFirstUser = existingUsers.length === 0;
|
|
108
|
+
}
|
|
102
109
|
let inviteRecord;
|
|
103
|
-
if (mode === 'invite') {
|
|
110
|
+
if (mode === 'invite' && !isFirstUser) {
|
|
104
111
|
if (!inviteCode) {
|
|
105
112
|
return c.json({ error: 'Registration requires an invite code' }, 403);
|
|
106
113
|
}
|
package/dist/routes/chat.js
CHANGED
|
@@ -9,8 +9,18 @@ import { streamText } from "hono/streaming";
|
|
|
9
9
|
import { zValidator } from "@hono/zod-validator";
|
|
10
10
|
import { z } from "zod";
|
|
11
11
|
import { randomUUID } from "node:crypto";
|
|
12
|
+
import { routeQuery, recordRoutingDecision, isSmartRouterEnabled, getCostComparison, } from "../providers/smart-router.js";
|
|
12
13
|
import { logger } from "../utils/logger.js";
|
|
14
|
+
import { rateLimit } from "../middleware/rate-limit.js";
|
|
15
|
+
import { contentFilter } from "../middleware/content-filter.js";
|
|
13
16
|
const chatRoutes = new Hono();
|
|
17
|
+
// Per-IP sliding-window rate limiter for chat send endpoints
|
|
18
|
+
const chatMaxRequests = parseInt(process.env['CHAT_RATE_LIMIT'] ?? '20', 10);
|
|
19
|
+
const chatRateLimiter = rateLimit({
|
|
20
|
+
maxRequests: chatMaxRequests,
|
|
21
|
+
windowMs: 60_000,
|
|
22
|
+
message: `Chat rate limit exceeded. Maximum ${chatMaxRequests} messages per minute.`,
|
|
23
|
+
});
|
|
14
24
|
let chatRuntimePromise = null;
|
|
15
25
|
let ProviderTypeSchema;
|
|
16
26
|
let aiProvider;
|
|
@@ -26,6 +36,7 @@ let listConversations;
|
|
|
26
36
|
let deleteConversation;
|
|
27
37
|
let addMessage;
|
|
28
38
|
let getConversationMessages;
|
|
39
|
+
let deleteMessage;
|
|
29
40
|
let getRecentConversationsWithPreview;
|
|
30
41
|
let compactMessages;
|
|
31
42
|
let getMemoryStats;
|
|
@@ -65,6 +76,7 @@ async function ensureChatRuntime() {
|
|
|
65
76
|
deleteConversation = chatModule.deleteConversation;
|
|
66
77
|
addMessage = chatModule.addMessage;
|
|
67
78
|
getConversationMessages = chatModule.getConversationMessages;
|
|
79
|
+
deleteMessage = chatModule.deleteMessage;
|
|
68
80
|
getRecentConversationsWithPreview =
|
|
69
81
|
chatModule.getRecentConversationsWithPreview;
|
|
70
82
|
compactMessages = chatModule.compactMessages;
|
|
@@ -168,6 +180,84 @@ chatRoutes.get("/model-capability", async (c) => {
|
|
|
168
180
|
const resolved = MODEL_ALIASES[model.toLowerCase()]?.model ?? model;
|
|
169
181
|
return c.json(getModelRouting(resolved));
|
|
170
182
|
});
|
|
183
|
+
/**
|
|
184
|
+
* POST /api/chat/send
|
|
185
|
+
* Simple one-shot chat - send a message and get a response
|
|
186
|
+
*/
|
|
187
|
+
chatRoutes.post("/send", chatRateLimiter, contentFilter(), zValidator("json", z.object({
|
|
188
|
+
message: z.string(),
|
|
189
|
+
model: z.string().optional(),
|
|
190
|
+
systemPrompt: z.string().optional(),
|
|
191
|
+
temperature: z.number().min(0).max(2).optional(),
|
|
192
|
+
maxTokens: z.number().positive().optional(),
|
|
193
|
+
})), async (c) => {
|
|
194
|
+
const body = c.req.valid("json");
|
|
195
|
+
try {
|
|
196
|
+
const messages = [
|
|
197
|
+
{
|
|
198
|
+
id: randomUUID(),
|
|
199
|
+
role: "user",
|
|
200
|
+
content: body.message,
|
|
201
|
+
timestamp: new Date().toISOString(),
|
|
202
|
+
},
|
|
203
|
+
];
|
|
204
|
+
// Smart routing: auto-select model if none specified
|
|
205
|
+
let routing;
|
|
206
|
+
let modelToUse = body.model;
|
|
207
|
+
if (!body.model && isSmartRouterEnabled()) {
|
|
208
|
+
const providers = new Set(aiProvider.getConfiguredProviders());
|
|
209
|
+
routing = routeQuery(body.message, providers);
|
|
210
|
+
modelToUse = routing.selectedModel.id;
|
|
211
|
+
recordRoutingDecision(routing);
|
|
212
|
+
}
|
|
213
|
+
const response = await aiProvider.chat({
|
|
214
|
+
messages,
|
|
215
|
+
model: modelToUse,
|
|
216
|
+
systemPrompt: body.systemPrompt,
|
|
217
|
+
temperature: body.temperature,
|
|
218
|
+
maxTokens: body.maxTokens,
|
|
219
|
+
});
|
|
220
|
+
// Track token usage for cost dashboard
|
|
221
|
+
if (response.usage?.totalTokens && response.model) {
|
|
222
|
+
await ensureChatRuntime();
|
|
223
|
+
trackChatUsage(response.model, response.usage.totalTokens, response.usage.promptTokens, response.usage.completionTokens);
|
|
224
|
+
}
|
|
225
|
+
return c.json({
|
|
226
|
+
id: response.id,
|
|
227
|
+
provider: response.provider,
|
|
228
|
+
model: response.model,
|
|
229
|
+
reply: response.content,
|
|
230
|
+
finishReason: response.finishReason,
|
|
231
|
+
usage: response.usage,
|
|
232
|
+
duration: response.duration,
|
|
233
|
+
...(routing && {
|
|
234
|
+
routing: {
|
|
235
|
+
smartRouted: true,
|
|
236
|
+
complexity: routing.complexity.tier,
|
|
237
|
+
confidence: Math.round(routing.complexity.confidence * 100),
|
|
238
|
+
reasoning: routing.complexity.reasoning,
|
|
239
|
+
savings: `${routing.savingsPercent}%`,
|
|
240
|
+
estimatedCost: `$${routing.estimatedCost.toFixed(4)}`,
|
|
241
|
+
summary: getCostComparison(routing),
|
|
242
|
+
...(routing.missingProviderHint && {
|
|
243
|
+
tip: {
|
|
244
|
+
addProvider: routing.missingProviderHint.provider,
|
|
245
|
+
reason: routing.missingProviderHint.reason,
|
|
246
|
+
savings: routing.missingProviderHint.estimatedSavings,
|
|
247
|
+
signupUrl: routing.missingProviderHint.signupUrl,
|
|
248
|
+
},
|
|
249
|
+
}),
|
|
250
|
+
},
|
|
251
|
+
}),
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
catch (error) {
|
|
255
|
+
logger.error("[Chat] Send error:", error instanceof Error ? error : undefined);
|
|
256
|
+
return c.json({
|
|
257
|
+
error: error instanceof Error ? error.message : "Chat send failed",
|
|
258
|
+
}, 500);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
171
261
|
/**
|
|
172
262
|
* POST /api/chat/completions
|
|
173
263
|
* Generate a chat completion
|
|
@@ -183,11 +273,37 @@ chatRoutes.post("/completions", zValidator("json", ChatCompletionSchema), async
|
|
|
183
273
|
}));
|
|
184
274
|
// Handle streaming
|
|
185
275
|
if (body.stream) {
|
|
276
|
+
// Smart route for streaming too
|
|
277
|
+
let streamRouting;
|
|
278
|
+
let streamModel = body.model;
|
|
279
|
+
if (!body.model && isSmartRouterEnabled()) {
|
|
280
|
+
const lastUserMsg = [...body.messages].reverse().find((m) => m.role === "user");
|
|
281
|
+
if (lastUserMsg) {
|
|
282
|
+
const providers = new Set(aiProvider.getConfiguredProviders());
|
|
283
|
+
streamRouting = routeQuery(lastUserMsg.content, providers, {
|
|
284
|
+
conversationLength: body.messages.length,
|
|
285
|
+
});
|
|
286
|
+
streamModel = streamRouting.selectedModel.id;
|
|
287
|
+
recordRoutingDecision(streamRouting);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
186
290
|
return streamText(c, async (stream) => {
|
|
187
291
|
try {
|
|
292
|
+
// Send routing info as first event in stream
|
|
293
|
+
if (streamRouting) {
|
|
294
|
+
await stream.write(`data: ${JSON.stringify({
|
|
295
|
+
routing: {
|
|
296
|
+
smartRouted: true,
|
|
297
|
+
complexity: streamRouting.complexity.tier,
|
|
298
|
+
savings: `${streamRouting.savingsPercent}%`,
|
|
299
|
+
model: streamRouting.selectedModel.id,
|
|
300
|
+
provider: streamRouting.selectedModel.provider,
|
|
301
|
+
},
|
|
302
|
+
})}\n\n`);
|
|
303
|
+
}
|
|
188
304
|
const response = await aiProvider.chatStream({
|
|
189
305
|
messages,
|
|
190
|
-
model:
|
|
306
|
+
model: streamModel,
|
|
191
307
|
systemPrompt: body.systemPrompt,
|
|
192
308
|
temperature: body.temperature,
|
|
193
309
|
maxTokens: body.maxTokens,
|
|
@@ -216,9 +332,23 @@ chatRoutes.post("/completions", zValidator("json", ChatCompletionSchema), async
|
|
|
216
332
|
}
|
|
217
333
|
// Non-streaming
|
|
218
334
|
try {
|
|
335
|
+
// Smart routing for completions
|
|
336
|
+
let routing;
|
|
337
|
+
let modelToUse = body.model;
|
|
338
|
+
if (!body.model && isSmartRouterEnabled()) {
|
|
339
|
+
const lastUserMsg = [...body.messages].reverse().find((m) => m.role === "user");
|
|
340
|
+
if (lastUserMsg) {
|
|
341
|
+
const providers = new Set(aiProvider.getConfiguredProviders());
|
|
342
|
+
routing = routeQuery(lastUserMsg.content, providers, {
|
|
343
|
+
conversationLength: body.messages.length,
|
|
344
|
+
});
|
|
345
|
+
modelToUse = routing.selectedModel.id;
|
|
346
|
+
recordRoutingDecision(routing);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
219
349
|
const response = await aiProvider.chat({
|
|
220
350
|
messages,
|
|
221
|
-
model:
|
|
351
|
+
model: modelToUse,
|
|
222
352
|
systemPrompt: body.systemPrompt,
|
|
223
353
|
temperature: body.temperature,
|
|
224
354
|
maxTokens: body.maxTokens,
|
|
@@ -234,6 +364,15 @@ chatRoutes.post("/completions", zValidator("json", ChatCompletionSchema), async
|
|
|
234
364
|
finishReason: response.finishReason,
|
|
235
365
|
usage: response.usage,
|
|
236
366
|
duration: response.duration,
|
|
367
|
+
...(routing && {
|
|
368
|
+
routing: {
|
|
369
|
+
smartRouted: true,
|
|
370
|
+
complexity: routing.complexity.tier,
|
|
371
|
+
savings: `${routing.savingsPercent}%`,
|
|
372
|
+
estimatedCost: `$${routing.estimatedCost.toFixed(4)}`,
|
|
373
|
+
summary: getCostComparison(routing),
|
|
374
|
+
},
|
|
375
|
+
}),
|
|
237
376
|
});
|
|
238
377
|
}
|
|
239
378
|
catch (error) {
|
|
@@ -751,14 +890,62 @@ chatRoutes.post("/conversations/:id/compact", async (c) => {
|
|
|
751
890
|
return c.json({ error: "Failed to compact conversation" }, 500);
|
|
752
891
|
}
|
|
753
892
|
});
|
|
893
|
+
/**
|
|
894
|
+
* DELETE /api/chat/conversations/:id/messages/:messageId
|
|
895
|
+
* Delete a single message from a conversation
|
|
896
|
+
*/
|
|
897
|
+
chatRoutes.delete("/conversations/:id/messages/:messageId", async (c) => {
|
|
898
|
+
const conversationId = c.req.param("id");
|
|
899
|
+
const messageId = c.req.param("messageId");
|
|
900
|
+
try {
|
|
901
|
+
const conversation = await getConversation(conversationId);
|
|
902
|
+
if (!conversation) {
|
|
903
|
+
return c.json({ error: "Conversation not found" }, 404);
|
|
904
|
+
}
|
|
905
|
+
await deleteMessage(conversationId, messageId);
|
|
906
|
+
return c.json({ success: true });
|
|
907
|
+
}
|
|
908
|
+
catch (error) {
|
|
909
|
+
logger.error("[Chat] Delete message error:", error instanceof Error ? error : undefined);
|
|
910
|
+
return c.json({ error: "Failed to delete message" }, 500);
|
|
911
|
+
}
|
|
912
|
+
});
|
|
913
|
+
/**
|
|
914
|
+
* GET /api/chat/conversations/:id/export
|
|
915
|
+
* Export a conversation as JSON
|
|
916
|
+
*/
|
|
917
|
+
chatRoutes.get("/conversations/:id/export", async (c) => {
|
|
918
|
+
const conversationId = c.req.param("id");
|
|
919
|
+
try {
|
|
920
|
+
const conversation = await getConversation(conversationId);
|
|
921
|
+
if (!conversation) {
|
|
922
|
+
return c.json({ error: "Conversation not found" }, 404);
|
|
923
|
+
}
|
|
924
|
+
const messages = await getConversationMessages(conversationId);
|
|
925
|
+
return c.json({
|
|
926
|
+
conversation: {
|
|
927
|
+
id: conversation.id,
|
|
928
|
+
title: conversation.title,
|
|
929
|
+
createdAt: conversation.createdAt,
|
|
930
|
+
},
|
|
931
|
+
messages,
|
|
932
|
+
exportedAt: new Date().toISOString(),
|
|
933
|
+
});
|
|
934
|
+
}
|
|
935
|
+
catch (error) {
|
|
936
|
+
logger.error("[Chat] Export conversation error:", error instanceof Error ? error : undefined);
|
|
937
|
+
return c.json({ error: "Failed to export conversation" }, 500);
|
|
938
|
+
}
|
|
939
|
+
});
|
|
754
940
|
/**
|
|
755
941
|
* POST /api/chat/conversations/:id/messages
|
|
756
942
|
* Send a message in a conversation (with context and history)
|
|
757
943
|
*/
|
|
758
|
-
chatRoutes.post("/conversations/:id/messages", zValidator("json", z.object({
|
|
944
|
+
chatRoutes.post("/conversations/:id/messages", chatRateLimiter, contentFilter(), zValidator("json", z.object({
|
|
759
945
|
content: z.string(),
|
|
760
946
|
model: z.string().optional(),
|
|
761
947
|
temperature: z.number().min(0).max(2).optional(),
|
|
948
|
+
stream: z.boolean().optional(),
|
|
762
949
|
})), async (c) => {
|
|
763
950
|
const conversationId = c.req.param("id");
|
|
764
951
|
const body = c.req.valid("json");
|
|
@@ -870,7 +1057,56 @@ chatRoutes.post("/conversations/:id/messages", zValidator("json", z.object({
|
|
|
870
1057
|
content: m.content,
|
|
871
1058
|
timestamp: m.createdAt,
|
|
872
1059
|
}));
|
|
873
|
-
//
|
|
1060
|
+
// Streaming branch
|
|
1061
|
+
if (body.stream) {
|
|
1062
|
+
return streamText(c, async (stream) => {
|
|
1063
|
+
try {
|
|
1064
|
+
let fullContent = "";
|
|
1065
|
+
const response = await aiProvider.chatStream({
|
|
1066
|
+
messages: chatMessages,
|
|
1067
|
+
model: body.model,
|
|
1068
|
+
systemPrompt,
|
|
1069
|
+
temperature: body.temperature,
|
|
1070
|
+
}, (chunk) => {
|
|
1071
|
+
fullContent += chunk;
|
|
1072
|
+
stream
|
|
1073
|
+
.write(`data: ${JSON.stringify({ content: chunk })}\n\n`)
|
|
1074
|
+
.catch((err) => {
|
|
1075
|
+
logger.error("[Chat] Stream write error:", err instanceof Error ? err : undefined);
|
|
1076
|
+
});
|
|
1077
|
+
});
|
|
1078
|
+
// Save assistant response after streaming completes
|
|
1079
|
+
const assistantMessage = await addMessage({
|
|
1080
|
+
conversationId,
|
|
1081
|
+
role: "assistant",
|
|
1082
|
+
content: fullContent || response.content,
|
|
1083
|
+
model: response.model,
|
|
1084
|
+
provider: response.provider,
|
|
1085
|
+
tokenUsage: response.usage
|
|
1086
|
+
? {
|
|
1087
|
+
prompt: response.usage.promptTokens,
|
|
1088
|
+
completion: response.usage.completionTokens,
|
|
1089
|
+
total: response.usage.totalTokens,
|
|
1090
|
+
}
|
|
1091
|
+
: undefined,
|
|
1092
|
+
cost: response.usage?.cost,
|
|
1093
|
+
});
|
|
1094
|
+
await stream.write(`data: ${JSON.stringify({
|
|
1095
|
+
done: true,
|
|
1096
|
+
usage: response.usage,
|
|
1097
|
+
messageId: assistantMessage.id,
|
|
1098
|
+
compaction: compactionInfo,
|
|
1099
|
+
})}\n\n`);
|
|
1100
|
+
}
|
|
1101
|
+
catch (error) {
|
|
1102
|
+
logger.error("[Chat] Conversation stream error:", error instanceof Error ? error : undefined);
|
|
1103
|
+
await stream.write(`data: ${JSON.stringify({
|
|
1104
|
+
error: error instanceof Error ? error.message : "Failed to send message",
|
|
1105
|
+
})}\n\n`);
|
|
1106
|
+
}
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1109
|
+
// Send to AI (non-streaming)
|
|
874
1110
|
const response = await aiProvider.chat({
|
|
875
1111
|
messages: chatMessages,
|
|
876
1112
|
model: body.model,
|
|
@@ -915,7 +1151,7 @@ chatRoutes.post("/conversations/:id/messages", zValidator("json", z.object({
|
|
|
915
1151
|
* POST /api/chat/conversations/:id/messages/with-tools
|
|
916
1152
|
* Send a message in a conversation with native tool calling enabled
|
|
917
1153
|
*/
|
|
918
|
-
chatRoutes.post("/conversations/:id/messages/with-tools", zValidator("json", z.object({
|
|
1154
|
+
chatRoutes.post("/conversations/:id/messages/with-tools", chatRateLimiter, contentFilter(), zValidator("json", z.object({
|
|
919
1155
|
content: z.string(),
|
|
920
1156
|
model: z.string().optional(),
|
|
921
1157
|
temperature: z.number().min(0).max(2).optional(),
|
|
@@ -993,6 +1229,10 @@ chatRoutes.post("/conversations/:id/messages/with-tools", zValidator("json", z.o
|
|
|
993
1229
|
const tools = enableTools
|
|
994
1230
|
? getChatToolsForModel(modelId, { conversationId })
|
|
995
1231
|
: [];
|
|
1232
|
+
logger.info(`[Chat] Tools for ${modelId}: ${tools.length} (enableTools=${enableTools})`, {
|
|
1233
|
+
component: 'Chat',
|
|
1234
|
+
toolNames: tools.map(t => t.name).join(', '),
|
|
1235
|
+
});
|
|
996
1236
|
// Build system prompt with context and tool mode
|
|
997
1237
|
const systemPrompt = await buildSystemPrompt(conversation.presetId, context, {
|
|
998
1238
|
enableTools: enableTools && tools.length > 0,
|
|
@@ -1322,7 +1562,7 @@ chatRoutes.post("/with-tools", zValidator("json", z.object({
|
|
|
1322
1562
|
* - complete - Session complete
|
|
1323
1563
|
* - error - Error occurred
|
|
1324
1564
|
*/
|
|
1325
|
-
chatRoutes.post("/conversations/:id/messages/agentic", zValidator("json", z.object({
|
|
1565
|
+
chatRoutes.post("/conversations/:id/messages/agentic", chatRateLimiter, contentFilter(), zValidator("json", z.object({
|
|
1326
1566
|
content: z.string(),
|
|
1327
1567
|
model: z.string().optional(),
|
|
1328
1568
|
provider: z.string().optional(),
|
|
@@ -1385,8 +1625,6 @@ chatRoutes.post("/conversations/:id/messages/agentic", zValidator("json", z.obje
|
|
|
1385
1625
|
conversationId,
|
|
1386
1626
|
sessionOverride,
|
|
1387
1627
|
};
|
|
1388
|
-
// Get tools - agentic mode uses model-aware filtering
|
|
1389
|
-
const tools = getChatToolsForModel(resolvedRef.model, { conversationId, includeAll: true });
|
|
1390
1628
|
// Build system prompt with agent mode (uses AGENT_MODE_SUFFIX)
|
|
1391
1629
|
const systemPrompt = await buildSystemPrompt(conversation.presetId, context, {
|
|
1392
1630
|
agentMode: true,
|
|
@@ -1429,11 +1667,14 @@ chatRoutes.post("/conversations/:id/messages/agentic", zValidator("json", z.obje
|
|
|
1429
1667
|
content: m.content,
|
|
1430
1668
|
timestamp: m.createdAt,
|
|
1431
1669
|
}));
|
|
1432
|
-
// Create tool handler
|
|
1670
|
+
// Create tool handler (triggers tool registration if first call)
|
|
1433
1671
|
const toolHandler = await createChatToolHandler({
|
|
1434
1672
|
conversationId,
|
|
1435
1673
|
securityMode: "full", // Full access in agentic mode (tools are pre-approved)
|
|
1436
1674
|
});
|
|
1675
|
+
// Get tools AFTER handler init (registry is now populated)
|
|
1676
|
+
const tools = getChatToolsForModel(resolvedRef.model, { conversationId });
|
|
1677
|
+
logger.info(`[Chat/Agentic] Tools for model ${resolvedRef.model}: ${tools.length}`);
|
|
1437
1678
|
// Set up SSE streaming response
|
|
1438
1679
|
c.header("Content-Type", "text/event-stream");
|
|
1439
1680
|
c.header("Cache-Control", "no-cache");
|
|
@@ -1491,11 +1732,15 @@ chatRoutes.post("/conversations/:id/messages/agentic", zValidator("json", z.obje
|
|
|
1491
1732
|
provider: body.provider,
|
|
1492
1733
|
temperature: body.temperature,
|
|
1493
1734
|
toolHandler,
|
|
1494
|
-
tools:
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1735
|
+
tools: (() => {
|
|
1736
|
+
const mapped = tools.map((t) => ({
|
|
1737
|
+
name: t.name,
|
|
1738
|
+
description: t.description,
|
|
1739
|
+
parameters: t.parameters,
|
|
1740
|
+
}));
|
|
1741
|
+
logger.info(`[Chat/Agentic] Sending ${mapped.length} tools: [${mapped.map(t => t.name).join(', ')}]`);
|
|
1742
|
+
return mapped;
|
|
1743
|
+
})(),
|
|
1499
1744
|
showThinking: body.showThinking,
|
|
1500
1745
|
maxSteps: body.maxSteps,
|
|
1501
1746
|
maxBudget: body.maxBudget,
|
package/dist/routes/costs.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Hono } from 'hono';
|
|
|
2
2
|
import { getUsageSummary } from '../costs/token-tracker.js';
|
|
3
3
|
import { getBudgetStatus } from '../costs/budget.js';
|
|
4
4
|
import { getStorage } from '../storage/index.js';
|
|
5
|
+
import { getRoutingStats, getCostOptimizationAdvice } from '../providers/smart-router.js';
|
|
5
6
|
const costs = new Hono();
|
|
6
7
|
// Get usage summary
|
|
7
8
|
costs.get('/summary', (c) => {
|
|
@@ -19,6 +20,37 @@ costs.get('/analytics', async (c) => {
|
|
|
19
20
|
const analytics = await storage.getCostAnalytics();
|
|
20
21
|
return c.json(analytics);
|
|
21
22
|
});
|
|
23
|
+
// Get smart routing stats (savings from auto-routing)
|
|
24
|
+
costs.get('/routing', (_c) => {
|
|
25
|
+
const stats = getRoutingStats();
|
|
26
|
+
return _c.json({
|
|
27
|
+
success: true,
|
|
28
|
+
data: {
|
|
29
|
+
...stats,
|
|
30
|
+
totalSaved: `$${stats.totalSaved.toFixed(4)}`,
|
|
31
|
+
avgSavingsPercent: `${Math.round(stats.avgSavingsPercent)}%`,
|
|
32
|
+
message: stats.totalRouted > 0
|
|
33
|
+
? `Smart routing saved $${stats.totalSaved.toFixed(2)} across ${stats.totalRouted} requests (avg ${Math.round(stats.avgSavingsPercent)}% savings)`
|
|
34
|
+
: 'No queries routed yet. Smart routing will show savings as you use profClaw.',
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
// Get cost optimization advice
|
|
39
|
+
costs.get('/optimize', async (c) => {
|
|
40
|
+
// Get configured providers dynamically
|
|
41
|
+
const { aiProvider } = await import('../providers/ai-sdk.js');
|
|
42
|
+
const providers = new Set(aiProvider.getConfiguredProviders());
|
|
43
|
+
const advice = getCostOptimizationAdvice(providers);
|
|
44
|
+
return c.json({
|
|
45
|
+
success: true,
|
|
46
|
+
data: {
|
|
47
|
+
configuredProviders: [...providers],
|
|
48
|
+
providerCount: providers.size,
|
|
49
|
+
recommendations: advice,
|
|
50
|
+
optimalSetup: advice.some(a => a.action.includes('cost-optimal')),
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
});
|
|
22
54
|
// Export cost report as CSV
|
|
23
55
|
costs.get('/export', async (c) => {
|
|
24
56
|
const format = c.req.query('format') || 'csv';
|