@geminilight/mindos 0.6.61 → 0.6.65
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/_standalone/.antigravity/mcp_config.json +14 -0
- package/_standalone/.mindos-build-version +1 -1
- package/_standalone/.next/BUILD_ID +1 -1
- package/_standalone/.next/app-path-routes-manifest.json +23 -23
- package/_standalone/.next/build-manifest.json +2 -2
- package/_standalone/.next/cache/.previewinfo +1 -1
- package/_standalone/.next/cache/.rscinfo +1 -1
- package/_standalone/.next/cache/config.json +3 -3
- package/_standalone/.next/prerender-manifest.json +3 -3
- package/_standalone/.next/server/app/.well-known/agent-card.json/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/_global-error.html +2 -2
- package/_standalone/.next/server/app/_global-error.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/_standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/_standalone/.next/server/app/_not-found/page.js +1 -1
- package/_standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/[agentKey]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/agents/page.js +1 -1
- package/_standalone/.next/server/app/agents/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/agents/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/delegations/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/discover/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/a2a/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/config/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route.js +1 -1
- package/_standalone/.next/server/app/api/acp/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/registry/route.js +1 -1
- package/_standalone/.next/server/app/api/acp/registry/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/acp/session/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agent-activity/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/copy-skill/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/agents/copy-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/detect/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/agents/custom/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask/route.js +53 -47
- package/_standalone/.next/server/app/api/ask/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/ask/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/ask-sessions/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/auth/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/backlinks/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/backlinks/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/bootstrap/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/changes/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/changes/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/export/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/export/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/extract-pdf/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/import/route.js +1 -1
- package/_standalone/.next/server/app/api/file/import/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/import/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/raw/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/raw/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/file/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/file/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/git/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/git/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/graph/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/graph/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/inbox/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/init/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/init/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route.js +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/mcp/agents/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/install-skill/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/mcp/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/monitoring/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/monitoring/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/recent-files/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/recent-files/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/search/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/search/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/list-models/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/list-models/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/reset-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/settings/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route.js +1 -1
- package/_standalone/.next/server/app/api/settings/test-key/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-path/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/check-port/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/generate-token/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/ls/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/setup/route.js +1 -1
- package/_standalone/.next/server/app/api/setup/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/skills/route.js +1 -1
- package/_standalone/.next/server/app/api/skills/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/sync/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/tree-version/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/tree-version/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/uninstall/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-check/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/update-status/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/api/workflows/route.js.nft.json +1 -1
- package/_standalone/.next/server/app/api/workflows/route_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/changes/page.js +1 -1
- package/_standalone/.next/server/app/changes/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/changes/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page.js +2 -2
- package/_standalone/.next/server/app/echo/[segment]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/[segment]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/echo/page.js +1 -1
- package/_standalone/.next/server/app/echo/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/echo/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/explore/page.js +1 -1
- package/_standalone/.next/server/app/explore/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/explore/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/help/page.js +1 -1
- package/_standalone/.next/server/app/help/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/help/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js +1 -1
- package/_standalone/.next/server/app/inbox/history/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/inbox/history/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/login/page.js +1 -1
- package/_standalone/.next/server/app/login/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/page.js +1 -1
- package/_standalone/.next/server/app/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/setup/page.js +2 -2
- package/_standalone/.next/server/app/setup/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/trash/page.js +3 -3
- package/_standalone/.next/server/app/trash/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/trash/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/view/[...path]/page.js +2 -2
- package/_standalone/.next/server/app/view/[...path]/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/view/[...path]/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app/wiki/page.js +1 -1
- package/_standalone/.next/server/app/wiki/page.js.nft.json +1 -1
- package/_standalone/.next/server/app/wiki/page_client-reference-manifest.js +1 -1
- package/_standalone/.next/server/app-paths-manifest.json +23 -23
- package/_standalone/.next/server/chunks/122.js +222 -0
- package/_standalone/.next/server/chunks/1550.js +1 -1
- package/_standalone/.next/server/chunks/1750.js +1 -1
- package/_standalone/.next/server/chunks/3113.js +52 -0
- package/_standalone/.next/server/chunks/6539.js +1 -1
- package/_standalone/.next/server/chunks/8388.js +3 -3
- package/_standalone/.next/server/chunks/953.js +3 -3
- package/_standalone/.next/server/pages/500.html +2 -2
- package/_standalone/.next/server/server-reference-manifest.js +1 -1
- package/_standalone/.next/server/server-reference-manifest.json +1 -1
- package/_standalone/.next/static/chunks/1001-99da82ec8d8c136f.js +1 -0
- package/_standalone/.next/static/chunks/1088-77544af0a50cb7a4.js +1 -0
- package/_standalone/.next/static/chunks/1467-87dde7eed498806f.js +1 -0
- package/_standalone/.next/static/chunks/5149-4d828886dda479fa.js +1 -0
- package/_standalone/.next/static/chunks/5581-c671163a2fe1b312.js +29 -0
- package/_standalone/.next/static/chunks/{7266-bb7be1128eccd48e.js → 5718-3837c3210a0e175f.js} +2 -2
- package/_standalone/.next/static/chunks/6636-53238eff89503f03.js +6 -0
- package/_standalone/.next/static/chunks/6757-1c1a89720fdda8f0.js +1 -0
- package/_standalone/.next/static/chunks/7129-20e9d2463a9da646.js +1 -0
- package/_standalone/.next/static/chunks/7294-cac25d97869afadc.js +1 -0
- package/_standalone/.next/static/chunks/8225-21e5cebc3731ddf0.js +1 -0
- package/_standalone/.next/static/chunks/8520-b51810e66293ceb8.js +22 -0
- package/_standalone/.next/static/chunks/9207-dc9c31b351a2ed78.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-2f5cf97e03dc1cc9.js +1 -0
- package/_standalone/.next/static/chunks/app/agents/page-50eac58d511dcc6e.js +1 -0
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-2a00f4686adf3885.js +11 -0
- package/_standalone/.next/static/chunks/app/layout-2cb7a6602d2e5d5f.js +168 -0
- package/_standalone/.next/static/chunks/app/{page-6a1f8d21c12b829e.js → page-5ab911b2226f6ff7.js} +1 -1
- package/_standalone/.next/static/chunks/app/setup/page-907b7c57fad2292b.js +1 -0
- package/_standalone/.next/static/chunks/app/trash/page-11a511b065ea84c2.js +1 -0
- package/_standalone/.next/static/chunks/app/view/[...path]/page-26e47dd4c533a58c.js +12 -0
- package/_standalone/.next/static/chunks/app/wiki/page-dce495b9048022fb.js +1 -0
- package/_standalone/.next/static/css/67e7918f5ed7d147.css +1 -0
- package/_standalone/.next/trace +65 -65
- package/_standalone/__tests__/acp/registry.test.ts +30 -20
- package/_standalone/__tests__/api/ask-attachments.test.ts +194 -0
- package/_standalone/__tests__/api/mcp-install.test.ts +49 -2
- package/_standalone/__tests__/api/settings.test.ts +16 -12
- package/_standalone/__tests__/api/setup.test.ts +11 -9
- package/_standalone/__tests__/api/test-key.test.ts +0 -10
- package/_standalone/__tests__/components/UpdateToast.test.ts +344 -0
- package/_standalone/__tests__/core/context.test.ts +48 -426
- package/_standalone/__tests__/lib/pi-skills.test.ts +4 -4
- package/_standalone/__tests__/lib/settings-ai-client.test.ts +32 -12
- package/_standalone/__tests__/setup.ts +5 -5
- package/_standalone/app/globals.css +4 -4
- package/_standalone/components/ActivityBar.tsx +17 -6
- package/_standalone/components/Panel.tsx +24 -6
- package/_standalone/components/SidebarLayout.tsx +36 -8
- package/_standalone/components/agents/AgentsMcpSection.tsx +2 -2
- package/_standalone/components/agents/AgentsOverviewSection.tsx +5 -1
- package/_standalone/components/agents/AgentsPanelA2aTab.tsx +173 -113
- package/_standalone/components/agents/AgentsSkillsSection.tsx +2 -2
- package/_standalone/components/ask/AskContent.tsx +83 -44
- package/_standalone/components/ask/AskHeader.tsx +8 -1
- package/_standalone/components/ask/MessageList.tsx +37 -3
- package/_standalone/components/ask/ProviderModelCapsule.tsx +444 -174
- package/_standalone/components/home/InboxSection.tsx +25 -25
- package/_standalone/components/settings/AiTab.tsx +353 -298
- package/_standalone/components/settings/CustomProviderFields.tsx +121 -0
- package/_standalone/components/settings/CustomProvidersCard.tsx +154 -0
- package/_standalone/components/settings/KnowledgeTab.tsx +6 -20
- package/_standalone/components/settings/McpAgentInstall.tsx +7 -2
- package/_standalone/components/settings/Primitives.tsx +48 -104
- package/_standalone/components/settings/ProviderModal.tsx +87 -0
- package/_standalone/components/settings/SettingsContent.tsx +2 -5
- package/_standalone/components/settings/TestButton.tsx +64 -0
- package/_standalone/components/settings/types.ts +3 -9
- package/_standalone/components/settings/useCustomProviderForm.ts +132 -0
- package/_standalone/components/setup/StepAI.tsx +12 -5
- package/_standalone/components/shared/ModelInput.tsx +220 -0
- package/_standalone/components/shared/ProviderSelect.tsx +126 -36
- package/_standalone/hooks/useAskChat.ts +100 -13
- package/_standalone/hooks/useAskPanel.ts +17 -1
- package/_standalone/lib/settings-ai-client.ts +17 -8
- package/_standalone/tsconfig.tsbuildinfo +1 -1
- package/app/.antigravity/mcp_config.json +14 -0
- package/app/app/api/ask/route.ts +154 -45
- package/app/app/api/mcp/agents/route.ts +3 -3
- package/app/app/api/settings/list-models/route.ts +36 -9
- package/app/app/api/settings/route.ts +14 -42
- package/app/app/api/settings/test-key/route.ts +78 -2
- package/app/app/api/setup/route.ts +36 -18
- package/app/app/api/skills/route.ts +1 -1
- package/app/app/globals.css +4 -4
- package/app/app/layout.tsx +5 -3
- package/app/app/view/[...path]/page.tsx +5 -0
- package/app/components/ActivityBar.tsx +17 -6
- package/app/components/HomeContent.tsx +11 -0
- package/app/components/InboxView.tsx +656 -0
- package/app/components/Panel.tsx +24 -6
- package/app/components/SidebarLayout.tsx +36 -8
- package/app/components/UpdateToast.tsx +255 -0
- package/app/components/agents/AgentDetailContent.tsx +8 -8
- package/app/components/agents/AgentsMcpSection.tsx +2 -2
- package/app/components/agents/AgentsOverviewSection.tsx +5 -1
- package/app/components/agents/AgentsPanelA2aTab.tsx +173 -113
- package/app/components/agents/AgentsSkillsSection.tsx +2 -2
- package/app/components/ask/AskContent.tsx +83 -44
- package/app/components/ask/AskHeader.tsx +8 -1
- package/app/components/ask/MessageList.tsx +37 -3
- package/app/components/ask/ProviderModelCapsule.tsx +444 -174
- package/app/components/home/InboxSection.tsx +25 -25
- package/app/components/settings/AiTab.tsx +353 -298
- package/app/components/settings/CustomProviderFields.tsx +121 -0
- package/app/components/settings/CustomProvidersCard.tsx +154 -0
- package/app/components/settings/KnowledgeTab.tsx +6 -20
- package/app/components/settings/McpAgentInstall.tsx +7 -2
- package/app/components/settings/Primitives.tsx +48 -104
- package/app/components/settings/ProviderModal.tsx +87 -0
- package/app/components/settings/SettingsContent.tsx +2 -5
- package/app/components/settings/TestButton.tsx +64 -0
- package/app/components/settings/types.ts +3 -9
- package/app/components/settings/useCustomProviderForm.ts +132 -0
- package/app/components/setup/StepAI.tsx +12 -5
- package/app/components/shared/ModelInput.tsx +220 -0
- package/app/components/shared/ProviderSelect.tsx +126 -36
- package/app/hooks/useAskChat.ts +100 -13
- package/app/hooks/useAskPanel.ts +17 -1
- package/app/lib/acp/registry.ts +92 -10
- package/app/lib/agent/context.ts +65 -0
- package/app/lib/agent/providers.ts +25 -0
- package/app/lib/agent/tools.ts +1 -1
- package/app/lib/custom-endpoints.ts +160 -0
- package/app/lib/fs.ts +8 -1
- package/app/lib/i18n/modules/ai-chat.ts +6 -0
- package/app/lib/i18n/modules/knowledge.ts +16 -0
- package/app/lib/i18n/modules/onboarding.ts +4 -0
- package/app/lib/i18n/modules/settings.ts +88 -2
- package/app/lib/mcp-agents.ts +11 -0
- package/app/lib/pi-integration/skills.ts +16 -4
- package/app/lib/settings-ai-client.ts +17 -8
- package/app/lib/settings.ts +68 -72
- package/app/lib/types.ts +4 -0
- package/bin/lib/mcp-agents.js +11 -0
- package/bin/lib/mcp-install.js +71 -7
- package/package.json +1 -1
- package/_standalone/.next/server/chunks/530.js +0 -218
- package/_standalone/.next/server/chunks/8955.js +0 -52
- package/_standalone/.next/static/chunks/1369-7d0ac5d1564eed1e.js +0 -1
- package/_standalone/.next/static/chunks/3427-2e61a5df1f5e55fb.js +0 -1
- package/_standalone/.next/static/chunks/5581-0c700c20718bd916.js +0 -29
- package/_standalone/.next/static/chunks/6297-085daa21037d5f81.js +0 -1
- package/_standalone/.next/static/chunks/6636-9bbc90fb3b8731fe.js +0 -6
- package/_standalone/.next/static/chunks/7637-904b0a381dc3ec02.js +0 -1
- package/_standalone/.next/static/chunks/8520-76d1b05072178b43.js +0 -22
- package/_standalone/.next/static/chunks/8658-16ff58b75ae37fbb.js +0 -1
- package/_standalone/.next/static/chunks/9905-a19d379cb225246e.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/[agentKey]/page-0ea3571c8fbae823.js +0 -1
- package/_standalone/.next/static/chunks/app/agents/page-66858acbcd1d4bf8.js +0 -1
- package/_standalone/.next/static/chunks/app/echo/[segment]/page-bf5c290fa3ccff09.js +0 -11
- package/_standalone/.next/static/chunks/app/layout-a5d5925b47e87cc3.js +0 -164
- package/_standalone/.next/static/chunks/app/setup/page-821714e7477be46c.js +0 -1
- package/_standalone/.next/static/chunks/app/trash/page-40bc7316806acd62.js +0 -1
- package/_standalone/.next/static/chunks/app/view/[...path]/page-6fbb14b8f322d0f0.js +0 -12
- package/_standalone/.next/static/chunks/app/wiki/page-ba36eccf4fe62cfe.js +0 -1
- package/_standalone/.next/static/css/b57c4eb3cc88308b.css +0 -1
- package/_standalone/lib/agent/context.ts +0 -403
- /package/_standalone/.next/static/{5GmVArEG8OX03azKICsGq → eIlwbGas1iRGonlPyEwj7}/_buildManifest.js +0 -0
- /package/_standalone/.next/static/{5GmVArEG8OX03azKICsGq → eIlwbGas1iRGonlPyEwj7}/_ssgManifest.js +0 -0
|
@@ -1,55 +1,84 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import { useState } from 'react';
|
|
4
|
-
import { CheckCircle2, ChevronDown, SkipForward } from 'lucide-react';
|
|
5
|
-
import { type ProviderId, PROVIDER_PRESETS, groupedProviders } from '@/lib/agent/providers';
|
|
4
|
+
import { CheckCircle2, ChevronDown, SkipForward, Plus } from 'lucide-react';
|
|
5
|
+
import { type ProviderId, PROVIDER_PRESETS, groupedProviders, ALL_PROVIDER_IDS } from '@/lib/agent/providers';
|
|
6
|
+
import { type Provider } from '@/lib/custom-endpoints';
|
|
6
7
|
import { useLocale } from '@/lib/stores/locale-store';
|
|
7
8
|
|
|
8
9
|
interface ProviderSelectProps {
|
|
9
|
-
value:
|
|
10
|
-
onChange: (id:
|
|
10
|
+
value: string | 'skip';
|
|
11
|
+
onChange: (id: string | 'skip') => void;
|
|
11
12
|
showSkip?: boolean;
|
|
12
13
|
compact?: boolean;
|
|
14
|
+
/** @deprecated Use customProviders (unified Provider[]) instead */
|
|
13
15
|
configuredProviders?: Set<ProviderId>;
|
|
16
|
+
customProviders?: Provider[];
|
|
17
|
+
onAdd?: () => void;
|
|
14
18
|
}
|
|
15
19
|
|
|
16
20
|
export default function ProviderSelect({
|
|
17
21
|
value, onChange, showSkip = false, compact = false, configuredProviders,
|
|
22
|
+
customProviders, onAdd,
|
|
18
23
|
}: ProviderSelectProps) {
|
|
19
24
|
const { locale } = useLocale();
|
|
20
25
|
const [showMore, setShowMore] = useState(false);
|
|
21
26
|
const groups = groupedProviders();
|
|
22
27
|
|
|
23
|
-
const
|
|
28
|
+
const hasConfigured = configuredProviders && configuredProviders.size > 0;
|
|
29
|
+
const hasCustom = customProviders && customProviders.length > 0;
|
|
30
|
+
|
|
31
|
+
// In compact settings mode: show provider list + Add button
|
|
32
|
+
// New model: customProviders IS the full list (unified Provider[])
|
|
33
|
+
// Legacy model: configuredProviders set + separate customProviders array
|
|
34
|
+
const useConfiguredMode = compact && (hasConfigured || hasCustom) && !showSkip;
|
|
35
|
+
|
|
36
|
+
// Legacy: Sorted configured provider IDs (for backward compat with old callers)
|
|
37
|
+
const configuredIds = hasConfigured
|
|
38
|
+
? ALL_PROVIDER_IDS.filter(id => configuredProviders!.has(id))
|
|
39
|
+
: [];
|
|
40
|
+
|
|
41
|
+
// Add panel shows ALL providers as protocol templates (can add multiple of the same type)
|
|
42
|
+
const { primary: primaryItems, more: moreItems } = groups;
|
|
43
|
+
|
|
44
|
+
/* ── Compact tab button (for legacy builtin-only mode) ── */
|
|
45
|
+
const renderCompactTab = (id: ProviderId) => {
|
|
24
46
|
const preset = PROVIDER_PRESETS[id];
|
|
25
47
|
const displayName = locale === 'zh' ? preset.nameZh : preset.name;
|
|
26
48
|
const isSelected = value === id;
|
|
27
49
|
const isConfigured = configuredProviders?.has(id);
|
|
28
50
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
{
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
{
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
return (
|
|
52
|
+
<button
|
|
53
|
+
key={id}
|
|
54
|
+
type="button"
|
|
55
|
+
onClick={() => onChange(id)}
|
|
56
|
+
className={`flex items-center gap-2 px-3 py-2 rounded-lg border text-left transition-all text-sm ${
|
|
57
|
+
isSelected
|
|
58
|
+
? 'border-[var(--amber)] bg-[var(--amber-subtle)] shadow-sm'
|
|
59
|
+
: 'border-border/50 hover:border-border hover:bg-muted/30'
|
|
60
|
+
}`}
|
|
61
|
+
>
|
|
62
|
+
<span className={`font-medium ${isSelected ? 'text-foreground' : 'text-muted-foreground'}`}>
|
|
63
|
+
{displayName}
|
|
64
|
+
</span>
|
|
65
|
+
{isConfigured && !isSelected && (
|
|
66
|
+
<CheckCircle2 size={12} className="text-success ml-auto shrink-0" />
|
|
67
|
+
)}
|
|
68
|
+
{isSelected && (
|
|
69
|
+
<CheckCircle2 size={14} className="ml-auto shrink-0" style={{ color: 'var(--amber)' }} />
|
|
70
|
+
)}
|
|
71
|
+
</button>
|
|
72
|
+
);
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/* ── Full card button (used in setup wizard / non-compact) ── */
|
|
76
|
+
const renderCard = (id: ProviderId) => {
|
|
77
|
+
const preset = PROVIDER_PRESETS[id];
|
|
78
|
+
const displayName = locale === 'zh' ? preset.nameZh : preset.name;
|
|
79
|
+
const description = locale === 'zh' ? preset.descriptionZh : preset.description;
|
|
80
|
+
const isSelected = value === id;
|
|
81
|
+
const isConfigured = configuredProviders?.has(id);
|
|
53
82
|
|
|
54
83
|
return (
|
|
55
84
|
<button
|
|
@@ -64,7 +93,10 @@ export default function ProviderSelect({
|
|
|
64
93
|
>
|
|
65
94
|
<div className="flex-1 min-w-0">
|
|
66
95
|
<p className="text-sm font-medium" style={{ color: 'var(--foreground)' }}>{displayName}</p>
|
|
67
|
-
|
|
96
|
+
{description && (
|
|
97
|
+
<p className="text-xs mt-0.5" style={{ color: 'var(--muted-foreground)' }}>{description}</p>
|
|
98
|
+
)}
|
|
99
|
+
<p className={`text-xs ${description ? 'mt-1' : 'mt-0.5'}`} style={{ color: 'var(--muted-foreground)' }}>
|
|
68
100
|
{preset.defaultModel}
|
|
69
101
|
</p>
|
|
70
102
|
</div>
|
|
@@ -78,16 +110,71 @@ export default function ProviderSelect({
|
|
|
78
110
|
);
|
|
79
111
|
};
|
|
80
112
|
|
|
81
|
-
|
|
113
|
+
/* ════════════════════════════════════════════
|
|
114
|
+
* MODE 1: Provider list + Add button
|
|
115
|
+
* (compact settings, has providers)
|
|
116
|
+
* ════════════════════════════════════════════ */
|
|
117
|
+
if (useConfiguredMode) {
|
|
118
|
+
return (
|
|
119
|
+
<div className="space-y-2">
|
|
120
|
+
{/* Providers row */}
|
|
121
|
+
<div className="flex flex-wrap gap-2">
|
|
122
|
+
{/* Legacy: built-in configured providers */}
|
|
123
|
+
{configuredIds.map(id => renderCompactTab(id))}
|
|
124
|
+
|
|
125
|
+
{/* Unified provider list (or legacy custom providers) */}
|
|
126
|
+
{customProviders?.map(cp => {
|
|
127
|
+
const isSelected = value === cp.id;
|
|
128
|
+
return (
|
|
129
|
+
<button
|
|
130
|
+
key={cp.id}
|
|
131
|
+
type="button"
|
|
132
|
+
onClick={() => onChange(cp.id)}
|
|
133
|
+
className={`flex items-center gap-2 px-3 py-2 rounded-lg border text-left transition-all text-sm ${
|
|
134
|
+
isSelected
|
|
135
|
+
? 'border-[var(--amber)] bg-[var(--amber-subtle)] shadow-sm'
|
|
136
|
+
: 'border-border/50 hover:border-border hover:bg-muted/30'
|
|
137
|
+
}`}
|
|
138
|
+
>
|
|
139
|
+
<span className={`font-medium ${isSelected ? 'text-foreground' : 'text-muted-foreground'}`}>
|
|
140
|
+
{cp.name}
|
|
141
|
+
</span>
|
|
142
|
+
{isSelected && (
|
|
143
|
+
<CheckCircle2 size={14} className="ml-auto shrink-0" style={{ color: 'var(--amber)' }} />
|
|
144
|
+
)}
|
|
145
|
+
</button>
|
|
146
|
+
);
|
|
147
|
+
})}
|
|
148
|
+
|
|
149
|
+
{/* Add button — opens form directly */}
|
|
150
|
+
{onAdd && (
|
|
151
|
+
<button
|
|
152
|
+
type="button"
|
|
153
|
+
onClick={onAdd}
|
|
154
|
+
className="flex items-center gap-1.5 px-3 py-2 rounded-lg border border-dashed border-border/50 text-sm text-muted-foreground hover:border-border hover:text-foreground transition-all"
|
|
155
|
+
>
|
|
156
|
+
<Plus size={14} />
|
|
157
|
+
<span>{locale === 'zh' ? '添加' : 'Add'}</span>
|
|
158
|
+
</button>
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/* ════════════════════════════════════════════
|
|
166
|
+
* MODE 2: Full list (setup wizard / no configured providers)
|
|
167
|
+
* Original behavior preserved
|
|
168
|
+
* ════════════════════════════════════════════ */
|
|
82
169
|
|
|
83
170
|
return (
|
|
84
171
|
<div className="space-y-2">
|
|
85
|
-
{/* Primary providers
|
|
172
|
+
{/* Primary providers */}
|
|
86
173
|
<div className={compact ? 'flex flex-wrap gap-2' : 'grid grid-cols-1 gap-2'}>
|
|
87
|
-
{primaryItems.map(
|
|
174
|
+
{primaryItems.map(id => compact ? renderCompactTab(id) : renderCard(id))}
|
|
88
175
|
</div>
|
|
89
176
|
|
|
90
|
-
{/*
|
|
177
|
+
{/* More toggle */}
|
|
91
178
|
{moreItems.length > 0 && (
|
|
92
179
|
<>
|
|
93
180
|
<button
|
|
@@ -98,12 +185,14 @@ export default function ProviderSelect({
|
|
|
98
185
|
<ChevronDown size={12} className={`transition-transform ${showMore ? 'rotate-180' : ''}`} />
|
|
99
186
|
{showMore
|
|
100
187
|
? (locale === 'zh' ? '收起' : 'Show less')
|
|
101
|
-
: (locale === 'zh'
|
|
188
|
+
: (locale === 'zh'
|
|
189
|
+
? `更多 (${moreItems.length})`
|
|
190
|
+
: `More (${moreItems.length})`)}
|
|
102
191
|
</button>
|
|
103
192
|
|
|
104
193
|
{showMore && (
|
|
105
194
|
<div className={compact ? 'flex flex-wrap gap-2' : 'grid grid-cols-1 gap-2'}>
|
|
106
|
-
{moreItems.map(
|
|
195
|
+
{moreItems.map(id => compact ? renderCompactTab(id) : renderCard(id))}
|
|
107
196
|
</div>
|
|
108
197
|
)}
|
|
109
198
|
</>
|
|
@@ -129,6 +218,7 @@ export default function ProviderSelect({
|
|
|
129
218
|
)}
|
|
130
219
|
</button>
|
|
131
220
|
)}
|
|
221
|
+
|
|
132
222
|
</div>
|
|
133
223
|
);
|
|
134
224
|
}
|
package/app/hooks/useAskChat.ts
CHANGED
|
@@ -28,21 +28,25 @@ export interface AskChatRefs {
|
|
|
28
28
|
interface UseAskChatOpts {
|
|
29
29
|
currentFile?: string;
|
|
30
30
|
chatMode: AskMode;
|
|
31
|
-
providerOverride: ProviderId | null;
|
|
31
|
+
providerOverride: ProviderId | `p_${string}` | null;
|
|
32
|
+
modelOverride: string | null;
|
|
32
33
|
onFirstMessage?: () => void;
|
|
33
34
|
refs: AskChatRefs;
|
|
34
35
|
errorLabels: { noResponse: string; stopped: string };
|
|
35
36
|
resetInputState: () => void;
|
|
37
|
+
onRestoreInput?: (userMessage: Message) => void;
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export function useAskChat({
|
|
39
41
|
currentFile,
|
|
40
42
|
chatMode,
|
|
41
43
|
providerOverride,
|
|
44
|
+
modelOverride,
|
|
42
45
|
onFirstMessage,
|
|
43
46
|
refs,
|
|
44
47
|
errorLabels,
|
|
45
48
|
resetInputState,
|
|
49
|
+
onRestoreInput,
|
|
46
50
|
}: UseAskChatOpts) {
|
|
47
51
|
const [isLoading, setIsLoading] = useState(false);
|
|
48
52
|
const [loadingPhase, setLoadingPhase] = useState<LoadingPhase>('connecting');
|
|
@@ -51,10 +55,68 @@ export function useAskChat({
|
|
|
51
55
|
const abortRef = useRef<AbortController | null>(null);
|
|
52
56
|
const firstMessageFired = useRef(false);
|
|
53
57
|
|
|
54
|
-
|
|
58
|
+
// Cooldown guard: after stop+retract, briefly block re-submission so that
|
|
59
|
+
// the mouseup on the stop-button position doesn't accidentally trigger the
|
|
60
|
+
// send button that React swaps in at the same DOM position.
|
|
61
|
+
const submitCooldownRef = useRef(false);
|
|
62
|
+
|
|
63
|
+
// Track the pending user message so we can retract it on stop.
|
|
64
|
+
// `userMessageIndex` is the index of the *user* message inside the messages
|
|
65
|
+
// array (the assistant placeholder sits at userMessageIndex + 1).
|
|
66
|
+
const pendingMessageRef = useRef<{
|
|
67
|
+
userMessageIndex: number;
|
|
68
|
+
userMessage: Message;
|
|
69
|
+
} | null>(null);
|
|
70
|
+
|
|
71
|
+
// When true the AbortError handler in submit() skips its own setMessages
|
|
72
|
+
// because stop() already cleaned up the messages array.
|
|
73
|
+
const retractedRef = useRef(false);
|
|
74
|
+
|
|
75
|
+
const stop = useCallback(() => {
|
|
76
|
+
const pending = pendingMessageRef.current;
|
|
77
|
+
|
|
78
|
+
// Abort the fetch first.
|
|
79
|
+
abortRef.current?.abort();
|
|
80
|
+
|
|
81
|
+
if (pending) {
|
|
82
|
+
retractedRef.current = true;
|
|
83
|
+
|
|
84
|
+
// Always remove the user message + assistant response (empty or partial)
|
|
85
|
+
// from the messages array. The user clicked stop — they don't want this
|
|
86
|
+
// exchange in the history at all.
|
|
87
|
+
refs.sessionRef.current?.setMessages(prev => {
|
|
88
|
+
const updated = [...prev];
|
|
89
|
+
const idx = pending.userMessageIndex;
|
|
90
|
+
|
|
91
|
+
// Remove assistant message first (at idx + 1) — may be empty placeholder
|
|
92
|
+
// or a partial streamed response.
|
|
93
|
+
if (idx + 1 < updated.length && updated[idx + 1]?.role === 'assistant') {
|
|
94
|
+
updated.splice(idx + 1, 1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Remove the user message.
|
|
98
|
+
if (idx < updated.length && updated[idx]?.role === 'user') {
|
|
99
|
+
updated.splice(idx, 1);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return updated;
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// Restore text (+ attachments) back into the input box.
|
|
106
|
+
onRestoreInput?.(pending.userMessage);
|
|
107
|
+
|
|
108
|
+
pendingMessageRef.current = null;
|
|
109
|
+
|
|
110
|
+
// Block re-submission for a short window so the browser's mouseup
|
|
111
|
+
// doesn't hit the send button that replaces the stop button.
|
|
112
|
+
submitCooldownRef.current = true;
|
|
113
|
+
setTimeout(() => { submitCooldownRef.current = false; }, 300);
|
|
114
|
+
}
|
|
115
|
+
}, [refs, onRestoreInput]);
|
|
55
116
|
|
|
56
117
|
const submit = useCallback(async (e: React.FormEvent) => {
|
|
57
118
|
e.preventDefault();
|
|
119
|
+
if (submitCooldownRef.current) return; // ignore accidental re-submit after stop
|
|
58
120
|
const m = refs.mentionRef.current;
|
|
59
121
|
const s = refs.slashRef.current;
|
|
60
122
|
const img = refs.imageUploadRef.current;
|
|
@@ -68,15 +130,33 @@ export function useAskChat({
|
|
|
68
130
|
const skill = refs.selectedSkillRef.current;
|
|
69
131
|
const acpAgent = refs.selectedAcpAgentRef.current;
|
|
70
132
|
const pendingImages = img.images.length > 0 ? [...img.images] : undefined;
|
|
133
|
+
// Only store explicitly user-chosen files (filter out auto-included currentFile)
|
|
134
|
+
const explicitAttached = refs.attachedFilesRef.current.filter(f => f !== currentFile);
|
|
135
|
+
const pendingAttachedFiles = explicitAttached.length > 0 ? explicitAttached : undefined;
|
|
136
|
+
const pendingUploadedNames = upl.localAttachments
|
|
137
|
+
.filter(f => f.status !== 'loading')
|
|
138
|
+
.map(f => f.name);
|
|
71
139
|
const userMsg: Message = {
|
|
72
140
|
role: 'user',
|
|
73
141
|
content: text,
|
|
74
142
|
timestamp: Date.now(),
|
|
75
143
|
...(skill && { skillName: skill.name }),
|
|
76
144
|
...(pendingImages && { images: pendingImages }),
|
|
145
|
+
...(pendingAttachedFiles && { attachedFiles: pendingAttachedFiles }),
|
|
146
|
+
...(pendingUploadedNames.length > 0 && { uploadedFileNames: pendingUploadedNames }),
|
|
77
147
|
};
|
|
78
148
|
img.clearImages();
|
|
79
149
|
const requestMessages = [...sess.messages, userMsg];
|
|
150
|
+
|
|
151
|
+
// Track the user message index for potential retraction on stop.
|
|
152
|
+
// The user message is at requestMessages.length - 1; the assistant
|
|
153
|
+
// placeholder we're about to insert will be at requestMessages.length.
|
|
154
|
+
pendingMessageRef.current = {
|
|
155
|
+
userMessageIndex: requestMessages.length - 1,
|
|
156
|
+
userMessage: userMsg,
|
|
157
|
+
};
|
|
158
|
+
retractedRef.current = false;
|
|
159
|
+
|
|
80
160
|
sess.setMessages([...requestMessages, { role: 'assistant', content: '', timestamp: Date.now() }]);
|
|
81
161
|
|
|
82
162
|
resetInputState();
|
|
@@ -114,6 +194,7 @@ export function useAskChat({
|
|
|
114
194
|
selectedAcpAgent: acpAgent,
|
|
115
195
|
mode: chatMode,
|
|
116
196
|
providerOverride: providerOverride ?? undefined,
|
|
197
|
+
modelOverride: modelOverride ?? undefined,
|
|
117
198
|
});
|
|
118
199
|
|
|
119
200
|
const doFetch = async (): Promise<{ finalMessage: Message }> => {
|
|
@@ -187,6 +268,8 @@ export function useAskChat({
|
|
|
187
268
|
return updated;
|
|
188
269
|
});
|
|
189
270
|
}
|
|
271
|
+
// Successfully received response — no longer retractable.
|
|
272
|
+
pendingMessageRef.current = null;
|
|
190
273
|
return;
|
|
191
274
|
} catch (err) {
|
|
192
275
|
lastError = err instanceof Error ? err : new Error(String(err));
|
|
@@ -198,18 +281,21 @@ export function useAskChat({
|
|
|
198
281
|
if (lastError) throw lastError;
|
|
199
282
|
} catch (err) {
|
|
200
283
|
if ((err as Error).name === 'AbortError') {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
284
|
+
// If stop() already retracted the messages, skip writing __error__stopped.
|
|
285
|
+
if (!retractedRef.current) {
|
|
286
|
+
refs.sessionRef.current?.setMessages(prev => {
|
|
287
|
+
const updated = [...prev];
|
|
288
|
+
const lastIdx = updated.length - 1;
|
|
289
|
+
if (lastIdx >= 0 && updated[lastIdx].role === 'assistant') {
|
|
290
|
+
const last = updated[lastIdx];
|
|
291
|
+
const hasContent = last.content.trim() || (last.parts && last.parts.length > 0);
|
|
292
|
+
if (!hasContent) {
|
|
293
|
+
updated[lastIdx] = { role: 'assistant', content: `__error__${errorLabels.stopped}` };
|
|
294
|
+
}
|
|
209
295
|
}
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
296
|
+
return updated;
|
|
297
|
+
});
|
|
298
|
+
}
|
|
213
299
|
} else {
|
|
214
300
|
const errMsg = err instanceof Error ? err.message : 'Something went wrong';
|
|
215
301
|
refs.sessionRef.current?.setMessages(prev => {
|
|
@@ -230,6 +316,7 @@ export function useAskChat({
|
|
|
230
316
|
setIsLoading(false);
|
|
231
317
|
setReconnectAttempt(0);
|
|
232
318
|
abortRef.current = null;
|
|
319
|
+
pendingMessageRef.current = null;
|
|
233
320
|
}
|
|
234
321
|
}, [currentFile, chatMode, providerOverride, errorLabels.noResponse, errorLabels.stopped, onFirstMessage, refs, resetInputState]);
|
|
235
322
|
|
package/app/hooks/useAskPanel.ts
CHANGED
|
@@ -33,6 +33,8 @@ export function useAskPanel(): AskPanelState {
|
|
|
33
33
|
const [desktopAskPopupOpen, setDesktopAskPopupOpen] = useState(false);
|
|
34
34
|
const [askInitialMessage, setAskInitialMessage] = useState('');
|
|
35
35
|
const [askMaximized, setAskMaximized] = useState(false);
|
|
36
|
+
const askMaximizedRef = useRef(false);
|
|
37
|
+
askMaximizedRef.current = askMaximized;
|
|
36
38
|
const [askOpenSource, setAskOpenSource] = useState<'user' | 'guide' | 'guide-next'>('user');
|
|
37
39
|
const [askAcpAgent, setAskAcpAgent] = useState<AcpAgentSelection | null>(null);
|
|
38
40
|
const prevWidthRef = useRef(RIGHT_ASK_DEFAULT_WIDTH);
|
|
@@ -60,7 +62,21 @@ export function useAskPanel(): AskPanelState {
|
|
|
60
62
|
}
|
|
61
63
|
};
|
|
62
64
|
window.addEventListener('storage', onStorage);
|
|
63
|
-
|
|
65
|
+
|
|
66
|
+
// Listen for "dock to panel" from home page fullscreen
|
|
67
|
+
const onOpenPanel = () => {
|
|
68
|
+
setAskPanelOpen(true);
|
|
69
|
+
if (askMaximizedRef.current) {
|
|
70
|
+
setAskMaximized(false);
|
|
71
|
+
setAskPanelWidth(prevWidthRef.current);
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
window.addEventListener('mindos:open-ask-panel', onOpenPanel);
|
|
75
|
+
|
|
76
|
+
return () => {
|
|
77
|
+
window.removeEventListener('storage', onStorage);
|
|
78
|
+
window.removeEventListener('mindos:open-ask-panel', onOpenPanel);
|
|
79
|
+
};
|
|
64
80
|
}, []);
|
|
65
81
|
|
|
66
82
|
// Bridge useAskModal store → right Ask panel or popup
|
package/app/lib/acp/registry.ts
CHANGED
|
@@ -2,10 +2,15 @@
|
|
|
2
2
|
* ACP Registry Client — Fetch and cache the ACP agent registry.
|
|
3
3
|
* The registry lists available ACP agents (Gemini CLI, Claude, Copilot, etc.)
|
|
4
4
|
* with their transport type, command, and metadata.
|
|
5
|
+
*
|
|
6
|
+
* Strategy: Built-in registry from AGENT_DESCRIPTORS is always available as a
|
|
7
|
+
* baseline. CDN registry is fetched in the background and merged on top —
|
|
8
|
+
* CDN entries update existing ones, new CDN-only entries are appended.
|
|
9
|
+
* If CDN is unreachable (e.g. in China), the built-in list still works.
|
|
5
10
|
*/
|
|
6
11
|
|
|
7
12
|
import type { AcpRegistry, AcpRegistryEntry } from './types';
|
|
8
|
-
import { getDescriptorDisplayName, getDescriptorDescription } from './agent-descriptors';
|
|
13
|
+
import { AGENT_DESCRIPTORS, getDescriptorDisplayName, getDescriptorDescription } from './agent-descriptors';
|
|
9
14
|
|
|
10
15
|
/* ── Constants ─────────────────────────────────────────────────────────── */
|
|
11
16
|
|
|
@@ -13,6 +18,58 @@ const REGISTRY_URL = 'https://cdn.agentclientprotocol.com/registry/v1/latest/reg
|
|
|
13
18
|
const CACHE_TTL_MS = 60 * 60 * 1000; // 1 hour
|
|
14
19
|
const FETCH_TIMEOUT_MS = 10_000;
|
|
15
20
|
|
|
21
|
+
/* ── Built-in Registry (from AGENT_DESCRIPTORS) ────────────────────────── */
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Generate a baseline registry from the local AGENT_DESCRIPTORS.
|
|
25
|
+
* This ensures agents like Gemini CLI, CodeBuddy, Claude etc. are always
|
|
26
|
+
* detectable even when CDN is unreachable.
|
|
27
|
+
*
|
|
28
|
+
* We deduplicate by binary name — e.g. 'gemini' and 'gemini-cli' both map
|
|
29
|
+
* to binary 'gemini', so we only keep the canonical entry (shorter ID or
|
|
30
|
+
* the one matching the CDN convention).
|
|
31
|
+
*/
|
|
32
|
+
function buildBuiltinRegistry(): AcpRegistryEntry[] {
|
|
33
|
+
// Preferred IDs per binary — matches what CDN uses
|
|
34
|
+
const CANONICAL_IDS: Record<string, string> = {
|
|
35
|
+
'gemini': 'gemini',
|
|
36
|
+
'claude': 'claude-acp',
|
|
37
|
+
'codebuddy': 'codebuddy-code',
|
|
38
|
+
'codex': 'codex-acp',
|
|
39
|
+
'pi': 'pi-acp',
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const seen = new Set<string>();
|
|
43
|
+
const entries: AcpRegistryEntry[] = [];
|
|
44
|
+
|
|
45
|
+
for (const [id, desc] of Object.entries(AGENT_DESCRIPTORS)) {
|
|
46
|
+
// Skip alias entries — only keep the canonical ID for each binary
|
|
47
|
+
const canonical = CANONICAL_IDS[desc.binary];
|
|
48
|
+
if (canonical && canonical !== id) continue;
|
|
49
|
+
if (seen.has(desc.binary)) continue;
|
|
50
|
+
seen.add(desc.binary);
|
|
51
|
+
|
|
52
|
+
entries.push({
|
|
53
|
+
id,
|
|
54
|
+
name: desc.displayName ?? id,
|
|
55
|
+
description: desc.description ?? '',
|
|
56
|
+
transport: desc.cmd === 'npx' ? 'npx' : 'stdio',
|
|
57
|
+
command: desc.cmd,
|
|
58
|
+
args: desc.args,
|
|
59
|
+
packageName: desc.installCmd?.match(/npm install -g (.+)/)?.[1],
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return entries;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
let builtinAgents: AcpRegistryEntry[] | null = null;
|
|
67
|
+
|
|
68
|
+
function getBuiltinAgents(): AcpRegistryEntry[] {
|
|
69
|
+
if (!builtinAgents) builtinAgents = buildBuiltinRegistry();
|
|
70
|
+
return builtinAgents;
|
|
71
|
+
}
|
|
72
|
+
|
|
16
73
|
/* ── Cache ─────────────────────────────────────────────────────────────── */
|
|
17
74
|
|
|
18
75
|
let cachedRegistry: AcpRegistry | null = null;
|
|
@@ -20,47 +77,72 @@ let cachedRegistry: AcpRegistry | null = null;
|
|
|
20
77
|
/* ── Public API ────────────────────────────────────────────────────────── */
|
|
21
78
|
|
|
22
79
|
/**
|
|
23
|
-
* Fetch the ACP registry from the CDN
|
|
24
|
-
*
|
|
80
|
+
* Fetch the ACP registry from the CDN and merge with built-in entries.
|
|
81
|
+
* Caches for 1 hour. Falls back to built-in registry if CDN is unreachable.
|
|
25
82
|
*/
|
|
26
|
-
export async function fetchAcpRegistry(): Promise<AcpRegistry
|
|
83
|
+
export async function fetchAcpRegistry(): Promise<AcpRegistry> {
|
|
27
84
|
// Return cached if still valid
|
|
28
85
|
if (cachedRegistry && Date.now() - new Date(cachedRegistry.fetchedAt).getTime() < CACHE_TTL_MS) {
|
|
29
86
|
return cachedRegistry;
|
|
30
87
|
}
|
|
31
88
|
|
|
89
|
+
const builtin = getBuiltinAgents();
|
|
90
|
+
|
|
32
91
|
try {
|
|
33
92
|
const res = await fetch(REGISTRY_URL, {
|
|
34
93
|
headers: { 'Accept': 'application/json' },
|
|
35
94
|
signal: AbortSignal.timeout(FETCH_TIMEOUT_MS),
|
|
36
95
|
});
|
|
37
96
|
|
|
38
|
-
if (!res.ok)
|
|
97
|
+
if (!res.ok) {
|
|
98
|
+
return cachedRegistry ?? makeRegistry(builtin, 'builtin');
|
|
99
|
+
}
|
|
39
100
|
|
|
40
101
|
const data = await res.json();
|
|
41
102
|
|
|
42
103
|
// The registry JSON may have varying shapes; normalize it
|
|
43
|
-
const
|
|
104
|
+
const cdnAgents: AcpRegistryEntry[] = parseRegistryEntries(data);
|
|
105
|
+
|
|
106
|
+
// Merge: CDN entries take precedence, built-in entries fill gaps
|
|
107
|
+
const merged = mergeRegistries(builtin, cdnAgents);
|
|
44
108
|
|
|
45
109
|
cachedRegistry = {
|
|
46
110
|
version: data.version ?? '1',
|
|
47
|
-
agents,
|
|
111
|
+
agents: merged,
|
|
48
112
|
fetchedAt: new Date().toISOString(),
|
|
49
113
|
};
|
|
50
114
|
|
|
51
115
|
return cachedRegistry;
|
|
52
116
|
} catch {
|
|
53
|
-
//
|
|
54
|
-
return cachedRegistry ??
|
|
117
|
+
// CDN unreachable — use built-in as baseline
|
|
118
|
+
return cachedRegistry ?? makeRegistry(builtin, 'builtin');
|
|
55
119
|
}
|
|
56
120
|
}
|
|
57
121
|
|
|
122
|
+
/** Merge built-in and CDN registries. CDN entries win on conflict; built-in fills gaps. */
|
|
123
|
+
function mergeRegistries(builtin: AcpRegistryEntry[], cdn: AcpRegistryEntry[]): AcpRegistryEntry[] {
|
|
124
|
+
const byId = new Map<string, AcpRegistryEntry>();
|
|
125
|
+
|
|
126
|
+
// Start with built-in
|
|
127
|
+
for (const entry of builtin) byId.set(entry.id, entry);
|
|
128
|
+
|
|
129
|
+
// CDN overwrites / adds
|
|
130
|
+
for (const entry of cdn) byId.set(entry.id, entry);
|
|
131
|
+
|
|
132
|
+
return Array.from(byId.values());
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function makeRegistry(agents: AcpRegistryEntry[], version: string): AcpRegistry {
|
|
136
|
+
return { version, agents, fetchedAt: new Date().toISOString() };
|
|
137
|
+
}
|
|
138
|
+
|
|
58
139
|
/**
|
|
59
140
|
* Get all available ACP agents from the registry.
|
|
141
|
+
* Always returns at least the built-in agents, even if CDN is unreachable.
|
|
60
142
|
*/
|
|
61
143
|
export async function getAcpAgents(): Promise<AcpRegistryEntry[]> {
|
|
62
144
|
const registry = await fetchAcpRegistry();
|
|
63
|
-
return registry
|
|
145
|
+
return registry.agents;
|
|
64
146
|
}
|
|
65
147
|
|
|
66
148
|
/**
|
package/app/lib/agent/context.ts
CHANGED
|
@@ -62,6 +62,71 @@ export function estimateTokens(messages: AgentMessage[]): number {
|
|
|
62
62
|
// Context limits by model family
|
|
63
63
|
// ---------------------------------------------------------------------------
|
|
64
64
|
|
|
65
|
+
/**
|
|
66
|
+
* Cache for Ollama model context window sizes.
|
|
67
|
+
* Key: "baseUrl::modelName", Value: num_ctx (token count).
|
|
68
|
+
* Avoids querying /api/show on every request.
|
|
69
|
+
*/
|
|
70
|
+
const ollamaContextCache = new Map<string, number>();
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Query Ollama's /api/show endpoint to get the actual context window (num_ctx)
|
|
74
|
+
* for a specific model. Returns undefined if the query fails or the model
|
|
75
|
+
* doesn't report its context size.
|
|
76
|
+
*
|
|
77
|
+
* Results are cached in-memory per baseUrl+model for the process lifetime.
|
|
78
|
+
*/
|
|
79
|
+
export async function getOllamaContextWindow(
|
|
80
|
+
baseUrl: string,
|
|
81
|
+
modelName: string,
|
|
82
|
+
): Promise<number | undefined> {
|
|
83
|
+
const cacheKey = `${baseUrl}::${modelName}`;
|
|
84
|
+
if (ollamaContextCache.has(cacheKey)) return ollamaContextCache.get(cacheKey);
|
|
85
|
+
|
|
86
|
+
// Ollama's /api/show endpoint is at the root, not under /v1
|
|
87
|
+
const ollamaBase = baseUrl.replace(/\/v1\/?$/, '');
|
|
88
|
+
try {
|
|
89
|
+
const resp = await fetch(`${ollamaBase}/api/show`, {
|
|
90
|
+
method: 'POST',
|
|
91
|
+
headers: { 'Content-Type': 'application/json' },
|
|
92
|
+
body: JSON.stringify({ name: modelName }),
|
|
93
|
+
signal: AbortSignal.timeout(3000),
|
|
94
|
+
});
|
|
95
|
+
if (!resp.ok) return undefined;
|
|
96
|
+
|
|
97
|
+
const data = await resp.json() as {
|
|
98
|
+
model_info?: Record<string, unknown>;
|
|
99
|
+
parameters?: string;
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// Method 1: model_info (structured, most reliable)
|
|
103
|
+
let numCtx: number | undefined;
|
|
104
|
+
if (data.model_info) {
|
|
105
|
+
// Different Ollama versions use different key names
|
|
106
|
+
const ctxVal = data.model_info['context_length']
|
|
107
|
+
?? data.model_info['num_ctx']
|
|
108
|
+
?? data.model_info['general.context_length'];
|
|
109
|
+
if (typeof ctxVal === 'number' && ctxVal > 0) {
|
|
110
|
+
numCtx = ctxVal;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
// Method 2: parse from parameters string (fallback)
|
|
115
|
+
if (!numCtx && typeof data.parameters === 'string') {
|
|
116
|
+
const match = data.parameters.match(/num_ctx\s+(\d+)/);
|
|
117
|
+
if (match) numCtx = parseInt(match[1], 10);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (numCtx && numCtx > 0) {
|
|
121
|
+
ollamaContextCache.set(cacheKey, numCtx);
|
|
122
|
+
return numCtx;
|
|
123
|
+
}
|
|
124
|
+
} catch {
|
|
125
|
+
// Network error, timeout, or Ollama not running — fail silently
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
129
|
+
|
|
65
130
|
const MODEL_LIMITS: Record<string, number> = {
|
|
66
131
|
'claude': 200_000,
|
|
67
132
|
'gpt-4o': 128_000,
|