@amir83nasr/10router 0.1.8 → 0.1.9
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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +6 -6
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +23 -23
- package/.next/react-loadable-manifest.json +9 -0
- package/.next/server/app/(dashboard)/dashboard/basic-chat/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/basic-chat/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/basic-chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js +2 -2
- package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/cli-tools/[toolId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/cli-tools/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/cli-tools/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/combos/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/combos/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/console-log/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/console-log/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/console-log/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/endpoint/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/endpoint/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/media-providers/systemone/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/profile/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/profile/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/[id]/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/new/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/new/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js +2 -2
- package/.next/server/app/(dashboard)/dashboard/proxy-pools/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/proxy-pools/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/pxpipe/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/pxpipe/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/pxpipe/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/quota/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/quota/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/quota/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/token-saver/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/token-saver/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/token-saver/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/usage/page.js +1 -1
- package/.next/server/app/(dashboard)/dashboard/usage/page.js.nft.json +1 -1
- package/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +5 -5
- package/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +5 -5
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/api/cli-tools/all-statuses/route.js +1 -1
- package/.next/server/app/api/cli-tools/claude-settings/route.js +1 -1
- package/.next/server/app/api/cli-tools/codex-settings/route.js +1 -1
- package/.next/server/app/api/cli-tools/cowork-mcp-registry/route.js +1 -1
- package/.next/server/app/api/cli-tools/cowork-mcp-tools/route.js +1 -1
- package/.next/server/app/api/cli-tools/cowork-settings/route.js +1 -1
- package/.next/server/app/api/cli-tools/dsh-settings/route.js +1 -1
- package/.next/server/app/api/cli-tools/opencode-settings/route.js +1 -1
- package/.next/server/app/api/combos/[id]/route.js +1 -1
- package/.next/server/app/api/combos/route.js +1 -1
- package/.next/server/app/api/oauth/[provider]/[action]/route.js +1 -1
- package/.next/server/app/api/oauth/codex/bulk-import/route.js +1 -1
- package/.next/server/app/api/oauth/codex/import-token/route.js +1 -1
- package/.next/server/app/api/providers/[id]/models/route.js +1 -1
- package/.next/server/app/api/providers/client/route.js +1 -1
- package/.next/server/app/api/providers/route.js +1 -1
- package/.next/server/app/api/translator/send/route.js +1 -1
- package/.next/server/app/api/translator/translate/route.js +1 -1
- package/.next/server/app/api/tunnel/tailscale-install/route.js +2 -2
- package/.next/server/app/api/usage/[connectionId]/codex-reset-credits/route.js +1 -1
- package/.next/server/app/api/usage/[connectionId]/route.js +1 -1
- package/.next/server/app/api/usage/stream/route.js +2 -6
- package/.next/server/app/api/v1/audio/speech/route.js +1 -1
- package/.next/server/app/api/v1/audio/transcriptions/route.js +1 -1
- package/.next/server/app/api/v1/embeddings/route.js +1 -1
- package/.next/server/app/api/v1/images/generations/route.js +1 -1
- package/.next/server/app/api/v1/systemone/route.js +1 -1
- package/.next/server/app/api/version/route.js +1 -1
- package/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/.next/server/app/callback.html +1 -1
- package/.next/server/app/callback.rsc +6 -6
- package/.next/server/app/callback.segments/_full.segment.rsc +6 -6
- package/.next/server/app/callback.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/callback.segments/callback/__PAGE__.segment.rsc +6 -6
- package/.next/server/app/dashboard/basic-chat.html +1 -1
- package/.next/server/app/dashboard/basic-chat.rsc +7 -7
- package/.next/server/app/dashboard/basic-chat.segments/!KGRhc2hib2FyZCk/dashboard/basic-chat/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/basic-chat.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/basic-chat.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/cli-tools.html +1 -1
- package/.next/server/app/dashboard/cli-tools.rsc +7 -7
- package/.next/server/app/dashboard/cli-tools.segments/!KGRhc2hib2FyZCk/dashboard/cli-tools/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/cli-tools.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/cli-tools.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/combos.html +1 -1
- package/.next/server/app/dashboard/combos.rsc +7 -7
- package/.next/server/app/dashboard/combos.segments/!KGRhc2hib2FyZCk/dashboard/combos/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/combos.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/combos.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/endpoint.html +1 -1
- package/.next/server/app/dashboard/endpoint.rsc +7 -7
- package/.next/server/app/dashboard/endpoint.segments/!KGRhc2hib2FyZCk/dashboard/endpoint/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/endpoint.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/endpoint.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/media-providers/systemone.html +1 -1
- package/.next/server/app/dashboard/media-providers/systemone.rsc +7 -7
- package/.next/server/app/dashboard/media-providers/systemone.segments/!KGRhc2hib2FyZCk/dashboard/media-providers/systemone/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/media-providers/systemone.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/media-providers/systemone.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/profile.html +1 -1
- package/.next/server/app/dashboard/profile.rsc +7 -7
- package/.next/server/app/dashboard/profile.segments/!KGRhc2hib2FyZCk/dashboard/profile/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/profile.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/profile.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/providers/new.html +1 -1
- package/.next/server/app/dashboard/providers/new.rsc +7 -7
- package/.next/server/app/dashboard/providers/new.segments/!KGRhc2hib2FyZCk/dashboard/providers/new/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/providers/new.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/providers/new.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/providers.html +1 -1
- package/.next/server/app/dashboard/providers.rsc +7 -7
- package/.next/server/app/dashboard/providers.segments/!KGRhc2hib2FyZCk/dashboard/providers/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/providers.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/providers.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/proxy-pools.html +1 -1
- package/.next/server/app/dashboard/proxy-pools.rsc +7 -7
- package/.next/server/app/dashboard/proxy-pools.segments/!KGRhc2hib2FyZCk/dashboard/proxy-pools/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/proxy-pools.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/proxy-pools.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/pxpipe.html +1 -1
- package/.next/server/app/dashboard/pxpipe.rsc +7 -7
- package/.next/server/app/dashboard/pxpipe.segments/!KGRhc2hib2FyZCk/dashboard/pxpipe/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/pxpipe.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/pxpipe.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/quota.html +2 -2
- package/.next/server/app/dashboard/quota.rsc +8 -8
- package/.next/server/app/dashboard/quota.segments/!KGRhc2hib2FyZCk/dashboard/quota/__PAGE__.segment.rsc +8 -8
- package/.next/server/app/dashboard/quota.segments/_full.segment.rsc +8 -8
- package/.next/server/app/dashboard/quota.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/.next/server/app/dashboard/settings/pricing.html +1 -1
- package/.next/server/app/dashboard/settings/pricing.rsc +6 -6
- package/.next/server/app/dashboard/settings/pricing.segments/_full.segment.rsc +6 -6
- package/.next/server/app/dashboard/settings/pricing.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/settings/pricing.segments/dashboard/settings/pricing/__PAGE__.segment.rsc +6 -6
- package/.next/server/app/dashboard/token-saver.html +1 -1
- package/.next/server/app/dashboard/token-saver.rsc +6 -6
- package/.next/server/app/dashboard/token-saver.segments/!KGRhc2hib2FyZCk/dashboard/token-saver/__PAGE__.segment.rsc +6 -6
- package/.next/server/app/dashboard/token-saver.segments/_full.segment.rsc +6 -6
- package/.next/server/app/dashboard/token-saver.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard/usage.html +2 -2
- package/.next/server/app/dashboard/usage.rsc +7 -7
- package/.next/server/app/dashboard/usage.segments/!KGRhc2hib2FyZCk/dashboard/usage/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard/usage.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard/usage.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/dashboard.html +1 -1
- package/.next/server/app/dashboard.rsc +7 -7
- package/.next/server/app/dashboard.segments/!KGRhc2hib2FyZCk/dashboard/__PAGE__.segment.rsc +7 -7
- package/.next/server/app/dashboard.segments/_full.segment.rsc +7 -7
- package/.next/server/app/dashboard.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +5 -5
- package/.next/server/app/index.segments/__PAGE__.segment.rsc +5 -5
- package/.next/server/app/index.segments/_full.segment.rsc +5 -5
- package/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/.next/server/app/landing.html +1 -1
- package/.next/server/app/landing.rsc +6 -6
- package/.next/server/app/landing.segments/_full.segment.rsc +6 -6
- package/.next/server/app/landing.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/landing.segments/landing/__PAGE__.segment.rsc +6 -6
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +5 -5
- package/.next/server/app/login.segments/_full.segment.rsc +5 -5
- package/.next/server/app/login.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +5 -5
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +6 -6
- package/.next/server/chunks/1003.js +1 -1
- package/.next/server/chunks/1011.js +1 -1
- package/.next/server/chunks/1194.js +1 -1
- package/.next/server/chunks/1289.js +1 -1
- package/.next/server/chunks/1412.js +1 -1
- package/.next/server/chunks/1633.js +1 -1
- package/.next/server/chunks/1985.js +1 -1
- package/.next/server/chunks/2282.js +8 -4
- package/.next/server/chunks/2339.js +1 -1
- package/.next/server/chunks/2801.js +1 -1
- package/.next/server/chunks/3425.js +1 -1
- package/.next/server/chunks/4364.js +1 -1
- package/.next/server/chunks/460.js +1 -1
- package/.next/server/chunks/5761.js +1 -1
- package/.next/server/chunks/6056.js +1 -1
- package/.next/server/chunks/6343.js +3 -3
- package/.next/server/chunks/6823.js +1 -1
- package/.next/server/chunks/7019.js +2 -2
- package/.next/server/chunks/7348.js +1 -1
- package/.next/server/chunks/7504.js +1 -1
- package/.next/server/chunks/7535.js +2 -2
- package/.next/server/chunks/8923.js +1 -1
- package/.next/server/chunks/9018.js +1 -1
- package/.next/server/chunks/9250.js +1 -1
- package/.next/server/chunks/9429.js +1 -1
- package/.next/server/chunks/9646.js +1 -1
- package/.next/server/chunks/9817.js +67 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/middleware.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{1278-605cc36f762c2ea7.js → 1278-efb46cc82262aa4e.js} +1 -1
- package/.next/static/chunks/{1471-69a7c30abf98c656.js → 1471-10f225f62f7469cc.js} +1 -1
- package/.next/static/chunks/{1699-49be310981e2759e.js → 1699-13ee6864a8a31a96.js} +2 -2
- package/.next/static/chunks/{1830-901fe48c3c62604f.js → 1830-d26d77c95932d7ce.js} +1 -1
- package/.next/static/chunks/1940.1f30124180f22498.js +1 -0
- package/.next/static/chunks/{2836-8e7f4c382297ac97.js → 2836-d97f0aa2718945d5.js} +1 -1
- package/.next/static/chunks/3445-99e12528f235cedb.js +1 -0
- package/.next/static/chunks/{3577-1f02993330d7fba7.js → 3577-cd98d40e3099e1b0.js} +1 -1
- package/.next/static/chunks/{5862-6f3a3a6d4c00100d.js → 5862-f98c2f3d480b80d2.js} +1 -1
- package/.next/static/chunks/6770-e2921b2ce695ed57.js +1 -0
- package/.next/static/chunks/7276-a15e4d56ec28aba8.js +1 -0
- package/.next/static/chunks/{9369-7ef21480b9132957.js → 9369-0d43b295968c2168.js} +1 -1
- package/.next/static/chunks/{9ce8c186-6cd204e9c27ecee1.js → 9ce8c186-3c7d7dbc5d428052.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/[toolId]/{page-9efe55fed2f7c81f.js → page-e8bceccb95695755.js} +2 -2
- package/.next/static/chunks/app/(dashboard)/dashboard/cli-tools/{page-9dcb29085167b384.js → page-adee408d9de02423.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/combos/{page-f5db9f681c6bface.js → page-d4c1e29e8d038f09.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/console-log/{page-d134cc313c9fa0b8.js → page-139200833f7a4ecc.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/endpoint/{page-f2d1a733e7f841cb.js → page-67516b120adbc4d7.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/media-providers/systemone/[id]/{page-0d6e623de6134598.js → page-b751d9603cb82e62.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/{page-e8f1d8be5e294fb0.js → page-315c9f52c472a700.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/providers/[id]/{page-c96cbcc4f5736e36.js → page-d5d480e209fdc55a.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/providers/new/{page-cc51346e464158b1.js → page-61b87a31ba21a055.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/providers/{page-1ee147fbe0693dc1.js → page-2396571281d02804.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/proxy-pools/{page-2287b1915fa887fc.js → page-cfd6bcb7e55d7d18.js} +2 -2
- package/.next/static/chunks/app/(dashboard)/dashboard/pxpipe/{page-696cb5c2703ca1ec.js → page-4d758f53c8cfc308.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/quota/{page-54a329d725734a1f.js → page-fef6edb7aafd8bd0.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/dashboard/usage/{page-a81f78bb43042c30.js → page-697f46461825d7fc.js} +1 -1
- package/.next/static/chunks/app/(dashboard)/{layout-c199eb2ad56ae96a.js → layout-5039502fc12707c9.js} +1 -1
- package/.next/static/chunks/app/{layout-9bd5877ae6198856.js → layout-8810d4df3081b5df.js} +1 -1
- package/.next/static/chunks/webpack-cb89101193742e2b.js +1 -0
- package/CHANGELOG.md +19 -0
- package/open-sse/executors/zed.js +98 -5
- package/open-sse/handlers/chatCore/sseToJsonHandler.js +11 -4
- package/open-sse/providers/pricing.js +24 -10
- package/open-sse/services/usage/antigravity-weekly.js +10 -0
- package/open-sse/services/usage/claude.js +15 -0
- package/open-sse/shared/zedAuth.js +43 -2
- package/open-sse/translator/concerns/prefetch.js +12 -4
- package/open-sse/translator/response/claude-to-openai.js +2 -2
- package/open-sse/utils/streamHandler.js +1 -5
- package/package.json +1 -1
- package/src/app/(dashboard)/dashboard/providers/[id]/BulkImportGrokCliModal.tsx +1 -1
- package/src/app/(dashboard)/dashboard/providers/[id]/page.tsx +1 -1
- package/src/app/(dashboard)/dashboard/usage/components/ProviderTopology.tsx +5 -2
- package/src/app/api/combos/[id]/route.js +38 -1
- package/src/app/api/combos/route.js +27 -2
- package/src/app/api/providers/[id]/models/route.js +12 -1
- package/src/app/api/providers/route.js +4 -1
- package/src/app/api/usage/stream/route.js +74 -68
- package/src/app/api/v1/models/route.js +20 -6
- package/src/lib/db/index.js +3 -0
- package/src/lib/db/repos/settingsRepo.js +22 -1
- package/src/lib/oauth/services/xai.js +4 -4
- package/src/lib/validateComboModels.ts +48 -0
- package/src/shared/components/UsageStats.tsx +7 -1
- package/src/shared/hooks/useShutdown.ts +2 -4
- package/src/sse/handlers/chat.js +5 -1
- package/src/sse/services/antigravityQuota.ts +7 -3
- package/src/sse/services/model.ts +9 -20
- package/.next/server/chunks/5351.js +0 -67
- package/.next/static/chunks/3973-424848b943e2ecab.js +0 -1
- package/.next/static/chunks/7276-16ef14f7b2cd478d.js +0 -1
- package/.next/static/chunks/webpack-452a2f4aec1a53ee.js +0 -1
- /package/.next/static/{iz7psrsEuHZGPvj7rbSWc → awjDWqWCZbU3VVSuN7-oA}/_buildManifest.js +0 -0
- /package/.next/static/{iz7psrsEuHZGPvj7rbSWc → awjDWqWCZbU3VVSuN7-oA}/_ssgManifest.js +0 -0
|
@@ -2,84 +2,90 @@ import { getUsageStats, statsEmitter, getActiveRequests } from "@/lib/usageDb";
|
|
|
2
2
|
|
|
3
3
|
export const dynamic = "force-dynamic";
|
|
4
4
|
|
|
5
|
+
// ── SHARED STATS CACHE ───────────────────────────────────────────────────
|
|
6
|
+
// Every open dashboard tab holds one of these streams, and statsEmitter fires
|
|
7
|
+
// on every saved request. Recomputing getUsageStats() (two full table reads +
|
|
8
|
+
// a 100-row scan + the whole daily-summary fold) once per client per event
|
|
9
|
+
// made server CPU scale with tabs × request rate. One cache + one in-flight
|
|
10
|
+
// recompute, shared by every subscriber in this process, makes N tabs cost the
|
|
11
|
+
// same as one. Module scope persists across requests in the Node server.
|
|
12
|
+
//
|
|
13
|
+
// Only the active/recent overlay is pushed downstream (that is all the client
|
|
14
|
+
// merges), so the heavy snapshot is read for its cached fields alone.
|
|
15
|
+
let cache = null;
|
|
16
|
+
let inflight = null;
|
|
17
|
+
|
|
18
|
+
// Concurrent bursts collapse onto a single getUsageStats() call.
|
|
19
|
+
function refreshStats() {
|
|
20
|
+
if (!inflight) {
|
|
21
|
+
inflight = Promise.resolve()
|
|
22
|
+
.then(() => getUsageStats("all"))
|
|
23
|
+
.then((stats) => {
|
|
24
|
+
cache = stats;
|
|
25
|
+
return stats;
|
|
26
|
+
})
|
|
27
|
+
.catch(() => cache) // keep serving the last good snapshot
|
|
28
|
+
.finally(() => {
|
|
29
|
+
inflight = null;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return inflight;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Fresh active/recent overlay, primed by the shared snapshot. Null before the
|
|
36
|
+
// first compute so callers can skip a duplicate push.
|
|
37
|
+
async function overlay() {
|
|
38
|
+
if (!cache) await refreshStats();
|
|
39
|
+
if (!cache) return null;
|
|
40
|
+
return getActiveRequests();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// ── STREAM ───────────────────────────────────────────────────────────────
|
|
5
44
|
export async function GET() {
|
|
6
45
|
const encoder = new TextEncoder();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
46
|
+
let closed = false;
|
|
47
|
+
let keepalive = null;
|
|
48
|
+
let controller = null;
|
|
49
|
+
|
|
50
|
+
const write = (chunk) => {
|
|
51
|
+
if (closed) return;
|
|
52
|
+
try {
|
|
53
|
+
controller.enqueue(encoder.encode(chunk));
|
|
54
|
+
} catch {
|
|
55
|
+
teardown();
|
|
56
|
+
}
|
|
13
57
|
};
|
|
14
58
|
|
|
15
|
-
const
|
|
16
|
-
async start(controller) {
|
|
17
|
-
// Full stats refresh (heavy) + immediate lightweight push
|
|
18
|
-
state.send = async () => {
|
|
19
|
-
if (state.closed) return;
|
|
20
|
-
try {
|
|
21
|
-
// Push lightweight update immediately so UI reflects changes fast
|
|
22
|
-
if (state.cachedStats) {
|
|
23
|
-
const { activeRequests, recentRequests, errorProvider } = await getActiveRequests();
|
|
24
|
-
const quickStats = {
|
|
25
|
-
...state.cachedStats,
|
|
26
|
-
activeRequests,
|
|
27
|
-
recentRequests,
|
|
28
|
-
errorProvider,
|
|
29
|
-
};
|
|
30
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(quickStats)}\n\n`));
|
|
31
|
-
}
|
|
32
|
-
// Then do full recalc and update cache
|
|
33
|
-
const stats = await getUsageStats();
|
|
34
|
-
state.cachedStats = stats;
|
|
35
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(stats)}\n\n`));
|
|
36
|
-
} catch {
|
|
37
|
-
state.closed = true;
|
|
38
|
-
statsEmitter.off("update", state.send);
|
|
39
|
-
statsEmitter.off("pending", state.sendPending);
|
|
40
|
-
clearInterval(state.keepalive);
|
|
41
|
-
}
|
|
42
|
-
};
|
|
59
|
+
const sendEvent = (payload) => write(`data: ${JSON.stringify(payload)}\n\n`);
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const stats = { ...state.cachedStats, activeRequests, recentRequests, errorProvider };
|
|
50
|
-
controller.enqueue(encoder.encode(`data: ${JSON.stringify(stats)}\n\n`));
|
|
51
|
-
} catch {
|
|
52
|
-
state.closed = true;
|
|
53
|
-
statsEmitter.off("update", state.send);
|
|
54
|
-
statsEmitter.off("pending", state.sendPending);
|
|
55
|
-
clearInterval(state.keepalive);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
61
|
+
const send = async () => {
|
|
62
|
+
if (closed) return;
|
|
63
|
+
const stats = await overlay();
|
|
64
|
+
if (stats && !closed) sendEvent(stats);
|
|
65
|
+
};
|
|
58
66
|
|
|
59
|
-
|
|
67
|
+
// Cheap path: only the active/recent overlay moved.
|
|
68
|
+
const sendPending = send;
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
|
|
70
|
+
const teardown = () => {
|
|
71
|
+
if (closed) return;
|
|
72
|
+
closed = true;
|
|
73
|
+
statsEmitter.off("update", send);
|
|
74
|
+
statsEmitter.off("pending", sendPending);
|
|
75
|
+
clearInterval(keepalive);
|
|
76
|
+
};
|
|
63
77
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
state.closed = true;
|
|
73
|
-
clearInterval(state.keepalive);
|
|
74
|
-
}
|
|
75
|
-
}, 25000);
|
|
78
|
+
const stream = new ReadableStream({
|
|
79
|
+
async start(c) {
|
|
80
|
+
controller = c;
|
|
81
|
+
await send();
|
|
82
|
+
if (closed) return;
|
|
83
|
+
statsEmitter.on("update", send);
|
|
84
|
+
statsEmitter.on("pending", sendPending);
|
|
85
|
+
keepalive = setInterval(() => write(": ping\n\n"), 25000);
|
|
76
86
|
},
|
|
77
|
-
|
|
78
87
|
cancel() {
|
|
79
|
-
|
|
80
|
-
statsEmitter.off("update", state.send);
|
|
81
|
-
statsEmitter.off("pending", state.sendPending);
|
|
82
|
-
clearInterval(state.keepalive);
|
|
88
|
+
teardown();
|
|
83
89
|
},
|
|
84
90
|
});
|
|
85
91
|
|
|
@@ -108,10 +108,22 @@ const LIVE_MODEL_RESOLVERS = {
|
|
|
108
108
|
return result?.models?.length ? { models: result.models } : null;
|
|
109
109
|
},
|
|
110
110
|
zed: async (conn) => {
|
|
111
|
-
const
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
111
|
+
const proxy = await resolveConnectionProxyConfig(conn.providerSpecificData || {});
|
|
112
|
+
const result = await resolveZedModels(
|
|
113
|
+
{
|
|
114
|
+
accessToken: conn.accessToken,
|
|
115
|
+
providerSpecificData: conn.providerSpecificData || {},
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
proxyOptions: {
|
|
119
|
+
connectionProxyEnabled: proxy.connectionProxyEnabled === true,
|
|
120
|
+
connectionProxyUrl: proxy.connectionProxyUrl || "",
|
|
121
|
+
connectionNoProxy: proxy.connectionNoProxy || "",
|
|
122
|
+
vercelRelayUrl: proxy.vercelRelayUrl || "",
|
|
123
|
+
strictProxy: proxy.strictProxy === true,
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
);
|
|
115
127
|
if (!result?.models?.length) return null;
|
|
116
128
|
return {
|
|
117
129
|
models: result.models
|
|
@@ -182,10 +194,12 @@ async function fetchCompatibleModelIds(connection) {
|
|
|
182
194
|
if (isOpenAICompatibleProvider(connection.provider)) {
|
|
183
195
|
headers.Authorization = `Bearer ${connection.apiKey}`;
|
|
184
196
|
} else if (isAnthropicCompatibleProvider(connection.provider)) {
|
|
197
|
+
// Anthropic's model list lives at the API root, not under /messages.
|
|
198
|
+
// `-"/messages".length` matters: a bare -9 eats the "m" of "models".
|
|
185
199
|
if (url.endsWith("/messages/models")) {
|
|
186
|
-
url = url.slice(0, -
|
|
200
|
+
url = url.slice(0, -"/messages".length);
|
|
187
201
|
} else if (url.endsWith("/messages")) {
|
|
188
|
-
url = `${url.slice(0, -
|
|
202
|
+
url = `${url.slice(0, -"/messages".length)}/models`;
|
|
189
203
|
}
|
|
190
204
|
headers["x-api-key"] = connection.apiKey;
|
|
191
205
|
headers["anthropic-version"] = "2023-06-01";
|
package/src/lib/db/index.js
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
// Public API barrel — all DB functions
|
|
2
2
|
import { getAdapter } from "./driver.js";
|
|
3
3
|
import { stringifyJson, parseJson } from "./helpers/jsonCol.js";
|
|
4
|
+
import { invalidateSettingsCache } from "./repos/settingsRepo.js";
|
|
4
5
|
|
|
5
6
|
// Settings
|
|
6
7
|
export {
|
|
7
8
|
getSettings,
|
|
8
9
|
updateSettings,
|
|
10
|
+
invalidateSettingsCache,
|
|
9
11
|
isCloudEnabled,
|
|
10
12
|
getCloudUrl,
|
|
11
13
|
exportSettings,
|
|
@@ -303,6 +305,7 @@ export async function importDb(payload) {
|
|
|
303
305
|
}
|
|
304
306
|
});
|
|
305
307
|
|
|
308
|
+
invalidateSettingsCache(); // writes here bypass updateSettings
|
|
306
309
|
return await exportDb();
|
|
307
310
|
}
|
|
308
311
|
|
|
@@ -62,10 +62,23 @@ const DEFAULT_SETTINGS = {
|
|
|
62
62
|
pxpipeTimeoutMs: 15000,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
+
// Settings are read ~3× per chat request (chat.js twice, auth.ts once) and
|
|
66
|
+
// re-merge ~40 defaults each time. Same short-TTL pattern as
|
|
67
|
+
// requestDetailsRepo's CONFIG_CACHE_TTL_MS; writes refresh it immediately.
|
|
68
|
+
const SETTINGS_CACHE_TTL_MS = 2000;
|
|
69
|
+
|
|
70
|
+
let cachedSettings = null;
|
|
71
|
+
let cachedSettingsTs = 0;
|
|
72
|
+
|
|
65
73
|
async function readRaw() {
|
|
74
|
+
if (cachedSettings && Date.now() - cachedSettingsTs < SETTINGS_CACHE_TTL_MS) {
|
|
75
|
+
return cachedSettings;
|
|
76
|
+
}
|
|
66
77
|
const db = await getAdapter();
|
|
67
78
|
const row = db.get(`SELECT data FROM settings WHERE id = 1`);
|
|
68
|
-
|
|
79
|
+
cachedSettings = row ? parseJson(row.data, {}) : {};
|
|
80
|
+
cachedSettingsTs = Date.now();
|
|
81
|
+
return cachedSettings;
|
|
69
82
|
}
|
|
70
83
|
|
|
71
84
|
// Merge raw settings with defaults; backward-compat for missing keys
|
|
@@ -92,6 +105,12 @@ export async function getSettings() {
|
|
|
92
105
|
return mergeWithDefaults(raw);
|
|
93
106
|
}
|
|
94
107
|
|
|
108
|
+
// For writers that bypass updateSettings (bulk restore in db/index.js).
|
|
109
|
+
export function invalidateSettingsCache() {
|
|
110
|
+
cachedSettings = null;
|
|
111
|
+
cachedSettingsTs = 0;
|
|
112
|
+
}
|
|
113
|
+
|
|
95
114
|
// Atomic read-merge-write inside transaction (prevents losing concurrent updates)
|
|
96
115
|
export async function updateSettings(updates) {
|
|
97
116
|
const db = await getAdapter();
|
|
@@ -105,6 +124,8 @@ export async function updateSettings(updates) {
|
|
|
105
124
|
[stringifyJson(next)],
|
|
106
125
|
);
|
|
107
126
|
});
|
|
127
|
+
cachedSettings = next;
|
|
128
|
+
cachedSettingsTs = Date.now();
|
|
108
129
|
return mergeWithDefaults(next);
|
|
109
130
|
}
|
|
110
131
|
|
|
@@ -202,10 +202,6 @@ export class XaiService extends OAuthService {
|
|
|
202
202
|
|
|
203
203
|
spinner.start("Waiting for xAI authorization...");
|
|
204
204
|
await new Promise((resolve, reject) => {
|
|
205
|
-
const timeout = setTimeout(
|
|
206
|
-
() => reject(new Error("Authentication timeout (5 minutes)")),
|
|
207
|
-
300000,
|
|
208
|
-
);
|
|
209
205
|
const iv = setInterval(() => {
|
|
210
206
|
if (callbackParams) {
|
|
211
207
|
clearInterval(iv);
|
|
@@ -213,6 +209,10 @@ export class XaiService extends OAuthService {
|
|
|
213
209
|
resolve();
|
|
214
210
|
}
|
|
215
211
|
}, 100);
|
|
212
|
+
const timeout = setTimeout(() => {
|
|
213
|
+
clearInterval(iv); // else the 100ms poll spins forever after reject
|
|
214
|
+
reject(new Error("Authentication timeout (5 minutes)"));
|
|
215
|
+
}, 300000);
|
|
216
216
|
});
|
|
217
217
|
close();
|
|
218
218
|
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// Combo member validation (server-side, POST/PUT /api/combos).
|
|
2
|
+
//
|
|
3
|
+
// A member is valid when it is `provider/model` (provider resolved later at
|
|
4
|
+
// request time), a model alias, or another combo (nested). Anything else —
|
|
5
|
+
// bare words like "Support"/"Last" from a bad paste — dies at request time
|
|
6
|
+
// with "Invalid model format" and burns the whole combo run, so reject it at
|
|
7
|
+
// save time with a message naming the bad entries.
|
|
8
|
+
|
|
9
|
+
export interface ComboMemberContext {
|
|
10
|
+
aliases?: Record<string, unknown>;
|
|
11
|
+
comboNames?: string[];
|
|
12
|
+
selfName?: string | null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function findComboMemberProblems(
|
|
16
|
+
members: unknown,
|
|
17
|
+
{ aliases = {}, comboNames = [], selfName = null }: ComboMemberContext = {},
|
|
18
|
+
): string[] {
|
|
19
|
+
if (!Array.isArray(members)) return ["models must be an array"];
|
|
20
|
+
const problems: string[] = [];
|
|
21
|
+
const seen = new Set<string>();
|
|
22
|
+
for (const raw of members) {
|
|
23
|
+
const m = typeof raw === "string" ? raw.trim() : "";
|
|
24
|
+
if (!m) {
|
|
25
|
+
problems.push("empty model entry");
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
if (seen.has(m)) {
|
|
29
|
+
problems.push(`duplicate model "${m}"`);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
seen.add(m);
|
|
33
|
+
if (m.includes("/")) {
|
|
34
|
+
const slash = m.indexOf("/");
|
|
35
|
+
if (slash === 0 || slash === m.length - 1)
|
|
36
|
+
problems.push(`bad model shape "${m}" (want provider/model)`);
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (selfName && m === selfName) {
|
|
40
|
+
problems.push(`combo "${m}" cannot include itself`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (aliases && aliases[m]) continue;
|
|
44
|
+
if (comboNames.includes(m)) continue;
|
|
45
|
+
problems.push(`unknown model "${m}" (want provider/model, an alias, or a combo)`);
|
|
46
|
+
}
|
|
47
|
+
return problems;
|
|
48
|
+
}
|
|
@@ -31,7 +31,13 @@ const ProviderTopology = dynamic(
|
|
|
31
31
|
() => import("@/app/(dashboard)/dashboard/usage/components/ProviderTopology"),
|
|
32
32
|
{ ssr: false },
|
|
33
33
|
);
|
|
34
|
-
|
|
34
|
+
// Lazy-load: keeps recharts out of the usage page's initial bundle
|
|
35
|
+
const UsageChart = dynamic(
|
|
36
|
+
() => import("@/app/(dashboard)/dashboard/usage/components/UsageChart"),
|
|
37
|
+
{
|
|
38
|
+
ssr: false,
|
|
39
|
+
},
|
|
40
|
+
);
|
|
35
41
|
import ProviderHealth from "@/app/(dashboard)/dashboard/usage/components/ProviderHealth";
|
|
36
42
|
|
|
37
43
|
function timeAgo(timestamp: any) {
|
|
@@ -32,6 +32,8 @@ export function useShutdown() {
|
|
|
32
32
|
timers.current.push(t as unknown as number);
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
|
+
// Poll finished: leaving the spinner is part of the same transition.
|
|
36
|
+
setShuttingDown(false);
|
|
35
37
|
if (Date.now() >= deadline - HEALTH_POLL_MS) setTimedOut(true);
|
|
36
38
|
else setStopped(true);
|
|
37
39
|
}, []);
|
|
@@ -60,9 +62,5 @@ export function useShutdown() {
|
|
|
60
62
|
setTimedOut(false);
|
|
61
63
|
}, []);
|
|
62
64
|
|
|
63
|
-
useEffect(() => {
|
|
64
|
-
if (stopped || timedOut) setShuttingDown(false);
|
|
65
|
-
}, [stopped, timedOut]);
|
|
66
|
-
|
|
67
65
|
return { confirmOpen, shuttingDown, stopped, timedOut, open, confirm, reset };
|
|
68
66
|
}
|
package/src/sse/handlers/chat.js
CHANGED
|
@@ -312,7 +312,11 @@ async function handleSingleModelChat(
|
|
|
312
312
|
if (pid) {
|
|
313
313
|
refreshedCredentials.projectId = pid;
|
|
314
314
|
// Persist to DB in background so subsequent requests have it immediately
|
|
315
|
-
updateProviderCredentials(credentials.connectionId, { projectId: pid }).catch(() => {
|
|
315
|
+
updateProviderCredentials(credentials.connectionId, { projectId: pid }).catch((err) => {
|
|
316
|
+
// Not fatal — next request re-resolves the projectId — but log it,
|
|
317
|
+
// otherwise a broken write silently costs latency on every request.
|
|
318
|
+
log.warn("CHAT", `failed to persist projectId for ${credentials.connectionId}:`, err);
|
|
319
|
+
});
|
|
316
320
|
}
|
|
317
321
|
}
|
|
318
322
|
|
|
@@ -134,14 +134,18 @@ async function _doRefresh(
|
|
|
134
134
|
const usage = await getAntigravityUsage(accessToken, providerSpecificData, proxyOptions);
|
|
135
135
|
// 401/403 usage responses can contain an empty quotas object plus message.
|
|
136
136
|
// Preserve known cache instead of replacing it with an upstream error response.
|
|
137
|
-
|
|
137
|
+
// (Empty `{}` is a valid empty snapshot, not a missing one.)
|
|
138
|
+
// Producer is untyped JS, so the shape is asserted at this boundary.
|
|
139
|
+
const quotas = usage?.quotas as
|
|
140
|
+
Record<string, { remainingPercentage: number; resetAt?: string }> | undefined;
|
|
141
|
+
if (!quotas || usage.message) return null;
|
|
138
142
|
|
|
139
143
|
// Update in-memory cache. Caller logs CACHE_BLOCK only if requested model is exhausted.
|
|
140
144
|
// Strike blocks are re-asserted after every refresh so an optimistic
|
|
141
145
|
// upstream reading cannot resurrect a pair we just circuit-broke.
|
|
142
|
-
quotaCache.set(connectionId, applyActiveStrikeBlocks(connectionId,
|
|
146
|
+
quotaCache.set(connectionId, applyActiveStrikeBlocks(connectionId, quotas));
|
|
143
147
|
|
|
144
|
-
return
|
|
148
|
+
return quotas;
|
|
145
149
|
} catch (e: any) {
|
|
146
150
|
log.warn("AG_QUOTA", `${connectionId.slice(0, 8)} | refresh failed: ${e.message}`);
|
|
147
151
|
return null;
|
|
@@ -46,26 +46,15 @@ export async function getModelInfo(modelStr: string): Promise<any> {
|
|
|
46
46
|
// Provider-node prefixes are user-defined. They must not override built-in
|
|
47
47
|
// provider ids/aliases such as `cf`, `openai`, or `hf`.
|
|
48
48
|
if (!RESERVED_PROVIDER_PREFIXES.has(parsed.providerAlias)) {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
(
|
|
58
|
-
);
|
|
59
|
-
if (matchedAnthropic) {
|
|
60
|
-
return { provider: matchedAnthropic.id, model: parsed.model };
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const embeddingNodes = await getProviderNodes({ type: "custom-embedding" });
|
|
64
|
-
const matchedEmbedding = embeddingNodes.find(
|
|
65
|
-
(node: any) => node.prefix === parsed.providerAlias,
|
|
66
|
-
);
|
|
67
|
-
if (matchedEmbedding) {
|
|
68
|
-
return { provider: matchedEmbedding.id, model: parsed.model };
|
|
49
|
+
// One scan instead of three identical type-filtered queries; prefix→id
|
|
50
|
+
// matching is unambiguous across node types (checked in that order).
|
|
51
|
+
const nodes = await getProviderNodes();
|
|
52
|
+
const NODE_TYPE_ORDER = ["openai-compatible", "anthropic-compatible", "custom-embedding"];
|
|
53
|
+
for (const type of NODE_TYPE_ORDER) {
|
|
54
|
+
const match = nodes.find(
|
|
55
|
+
(node: any) => node.type === type && node.prefix === parsed.providerAlias,
|
|
56
|
+
);
|
|
57
|
+
if (match) return { provider: match.id, model: parsed.model };
|
|
69
58
|
}
|
|
70
59
|
}
|
|
71
60
|
return {
|