omniroute 2.8.5 → 2.8.7
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/app/.next/BUILD_ID +1 -1
- package/app/.next/build-manifest.json +2 -2
- package/app/.next/prerender-manifest.json +3 -3
- package/app/.next/server/app/(dashboard)/dashboard/a2a/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/agents/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/analytics/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/api-manager/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/audit-log/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/auto-combo/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/cli-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/combos/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/costs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/endpoint/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/health/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/limits/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/logs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/mcp/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/media/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/onboarding/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/playground/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/profile/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/[id]/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/new/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/providers/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/search-tools/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/settings/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/settings/pricing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/translator/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/(dashboard)/dashboard/usage/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/400/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/401/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/403/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/408/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/429/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/500/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/502/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/503/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/_global-error.html +2 -2
- package/app/.next/server/app/_global-error.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/app/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/app/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/api/acp/agents/route.js +1 -1
- package/app/.next/server/app/api/acp/agents/route.js.nft.json +1 -1
- package/app/.next/server/app/api/auth/login/route.js +1 -1
- package/app/.next/server/app/api/auth/login/route.js.nft.json +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route.js +1 -1
- package/app/.next/server/app/api/cli-tools/antigravity-mitm/alias/route.js.nft.json +1 -1
- package/app/.next/server/app/api/cloud/auth/route.js +1 -1
- package/app/.next/server/app/api/cloud/auth/route.js.nft.json +1 -1
- package/app/.next/server/app/api/cloud/credentials/update/route.js +1 -1
- package/app/.next/server/app/api/cloud/credentials/update/route.js.nft.json +1 -1
- package/app/.next/server/app/api/cloud/model/resolve/route.js +1 -1
- package/app/.next/server/app/api/cloud/model/resolve/route.js.nft.json +1 -1
- package/app/.next/server/app/api/cloud/models/alias/route.js +1 -1
- package/app/.next/server/app/api/cloud/models/alias/route.js.nft.json +1 -1
- package/app/.next/server/app/api/combos/[id]/route.js +1 -1
- package/app/.next/server/app/api/combos/[id]/route.js.nft.json +1 -1
- package/app/.next/server/app/api/combos/route.js +1 -1
- package/app/.next/server/app/api/combos/route.js.nft.json +1 -1
- package/app/.next/server/app/api/combos/test/route.js +1 -1
- package/app/.next/server/app/api/combos/test/route.js.nft.json +1 -1
- package/app/.next/server/app/api/db-backups/export/route.js +1 -1
- package/app/.next/server/app/api/db-backups/export/route.js.nft.json +1 -1
- package/app/.next/server/app/api/db-backups/import/route.js +1 -1
- package/app/.next/server/app/api/db-backups/import/route.js.nft.json +1 -1
- package/app/.next/server/app/api/db-backups/route.js +1 -1
- package/app/.next/server/app/api/db-backups/route.js.nft.json +1 -1
- package/app/.next/server/app/api/keys/[id]/route.js +1 -1
- package/app/.next/server/app/api/keys/[id]/route.js.nft.json +1 -1
- package/app/.next/server/app/api/keys/route.js +1 -1
- package/app/.next/server/app/api/keys/route.js.nft.json +1 -1
- package/app/.next/server/app/api/logs/detail/route.js +1 -1
- package/app/.next/server/app/api/logs/detail/route.js.nft.json +1 -1
- package/app/.next/server/app/api/models/alias/route.js +1 -1
- package/app/.next/server/app/api/models/alias/route.js.nft.json +1 -1
- package/app/.next/server/app/api/models/openrouter-catalog/route.js +1 -1
- package/app/.next/server/app/api/models/openrouter-catalog/route.js.nft.json +1 -1
- package/app/.next/server/app/api/models/route.js +1 -1
- package/app/.next/server/app/api/models/route.js.nft.json +1 -1
- package/app/.next/server/app/api/monitoring/health/route.js +1 -1
- package/app/.next/server/app/api/monitoring/health/route.js.nft.json +1 -1
- package/app/.next/server/app/api/oauth/[provider]/[action]/route.js +1 -1
- package/app/.next/server/app/api/oauth/[provider]/[action]/route.js.nft.json +1 -1
- package/app/.next/server/app/api/oauth/cursor/auto-import/route.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/auto-import/route.js.nft.json +1 -1
- package/app/.next/server/app/api/oauth/cursor/import/route.js +1 -1
- package/app/.next/server/app/api/oauth/cursor/import/route.js.nft.json +1 -1
- package/app/.next/server/app/api/oauth/kiro/auto-import/route.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/auto-import/route.js.nft.json +1 -1
- package/app/.next/server/app/api/oauth/kiro/import/route.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/import/route.js.nft.json +1 -1
- package/app/.next/server/app/api/oauth/kiro/social-exchange/route.js +1 -1
- package/app/.next/server/app/api/oauth/kiro/social-exchange/route.js.nft.json +1 -1
- package/app/.next/server/app/api/pricing/models/route.js +1 -1
- package/app/.next/server/app/api/pricing/models/route.js.nft.json +1 -1
- package/app/.next/server/app/api/pricing/route.js +1 -1
- package/app/.next/server/app/api/pricing/route.js.nft.json +1 -1
- package/app/.next/server/app/api/provider-models/route.js +2 -2
- package/app/.next/server/app/api/provider-models/route.js.nft.json +1 -1
- package/app/.next/server/app/api/provider-nodes/[id]/route.js +1 -1
- package/app/.next/server/app/api/provider-nodes/[id]/route.js.nft.json +1 -1
- package/app/.next/server/app/api/provider-nodes/route.js +1 -1
- package/app/.next/server/app/api/provider-nodes/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/[id]/models/route.js +1 -1
- package/app/.next/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/[id]/refresh/route.js +1 -1
- package/app/.next/server/app/api/providers/[id]/refresh/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/[id]/route.js +1 -1
- package/app/.next/server/app/api/providers/[id]/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/[id]/test/route.js +1 -1
- package/app/.next/server/app/api/providers/[id]/test/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/client/route.js +1 -1
- package/app/.next/server/app/api/providers/client/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/route.js +1 -1
- package/app/.next/server/app/api/providers/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/test-batch/route.js +2 -2
- package/app/.next/server/app/api/providers/test-batch/route.js.nft.json +1 -1
- package/app/.next/server/app/api/providers/validate/route.js +1 -1
- package/app/.next/server/app/api/providers/validate/route.js.nft.json +1 -1
- package/app/.next/server/app/api/rate-limits/route.js +1 -1
- package/app/.next/server/app/api/rate-limits/route.js.nft.json +1 -1
- package/app/.next/server/app/api/resilience/route.js +1 -1
- package/app/.next/server/app/api/resilience/route.js.nft.json +1 -1
- package/app/.next/server/app/api/search/providers/route.js +1 -1
- package/app/.next/server/app/api/search/providers/route.js.nft.json +1 -1
- package/app/.next/server/app/api/search/stats/route.js +1 -1
- package/app/.next/server/app/api/search/stats/route.js.nft.json +1 -1
- package/app/.next/server/app/api/settings/codex-service-tier/route.js +1 -1
- package/app/.next/server/app/api/settings/codex-service-tier/route.js.nft.json +1 -1
- package/app/.next/server/app/api/settings/combo-defaults/route.js +1 -1
- package/app/.next/server/app/api/settings/combo-defaults/route.js.nft.json +1 -1
- package/app/.next/server/app/api/settings/proxies/assignments/route.js +2 -2
- package/app/.next/server/app/api/settings/proxies/bulk-assign/route.js +2 -2
- package/app/.next/server/app/api/settings/proxies/route.js +1 -1
- package/app/.next/server/app/api/settings/proxy/route.js +2 -2
- package/app/.next/server/app/api/settings/require-login/route.js +1 -1
- package/app/.next/server/app/api/settings/require-login/route.js.nft.json +1 -1
- package/app/.next/server/app/api/settings/route.js +1 -1
- package/app/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/app/.next/server/app/api/settings/system-prompt/route.js +1 -1
- package/app/.next/server/app/api/settings/system-prompt/route.js.nft.json +1 -1
- package/app/.next/server/app/api/settings/thinking-budget/route.js +1 -1
- package/app/.next/server/app/api/settings/thinking-budget/route.js.nft.json +1 -1
- package/app/.next/server/app/api/sync/cloud/route.js +1 -1
- package/app/.next/server/app/api/sync/cloud/route.js.nft.json +1 -1
- package/app/.next/server/app/api/sync/initialize/route.js +1 -1
- package/app/.next/server/app/api/sync/initialize/route.js.nft.json +1 -1
- package/app/.next/server/app/api/system/version/route.js +1 -1
- package/app/.next/server/app/api/system/version/route.js.nft.json +1 -1
- package/app/.next/server/app/api/translator/send/route.js +1 -1
- package/app/.next/server/app/api/translator/send/route.js.nft.json +1 -1
- package/app/.next/server/app/api/translator/translate/route.js +1 -1
- package/app/.next/server/app/api/translator/translate/route.js.nft.json +1 -1
- package/app/.next/server/app/api/usage/quota/route.js +1 -1
- package/app/.next/server/app/api/usage/quota/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/embeddings/route.js +7 -6
- package/app/.next/server/app/api/v1/embeddings/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/management/proxies/assignments/route.js +1 -1
- package/app/.next/server/app/api/v1/management/proxies/assignments/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/management/proxies/bulk-assign/route.js +1 -1
- package/app/.next/server/app/api/v1/management/proxies/bulk-assign/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/management/proxies/health/route.js +1 -1
- package/app/.next/server/app/api/v1/management/proxies/health/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/management/proxies/route.js +1 -1
- package/app/.next/server/app/api/v1/management/proxies/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/models/route.js +1 -1
- package/app/.next/server/app/api/v1/models/route.js.nft.json +1 -1
- package/app/.next/server/app/api/v1/route.js +1 -1
- package/app/.next/server/app/api/v1/route.js.nft.json +1 -1
- package/app/.next/server/app/callback/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/forbidden/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/forgot-password/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/landing/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/maintenance/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/offline/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/status/page_client-reference-manifest.js +1 -1
- package/app/.next/server/app/terms/page_client-reference-manifest.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__007da72e._.js +3 -0
- package/app/.next/server/chunks/[root-of-the-server]__09c944b3._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__784fb7c5._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__7d9b23e7._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__80e3bfc3._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__84e445b2._.js +2 -2
- package/app/.next/server/chunks/[root-of-the-server]__92cb0def._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__a630d6ef._.js +5 -5
- package/app/.next/server/chunks/[root-of-the-server]__c8e3c8a9._.js +50 -0
- package/app/.next/server/chunks/[root-of-the-server]__d4563e10._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__db2f9fe0._.js +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__e27a89bd._.js +1 -1
- package/app/.next/server/chunks/_05c48915._.js +1 -1
- package/app/.next/server/chunks/_1244636c._.js +2 -2
- package/app/.next/server/chunks/_14963fed._.js +1 -1
- package/app/.next/server/chunks/_1717e651._.js +1 -1
- package/app/.next/server/chunks/_2115d8de._.js +1 -1
- package/app/.next/server/chunks/_3ac953eb._.js +1 -1
- package/app/.next/server/chunks/_4b8fd853._.js +1 -1
- package/app/.next/server/chunks/_5677b5e2._.js +1 -1
- package/app/.next/server/chunks/_5bbb2e7a._.js +1 -1
- package/app/.next/server/chunks/_68683848._.js +1 -1
- package/app/.next/server/chunks/_b39b1914._.js +3 -0
- package/app/.next/server/chunks/_c05b9de3._.js +1 -1
- package/app/.next/server/chunks/_c795fc74._.js +1 -1
- package/app/.next/server/chunks/_ee7b7859._.js +1 -1
- package/app/.next/server/chunks/_ee9b677b._.js +1 -1
- package/app/.next/server/chunks/open-sse_translator_index_ts_f5fd0821._.js +2 -2
- package/app/.next/server/chunks/src_lib_localDb_ts_83220848._.js +1 -1
- package/app/.next/server/chunks/src_shared_validation_schemas_ts_4e63863a._.js +1 -1
- package/app/.next/server/chunks/ssr/[root-of-the-server]__9affb65e._.js +1 -1
- package/app/.next/server/chunks/ssr/[root-of-the-server]__a6942102._.js +1 -1
- package/app/.next/server/chunks/ssr/src_9197fb9b._.js +1 -1
- package/app/.next/server/chunks/ssr/src_d3225e36._.js +1 -1
- package/app/.next/server/chunks/ssr/src_i18n_messages_en_json_c3d5c412._.js +1 -1
- package/app/.next/server/chunks/ssr/src_i18n_messages_zh-CN_json_f4112d90._.js +1 -1
- package/app/.next/server/pages/500.html +2 -2
- package/app/.next/server/server-reference-manifest.js +1 -1
- package/app/.next/server/server-reference-manifest.json +1 -1
- package/app/.next/static/chunks/1042694db0c08f1f.css +1 -0
- package/app/.next/static/chunks/{ec1938d17386c6db.js → 34569b4e9d93c0ad.js} +2 -2
- package/app/.next/static/chunks/{d9a70775eb233dc3.js → 53e0c73d409ce003.js} +1 -1
- package/app/.next/static/chunks/91761ba00c702cff.js +1 -0
- package/app/CHANGELOG.md +50 -0
- package/app/docs/openapi.yaml +1 -1
- package/app/open-sse/handlers/chatCore.ts +6 -2
- package/app/open-sse/services/rateLimitManager.ts +10 -5
- package/app/open-sse/services/roleNormalizer.ts +14 -19
- package/app/open-sse/translator/index.ts +27 -3
- package/app/package-lock.json +2 -2
- package/app/package.json +1 -1
- package/app/src/app/(dashboard)/dashboard/cli-tools/CLIToolsPageClient.tsx +12 -0
- package/app/src/app/(dashboard)/dashboard/cli-tools/components/AntigravityToolCard.tsx +5 -5
- package/app/src/app/(dashboard)/dashboard/providers/[id]/page.tsx +381 -62
- package/app/src/app/api/provider-models/route.ts +47 -6
- package/app/src/app/api/v1/embeddings/route.ts +33 -3
- package/app/src/i18n/messages/en.json +10 -0
- package/app/src/i18n/messages/zh-CN.json +10 -0
- package/app/src/lib/db/models.ts +130 -13
- package/app/src/lib/localDb.ts +5 -0
- package/app/src/shared/validation/schemas.ts +1 -0
- package/package.json +1 -1
- package/app/.next/server/chunks/[root-of-the-server]__3972de72._.js +0 -50
- package/app/.next/server/chunks/[root-of-the-server]__6b56b04f._.js +0 -3
- package/app/.next/static/chunks/af071ff826ecff1b.css +0 -1
- package/app/.next/static/chunks/d19ab4efcaddd1db.js +0 -1
- /package/app/.next/static/{coLESPH6_RrEzzULWq8F5 → zi0Yj1AW2_CKS-WmB5ZUc}/_buildManifest.js +0 -0
- /package/app/.next/static/{coLESPH6_RrEzzULWq8F5 → zi0Yj1AW2_CKS-WmB5ZUc}/_clientMiddlewareManifest.json +0 -0
- /package/app/.next/static/{coLESPH6_RrEzzULWq8F5 → zi0Yj1AW2_CKS-WmB5ZUc}/_ssgManifest.js +0 -0
|
@@ -43,6 +43,78 @@ function normalizeCodexLimitPolicy(policy: unknown): { use5h: boolean; useWeekly
|
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
+
function ModelCompatPopover({
|
|
47
|
+
t,
|
|
48
|
+
normalizeToolCallId,
|
|
49
|
+
preserveDeveloperRole,
|
|
50
|
+
showDeveloperToggle = true,
|
|
51
|
+
onNormalizeChange,
|
|
52
|
+
onPreserveChange,
|
|
53
|
+
disabled,
|
|
54
|
+
}: {
|
|
55
|
+
t: (key: string) => string;
|
|
56
|
+
normalizeToolCallId: boolean;
|
|
57
|
+
preserveDeveloperRole?: boolean;
|
|
58
|
+
showDeveloperToggle?: boolean;
|
|
59
|
+
onNormalizeChange: (v: boolean) => void;
|
|
60
|
+
onPreserveChange: (v: boolean) => void;
|
|
61
|
+
disabled?: boolean;
|
|
62
|
+
}) {
|
|
63
|
+
const [open, setOpen] = useState(false);
|
|
64
|
+
const ref = useRef<HTMLDivElement>(null);
|
|
65
|
+
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (!open) return;
|
|
68
|
+
const onDocClick = (e: MouseEvent) => {
|
|
69
|
+
if (ref.current && !ref.current.contains(e.target as Node)) setOpen(false);
|
|
70
|
+
};
|
|
71
|
+
document.addEventListener("mousedown", onDocClick);
|
|
72
|
+
return () => document.removeEventListener("mousedown", onDocClick);
|
|
73
|
+
}, [open]);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div className="relative inline-block" ref={ref}>
|
|
77
|
+
<button
|
|
78
|
+
type="button"
|
|
79
|
+
onClick={() => setOpen((v) => !v)}
|
|
80
|
+
disabled={disabled}
|
|
81
|
+
className="inline-flex items-center gap-1 px-2 py-1 text-xs rounded-md border border-border bg-sidebar/50 hover:bg-sidebar text-text-muted hover:text-text-main disabled:opacity-50"
|
|
82
|
+
title={t("compatAdjustmentsTitle")}
|
|
83
|
+
>
|
|
84
|
+
<span className="material-symbols-outlined text-sm">tune</span>
|
|
85
|
+
{t("compatButtonLabel")}
|
|
86
|
+
</button>
|
|
87
|
+
{open && (
|
|
88
|
+
<div className="absolute left-0 top-full mt-1 z-50 min-w-[200px] p-3 rounded-lg border border-border bg-white dark:bg-zinc-900 shadow-xl ring-1 ring-black/5 dark:ring-white/10">
|
|
89
|
+
<p className="text-[10px] font-semibold uppercase tracking-wide text-text-muted mb-2">
|
|
90
|
+
{t("compatAdjustmentsTitle")}
|
|
91
|
+
</p>
|
|
92
|
+
<div className="flex flex-col gap-3">
|
|
93
|
+
<Toggle
|
|
94
|
+
size="sm"
|
|
95
|
+
label={t("compatToolIdShort")}
|
|
96
|
+
title={t("normalizeToolCallIdLabel")}
|
|
97
|
+
checked={normalizeToolCallId}
|
|
98
|
+
onChange={onNormalizeChange}
|
|
99
|
+
disabled={disabled}
|
|
100
|
+
/>
|
|
101
|
+
{showDeveloperToggle && (
|
|
102
|
+
<Toggle
|
|
103
|
+
size="sm"
|
|
104
|
+
label={t("compatDoNotPreserveDeveloper")}
|
|
105
|
+
title={t("preserveDeveloperRoleLabel")}
|
|
106
|
+
checked={preserveDeveloperRole === false}
|
|
107
|
+
onChange={(checked) => onPreserveChange(!checked)}
|
|
108
|
+
disabled={disabled}
|
|
109
|
+
/>
|
|
110
|
+
)}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
)}
|
|
114
|
+
</div>
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
|
|
46
118
|
export default function ProviderDetailPage() {
|
|
47
119
|
const params = useParams();
|
|
48
120
|
const router = useRouter();
|
|
@@ -76,6 +148,15 @@ export default function ProviderDetailPage() {
|
|
|
76
148
|
error: "",
|
|
77
149
|
importedCount: 0,
|
|
78
150
|
});
|
|
151
|
+
const [modelMeta, setModelMeta] = useState<{
|
|
152
|
+
customModels: Record<string, unknown>[];
|
|
153
|
+
modelCompatOverrides: {
|
|
154
|
+
id: string;
|
|
155
|
+
normalizeToolCallId?: boolean;
|
|
156
|
+
preserveOpenAIDeveloperRole?: boolean;
|
|
157
|
+
}[];
|
|
158
|
+
}>({ customModels: [], modelCompatOverrides: [] });
|
|
159
|
+
const [compatSavingModelId, setCompatSavingModelId] = useState<string | null>(null);
|
|
79
160
|
|
|
80
161
|
const providerInfo = providerNode
|
|
81
162
|
? {
|
|
@@ -119,6 +200,23 @@ export default function ProviderDetailPage() {
|
|
|
119
200
|
}
|
|
120
201
|
}, []);
|
|
121
202
|
|
|
203
|
+
const fetchProviderModelMeta = useCallback(async () => {
|
|
204
|
+
if (isSearchProvider) return;
|
|
205
|
+
try {
|
|
206
|
+
const res = await fetch(`/api/provider-models?provider=${encodeURIComponent(providerId)}`, {
|
|
207
|
+
cache: "no-store",
|
|
208
|
+
});
|
|
209
|
+
if (!res.ok) return;
|
|
210
|
+
const data = await res.json();
|
|
211
|
+
setModelMeta({
|
|
212
|
+
customModels: data.models || [],
|
|
213
|
+
modelCompatOverrides: data.modelCompatOverrides || [],
|
|
214
|
+
});
|
|
215
|
+
} catch (e) {
|
|
216
|
+
console.error("fetchProviderModelMeta", e);
|
|
217
|
+
}
|
|
218
|
+
}, [providerId, isSearchProvider]);
|
|
219
|
+
|
|
122
220
|
const fetchConnections = useCallback(async () => {
|
|
123
221
|
try {
|
|
124
222
|
const [connectionsRes, nodesRes] = await Promise.all([
|
|
@@ -186,6 +284,11 @@ export default function ProviderDetailPage() {
|
|
|
186
284
|
.catch(() => {});
|
|
187
285
|
}, [fetchConnections, fetchAliases]);
|
|
188
286
|
|
|
287
|
+
useEffect(() => {
|
|
288
|
+
if (loading || isSearchProvider) return;
|
|
289
|
+
fetchProviderModelMeta();
|
|
290
|
+
}, [loading, isSearchProvider, fetchProviderModelMeta]);
|
|
291
|
+
|
|
189
292
|
// Auto-open Add Connection modal when no connections exist (better UX)
|
|
190
293
|
// Only fires once on initial load, not on HMR remounts or after user dismissal
|
|
191
294
|
useEffect(() => {
|
|
@@ -670,6 +773,79 @@ export default function ProviderDetailPage() {
|
|
|
670
773
|
|
|
671
774
|
const canImportModels = connections.some((conn) => conn.isActive !== false);
|
|
672
775
|
|
|
776
|
+
const effectiveModelNormalize = (modelId: string) => {
|
|
777
|
+
const c = modelMeta.customModels.find((m: { id?: string }) => m.id === modelId) as
|
|
778
|
+
| { normalizeToolCallId?: boolean }
|
|
779
|
+
| undefined;
|
|
780
|
+
if (c) return Boolean(c.normalizeToolCallId);
|
|
781
|
+
const o = modelMeta.modelCompatOverrides.find((e) => e.id === modelId);
|
|
782
|
+
return Boolean(o?.normalizeToolCallId);
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
const effectiveModelPreserveDeveloper = (modelId: string) => {
|
|
786
|
+
const c = modelMeta.customModels.find((m: { id?: string }) => m.id === modelId) as
|
|
787
|
+
| Record<string, unknown>
|
|
788
|
+
| undefined;
|
|
789
|
+
if (c && Object.prototype.hasOwnProperty.call(c, "preserveOpenAIDeveloperRole")) {
|
|
790
|
+
return Boolean(c.preserveOpenAIDeveloperRole);
|
|
791
|
+
}
|
|
792
|
+
const o = modelMeta.modelCompatOverrides.find((e) => e.id === modelId);
|
|
793
|
+
if (o && Object.prototype.hasOwnProperty.call(o, "preserveOpenAIDeveloperRole")) {
|
|
794
|
+
return Boolean(o.preserveOpenAIDeveloperRole);
|
|
795
|
+
}
|
|
796
|
+
return true;
|
|
797
|
+
};
|
|
798
|
+
|
|
799
|
+
const saveModelCompatFlags = async (
|
|
800
|
+
modelId: string,
|
|
801
|
+
patch: { normalizeToolCallId?: boolean; preserveOpenAIDeveloperRole?: boolean }
|
|
802
|
+
) => {
|
|
803
|
+
setCompatSavingModelId(modelId);
|
|
804
|
+
try {
|
|
805
|
+
const c = modelMeta.customModels.find((m: { id?: string }) => m.id === modelId) as Record<
|
|
806
|
+
string,
|
|
807
|
+
unknown
|
|
808
|
+
> | null;
|
|
809
|
+
let body: Record<string, unknown>;
|
|
810
|
+
if (c) {
|
|
811
|
+
body = {
|
|
812
|
+
provider: providerId,
|
|
813
|
+
modelId,
|
|
814
|
+
modelName: (c.name as string) || modelId,
|
|
815
|
+
source: (c.source as string) || "manual",
|
|
816
|
+
apiFormat: (c.apiFormat as string) || "chat-completions",
|
|
817
|
+
supportedEndpoints:
|
|
818
|
+
Array.isArray(c.supportedEndpoints) && (c.supportedEndpoints as unknown[]).length
|
|
819
|
+
? c.supportedEndpoints
|
|
820
|
+
: ["chat"],
|
|
821
|
+
normalizeToolCallId:
|
|
822
|
+
patch.normalizeToolCallId !== undefined
|
|
823
|
+
? patch.normalizeToolCallId
|
|
824
|
+
: Boolean(c.normalizeToolCallId),
|
|
825
|
+
preserveOpenAIDeveloperRole:
|
|
826
|
+
patch.preserveOpenAIDeveloperRole !== undefined
|
|
827
|
+
? patch.preserveOpenAIDeveloperRole
|
|
828
|
+
: Object.prototype.hasOwnProperty.call(c, "preserveOpenAIDeveloperRole")
|
|
829
|
+
? Boolean(c.preserveOpenAIDeveloperRole)
|
|
830
|
+
: true,
|
|
831
|
+
};
|
|
832
|
+
} else {
|
|
833
|
+
body = { provider: providerId, modelId, ...patch };
|
|
834
|
+
}
|
|
835
|
+
const res = await fetch("/api/provider-models", {
|
|
836
|
+
method: "PUT",
|
|
837
|
+
headers: { "Content-Type": "application/json" },
|
|
838
|
+
body: JSON.stringify(body),
|
|
839
|
+
});
|
|
840
|
+
if (res.ok) await fetchProviderModelMeta();
|
|
841
|
+
else notify.error(t("failedSaveCustomModel"));
|
|
842
|
+
} catch {
|
|
843
|
+
notify.error(t("failedSaveCustomModel"));
|
|
844
|
+
} finally {
|
|
845
|
+
setCompatSavingModelId(null);
|
|
846
|
+
}
|
|
847
|
+
};
|
|
848
|
+
|
|
673
849
|
const renderModelsSection = () => {
|
|
674
850
|
if (isCompatible) {
|
|
675
851
|
return (
|
|
@@ -684,6 +860,12 @@ export default function ProviderDetailPage() {
|
|
|
684
860
|
connections={connections}
|
|
685
861
|
isAnthropic={isAnthropicCompatible}
|
|
686
862
|
onImportWithProgress={handleCompatibleImportWithProgress}
|
|
863
|
+
t={t}
|
|
864
|
+
effectiveModelNormalize={effectiveModelNormalize}
|
|
865
|
+
effectiveModelPreserveDeveloper={effectiveModelPreserveDeveloper}
|
|
866
|
+
saveModelCompatFlags={saveModelCompatFlags}
|
|
867
|
+
compatSavingModelId={compatSavingModelId}
|
|
868
|
+
onModelsChanged={fetchProviderModelMeta}
|
|
687
869
|
/>
|
|
688
870
|
);
|
|
689
871
|
}
|
|
@@ -711,6 +893,11 @@ export default function ProviderDetailPage() {
|
|
|
711
893
|
onCopy={copy}
|
|
712
894
|
onSetAlias={handleSetAlias}
|
|
713
895
|
onDeleteAlias={handleDeleteAlias}
|
|
896
|
+
t={t}
|
|
897
|
+
effectiveModelNormalize={effectiveModelNormalize}
|
|
898
|
+
effectiveModelPreserveDeveloper={effectiveModelPreserveDeveloper}
|
|
899
|
+
saveModelCompatFlags={saveModelCompatFlags}
|
|
900
|
+
compatSavingModelId={compatSavingModelId}
|
|
714
901
|
/>
|
|
715
902
|
</div>
|
|
716
903
|
);
|
|
@@ -759,8 +946,17 @@ export default function ProviderDetailPage() {
|
|
|
759
946
|
alias={existingAlias}
|
|
760
947
|
copied={copied}
|
|
761
948
|
onCopy={copy}
|
|
762
|
-
|
|
763
|
-
|
|
949
|
+
t={t}
|
|
950
|
+
showDeveloperToggle
|
|
951
|
+
normalizeToolCallId={effectiveModelNormalize(model.id)}
|
|
952
|
+
preserveDeveloperRole={effectiveModelPreserveDeveloper(model.id)}
|
|
953
|
+
onNormalizeChange={(v) =>
|
|
954
|
+
saveModelCompatFlags(model.id, { normalizeToolCallId: v })
|
|
955
|
+
}
|
|
956
|
+
onPreserveChange={(v) =>
|
|
957
|
+
saveModelCompatFlags(model.id, { preserveOpenAIDeveloperRole: v })
|
|
958
|
+
}
|
|
959
|
+
compatDisabled={compatSavingModelId === model.id}
|
|
764
960
|
/>
|
|
765
961
|
);
|
|
766
962
|
})}
|
|
@@ -1078,6 +1274,7 @@ export default function ProviderDetailPage() {
|
|
|
1078
1274
|
providerAlias={providerDisplayAlias}
|
|
1079
1275
|
copied={copied}
|
|
1080
1276
|
onCopy={copy}
|
|
1277
|
+
onModelsChanged={fetchProviderModelMeta}
|
|
1081
1278
|
/>
|
|
1082
1279
|
)}
|
|
1083
1280
|
</Card>
|
|
@@ -1282,23 +1479,48 @@ export default function ProviderDetailPage() {
|
|
|
1282
1479
|
);
|
|
1283
1480
|
}
|
|
1284
1481
|
|
|
1285
|
-
function ModelRow({
|
|
1286
|
-
|
|
1482
|
+
function ModelRow({
|
|
1483
|
+
model,
|
|
1484
|
+
fullModel,
|
|
1485
|
+
alias,
|
|
1486
|
+
copied,
|
|
1487
|
+
onCopy,
|
|
1488
|
+
t,
|
|
1489
|
+
showDeveloperToggle = true,
|
|
1490
|
+
normalizeToolCallId,
|
|
1491
|
+
preserveDeveloperRole,
|
|
1492
|
+
onNormalizeChange,
|
|
1493
|
+
onPreserveChange,
|
|
1494
|
+
compatDisabled,
|
|
1495
|
+
}: any) {
|
|
1287
1496
|
return (
|
|
1288
|
-
<div className="flex
|
|
1289
|
-
<
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
</code>
|
|
1293
|
-
<button
|
|
1294
|
-
onClick={() => onCopy(fullModel, `model-${model.id}`)}
|
|
1295
|
-
className="p-0.5 hover:bg-sidebar rounded text-text-muted hover:text-primary"
|
|
1296
|
-
title={t("copyModel")}
|
|
1297
|
-
>
|
|
1298
|
-
<span className="material-symbols-outlined text-sm">
|
|
1299
|
-
{copied === `model-${model.id}` ? "check" : "content_copy"}
|
|
1497
|
+
<div className="flex flex-col px-3 py-2 rounded-lg border border-border hover:bg-sidebar/50 min-w-[220px] max-w-md">
|
|
1498
|
+
<div className="flex items-center gap-2 flex-wrap">
|
|
1499
|
+
<span className="material-symbols-outlined text-base text-text-muted shrink-0">
|
|
1500
|
+
smart_toy
|
|
1300
1501
|
</span>
|
|
1301
|
-
|
|
1502
|
+
<code className="text-xs text-text-muted font-mono bg-sidebar px-1.5 py-0.5 rounded">
|
|
1503
|
+
{fullModel}
|
|
1504
|
+
</code>
|
|
1505
|
+
<button
|
|
1506
|
+
onClick={() => onCopy(fullModel, `model-${model.id}`)}
|
|
1507
|
+
className="p-0.5 hover:bg-sidebar rounded text-text-muted hover:text-primary"
|
|
1508
|
+
title={t("copyModel")}
|
|
1509
|
+
>
|
|
1510
|
+
<span className="material-symbols-outlined text-sm">
|
|
1511
|
+
{copied === `model-${model.id}` ? "check" : "content_copy"}
|
|
1512
|
+
</span>
|
|
1513
|
+
</button>
|
|
1514
|
+
</div>
|
|
1515
|
+
<ModelCompatPopover
|
|
1516
|
+
t={t}
|
|
1517
|
+
normalizeToolCallId={Boolean(normalizeToolCallId)}
|
|
1518
|
+
preserveDeveloperRole={preserveDeveloperRole}
|
|
1519
|
+
showDeveloperToggle={showDeveloperToggle}
|
|
1520
|
+
onNormalizeChange={onNormalizeChange}
|
|
1521
|
+
onPreserveChange={onPreserveChange}
|
|
1522
|
+
disabled={compatDisabled}
|
|
1523
|
+
/>
|
|
1302
1524
|
</div>
|
|
1303
1525
|
);
|
|
1304
1526
|
}
|
|
@@ -1311,6 +1533,13 @@ ModelRow.propTypes = {
|
|
|
1311
1533
|
alias: PropTypes.string,
|
|
1312
1534
|
copied: PropTypes.string,
|
|
1313
1535
|
onCopy: PropTypes.func.isRequired,
|
|
1536
|
+
t: PropTypes.func,
|
|
1537
|
+
showDeveloperToggle: PropTypes.bool,
|
|
1538
|
+
normalizeToolCallId: PropTypes.bool,
|
|
1539
|
+
preserveDeveloperRole: PropTypes.bool,
|
|
1540
|
+
onNormalizeChange: PropTypes.func,
|
|
1541
|
+
onPreserveChange: PropTypes.func,
|
|
1542
|
+
compatDisabled: PropTypes.bool,
|
|
1314
1543
|
};
|
|
1315
1544
|
|
|
1316
1545
|
function PassthroughModelsSection({
|
|
@@ -1320,12 +1549,15 @@ function PassthroughModelsSection({
|
|
|
1320
1549
|
onCopy,
|
|
1321
1550
|
onSetAlias,
|
|
1322
1551
|
onDeleteAlias,
|
|
1552
|
+
t,
|
|
1553
|
+
effectiveModelNormalize,
|
|
1554
|
+
effectiveModelPreserveDeveloper,
|
|
1555
|
+
saveModelCompatFlags,
|
|
1556
|
+
compatSavingModelId,
|
|
1323
1557
|
}) {
|
|
1324
|
-
const t = useTranslations("providers");
|
|
1325
1558
|
const [newModel, setNewModel] = useState("");
|
|
1326
1559
|
const [adding, setAdding] = useState(false);
|
|
1327
1560
|
|
|
1328
|
-
// Filter aliases for this provider - models are persisted via alias
|
|
1329
1561
|
const providerAliases = Object.entries(modelAliases).filter(([, model]: [string, any]) =>
|
|
1330
1562
|
(model as string).startsWith(`${providerAlias}/`)
|
|
1331
1563
|
);
|
|
@@ -1400,6 +1632,15 @@ function PassthroughModelsSection({
|
|
|
1400
1632
|
copied={copied}
|
|
1401
1633
|
onCopy={onCopy}
|
|
1402
1634
|
onDeleteAlias={() => onDeleteAlias(alias)}
|
|
1635
|
+
t={t}
|
|
1636
|
+
showDeveloperToggle
|
|
1637
|
+
normalizeToolCallId={effectiveModelNormalize(modelId)}
|
|
1638
|
+
preserveDeveloperRole={effectiveModelPreserveDeveloper(modelId)}
|
|
1639
|
+
onNormalizeChange={(v) => saveModelCompatFlags(modelId, { normalizeToolCallId: v })}
|
|
1640
|
+
onPreserveChange={(v) =>
|
|
1641
|
+
saveModelCompatFlags(modelId, { preserveOpenAIDeveloperRole: v })
|
|
1642
|
+
}
|
|
1643
|
+
compatDisabled={compatSavingModelId === modelId}
|
|
1403
1644
|
/>
|
|
1404
1645
|
))}
|
|
1405
1646
|
</div>
|
|
@@ -1415,41 +1656,69 @@ PassthroughModelsSection.propTypes = {
|
|
|
1415
1656
|
onCopy: PropTypes.func.isRequired,
|
|
1416
1657
|
onSetAlias: PropTypes.func.isRequired,
|
|
1417
1658
|
onDeleteAlias: PropTypes.func.isRequired,
|
|
1659
|
+
t: PropTypes.func.isRequired,
|
|
1660
|
+
effectiveModelNormalize: PropTypes.func.isRequired,
|
|
1661
|
+
effectiveModelPreserveDeveloper: PropTypes.func.isRequired,
|
|
1662
|
+
saveModelCompatFlags: PropTypes.func.isRequired,
|
|
1663
|
+
compatSavingModelId: PropTypes.string,
|
|
1418
1664
|
};
|
|
1419
1665
|
|
|
1420
|
-
function PassthroughModelRow({
|
|
1421
|
-
|
|
1666
|
+
function PassthroughModelRow({
|
|
1667
|
+
modelId,
|
|
1668
|
+
fullModel,
|
|
1669
|
+
copied,
|
|
1670
|
+
onCopy,
|
|
1671
|
+
onDeleteAlias,
|
|
1672
|
+
t,
|
|
1673
|
+
showDeveloperToggle = true,
|
|
1674
|
+
normalizeToolCallId,
|
|
1675
|
+
preserveDeveloperRole,
|
|
1676
|
+
onNormalizeChange,
|
|
1677
|
+
onPreserveChange,
|
|
1678
|
+
compatDisabled,
|
|
1679
|
+
}: any) {
|
|
1422
1680
|
return (
|
|
1423
|
-
<div className="flex
|
|
1424
|
-
<
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
<
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1681
|
+
<div className="flex flex-col gap-0 p-3 rounded-lg border border-border hover:bg-sidebar/50">
|
|
1682
|
+
<div className="flex items-start gap-3">
|
|
1683
|
+
<span className="material-symbols-outlined text-base text-text-muted shrink-0">
|
|
1684
|
+
smart_toy
|
|
1685
|
+
</span>
|
|
1686
|
+
<div className="flex-1 min-w-0">
|
|
1687
|
+
<p className="text-sm font-medium truncate">{modelId}</p>
|
|
1688
|
+
<div className="flex items-center gap-1 mt-1 flex-wrap">
|
|
1689
|
+
<code className="text-xs text-text-muted font-mono bg-sidebar px-1.5 py-0.5 rounded">
|
|
1690
|
+
{fullModel}
|
|
1691
|
+
</code>
|
|
1692
|
+
<button
|
|
1693
|
+
onClick={() => onCopy(fullModel, `model-${modelId}`)}
|
|
1694
|
+
className="p-0.5 hover:bg-sidebar rounded text-text-muted hover:text-primary"
|
|
1695
|
+
title={t("copyModel")}
|
|
1696
|
+
>
|
|
1697
|
+
<span className="material-symbols-outlined text-sm">
|
|
1698
|
+
{copied === `model-${modelId}` ? "check" : "content_copy"}
|
|
1699
|
+
</span>
|
|
1700
|
+
</button>
|
|
1701
|
+
</div>
|
|
1442
1702
|
</div>
|
|
1703
|
+
<button
|
|
1704
|
+
onClick={onDeleteAlias}
|
|
1705
|
+
className="p-1 hover:bg-red-50 rounded text-red-500 shrink-0"
|
|
1706
|
+
title={t("removeModel")}
|
|
1707
|
+
>
|
|
1708
|
+
<span className="material-symbols-outlined text-sm">delete</span>
|
|
1709
|
+
</button>
|
|
1710
|
+
</div>
|
|
1711
|
+
<div className="pl-9">
|
|
1712
|
+
<ModelCompatPopover
|
|
1713
|
+
t={t}
|
|
1714
|
+
normalizeToolCallId={Boolean(normalizeToolCallId)}
|
|
1715
|
+
preserveDeveloperRole={preserveDeveloperRole}
|
|
1716
|
+
showDeveloperToggle={showDeveloperToggle}
|
|
1717
|
+
onNormalizeChange={onNormalizeChange}
|
|
1718
|
+
onPreserveChange={onPreserveChange}
|
|
1719
|
+
disabled={compatDisabled}
|
|
1720
|
+
/>
|
|
1443
1721
|
</div>
|
|
1444
|
-
|
|
1445
|
-
{/* Delete button */}
|
|
1446
|
-
<button
|
|
1447
|
-
onClick={onDeleteAlias}
|
|
1448
|
-
className="p-1 hover:bg-red-50 rounded text-red-500"
|
|
1449
|
-
title={t("removeModel")}
|
|
1450
|
-
>
|
|
1451
|
-
<span className="material-symbols-outlined text-sm">delete</span>
|
|
1452
|
-
</button>
|
|
1453
1722
|
</div>
|
|
1454
1723
|
);
|
|
1455
1724
|
}
|
|
@@ -1460,11 +1729,18 @@ PassthroughModelRow.propTypes = {
|
|
|
1460
1729
|
copied: PropTypes.string,
|
|
1461
1730
|
onCopy: PropTypes.func.isRequired,
|
|
1462
1731
|
onDeleteAlias: PropTypes.func.isRequired,
|
|
1732
|
+
t: PropTypes.func,
|
|
1733
|
+
showDeveloperToggle: PropTypes.bool,
|
|
1734
|
+
normalizeToolCallId: PropTypes.bool,
|
|
1735
|
+
preserveDeveloperRole: PropTypes.bool,
|
|
1736
|
+
onNormalizeChange: PropTypes.func,
|
|
1737
|
+
onPreserveChange: PropTypes.func,
|
|
1738
|
+
compatDisabled: PropTypes.bool,
|
|
1463
1739
|
};
|
|
1464
1740
|
|
|
1465
1741
|
// ============ Custom Models Section (for ALL providers) ============
|
|
1466
1742
|
|
|
1467
|
-
function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
1743
|
+
function CustomModelsSection({ providerId, providerAlias, copied, onCopy, onModelsChanged }) {
|
|
1468
1744
|
const t = useTranslations("providers");
|
|
1469
1745
|
const notify = useNotificationStore();
|
|
1470
1746
|
const [customModels, setCustomModels] = useState([]);
|
|
@@ -1478,6 +1754,7 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1478
1754
|
const [editingApiFormat, setEditingApiFormat] = useState("chat-completions");
|
|
1479
1755
|
const [editingEndpoints, setEditingEndpoints] = useState<string[]>(["chat"]);
|
|
1480
1756
|
const [editingNormalizeToolCallId, setEditingNormalizeToolCallId] = useState(false);
|
|
1757
|
+
const [editingPreserveDeveloperRole, setEditingPreserveDeveloperRole] = useState(false);
|
|
1481
1758
|
const [savingModelId, setSavingModelId] = useState<string | null>(null);
|
|
1482
1759
|
|
|
1483
1760
|
const fetchCustomModels = useCallback(async () => {
|
|
@@ -1519,6 +1796,7 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1519
1796
|
setNewApiFormat("chat-completions");
|
|
1520
1797
|
setNewEndpoints(["chat"]);
|
|
1521
1798
|
await fetchCustomModels();
|
|
1799
|
+
onModelsChanged?.();
|
|
1522
1800
|
}
|
|
1523
1801
|
} catch (e) {
|
|
1524
1802
|
console.error("Failed to add custom model:", e);
|
|
@@ -1536,6 +1814,7 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1536
1814
|
}
|
|
1537
1815
|
);
|
|
1538
1816
|
await fetchCustomModels();
|
|
1817
|
+
onModelsChanged?.();
|
|
1539
1818
|
} catch (e) {
|
|
1540
1819
|
console.error("Failed to remove custom model:", e);
|
|
1541
1820
|
}
|
|
@@ -1550,6 +1829,11 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1550
1829
|
: ["chat"]
|
|
1551
1830
|
);
|
|
1552
1831
|
setEditingNormalizeToolCallId(Boolean(model.normalizeToolCallId));
|
|
1832
|
+
setEditingPreserveDeveloperRole(
|
|
1833
|
+
Object.prototype.hasOwnProperty.call(model, "preserveOpenAIDeveloperRole")
|
|
1834
|
+
? Boolean(model.preserveOpenAIDeveloperRole)
|
|
1835
|
+
: true
|
|
1836
|
+
);
|
|
1553
1837
|
};
|
|
1554
1838
|
|
|
1555
1839
|
const cancelEdit = () => {
|
|
@@ -1557,6 +1841,7 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1557
1841
|
setEditingApiFormat("chat-completions");
|
|
1558
1842
|
setEditingEndpoints(["chat"]);
|
|
1559
1843
|
setEditingNormalizeToolCallId(false);
|
|
1844
|
+
setEditingPreserveDeveloperRole(true);
|
|
1560
1845
|
setSavingModelId(null);
|
|
1561
1846
|
};
|
|
1562
1847
|
|
|
@@ -1581,6 +1866,7 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1581
1866
|
apiFormat: editingApiFormat,
|
|
1582
1867
|
supportedEndpoints: editingEndpoints,
|
|
1583
1868
|
normalizeToolCallId: editingNormalizeToolCallId,
|
|
1869
|
+
preserveOpenAIDeveloperRole: editingPreserveDeveloperRole,
|
|
1584
1870
|
}),
|
|
1585
1871
|
});
|
|
1586
1872
|
|
|
@@ -1589,6 +1875,7 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1589
1875
|
}
|
|
1590
1876
|
|
|
1591
1877
|
await fetchCustomModels();
|
|
1878
|
+
onModelsChanged?.();
|
|
1592
1879
|
notify.success("Saved model endpoint settings");
|
|
1593
1880
|
cancelEdit();
|
|
1594
1881
|
} catch (e) {
|
|
@@ -1745,11 +2032,19 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1745
2032
|
{model.normalizeToolCallId && (
|
|
1746
2033
|
<span
|
|
1747
2034
|
className="text-[10px] px-1.5 py-0.5 rounded-full bg-slate-500/15 text-slate-400 font-medium"
|
|
1748
|
-
title="
|
|
2035
|
+
title={t("normalizeToolCallIdLabel")}
|
|
1749
2036
|
>
|
|
1750
2037
|
ID×9
|
|
1751
2038
|
</span>
|
|
1752
2039
|
)}
|
|
2040
|
+
{model.preserveOpenAIDeveloperRole === false && (
|
|
2041
|
+
<span
|
|
2042
|
+
className="text-[10px] px-1.5 py-0.5 rounded-full bg-cyan-500/15 text-cyan-400 font-medium"
|
|
2043
|
+
title={t("compatDoNotPreserveDeveloper")}
|
|
2044
|
+
>
|
|
2045
|
+
{t("compatBadgeNoPreserve")}
|
|
2046
|
+
</span>
|
|
2047
|
+
)}
|
|
1753
2048
|
</div>
|
|
1754
2049
|
|
|
1755
2050
|
{editingModelId === model.id && (
|
|
@@ -1802,16 +2097,17 @@ function CustomModelsSection({ providerId, providerAlias, copied, onCopy }) {
|
|
|
1802
2097
|
))}
|
|
1803
2098
|
</div>
|
|
1804
2099
|
</div>
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
2100
|
+
</div>
|
|
2101
|
+
<div className="mt-3 pt-3 border-t border-border/80 w-full">
|
|
2102
|
+
<ModelCompatPopover
|
|
2103
|
+
t={t}
|
|
2104
|
+
normalizeToolCallId={editingNormalizeToolCallId}
|
|
2105
|
+
preserveDeveloperRole={editingPreserveDeveloperRole}
|
|
2106
|
+
showDeveloperToggle
|
|
2107
|
+
onNormalizeChange={setEditingNormalizeToolCallId}
|
|
2108
|
+
onPreserveChange={setEditingPreserveDeveloperRole}
|
|
2109
|
+
disabled={savingModelId === model.id}
|
|
2110
|
+
/>
|
|
1815
2111
|
</div>
|
|
1816
2112
|
<div className="mt-3 flex items-center gap-2">
|
|
1817
2113
|
<Button
|
|
@@ -1860,6 +2156,7 @@ CustomModelsSection.propTypes = {
|
|
|
1860
2156
|
providerAlias: PropTypes.string.isRequired,
|
|
1861
2157
|
copied: PropTypes.string,
|
|
1862
2158
|
onCopy: PropTypes.func.isRequired,
|
|
2159
|
+
onModelsChanged: PropTypes.func,
|
|
1863
2160
|
};
|
|
1864
2161
|
|
|
1865
2162
|
function CompatibleModelsSection({
|
|
@@ -1873,8 +2170,13 @@ function CompatibleModelsSection({
|
|
|
1873
2170
|
connections,
|
|
1874
2171
|
isAnthropic,
|
|
1875
2172
|
onImportWithProgress,
|
|
2173
|
+
t,
|
|
2174
|
+
effectiveModelNormalize,
|
|
2175
|
+
effectiveModelPreserveDeveloper,
|
|
2176
|
+
saveModelCompatFlags,
|
|
2177
|
+
compatSavingModelId,
|
|
2178
|
+
onModelsChanged,
|
|
1876
2179
|
}) {
|
|
1877
|
-
const t = useTranslations("providers");
|
|
1878
2180
|
const [newModel, setNewModel] = useState("");
|
|
1879
2181
|
const [adding, setAdding] = useState(false);
|
|
1880
2182
|
const [importing, setImporting] = useState(false);
|
|
@@ -1940,6 +2242,7 @@ function CompatibleModelsSection({
|
|
|
1940
2242
|
await onSetAlias(modelId, resolvedAlias, providerStorageAlias);
|
|
1941
2243
|
setNewModel("");
|
|
1942
2244
|
notify.success(t("modelAddedSuccess", { modelId }));
|
|
2245
|
+
onModelsChanged?.();
|
|
1943
2246
|
} catch (error) {
|
|
1944
2247
|
console.error("Error adding model:", error);
|
|
1945
2248
|
notify.error(error instanceof Error ? error.message : t("failedAddModelTryAgain"));
|
|
@@ -2016,6 +2319,7 @@ function CompatibleModelsSection({
|
|
|
2016
2319
|
// Also delete the alias
|
|
2017
2320
|
await onDeleteAlias(alias);
|
|
2018
2321
|
notify.success(t("modelRemovedSuccess"));
|
|
2322
|
+
onModelsChanged?.();
|
|
2019
2323
|
} catch (error) {
|
|
2020
2324
|
console.error("Error deleting model:", error);
|
|
2021
2325
|
notify.error(error instanceof Error ? error.message : t("failedDeleteModelTryAgain"));
|
|
@@ -2078,6 +2382,15 @@ function CompatibleModelsSection({
|
|
|
2078
2382
|
copied={copied}
|
|
2079
2383
|
onCopy={onCopy}
|
|
2080
2384
|
onDeleteAlias={() => handleDeleteModel(modelId, alias)}
|
|
2385
|
+
t={t}
|
|
2386
|
+
showDeveloperToggle={!isAnthropic}
|
|
2387
|
+
normalizeToolCallId={effectiveModelNormalize(modelId)}
|
|
2388
|
+
preserveDeveloperRole={effectiveModelPreserveDeveloper(modelId)}
|
|
2389
|
+
onNormalizeChange={(v) => saveModelCompatFlags(modelId, { normalizeToolCallId: v })}
|
|
2390
|
+
onPreserveChange={(v) =>
|
|
2391
|
+
saveModelCompatFlags(modelId, { preserveOpenAIDeveloperRole: v })
|
|
2392
|
+
}
|
|
2393
|
+
compatDisabled={compatSavingModelId === modelId}
|
|
2081
2394
|
/>
|
|
2082
2395
|
))}
|
|
2083
2396
|
</div>
|
|
@@ -2102,6 +2415,12 @@ CompatibleModelsSection.propTypes = {
|
|
|
2102
2415
|
).isRequired,
|
|
2103
2416
|
isAnthropic: PropTypes.bool,
|
|
2104
2417
|
onImportWithProgress: PropTypes.func.isRequired,
|
|
2418
|
+
t: PropTypes.func.isRequired,
|
|
2419
|
+
effectiveModelNormalize: PropTypes.func.isRequired,
|
|
2420
|
+
effectiveModelPreserveDeveloper: PropTypes.func.isRequired,
|
|
2421
|
+
saveModelCompatFlags: PropTypes.func.isRequired,
|
|
2422
|
+
compatSavingModelId: PropTypes.string,
|
|
2423
|
+
onModelsChanged: PropTypes.func,
|
|
2105
2424
|
};
|
|
2106
2425
|
|
|
2107
2426
|
function CooldownTimer({ until }) {
|