@whxway/loom 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/build-manifest.json +3 -3
- package/.next/cache/.tsbuildinfo +1 -1
- package/.next/diagnostics/route-bundle-stats.json +35 -35
- package/.next/fallback-build-manifest.json +3 -3
- package/.next/server/app/(auth)/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/logs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/mcp/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/mcp/presets/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/models/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/audio/speech/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/audio/transcription/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/chat/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/embedding/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/image/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/playground/video/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/providers/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/providers/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/settings/api-keys/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(dashboard)/settings/users/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/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.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 +2 -2
- package/.next/server/app/_not-found.rsc +3 -3
- package/.next/server/app/_not-found.segments/_full.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/adapters/route.js.nft.json +1 -1
- package/.next/server/app/api/apikeys/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/apikeys/route.js.nft.json +1 -1
- package/.next/server/app/api/capabilities/route.js.nft.json +1 -1
- package/.next/server/app/api/conversations/[id]/messages/route.js.nft.json +1 -1
- package/.next/server/app/api/conversations/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/conversations/route.js.nft.json +1 -1
- package/.next/server/app/api/health/route.js.nft.json +1 -1
- package/.next/server/app/api/login/route.js.nft.json +1 -1
- package/.next/server/app/api/logout/route.js.nft.json +1 -1
- package/.next/server/app/api/logs/generations/[id]/images/[idx]/route.js.nft.json +1 -1
- package/.next/server/app/api/logs/generations/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/logs/generations/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/presets/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/servers/[id]/check/route.js +1 -1
- package/.next/server/app/api/mcp/servers/[id]/check/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/servers/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/servers/[id]/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/servers/route.js.nft.json +1 -1
- package/.next/server/app/api/messages/[id]/rate/route.js.nft.json +1 -1
- package/.next/server/app/api/models/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/models/route.js.nft.json +1 -1
- package/.next/server/app/api/ping/route.js.nft.json +1 -1
- package/.next/server/app/api/playground/chat/route.js +4 -4
- package/.next/server/app/api/playground/chat/route.js.nft.json +1 -1
- package/.next/server/app/api/playground/embedding/route.js +4 -4
- package/.next/server/app/api/playground/embedding/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/[id]/check/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/[id]/models/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/probe/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/reload/route.js.nft.json +1 -1
- package/.next/server/app/api/providers/route.js.nft.json +1 -1
- package/.next/server/app/api/stats/models/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/stats/route.js.nft.json +1 -1
- package/.next/server/app/api/tools/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/users/[username]/route.js.nft.json +1 -1
- package/.next/server/app/api/users/me/preferences/route.js +1 -1
- package/.next/server/app/api/users/me/preferences/route.js.nft.json +1 -1
- package/.next/server/app/api/users/me/route.js.nft.json +1 -1
- package/.next/server/app/api/users/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/audio/speech/route.js +1 -1
- package/.next/server/app/api/v1/audio/speech/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/audio/transcriptions/route.js +4 -4
- package/.next/server/app/api/v1/audio/transcriptions/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/chat/completions/route.js +1 -1
- package/.next/server/app/api/v1/chat/completions/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/embeddings/route.js +1 -1
- package/.next/server/app/api/v1/embeddings/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/images/generations/route.js +1 -1
- package/.next/server/app/api/v1/images/generations/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/models/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/rerank/route.js +1 -1
- package/.next/server/app/api/v1/rerank/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/videos/[id]/content/route.js +4 -4
- package/.next/server/app/api/v1/videos/[id]/content/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/videos/[id]/route.js +4 -4
- package/.next/server/app/api/v1/videos/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/v1/videos/route.js +1 -1
- package/.next/server/app/api/v1/videos/route.js.nft.json +1 -1
- package/.next/server/app/api/variants/route.js.nft.json +1 -1
- package/.next/server/app/index.html +2 -2
- package/.next/server/app/index.rsc +7 -7
- package/.next/server/app/index.segments/!KGRhc2hib2FyZCk/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/index.segments/_full.segment.rsc +7 -7
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.html +2 -2
- package/.next/server/app/login.rsc +3 -3
- package/.next/server/app/login.segments/!KGF1dGgp/login/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/login.segments/!KGF1dGgp/login.segment.rsc +1 -1
- package/.next/server/app/login.segments/!KGF1dGgp.segment.rsc +1 -1
- package/.next/server/app/login.segments/_full.segment.rsc +3 -3
- package/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/logs.html +2 -2
- package/.next/server/app/logs.rsc +7 -7
- package/.next/server/app/logs.segments/!KGRhc2hib2FyZCk/logs/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/logs.segments/!KGRhc2hib2FyZCk/logs.segment.rsc +1 -1
- package/.next/server/app/logs.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/logs.segments/_full.segment.rsc +7 -7
- package/.next/server/app/logs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/logs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/logs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/mcp/presets.html +2 -2
- package/.next/server/app/mcp/presets.rsc +7 -7
- package/.next/server/app/mcp/presets.segments/!KGRhc2hib2FyZCk/mcp/presets/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/mcp/presets.segments/!KGRhc2hib2FyZCk/mcp/presets.segment.rsc +1 -1
- package/.next/server/app/mcp/presets.segments/!KGRhc2hib2FyZCk/mcp.segment.rsc +1 -1
- package/.next/server/app/mcp/presets.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/mcp/presets.segments/_full.segment.rsc +7 -7
- package/.next/server/app/mcp/presets.segments/_head.segment.rsc +1 -1
- package/.next/server/app/mcp/presets.segments/_index.segment.rsc +2 -2
- package/.next/server/app/mcp/presets.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/mcp.html +2 -2
- package/.next/server/app/mcp.rsc +7 -7
- package/.next/server/app/mcp.segments/!KGRhc2hib2FyZCk/mcp/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/mcp.segments/!KGRhc2hib2FyZCk/mcp.segment.rsc +1 -1
- package/.next/server/app/mcp.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/mcp.segments/_full.segment.rsc +7 -7
- package/.next/server/app/mcp.segments/_head.segment.rsc +1 -1
- package/.next/server/app/mcp.segments/_index.segment.rsc +2 -2
- package/.next/server/app/mcp.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground/audio/speech.html +2 -2
- package/.next/server/app/playground/audio/speech.rsc +8 -8
- package/.next/server/app/playground/audio/speech.segments/!KGRhc2hib2FyZCk/playground/audio/speech/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground/audio/speech.segments/!KGRhc2hib2FyZCk/playground/audio/speech.segment.rsc +1 -1
- package/.next/server/app/playground/audio/speech.segments/!KGRhc2hib2FyZCk/playground/audio.segment.rsc +1 -1
- package/.next/server/app/playground/audio/speech.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground/audio/speech.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground/audio/speech.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground/audio/speech.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground/audio/speech.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground/audio/speech.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground/audio/transcription.html +2 -2
- package/.next/server/app/playground/audio/transcription.rsc +8 -8
- package/.next/server/app/playground/audio/transcription.segments/!KGRhc2hib2FyZCk/playground/audio/transcription/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground/audio/transcription.segments/!KGRhc2hib2FyZCk/playground/audio/transcription.segment.rsc +1 -1
- package/.next/server/app/playground/audio/transcription.segments/!KGRhc2hib2FyZCk/playground/audio.segment.rsc +1 -1
- package/.next/server/app/playground/audio/transcription.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground/audio/transcription.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground/audio/transcription.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground/audio/transcription.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground/audio/transcription.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground/audio/transcription.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground/chat.html +2 -2
- package/.next/server/app/playground/chat.rsc +8 -8
- package/.next/server/app/playground/chat.segments/!KGRhc2hib2FyZCk/playground/chat/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground/chat.segments/!KGRhc2hib2FyZCk/playground/chat.segment.rsc +1 -1
- package/.next/server/app/playground/chat.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground/chat.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground/chat.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground/chat.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground/chat.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground/chat.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground/embedding.html +2 -2
- package/.next/server/app/playground/embedding.rsc +8 -8
- package/.next/server/app/playground/embedding.segments/!KGRhc2hib2FyZCk/playground/embedding/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground/embedding.segments/!KGRhc2hib2FyZCk/playground/embedding.segment.rsc +1 -1
- package/.next/server/app/playground/embedding.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground/embedding.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground/embedding.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground/embedding.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground/embedding.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground/embedding.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground/image.html +2 -2
- package/.next/server/app/playground/image.rsc +8 -8
- package/.next/server/app/playground/image.segments/!KGRhc2hib2FyZCk/playground/image/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground/image.segments/!KGRhc2hib2FyZCk/playground/image.segment.rsc +1 -1
- package/.next/server/app/playground/image.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground/image.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground/image.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground/image.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground/image.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground/image.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground/video.html +2 -2
- package/.next/server/app/playground/video.rsc +8 -8
- package/.next/server/app/playground/video.segments/!KGRhc2hib2FyZCk/playground/video/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground/video.segments/!KGRhc2hib2FyZCk/playground/video.segment.rsc +1 -1
- package/.next/server/app/playground/video.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground/video.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground/video.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground/video.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground/video.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground/video.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/playground.html +2 -2
- package/.next/server/app/playground.rsc +8 -8
- package/.next/server/app/playground.segments/!KGRhc2hib2FyZCk/playground/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/playground.segments/!KGRhc2hib2FyZCk/playground.segment.rsc +2 -2
- package/.next/server/app/playground.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/playground.segments/_full.segment.rsc +8 -8
- package/.next/server/app/playground.segments/_head.segment.rsc +1 -1
- package/.next/server/app/playground.segments/_index.segment.rsc +2 -2
- package/.next/server/app/playground.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/providers.html +2 -2
- package/.next/server/app/providers.rsc +7 -7
- package/.next/server/app/providers.segments/!KGRhc2hib2FyZCk/providers/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/providers.segments/!KGRhc2hib2FyZCk/providers.segment.rsc +1 -1
- package/.next/server/app/providers.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/providers.segments/_full.segment.rsc +7 -7
- package/.next/server/app/providers.segments/_head.segment.rsc +1 -1
- package/.next/server/app/providers.segments/_index.segment.rsc +2 -2
- package/.next/server/app/providers.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/api-keys.html +2 -2
- package/.next/server/app/settings/api-keys.rsc +7 -7
- package/.next/server/app/settings/api-keys.segments/!KGRhc2hib2FyZCk/settings/api-keys/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings/api-keys.segments/!KGRhc2hib2FyZCk/settings/api-keys.segment.rsc +1 -1
- package/.next/server/app/settings/api-keys.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
- package/.next/server/app/settings/api-keys.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/settings/api-keys.segments/_full.segment.rsc +7 -7
- package/.next/server/app/settings/api-keys.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/api-keys.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings/api-keys.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/users.html +2 -2
- package/.next/server/app/settings/users.rsc +7 -7
- package/.next/server/app/settings/users.segments/!KGRhc2hib2FyZCk/settings/users/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings/users.segments/!KGRhc2hib2FyZCk/settings/users.segment.rsc +1 -1
- package/.next/server/app/settings/users.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
- package/.next/server/app/settings/users.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/settings/users.segments/_full.segment.rsc +7 -7
- package/.next/server/app/settings/users.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings/users.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings/users.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.html +2 -2
- package/.next/server/app/settings.rsc +8 -8
- package/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings.segments/!KGRhc2hib2FyZCk/settings.segment.rsc +1 -1
- package/.next/server/app/settings.segments/!KGRhc2hib2FyZCk.segment.rsc +3 -3
- package/.next/server/app/settings.segments/_full.segment.rsc +8 -8
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/chunks/[root-of-the-server]__019oqc3._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__019oqc3._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__01ou67p._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__01ou67p._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__02sypva._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__02sypva._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__0myi8j1._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__0myi8j1._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__0wiw6hu._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0wiw6hu._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0xrm_9r._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0xrm_9r._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__11t79he._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__11t79he._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__1fs5lo-._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1fs5lo-._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__1qg3d87._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__1qg3d87._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__1zgou-a._.js +6 -0
- package/.next/server/chunks/[root-of-the-server]__1zgou-a._.js.map +1 -0
- package/.next/server/chunks/_00k5vl0._.js +3 -0
- package/.next/server/chunks/_00k5vl0._.js.map +1 -0
- package/.next/server/chunks/_06hthvw._.js +3 -0
- package/.next/server/chunks/_06hthvw._.js.map +1 -0
- package/.next/server/chunks/_0c6vpbw._.js +3 -0
- package/.next/server/chunks/_0c6vpbw._.js.map +1 -0
- package/.next/server/chunks/_0hawg18._.js +3 -0
- package/.next/server/chunks/_0hawg18._.js.map +1 -0
- package/.next/server/chunks/_0kr91st._.js +3 -0
- package/.next/server/chunks/_0kr91st._.js.map +1 -0
- package/.next/server/chunks/_1i4x7k4._.js +3 -0
- package/.next/server/chunks/_1i4x7k4._.js.map +1 -0
- package/.next/server/chunks/_1lk_ovb._.js +3 -0
- package/.next/server/chunks/_1lk_ovb._.js.map +1 -0
- package/.next/server/chunks/_1wk63w9._.js +3 -0
- package/.next/server/chunks/_1wk63w9._.js.map +1 -0
- package/.next/server/chunks/_1wl3z8e._.js +3 -0
- package/.next/server/chunks/_1wl3z8e._.js.map +1 -0
- package/.next/server/chunks/lib_server_11s_lvw._.js +1 -1
- package/.next/server/chunks/lib_server_11s_lvw._.js.map +1 -1
- package/.next/server/chunks/lib_server_gateway_index_ts_1nvei3v._.js +2 -2
- package/.next/server/chunks/lib_server_gateway_index_ts_1nvei3v._.js.map +1 -1
- package/.next/server/chunks/ssr/app_(dashboard)_settings_page_tsx_1hwv4x8._.js +2 -2
- package/.next/server/chunks/ssr/app_(dashboard)_settings_page_tsx_1hwv4x8._.js.map +1 -1
- package/.next/server/chunks/ssr/lib_schemas_preferences_ts_1fy1exu._.js +1 -1
- package/.next/server/chunks/ssr/lib_schemas_preferences_ts_1fy1exu._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +2 -2
- package/.next/server/pages/500.html +1 -1
- package/.next/static/chunks/{2zeeni2y2fh59.js → 1si1c1m377t3w.js} +1 -1
- package/.next/static/chunks/2yzdc8m536xea.css +1 -0
- package/.next/static/chunks/3oj24pftrz5zy.js +11 -0
- package/.next/trace +2 -2
- package/.next/trace-build +1 -1
- package/bin/loom.mjs +1 -1
- package/drizzle/0019_timeout_default_3600.sql +36 -0
- package/drizzle/meta/0019_snapshot.json +1309 -0
- package/drizzle/meta/_journal.json +7 -0
- package/package.json +1 -1
- package/.next/server/chunks/[root-of-the-server]__00b7x8i._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__00b7x8i._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__022u2d9._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__022u2d9._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__0g3mnim._.js +0 -6
- package/.next/server/chunks/[root-of-the-server]__0g3mnim._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__1gon00b._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1gon00b._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__1xj9qqs._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__1xj9qqs._.js.map +0 -1
- package/.next/server/chunks/_028m5t0._.js +0 -3
- package/.next/server/chunks/_028m5t0._.js.map +0 -1
- package/.next/server/chunks/_0eq8a_c._.js +0 -3
- package/.next/server/chunks/_0eq8a_c._.js.map +0 -1
- package/.next/server/chunks/_0n06usu._.js +0 -3
- package/.next/server/chunks/_0n06usu._.js.map +0 -1
- package/.next/server/chunks/_0tcchv1._.js +0 -3
- package/.next/server/chunks/_0tcchv1._.js.map +0 -1
- package/.next/server/chunks/_14120rw._.js +0 -3
- package/.next/server/chunks/_14120rw._.js.map +0 -1
- package/.next/server/chunks/_1633jn_._.js +0 -3
- package/.next/server/chunks/_1633jn_._.js.map +0 -1
- package/.next/server/chunks/_19jpf08._.js +0 -3
- package/.next/server/chunks/_19jpf08._.js.map +0 -1
- package/.next/server/chunks/_1gi5m-_._.js +0 -3
- package/.next/server/chunks/_1gi5m-_._.js.map +0 -1
- package/.next/server/chunks/_1jgm_7u._.js +0 -3
- package/.next/server/chunks/_1jgm_7u._.js.map +0 -1
- package/.next/static/chunks/0cbg1vmtl84ae.css +0 -1
- package/.next/static/chunks/29p-wdja_cbgh.js +0 -11
- /package/.next/static/{wCZkC7ZaYrxG37d-e2tac → TZ8IS4-HWznFu8M4EwNGp}/_buildManifest.js +0 -0
- /package/.next/static/{wCZkC7ZaYrxG37d-e2tac → TZ8IS4-HWznFu8M4EwNGp}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{wCZkC7ZaYrxG37d-e2tac → TZ8IS4-HWznFu8M4EwNGp}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../lib/server/gateway/index.ts","../../../lib/server/gateway/log.ts","../../../lib/server/gateway/stream.ts","../../../lib/server/gateway/non-stream.ts","../../../lib/server/gateway/multipart.ts"],"sourcesContent":["import \"server-only\";\nimport { eq } from \"drizzle-orm\";\nimport { db, schema } from \"../db\";\nimport { authenticateGateway, type SessionUser } from \"../auth\";\nimport { decryptSecret } from \"../crypto\";\nimport { findModelByIdOrName } from \"../models\";\nimport { getDiscoveryStatus, resolveByDiscovery } from \"../discovery\";\nimport { classifyModel, getCapability } from \"../capabilities\";\n// Side-effect import: registers every built-in capability.\nimport \"../capabilities/register\";\nimport {\n resolveAdapter,\n resolveVariantId,\n type UpstreamCallArgs,\n} from \"../adapters\";\n// Side-effect import: registers every built-in adapter.\nimport \"../adapters/register\";\nimport { applyFieldFilter } from \"../adapters/openai\";\nimport { getVariant, type VariantContext } from \"../api-variants\";\n// Side-effect import: registers every built-in upstream API variant.\nimport \"../api-variants/register\";\nimport { badRequest, HttpError, notFound } from \"../response\";\nimport type { Model, Provider } from \"../db/schema\";\n\nimport { completeLog, startLog } from \"./log\";\nimport { handleStream } from \"./stream\";\nimport { handleNonStream } from \"./non-stream\";\nimport type {\n AssembledToolCall,\n ForwardGenerationOpts,\n ForwardResult,\n ResolvedModel,\n} from \"./types\";\n\n// Re-exports keep the public API stable for callers that import from\n// `@/lib/server/gateway`. Splitting log/stream/non-stream/types into\n// sibling files is an internal refactor only.\nexport { authenticateGateway };\nexport type { AssembledToolCall, ForwardGenerationOpts, ForwardResult, ResolvedModel };\nexport { forwardMultipartGeneration, gatewayProxy } from \"./multipart\";\n\n// =============================================================================\n// Model resolution\n// =============================================================================\n\nfunction transientModel(name: string, provider: Provider, upstreamModelId: string, capability: string): Model {\n const now = new Date().toISOString();\n return {\n id: `discovered:${provider.id}:${upstreamModelId}`,\n name,\n providerId: provider.id,\n upstreamModelId,\n type: capability,\n defaultParams: {},\n contextWindow: null,\n maxTokens: null,\n outputDimension: null,\n pricing: null,\n description: null,\n knowledgeDate: null,\n timeout: 60,\n maxRetries: 2,\n httpProxy: null,\n enabled: true,\n apiVariantId: null,\n discoveredMetadata: null,\n createdAt: now,\n updatedAt: now,\n } as Model;\n}\n\nexport async function resolveModel(name: string): Promise<ResolvedModel> {\n const model = findModelByIdOrName(name);\n if (model) {\n if (!model.enabled) throw badRequest(`Model \"${name}\" is disabled`);\n const provider = db.select().from(schema.providers).where(eq(schema.providers.id, model.providerId)).get();\n if (!provider) throw notFound(`Provider for model \"${name}\" not found`);\n if (!provider.enabled) throw badRequest(`Provider \"${provider.name}\" is disabled`);\n const adapter = resolveAdapter(provider);\n // Re-project DB snapshot (or warm cache) into adapter-shaped meta.\n let rawMeta: unknown = model.discoveredMetadata;\n if (rawMeta === null || rawMeta === undefined) {\n const cached = getDiscoveryStatus(provider.id);\n const hit = cached?.models.find((m) => m.id === model.upstreamModelId);\n rawMeta = hit?.meta.raw ?? { id: model.upstreamModelId };\n }\n const meta = adapter.extractModelMeta(rawMeta, provider);\n return {\n model,\n provider,\n adapter,\n meta,\n apiKey: decryptSecret(provider.apiKeyEncrypted),\n discovered: false,\n };\n }\n\n const discovered = await resolveByDiscovery(name);\n if (!discovered) throw notFound(`Model \"${name}\" not found in any provider`);\n\n const { provider, upstreamModelId, meta } = discovered;\n const adapter = resolveAdapter(provider);\n const capability = classifyModel(upstreamModelId);\n return {\n model: transientModel(name, provider, upstreamModelId, capability),\n provider,\n adapter,\n meta,\n apiKey: decryptSecret(provider.apiKeyEncrypted),\n discovered: true,\n };\n}\n\n/** Merge defaults under the caller's body.\n *\n * Precedence (low → high): provider.default_params → model.default_params\n * → caller body. Model defaults inherit from provider; caller body\n * always wins. The gateway never injects fields on its own. */\nexport function mergeParams(\n body: Record<string, unknown>,\n model: Model,\n provider: Provider,\n): Record<string, unknown> {\n const providerDefaults = (provider.defaultParams ?? {}) as Record<string, unknown>;\n const modelDefaults = (model.defaultParams ?? {}) as Record<string, unknown>;\n return { ...providerDefaults, ...modelDefaults, ...body };\n}\n\n// =============================================================================\n// Forward\n// =============================================================================\n\n/**\n * Generic capability-aware upstream forwarder.\n *\n * Pipeline (gateway owns; never branches on provider/variant id):\n *\n * 1. mergeParams — caller body wins over model/provider defaults\n * 2. applyFieldFilter — adapter-meta accept/reject (canonical shape)\n * 3. variant.transformRequest — canonical → variant-specific body\n * 4. adapter.finalizeRequest — last-mile transport polish\n * 5. POST adapter.upstreamUrl, adapter.upstreamHeaders\n * 6a. non-stream: variant.parseResponse → normalized chat-completion JSON\n * 6b. stream: variant.parseStreamChunk per SSE event; transcode to\n * chat-completion-shaped SSE so the user-facing API is\n * uniform regardless of upstream variant\n *\n * Adding a new upstream API shape = one file in api-variants/.\n * Adding a new upstream provider flavour = one file in adapters/.\n * Adding a new user-facing modality = one file in capabilities/ + one\n * matching variant + a 6-line Route Handler.\n */\nexport async function forwardGeneration(\n user: SessionUser,\n capabilityId: string,\n body: Record<string, unknown>,\n opts: ForwardGenerationOpts = {},\n): Promise<ForwardResult> {\n const capability = getCapability(capabilityId);\n if (!capability) throw badRequest(`Unknown capability \"${capabilityId}\"`);\n\n const requestedModel = typeof body.model === \"string\" ? body.model : \"\";\n if (!requestedModel) throw badRequest(\"`model` is required\");\n\n const { model, provider, adapter, meta, apiKey } = await resolveModel(requestedModel);\n\n const variantId = resolveVariantId(adapter, capability, model, meta);\n const variant = getVariant(variantId);\n if (!variant) throw badRequest(`No upstream variant registered for \"${variantId}\"`);\n if (variant.capability !== capability.id) {\n throw badRequest(\n `Variant \"${variantId}\" serves \"${variant.capability}\", not \"${capability.id}\"`,\n );\n }\n\n const stream = !!variant.supportsStreaming && !!body.stream;\n const ctx: VariantContext = { provider, model, meta, capability, stream };\n const callArgs: UpstreamCallArgs = { provider, model, meta, capability, variant, stream };\n\n // Build the upstream body in stages.\n const merged = mergeParams(body, model, provider);\n const filtered = applyFieldFilter(merged, meta);\n const transformed = variant.transformRequest?.(filtered, ctx) ?? filtered;\n const upstreamBody = adapter.finalizeRequest?.(transformed, callArgs) ?? transformed;\n\n // Summarize the canonical (pre-translation) body so logs reflect intent.\n const inputSummary = capability.summarizeInput?.(merged) ?? null;\n const logId = startLog({\n userId: user.id,\n modelName: model.name,\n capability: capability.id,\n requestBody: upstreamBody,\n inputSummary: inputSummary?.slice(0, 1000) ?? null,\n conversationId: opts.conversationId,\n messageId: opts.messageId,\n });\n\n const started = Date.now();\n // Honour the model's configured timeout (admin sets it on the\n // model row; defaults to 60s). Combine with the caller-supplied\n // signal so EITHER a client disconnect OR the deadline aborts\n // the upstream request. Streaming responses don't tick down the\n // timeout per-chunk — it's a TTFB-ish bound that errors out if\n // the upstream hangs before sending headers.\n const timeoutMs = Math.max(1, model.timeout) * 1000;\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\n const combinedSignal = opts.signal\n ? AbortSignal.any([opts.signal, timeoutSignal])\n : timeoutSignal;\n\n let upstream: Response;\n try {\n upstream = await fetch(adapter.upstreamUrl(callArgs), {\n method: \"POST\",\n headers: adapter.upstreamHeaders(callArgs, apiKey),\n body: JSON.stringify(upstreamBody),\n signal: combinedSignal,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n completeLog(logId, { status: \"failed\", reason: message, totalLatencyMs: Date.now() - started });\n throw new HttpError(`Upstream request failed: ${message}`, 502);\n }\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => upstream.statusText);\n completeLog(logId, {\n status: \"failed\",\n reason: `Upstream HTTP ${upstream.status}`,\n output: text.slice(0, 4000),\n totalLatencyMs: Date.now() - started,\n });\n return {\n response: new Response(text, {\n status: upstream.status,\n headers: { \"Content-Type\": upstream.headers.get(\"Content-Type\") ?? \"application/json\" },\n }),\n logId,\n };\n }\n\n if (!stream) {\n return handleNonStream({ upstream, variant, ctx, opts, started, logId });\n }\n return handleStream({ upstream, variant, ctx, opts, started, logId, model });\n}\n","import \"server-only\";\nimport { randomUUID } from \"node:crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { db, schema } from \"../db\";\n\n/**\n * Generation-log writers. Two-phase by design — `startLog` returns a\n * row id before the upstream call begins so the response stream can\n * carry `X-Generation-ID` immediately; `completeLog` patches the\n * outcome (tokens / latency / merged response body) once the call\n * settles. Stays a private internal of the gateway module so the\n * `generationLogs` table column shape can evolve without touching\n * variant or adapter code.\n */\n\nexport interface GatewayLogPayload {\n userId: string;\n modelName: string;\n capability: string;\n requestBody: Record<string, unknown>;\n inputSummary: string | null;\n conversationId?: string;\n messageId?: string;\n}\n\n// Fields that represent INPUT DATA (not sampling kwargs). Stripped\n// from `generation_kwargs` so the kwargs column only carries model\n// + sampling params + tool config — not megabytes of messages /\n// images / audio / files / embeddings input. The full body is still\n// persisted under `input` for the \"Conversation\" / \"Input\" accordion.\nconst INPUT_DATA_KEYS = new Set([\n \"messages\", // chat.completions\n \"input\", // embeddings, audio.speech, responses\n \"image\", // image edits\n \"mask\", // image edits\n \"file\", // audio.transcription multipart\n \"prompt\", // image generation, video, audio.transcription\n \"tools\", // chat tool catalog (can be large)\n]);\n\nfunction extractKwargs(body: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(body)) {\n if (INPUT_DATA_KEYS.has(k)) continue;\n out[k] = v;\n }\n return out;\n}\n\n// Lossy compression of base64 blobs inside the request body before it\n// hits the DB. Multimodal chats can carry MB-sized data URLs (image,\n// audio, file attachments); persisting them verbatim into the `input`\n// JSON column would bloat the DB and crash the log JSON viewer.\n// FE display already replaces them with short placeholders, so storing\n// the full blob serves no use case — we can't \"replay\" a request from\n// the FE either.\n//\n// Threshold is generous (2 KB) so legitimate short b64 (e.g. an icon)\n// is preserved. Anything bigger collapses to a `[base64 ..., ~NN KB]`\n// marker carrying the same shape as the FE display sanitizer for a\n// uniform viewer experience.\nconst B64_INLINE_THRESHOLD = 2048;\nconst BARE_B64_HEAD_PROBE = /^[A-Za-z0-9+/=]+$/;\n\nfunction sanitizeStringForLog(s: string): string {\n if (s.length <= B64_INLINE_THRESHOLD) return s;\n if (s.startsWith(\"data:\")) {\n const semi = s.indexOf(\";\");\n const mime = semi > 5 ? s.slice(5, semi) : \"binary\";\n const kb = Math.round(s.length / 1024);\n const kind = mime.startsWith(\"image/\") ? \"image\" : \"file\";\n return `[base64 ${kind} ${mime}, ~${kb} KB]`;\n }\n if (BARE_B64_HEAD_PROBE.test(s.slice(0, 96))) {\n const kb = Math.round(s.length / 1024);\n return `[base64 blob, ~${kb} KB]`;\n }\n return s;\n}\n\nfunction sanitizeBodyForLog(value: unknown): unknown {\n if (typeof value === \"string\") return sanitizeStringForLog(value);\n if (Array.isArray(value)) return value.map(sanitizeBodyForLog);\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = sanitizeBodyForLog(v);\n }\n return out;\n }\n return value;\n}\n\nexport function startLog(payload: GatewayLogPayload): string {\n const id = randomUUID();\n const sanitizedInput = sanitizeBodyForLog(payload.requestBody) as Record<string, unknown>;\n db.insert(schema.generationLogs).values({\n id,\n userId: payload.userId,\n modelName: payload.modelName,\n capability: payload.capability,\n status: \"pending\",\n input: sanitizedInput,\n inputSummary: payload.inputSummary,\n generationKwargs: extractKwargs(sanitizedInput),\n conversationId: payload.conversationId ?? null,\n messageId: payload.messageId ?? null,\n }).run();\n return id;\n}\n\nexport interface GatewayLogCompletion {\n status: \"completed\" | \"failed\";\n output?: string | null;\n reason?: string | null;\n generation?: Record<string, unknown> | null;\n promptTokens?: number | null;\n completionTokens?: number | null;\n totalTokens?: number | null;\n firstTokenLatencyMs?: number | null;\n totalLatencyMs?: number;\n}\n\nexport function completeLog(id: string, fields: GatewayLogCompletion): void {\n db.update(schema.generationLogs).set({\n status: fields.status,\n output: fields.output ?? null,\n reason: fields.reason ?? null,\n generation: fields.generation ?? null,\n promptTokens: fields.promptTokens ?? null,\n completionTokens: fields.completionTokens ?? null,\n totalTokens: fields.totalTokens ?? null,\n firstTokenLatencyMs: fields.firstTokenLatencyMs ?? null,\n totalLatencyMs: fields.totalLatencyMs ?? null,\n updatedAt: new Date().toISOString(),\n }).where(eq(schema.generationLogs.id, id)).run();\n}\n","import \"server-only\";\nimport type { UpstreamApiVariant, VariantContext } from \"../api-variants\";\nimport type { Model } from \"../db/schema\";\nimport { HttpError } from \"../response\";\nimport { completeLog } from \"./log\";\nimport type { ForwardGenerationOpts, ForwardResult } from \"./types\";\n\n// Shared stateless encoder for the per-chunk re-emission. The decoder\n// stays per-stream because it accumulates partial multi-byte chars\n// across `stream: true` calls.\nconst STREAM_ENCODER = new TextEncoder();\n\n/**\n * Streaming branch of forwardGeneration. Transcodes whatever the\n * upstream variant emits into chat-completion-shaped SSE so the\n * user-facing API is uniform regardless of upstream variant\n * (chat.completions, responses, …).\n *\n * Per-chunk responsibilities:\n * - text deltas → accumulate + forward + record TTFT\n * - tool_call deltas → accumulate by streaming index, forward as\n * OpenAI-shaped `delta.tool_calls`\n * - usage / id / model / system_fingerprint → propagate to the\n * merged terminal log entry\n *\n * On flush: emit a terminal stop chunk + [DONE], persist the merged\n * response in canonical chat-completion shape, and surface the\n * assembled tool_calls + finish_reason via opts.onComplete so the\n * playground orchestrator can drive its tool-execution loop.\n */\nexport function handleStream({\n upstream,\n variant,\n ctx,\n opts,\n started,\n logId,\n model,\n}: {\n upstream: Response;\n variant: UpstreamApiVariant;\n ctx: VariantContext;\n opts: ForwardGenerationOpts;\n started: number;\n logId: string;\n model: Model;\n}): ForwardResult {\n if (!upstream.body) {\n completeLog(logId, {\n status: \"failed\",\n reason: \"Upstream returned empty stream\",\n totalLatencyMs: Date.now() - started,\n });\n throw new HttpError(\"Upstream returned empty stream\", 502);\n }\n\n let accumContent = \"\";\n let accumReasoning = \"\";\n let usage: Record<string, unknown> | undefined;\n let streamModel: string | undefined;\n let streamId: string | undefined;\n let systemFingerprint: string | undefined;\n let finishReason: string | null = null;\n let buf = \"\";\n let firstTokenMs: number | null = null;\n\n // Tool-call accumulator keyed by streaming `index`. OpenAI streams\n // tool calls as `{index, id, function:{name, arguments(_delta)}}` —\n // we concatenate `arguments` per-index across chunks.\n const toolAcc = new Map<number, { id?: string; name?: string; arguments: string }>();\n\n const decoder = new TextDecoder();\n const createdAt = Math.floor(started / 1000);\n\n const emitChunk = (\n controller: TransformStreamDefaultController<Uint8Array>,\n delta: {\n content?: string;\n reasoning?: string;\n toolCalls?: NonNullable<ReturnType<UpstreamApiVariant[\"parseStreamChunk\"]>>[\"toolCalls\"];\n },\n usagePayload?: Record<string, unknown>,\n chunkFinishReason: string | null = null,\n ) => {\n const messageDelta: Record<string, unknown> = {};\n if (delta.content) messageDelta.content = delta.content;\n if (delta.reasoning) messageDelta.reasoning_content = delta.reasoning;\n if (delta.toolCalls && delta.toolCalls.length > 0) {\n messageDelta.tool_calls = delta.toolCalls.map((tc) => ({\n index: tc.index,\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.name,\n arguments: tc.argumentsDelta,\n },\n }));\n }\n const chunkObj: Record<string, unknown> = {\n id: streamId ?? logId,\n object: \"chat.completion.chunk\",\n created: createdAt,\n model: streamModel ?? model.upstreamModelId,\n choices: [\n {\n index: 0,\n delta: messageDelta,\n finish_reason: chunkFinishReason,\n },\n ],\n };\n if (systemFingerprint) chunkObj.system_fingerprint = systemFingerprint;\n if (usagePayload) chunkObj.usage = usagePayload;\n controller.enqueue(STREAM_ENCODER.encode(`data: ${JSON.stringify(chunkObj)}\\n\\n`));\n };\n\n const transformer = new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n buf += decoder.decode(chunk, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() || \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) continue;\n const data = trimmed.slice(5).trim();\n if (!data || data === \"[DONE]\") continue;\n\n let json: unknown;\n try {\n json = JSON.parse(data);\n } catch {\n continue; // mid-stream parse error\n }\n\n const delta = variant.parseStreamChunk(json, ctx);\n if (!delta) continue;\n\n if (delta.id && !streamId) streamId = delta.id;\n if (delta.model) streamModel = delta.model;\n if (delta.systemFingerprint) systemFingerprint = delta.systemFingerprint;\n if (delta.usage) usage = delta.usage;\n if (delta.finishReason) finishReason = delta.finishReason;\n\n if (delta.toolCalls && delta.toolCalls.length > 0) {\n for (const tc of delta.toolCalls) {\n const slot = toolAcc.get(tc.index) ?? { arguments: \"\" };\n if (tc.id) slot.id = tc.id;\n if (tc.name) slot.name = tc.name;\n if (tc.argumentsDelta) slot.arguments += tc.argumentsDelta;\n toolAcc.set(tc.index, slot);\n }\n if (firstTokenMs === null) firstTokenMs = Date.now() - started;\n }\n\n const hasText = !!(delta.content || delta.reasoning);\n if (hasText) {\n if (firstTokenMs === null) firstTokenMs = Date.now() - started;\n if (delta.content) accumContent += delta.content;\n if (delta.reasoning) accumReasoning += delta.reasoning;\n opts.onStreamDelta?.({\n content: delta.content ?? \"\",\n reasoning: delta.reasoning ?? \"\",\n });\n }\n if (hasText || (delta.toolCalls && delta.toolCalls.length > 0)) {\n emitChunk(controller, {\n content: delta.content,\n reasoning: delta.reasoning,\n toolCalls: delta.toolCalls,\n });\n }\n }\n },\n flush(controller) {\n // Assemble fully-merged tool_calls for both the log and the\n // onComplete callback. Sorted by index to keep deterministic\n // ordering across attempts.\n const orderedToolCalls = Array.from(toolAcc.entries())\n .sort(([a], [b]) => a - b)\n .map(([, v]) => ({\n id: v.id ?? \"\",\n name: v.name ?? \"\",\n arguments: v.arguments,\n }))\n .filter((tc) => tc.name);\n\n const closingReason = finishReason ?? (orderedToolCalls.length > 0 ? \"tool_calls\" : \"stop\");\n // Terminal stop chunk (carries final usage if known) + [DONE].\n emitChunk(controller, {}, usage, closingReason);\n controller.enqueue(STREAM_ENCODER.encode(\"data: [DONE]\\n\\n\"));\n\n // Persist the merged log entry in canonical chat-completion shape.\n const u = usage as { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number } | undefined;\n const message: Record<string, unknown> = { role: \"assistant\", content: accumContent };\n if (accumReasoning) message.reasoning_content = accumReasoning;\n if (orderedToolCalls.length > 0) {\n message.tool_calls = orderedToolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\",\n function: { name: tc.name, arguments: tc.arguments },\n }));\n }\n const mergedResponse: Record<string, unknown> = {\n id: streamId ?? logId,\n object: \"chat.completion\",\n created: createdAt,\n model: streamModel ?? model.upstreamModelId,\n choices: [{ index: 0, message, finish_reason: closingReason }],\n };\n if (systemFingerprint) mergedResponse.system_fingerprint = systemFingerprint;\n if (usage) mergedResponse.usage = usage;\n\n completeLog(logId, {\n status: \"completed\",\n output: accumContent,\n generation: mergedResponse,\n promptTokens: u?.prompt_tokens ?? null,\n completionTokens: u?.completion_tokens ?? null,\n totalTokens: u?.total_tokens ?? null,\n firstTokenLatencyMs: firstTokenMs,\n totalLatencyMs: Date.now() - started,\n });\n opts.onComplete?.({\n content: accumContent,\n reasoning: accumReasoning,\n usage,\n toolCalls: orderedToolCalls.length > 0 ? orderedToolCalls : undefined,\n finishReason: closingReason,\n });\n },\n });\n\n const piped = upstream.body.pipeThrough(transformer);\n return {\n response: new Response(piped, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n },\n }),\n logId,\n };\n}\n","import \"server-only\";\nimport type { UpstreamApiVariant, VariantContext } from \"../api-variants\";\nimport { persistImageArtifacts } from \"./artifacts\";\nimport { completeLog } from \"./log\";\nimport type { ForwardGenerationOpts, ForwardResult } from \"./types\";\n\n/**\n * Non-streaming branch of forwardGeneration. JSON responses are\n * variant-parsed into canonical chat-completion shape + logged;\n * binary responses are passed through with their content-type. Stays\n * separate from the streaming branch so future variant work (e.g. a\n * non-stream-only embeddings variant) can iterate here without\n * touching the transform pipeline.\n */\nexport async function handleNonStream({\n upstream,\n variant,\n ctx,\n opts,\n started,\n logId,\n}: {\n upstream: Response;\n variant: UpstreamApiVariant;\n ctx: VariantContext;\n opts: ForwardGenerationOpts;\n started: number;\n logId: string;\n}): Promise<ForwardResult> {\n const contentType = upstream.headers.get(\"Content-Type\") ?? \"\";\n\n if (contentType.startsWith(\"application/json\")) {\n const json = await upstream.json().catch(() => ({}));\n const parsed = variant.parseResponse(json, ctx);\n\n // Image responses can carry MB-sized base64 blobs per entry —\n // persisting those verbatim into the JSON column would bloat\n // the DB and crash the log JSON viewer. We persist them to\n // disk under data/log-artifacts/<logId>/ and rewrite the LOG\n // COPY of `normalized.data[]` so each entry references a\n // stable `/api/logs/.../images/<idx>` URL instead. The\n // unmodified `parsed.normalized` (with b64_json intact) is\n // still forwarded to the API caller so client playgrounds\n // keep working.\n let logNormalized: Record<string, unknown> = parsed.normalized;\n if (ctx.capability.id === \"image\") {\n try {\n logNormalized = structuredClone(parsed.normalized);\n await persistImageArtifacts(logId, logNormalized);\n } catch (err) {\n console.error(\"[loom] persistImageArtifacts failed:\", err);\n logNormalized = parsed.normalized;\n }\n }\n\n completeLog(logId, {\n status: \"completed\",\n output: parsed.output,\n generation: logNormalized,\n promptTokens: parsed.promptTokens,\n completionTokens: parsed.completionTokens,\n totalTokens: parsed.totalTokens,\n totalLatencyMs: Date.now() - started,\n });\n opts.onComplete?.({\n content: parsed.output ?? \"\",\n reasoning: \"\",\n usage: parsed.normalized.usage as Record<string, unknown> | undefined,\n toolCalls: parsed.toolCalls,\n finishReason: parsed.finishReason,\n });\n return {\n response: new Response(JSON.stringify(parsed.normalized), {\n headers: { \"Content-Type\": \"application/json\" },\n }),\n logId,\n };\n }\n\n // Binary or unknown — log size, pass through.\n const buf = await upstream.arrayBuffer();\n completeLog(logId, {\n status: \"completed\",\n output: `binary response (${contentType || \"unknown\"}, ${buf.byteLength} bytes)`,\n totalLatencyMs: Date.now() - started,\n });\n return {\n response: new Response(buf, {\n headers: { \"Content-Type\": contentType || \"application/octet-stream\" },\n }),\n logId,\n };\n}\n","import \"server-only\";\nimport type { SessionUser } from \"../auth\";\nimport { getCapability } from \"../capabilities\";\nimport { resolveVariantId, type UpstreamCallArgs } from \"../adapters\";\nimport { getVariant, type VariantContext } from \"../api-variants\";\nimport { badRequest, HttpError } from \"../response\";\nimport { resolveModel } from \"./index\";\nimport { completeLog, startLog } from \"./log\";\nimport { handleNonStream } from \"./non-stream\";\nimport type { ForwardResult } from \"./types\";\n\n/**\n * Multipart upstream forwarder for capabilities whose upstream wire\n * shape is `multipart/form-data` (audio.transcription, video create).\n *\n * The standard JSON pipeline in `forwardGeneration` doesn't apply\n * here — there's no canonical chat-completion body to merge, no\n * `transformRequest`, no `applyFieldFilter`. We resolve the model →\n * provider, post the FormData verbatim (letting fetch set the\n * Content-Type with the right boundary), and route the response\n * through the same `handleNonStream` path so logs stay uniform.\n *\n * `model` MUST be present as a form field — same contract as the\n * JSON gateway.\n */\nexport async function forwardMultipartGeneration(\n user: SessionUser,\n capabilityId: string,\n form: FormData,\n): Promise<ForwardResult> {\n const capability = getCapability(capabilityId);\n if (!capability) throw badRequest(`Unknown capability \"${capabilityId}\"`);\n\n const requestedModel = form.get(\"model\");\n if (typeof requestedModel !== \"string\" || !requestedModel) {\n throw badRequest(\"`model` form field is required\");\n }\n\n const { model, provider, adapter, meta, apiKey } = await resolveModel(requestedModel);\n\n const variantId = resolveVariantId(adapter, capability, model, meta);\n const variant = getVariant(variantId);\n if (!variant) throw badRequest(`No upstream variant registered for \"${variantId}\"`);\n if (variant.capability !== capability.id) {\n throw badRequest(\n `Variant \"${variantId}\" serves \"${variant.capability}\", not \"${capability.id}\"`,\n );\n }\n\n const ctx: VariantContext = { provider, model, meta, capability, stream: false };\n const callArgs: UpstreamCallArgs = { provider, model, meta, capability, variant, stream: false };\n\n // Re-stamp model with upstream id so providers / Azure deployment\n // routing stays consistent with the JSON path.\n const upstreamForm = new FormData();\n for (const [k, v] of form.entries()) {\n if (k === \"model\") continue;\n upstreamForm.append(k, v);\n }\n upstreamForm.append(\"model\", model.upstreamModelId);\n\n // Summarise BEFORE the upstream-id rewrite so logs reflect the\n // caller-facing model + any text prompt fields.\n const summary = summariseForm(form, capability.id);\n const logId = startLog({\n userId: user.id,\n modelName: model.name,\n capability: capability.id,\n requestBody: redactForm(form),\n inputSummary: summary?.slice(0, 1000) ?? null,\n });\n\n // Drop the JSON Content-Type the adapter would have set — fetch\n // generates `multipart/form-data; boundary=…` automatically when\n // body is FormData and Content-Type is absent.\n const headers = { ...adapter.upstreamHeaders(callArgs, apiKey) };\n delete headers[\"Content-Type\"];\n delete headers[\"content-type\"];\n\n const started = Date.now();\n // Multipart endpoints are non-stream (audio.speech / transcription\n // returns the full audio buffer, video create returns a job id),\n // so the model.timeout is a real wall-clock cap on the upstream\n // call — useful for stuck providers.\n const timeoutMs = Math.max(1, model.timeout) * 1000;\n let upstream: Response;\n try {\n upstream = await fetch(adapter.upstreamUrl(callArgs), {\n method: \"POST\",\n headers,\n body: upstreamForm,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n completeLog(logId, { status: \"failed\", reason: message, totalLatencyMs: Date.now() - started });\n throw new HttpError(`Upstream request failed: ${message}`, 502);\n }\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => upstream.statusText);\n completeLog(logId, {\n status: \"failed\",\n reason: `Upstream HTTP ${upstream.status}`,\n output: text.slice(0, 4000),\n totalLatencyMs: Date.now() - started,\n });\n return {\n response: new Response(text, {\n status: upstream.status,\n headers: { \"Content-Type\": upstream.headers.get(\"Content-Type\") ?? \"application/json\" },\n }),\n logId,\n };\n }\n\n return handleNonStream({ upstream, variant, ctx, opts: {}, started, logId });\n}\n\nfunction summariseForm(form: FormData, capabilityId: string): string | null {\n const prompt = form.get(\"prompt\");\n if (typeof prompt === \"string\" && prompt) return prompt;\n if (capabilityId === \"audio.transcription\") {\n const f = form.get(\"file\");\n const name = f instanceof File ? f.name : null;\n const size = f instanceof File ? f.size : null;\n if (name) return `audio file: ${name}${size ? ` (${size} bytes)` : \"\"}`;\n return \"audio input\";\n }\n return null;\n}\n\nfunction redactForm(form: FormData): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of form.entries()) {\n if (v instanceof File) {\n out[k] = { _kind: \"file\", name: v.name, type: v.type, size: v.size };\n } else {\n const s = String(v);\n out[k] = s.length > 4000 ? `${s.slice(0, 4000)}…(+${s.length - 4000})` : s;\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Generic upstream proxy: used by polling/download/delete endpoints that hang\n// off the same provider as the create call (e.g. GET /videos/{id}, DELETE\n// /videos/{id}, GET /videos/{id}/content).\n// ---------------------------------------------------------------------------\n\ninterface ProxyArgs {\n user: SessionUser;\n /** Caller-facing model name so we can resolve which provider owns this resource. */\n modelName: string;\n /** Relative path appended to provider.baseUrl (must include leading slash). */\n path: string;\n method?: \"GET\" | \"DELETE\" | \"POST\";\n /** Optional query string (no leading `?`). */\n query?: string;\n body?: BodyInit;\n /** Override / supplement adapter headers. */\n headers?: Record<string, string>;\n}\n\n/**\n * Lightweight proxy for follow-up requests that ride on top of a\n * previously-created resource. No gateway pipeline, no log — the\n * resource creation was already logged at submit time.\n */\nexport async function gatewayProxy(args: ProxyArgs): Promise<Response> {\n const { provider, apiKey } = await resolveModel(args.modelName);\n if (!provider.enabled) throw badRequest(`Provider \"${provider.name}\" is disabled`);\n\n const baseUrl = provider.baseUrl.replace(/\\/$/, \"\");\n let url = `${baseUrl}${args.path}`;\n if (args.query) url += `?${args.query}`;\n\n const headers: Record<string, string> = {};\n if (apiKey) headers[\"Authorization\"] = `Bearer ${apiKey}`;\n Object.assign(headers, args.headers ?? {});\n if (args.body && !headers[\"Content-Type\"] && !(args.body instanceof FormData)) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const res = await fetch(url, {\n method: args.method ?? \"GET\",\n headers,\n body: args.body,\n });\n\n // Pass-through: preserve content-type so binary downloads work.\n const passthroughHeaders: Record<string, string> = {\n \"Content-Type\": res.headers.get(\"Content-Type\") ?? \"application/octet-stream\",\n };\n const cl = res.headers.get(\"Content-Length\");\n if (cl) passthroughHeaders[\"Content-Length\"] = cl;\n const cd = res.headers.get(\"Content-Disposition\");\n if (cd) passthroughHeaders[\"Content-Disposition\"] = cd;\n\n return new Response(res.body, {\n status: res.status,\n statusText: res.statusText,\n headers: passthroughHeaders,\n });\n}\n"],"names":["INPUT_DATA_KEYS","Set","extractKwargs","body","out","k","v","Object","entries","has","B64_INLINE_THRESHOLD","BARE_B64_HEAD_PROBE","sanitizeStringForLog","s","length","startsWith","semi","indexOf","mime","slice","kb","Math","round","kind","test","sanitizeBodyForLog","value","Array","isArray","map","startLog","payload","id","sanitizedInput","requestBody","insert","generationLogs","values","userId","modelName","capability","status","input","inputSummary","generationKwargs","conversationId","messageId","run","completeLog","fields","update","set","output","reason","generation","promptTokens","completionTokens","totalTokens","firstTokenLatencyMs","totalLatencyMs","updatedAt","Date","toISOString","where"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../lib/server/gateway/index.ts","../../../lib/server/gateway/log.ts","../../../lib/server/gateway/stream.ts","../../../lib/server/gateway/non-stream.ts","../../../lib/server/gateway/multipart.ts"],"sourcesContent":["import \"server-only\";\nimport { eq } from \"drizzle-orm\";\nimport { db, schema } from \"../db\";\nimport { authenticateGateway, type SessionUser } from \"../auth\";\nimport { decryptSecret } from \"../crypto\";\nimport { findModelByIdOrName } from \"../models\";\nimport { getDiscoveryStatus, resolveByDiscovery } from \"../discovery\";\nimport { classifyModel, getCapability } from \"../capabilities\";\n// Side-effect import: registers every built-in capability.\nimport \"../capabilities/register\";\nimport {\n resolveAdapter,\n resolveVariantId,\n type UpstreamCallArgs,\n} from \"../adapters\";\n// Side-effect import: registers every built-in adapter.\nimport \"../adapters/register\";\nimport { applyFieldFilter } from \"../adapters/openai\";\nimport { getVariant, type VariantContext } from \"../api-variants\";\n// Side-effect import: registers every built-in upstream API variant.\nimport \"../api-variants/register\";\nimport { getPreferences } from \"../preferences\";\nimport { badRequest, HttpError, notFound } from \"../response\";\nimport type { Model, Provider } from \"../db/schema\";\n\nimport { completeLog, startLog } from \"./log\";\nimport { handleStream } from \"./stream\";\nimport { handleNonStream } from \"./non-stream\";\nimport type {\n AssembledToolCall,\n ForwardGenerationOpts,\n ForwardResult,\n ResolvedModel,\n} from \"./types\";\n\n// Re-exports keep the public API stable for callers that import from\n// `@/lib/server/gateway`. Splitting log/stream/non-stream/types into\n// sibling files is an internal refactor only.\nexport { authenticateGateway };\nexport type { AssembledToolCall, ForwardGenerationOpts, ForwardResult, ResolvedModel };\nexport { forwardMultipartGeneration, gatewayProxy } from \"./multipart\";\n\n// =============================================================================\n// Model resolution\n// =============================================================================\n\nfunction transientModel(name: string, provider: Provider, upstreamModelId: string, capability: string): Model {\n const now = new Date().toISOString();\n return {\n id: `discovered:${provider.id}:${upstreamModelId}`,\n name,\n providerId: provider.id,\n upstreamModelId,\n type: capability,\n defaultParams: {},\n contextWindow: null,\n maxTokens: null,\n outputDimension: null,\n pricing: null,\n description: null,\n knowledgeDate: null,\n timeout: 3600,\n maxRetries: 2,\n httpProxy: null,\n enabled: true,\n apiVariantId: null,\n discoveredMetadata: null,\n createdAt: now,\n updatedAt: now,\n } as Model;\n}\n\nexport async function resolveModel(name: string): Promise<ResolvedModel> {\n const model = findModelByIdOrName(name);\n if (model) {\n if (!model.enabled) throw badRequest(`Model \"${name}\" is disabled`);\n const provider = db.select().from(schema.providers).where(eq(schema.providers.id, model.providerId)).get();\n if (!provider) throw notFound(`Provider for model \"${name}\" not found`);\n if (!provider.enabled) throw badRequest(`Provider \"${provider.name}\" is disabled`);\n const adapter = resolveAdapter(provider);\n // Re-project DB snapshot (or warm cache) into adapter-shaped meta.\n let rawMeta: unknown = model.discoveredMetadata;\n if (rawMeta === null || rawMeta === undefined) {\n const cached = getDiscoveryStatus(provider.id);\n const hit = cached?.models.find((m) => m.id === model.upstreamModelId);\n rawMeta = hit?.meta.raw ?? { id: model.upstreamModelId };\n }\n const meta = adapter.extractModelMeta(rawMeta, provider);\n return {\n model,\n provider,\n adapter,\n meta,\n apiKey: decryptSecret(provider.apiKeyEncrypted),\n discovered: false,\n };\n }\n\n const discovered = await resolveByDiscovery(name);\n if (!discovered) throw notFound(`Model \"${name}\" not found in any provider`);\n\n const { provider, upstreamModelId, meta } = discovered;\n const adapter = resolveAdapter(provider);\n const capability = classifyModel(upstreamModelId);\n return {\n model: transientModel(name, provider, upstreamModelId, capability),\n provider,\n adapter,\n meta,\n apiKey: decryptSecret(provider.apiKeyEncrypted),\n discovered: true,\n };\n}\n\n/** Merge defaults under the caller's body.\n *\n * Precedence (low → high): provider.default_params → model.default_params\n * → caller body. Model defaults inherit from provider; caller body\n * always wins. The gateway never injects fields on its own. */\nexport function mergeParams(\n body: Record<string, unknown>,\n model: Model,\n provider: Provider,\n): Record<string, unknown> {\n const providerDefaults = (provider.defaultParams ?? {}) as Record<string, unknown>;\n const modelDefaults = (model.defaultParams ?? {}) as Record<string, unknown>;\n return { ...providerDefaults, ...modelDefaults, ...body };\n}\n\n// =============================================================================\n// Forward\n// =============================================================================\n\n/**\n * Generic capability-aware upstream forwarder.\n *\n * Pipeline (gateway owns; never branches on provider/variant id):\n *\n * 1. mergeParams — caller body wins over model/provider defaults\n * 2. applyFieldFilter — adapter-meta accept/reject (canonical shape)\n * 3. variant.transformRequest — canonical → variant-specific body\n * 4. adapter.finalizeRequest — last-mile transport polish\n * 5. POST adapter.upstreamUrl, adapter.upstreamHeaders\n * 6a. non-stream: variant.parseResponse → normalized chat-completion JSON\n * 6b. stream: variant.parseStreamChunk per SSE event; transcode to\n * chat-completion-shaped SSE so the user-facing API is\n * uniform regardless of upstream variant\n *\n * Adding a new upstream API shape = one file in api-variants/.\n * Adding a new upstream provider flavour = one file in adapters/.\n * Adding a new user-facing modality = one file in capabilities/ + one\n * matching variant + a 6-line Route Handler.\n */\nexport async function forwardGeneration(\n user: SessionUser,\n capabilityId: string,\n body: Record<string, unknown>,\n opts: ForwardGenerationOpts = {},\n): Promise<ForwardResult> {\n const capability = getCapability(capabilityId);\n if (!capability) throw badRequest(`Unknown capability \"${capabilityId}\"`);\n\n const requestedModel = typeof body.model === \"string\" ? body.model : \"\";\n if (!requestedModel) throw badRequest(\"`model` is required\");\n\n const { model, provider, adapter, meta, apiKey } = await resolveModel(requestedModel);\n\n const variantId = resolveVariantId(adapter, capability, model, meta);\n const variant = getVariant(variantId);\n if (!variant) throw badRequest(`No upstream variant registered for \"${variantId}\"`);\n if (variant.capability !== capability.id) {\n throw badRequest(\n `Variant \"${variantId}\" serves \"${variant.capability}\", not \"${capability.id}\"`,\n );\n }\n\n const stream = !!variant.supportsStreaming && !!body.stream;\n const ctx: VariantContext = { provider, model, meta, capability, stream };\n const callArgs: UpstreamCallArgs = { provider, model, meta, capability, variant, stream };\n\n // Build the upstream body in stages.\n const merged = mergeParams(body, model, provider);\n const filtered = applyFieldFilter(merged, meta);\n const transformed = variant.transformRequest?.(filtered, ctx) ?? filtered;\n const upstreamBody = adapter.finalizeRequest?.(transformed, callArgs) ?? transformed;\n\n // Summarize the canonical (pre-translation) body so logs reflect intent.\n const inputSummary = capability.summarizeInput?.(merged) ?? null;\n const logId = startLog({\n userId: user.id,\n modelName: model.name,\n capability: capability.id,\n requestBody: upstreamBody,\n inputSummary: inputSummary?.slice(0, 1000) ?? null,\n conversationId: opts.conversationId,\n messageId: opts.messageId,\n });\n\n const started = Date.now();\n // Pick the operative timeout: the user's per-account\n // `gateway_timeout_seconds` preference wins over the per-model\n // value because the user explicitly chose it from settings —\n // model.timeout remains the in-DB fallback for callers without a\n // preferences row yet (forward-compat default kicks in via\n // getPreferences). Combine with the caller-supplied signal so\n // EITHER a client disconnect OR the deadline aborts the upstream\n // request. Streaming responses don't tick down the timeout\n // per-chunk — it's a TTFB-ish bound that errors out if the\n // upstream hangs before sending headers.\n const userTimeoutSec = getPreferences(user.id).gateway_timeout_seconds;\n const timeoutMs = Math.max(1, userTimeoutSec || model.timeout) * 1000;\n const timeoutSignal = AbortSignal.timeout(timeoutMs);\n const combinedSignal = opts.signal\n ? AbortSignal.any([opts.signal, timeoutSignal])\n : timeoutSignal;\n\n let upstream: Response;\n try {\n upstream = await fetch(adapter.upstreamUrl(callArgs), {\n method: \"POST\",\n headers: adapter.upstreamHeaders(callArgs, apiKey),\n body: JSON.stringify(upstreamBody),\n signal: combinedSignal,\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n completeLog(logId, { status: \"failed\", reason: message, totalLatencyMs: Date.now() - started });\n throw new HttpError(`Upstream request failed: ${message}`, 502);\n }\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => upstream.statusText);\n completeLog(logId, {\n status: \"failed\",\n reason: `Upstream HTTP ${upstream.status}`,\n output: text.slice(0, 4000),\n totalLatencyMs: Date.now() - started,\n });\n return {\n response: new Response(text, {\n status: upstream.status,\n headers: { \"Content-Type\": upstream.headers.get(\"Content-Type\") ?? \"application/json\" },\n }),\n logId,\n };\n }\n\n if (!stream) {\n return handleNonStream({ upstream, variant, ctx, opts, started, logId });\n }\n return handleStream({ upstream, variant, ctx, opts, started, logId, model });\n}\n","import \"server-only\";\nimport { randomUUID } from \"node:crypto\";\nimport { eq } from \"drizzle-orm\";\nimport { db, schema } from \"../db\";\n\n/**\n * Generation-log writers. Two-phase by design — `startLog` returns a\n * row id before the upstream call begins so the response stream can\n * carry `X-Generation-ID` immediately; `completeLog` patches the\n * outcome (tokens / latency / merged response body) once the call\n * settles. Stays a private internal of the gateway module so the\n * `generationLogs` table column shape can evolve without touching\n * variant or adapter code.\n */\n\nexport interface GatewayLogPayload {\n userId: string;\n modelName: string;\n capability: string;\n requestBody: Record<string, unknown>;\n inputSummary: string | null;\n conversationId?: string;\n messageId?: string;\n}\n\n// Fields that represent INPUT DATA (not sampling kwargs). Stripped\n// from `generation_kwargs` so the kwargs column only carries model\n// + sampling params + tool config — not megabytes of messages /\n// images / audio / files / embeddings input. The full body is still\n// persisted under `input` for the \"Conversation\" / \"Input\" accordion.\nconst INPUT_DATA_KEYS = new Set([\n \"messages\", // chat.completions\n \"input\", // embeddings, audio.speech, responses\n \"image\", // image edits\n \"mask\", // image edits\n \"file\", // audio.transcription multipart\n \"prompt\", // image generation, video, audio.transcription\n \"tools\", // chat tool catalog (can be large)\n]);\n\nfunction extractKwargs(body: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(body)) {\n if (INPUT_DATA_KEYS.has(k)) continue;\n out[k] = v;\n }\n return out;\n}\n\n// Lossy compression of base64 blobs inside the request body before it\n// hits the DB. Multimodal chats can carry MB-sized data URLs (image,\n// audio, file attachments); persisting them verbatim into the `input`\n// JSON column would bloat the DB and crash the log JSON viewer.\n// FE display already replaces them with short placeholders, so storing\n// the full blob serves no use case — we can't \"replay\" a request from\n// the FE either.\n//\n// Threshold is generous (2 KB) so legitimate short b64 (e.g. an icon)\n// is preserved. Anything bigger collapses to a `[base64 ..., ~NN KB]`\n// marker carrying the same shape as the FE display sanitizer for a\n// uniform viewer experience.\nconst B64_INLINE_THRESHOLD = 2048;\nconst BARE_B64_HEAD_PROBE = /^[A-Za-z0-9+/=]+$/;\n\nfunction sanitizeStringForLog(s: string): string {\n if (s.length <= B64_INLINE_THRESHOLD) return s;\n if (s.startsWith(\"data:\")) {\n const semi = s.indexOf(\";\");\n const mime = semi > 5 ? s.slice(5, semi) : \"binary\";\n const kb = Math.round(s.length / 1024);\n const kind = mime.startsWith(\"image/\") ? \"image\" : \"file\";\n return `[base64 ${kind} ${mime}, ~${kb} KB]`;\n }\n if (BARE_B64_HEAD_PROBE.test(s.slice(0, 96))) {\n const kb = Math.round(s.length / 1024);\n return `[base64 blob, ~${kb} KB]`;\n }\n return s;\n}\n\nfunction sanitizeBodyForLog(value: unknown): unknown {\n if (typeof value === \"string\") return sanitizeStringForLog(value);\n if (Array.isArray(value)) return value.map(sanitizeBodyForLog);\n if (value && typeof value === \"object\") {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(value as Record<string, unknown>)) {\n out[k] = sanitizeBodyForLog(v);\n }\n return out;\n }\n return value;\n}\n\nexport function startLog(payload: GatewayLogPayload): string {\n const id = randomUUID();\n const sanitizedInput = sanitizeBodyForLog(payload.requestBody) as Record<string, unknown>;\n db.insert(schema.generationLogs).values({\n id,\n userId: payload.userId,\n modelName: payload.modelName,\n capability: payload.capability,\n status: \"pending\",\n input: sanitizedInput,\n inputSummary: payload.inputSummary,\n generationKwargs: extractKwargs(sanitizedInput),\n conversationId: payload.conversationId ?? null,\n messageId: payload.messageId ?? null,\n }).run();\n return id;\n}\n\nexport interface GatewayLogCompletion {\n status: \"completed\" | \"failed\";\n output?: string | null;\n reason?: string | null;\n generation?: Record<string, unknown> | null;\n promptTokens?: number | null;\n completionTokens?: number | null;\n totalTokens?: number | null;\n firstTokenLatencyMs?: number | null;\n totalLatencyMs?: number;\n}\n\nexport function completeLog(id: string, fields: GatewayLogCompletion): void {\n db.update(schema.generationLogs).set({\n status: fields.status,\n output: fields.output ?? null,\n reason: fields.reason ?? null,\n generation: fields.generation ?? null,\n promptTokens: fields.promptTokens ?? null,\n completionTokens: fields.completionTokens ?? null,\n totalTokens: fields.totalTokens ?? null,\n firstTokenLatencyMs: fields.firstTokenLatencyMs ?? null,\n totalLatencyMs: fields.totalLatencyMs ?? null,\n updatedAt: new Date().toISOString(),\n }).where(eq(schema.generationLogs.id, id)).run();\n}\n","import \"server-only\";\nimport type { UpstreamApiVariant, VariantContext } from \"../api-variants\";\nimport type { Model } from \"../db/schema\";\nimport { HttpError } from \"../response\";\nimport { completeLog } from \"./log\";\nimport type { ForwardGenerationOpts, ForwardResult } from \"./types\";\n\n// Shared stateless encoder for the per-chunk re-emission. The decoder\n// stays per-stream because it accumulates partial multi-byte chars\n// across `stream: true` calls.\nconst STREAM_ENCODER = new TextEncoder();\n\n/**\n * Streaming branch of forwardGeneration. Transcodes whatever the\n * upstream variant emits into chat-completion-shaped SSE so the\n * user-facing API is uniform regardless of upstream variant\n * (chat.completions, responses, …).\n *\n * Per-chunk responsibilities:\n * - text deltas → accumulate + forward + record TTFT\n * - tool_call deltas → accumulate by streaming index, forward as\n * OpenAI-shaped `delta.tool_calls`\n * - usage / id / model / system_fingerprint → propagate to the\n * merged terminal log entry\n *\n * On flush: emit a terminal stop chunk + [DONE], persist the merged\n * response in canonical chat-completion shape, and surface the\n * assembled tool_calls + finish_reason via opts.onComplete so the\n * playground orchestrator can drive its tool-execution loop.\n */\nexport function handleStream({\n upstream,\n variant,\n ctx,\n opts,\n started,\n logId,\n model,\n}: {\n upstream: Response;\n variant: UpstreamApiVariant;\n ctx: VariantContext;\n opts: ForwardGenerationOpts;\n started: number;\n logId: string;\n model: Model;\n}): ForwardResult {\n if (!upstream.body) {\n completeLog(logId, {\n status: \"failed\",\n reason: \"Upstream returned empty stream\",\n totalLatencyMs: Date.now() - started,\n });\n throw new HttpError(\"Upstream returned empty stream\", 502);\n }\n\n let accumContent = \"\";\n let accumReasoning = \"\";\n let usage: Record<string, unknown> | undefined;\n let streamModel: string | undefined;\n let streamId: string | undefined;\n let systemFingerprint: string | undefined;\n let finishReason: string | null = null;\n let buf = \"\";\n let firstTokenMs: number | null = null;\n\n // Tool-call accumulator keyed by streaming `index`. OpenAI streams\n // tool calls as `{index, id, function:{name, arguments(_delta)}}` —\n // we concatenate `arguments` per-index across chunks.\n const toolAcc = new Map<number, { id?: string; name?: string; arguments: string }>();\n\n const decoder = new TextDecoder();\n const createdAt = Math.floor(started / 1000);\n\n const emitChunk = (\n controller: TransformStreamDefaultController<Uint8Array>,\n delta: {\n content?: string;\n reasoning?: string;\n toolCalls?: NonNullable<ReturnType<UpstreamApiVariant[\"parseStreamChunk\"]>>[\"toolCalls\"];\n },\n usagePayload?: Record<string, unknown>,\n chunkFinishReason: string | null = null,\n ) => {\n const messageDelta: Record<string, unknown> = {};\n if (delta.content) messageDelta.content = delta.content;\n if (delta.reasoning) messageDelta.reasoning_content = delta.reasoning;\n if (delta.toolCalls && delta.toolCalls.length > 0) {\n messageDelta.tool_calls = delta.toolCalls.map((tc) => ({\n index: tc.index,\n id: tc.id,\n type: \"function\" as const,\n function: {\n name: tc.name,\n arguments: tc.argumentsDelta,\n },\n }));\n }\n const chunkObj: Record<string, unknown> = {\n id: streamId ?? logId,\n object: \"chat.completion.chunk\",\n created: createdAt,\n model: streamModel ?? model.upstreamModelId,\n choices: [\n {\n index: 0,\n delta: messageDelta,\n finish_reason: chunkFinishReason,\n },\n ],\n };\n if (systemFingerprint) chunkObj.system_fingerprint = systemFingerprint;\n if (usagePayload) chunkObj.usage = usagePayload;\n controller.enqueue(STREAM_ENCODER.encode(`data: ${JSON.stringify(chunkObj)}\\n\\n`));\n };\n\n const transformer = new TransformStream<Uint8Array, Uint8Array>({\n transform(chunk, controller) {\n buf += decoder.decode(chunk, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() || \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed.startsWith(\"data:\")) continue;\n const data = trimmed.slice(5).trim();\n if (!data || data === \"[DONE]\") continue;\n\n let json: unknown;\n try {\n json = JSON.parse(data);\n } catch {\n continue; // mid-stream parse error\n }\n\n const delta = variant.parseStreamChunk(json, ctx);\n if (!delta) continue;\n\n if (delta.id && !streamId) streamId = delta.id;\n if (delta.model) streamModel = delta.model;\n if (delta.systemFingerprint) systemFingerprint = delta.systemFingerprint;\n if (delta.usage) usage = delta.usage;\n if (delta.finishReason) finishReason = delta.finishReason;\n\n if (delta.toolCalls && delta.toolCalls.length > 0) {\n for (const tc of delta.toolCalls) {\n const slot = toolAcc.get(tc.index) ?? { arguments: \"\" };\n if (tc.id) slot.id = tc.id;\n if (tc.name) slot.name = tc.name;\n if (tc.argumentsDelta) slot.arguments += tc.argumentsDelta;\n toolAcc.set(tc.index, slot);\n }\n if (firstTokenMs === null) firstTokenMs = Date.now() - started;\n }\n\n const hasText = !!(delta.content || delta.reasoning);\n if (hasText) {\n if (firstTokenMs === null) firstTokenMs = Date.now() - started;\n if (delta.content) accumContent += delta.content;\n if (delta.reasoning) accumReasoning += delta.reasoning;\n opts.onStreamDelta?.({\n content: delta.content ?? \"\",\n reasoning: delta.reasoning ?? \"\",\n });\n }\n if (hasText || (delta.toolCalls && delta.toolCalls.length > 0)) {\n emitChunk(controller, {\n content: delta.content,\n reasoning: delta.reasoning,\n toolCalls: delta.toolCalls,\n });\n }\n }\n },\n flush(controller) {\n // Assemble fully-merged tool_calls for both the log and the\n // onComplete callback. Sorted by index to keep deterministic\n // ordering across attempts.\n const orderedToolCalls = Array.from(toolAcc.entries())\n .sort(([a], [b]) => a - b)\n .map(([, v]) => ({\n id: v.id ?? \"\",\n name: v.name ?? \"\",\n arguments: v.arguments,\n }))\n .filter((tc) => tc.name);\n\n const closingReason = finishReason ?? (orderedToolCalls.length > 0 ? \"tool_calls\" : \"stop\");\n // Terminal stop chunk (carries final usage if known) + [DONE].\n emitChunk(controller, {}, usage, closingReason);\n controller.enqueue(STREAM_ENCODER.encode(\"data: [DONE]\\n\\n\"));\n\n // Persist the merged log entry in canonical chat-completion shape.\n const u = usage as { prompt_tokens?: number; completion_tokens?: number; total_tokens?: number } | undefined;\n const message: Record<string, unknown> = { role: \"assistant\", content: accumContent };\n if (accumReasoning) message.reasoning_content = accumReasoning;\n if (orderedToolCalls.length > 0) {\n message.tool_calls = orderedToolCalls.map((tc) => ({\n id: tc.id,\n type: \"function\",\n function: { name: tc.name, arguments: tc.arguments },\n }));\n }\n const mergedResponse: Record<string, unknown> = {\n id: streamId ?? logId,\n object: \"chat.completion\",\n created: createdAt,\n model: streamModel ?? model.upstreamModelId,\n choices: [{ index: 0, message, finish_reason: closingReason }],\n };\n if (systemFingerprint) mergedResponse.system_fingerprint = systemFingerprint;\n if (usage) mergedResponse.usage = usage;\n\n completeLog(logId, {\n status: \"completed\",\n output: accumContent,\n generation: mergedResponse,\n promptTokens: u?.prompt_tokens ?? null,\n completionTokens: u?.completion_tokens ?? null,\n totalTokens: u?.total_tokens ?? null,\n firstTokenLatencyMs: firstTokenMs,\n totalLatencyMs: Date.now() - started,\n });\n opts.onComplete?.({\n content: accumContent,\n reasoning: accumReasoning,\n usage,\n toolCalls: orderedToolCalls.length > 0 ? orderedToolCalls : undefined,\n finishReason: closingReason,\n });\n },\n });\n\n const piped = upstream.body.pipeThrough(transformer);\n return {\n response: new Response(piped, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n },\n }),\n logId,\n };\n}\n","import \"server-only\";\nimport type { UpstreamApiVariant, VariantContext } from \"../api-variants\";\nimport { persistImageArtifacts } from \"./artifacts\";\nimport { completeLog } from \"./log\";\nimport type { ForwardGenerationOpts, ForwardResult } from \"./types\";\n\n/**\n * Non-streaming branch of forwardGeneration. JSON responses are\n * variant-parsed into canonical chat-completion shape + logged;\n * binary responses are passed through with their content-type. Stays\n * separate from the streaming branch so future variant work (e.g. a\n * non-stream-only embeddings variant) can iterate here without\n * touching the transform pipeline.\n */\nexport async function handleNonStream({\n upstream,\n variant,\n ctx,\n opts,\n started,\n logId,\n}: {\n upstream: Response;\n variant: UpstreamApiVariant;\n ctx: VariantContext;\n opts: ForwardGenerationOpts;\n started: number;\n logId: string;\n}): Promise<ForwardResult> {\n const contentType = upstream.headers.get(\"Content-Type\") ?? \"\";\n\n if (contentType.startsWith(\"application/json\")) {\n const json = await upstream.json().catch(() => ({}));\n const parsed = variant.parseResponse(json, ctx);\n\n // Image responses can carry MB-sized base64 blobs per entry —\n // persisting those verbatim into the JSON column would bloat\n // the DB and crash the log JSON viewer. We persist them to\n // disk under data/log-artifacts/<logId>/ and rewrite the LOG\n // COPY of `normalized.data[]` so each entry references a\n // stable `/api/logs/.../images/<idx>` URL instead. The\n // unmodified `parsed.normalized` (with b64_json intact) is\n // still forwarded to the API caller so client playgrounds\n // keep working.\n let logNormalized: Record<string, unknown> = parsed.normalized;\n if (ctx.capability.id === \"image\") {\n try {\n logNormalized = structuredClone(parsed.normalized);\n await persistImageArtifacts(logId, logNormalized);\n } catch (err) {\n console.error(\"[loom] persistImageArtifacts failed:\", err);\n logNormalized = parsed.normalized;\n }\n }\n\n completeLog(logId, {\n status: \"completed\",\n output: parsed.output,\n generation: logNormalized,\n promptTokens: parsed.promptTokens,\n completionTokens: parsed.completionTokens,\n totalTokens: parsed.totalTokens,\n totalLatencyMs: Date.now() - started,\n });\n opts.onComplete?.({\n content: parsed.output ?? \"\",\n reasoning: \"\",\n usage: parsed.normalized.usage as Record<string, unknown> | undefined,\n toolCalls: parsed.toolCalls,\n finishReason: parsed.finishReason,\n });\n return {\n response: new Response(JSON.stringify(parsed.normalized), {\n headers: { \"Content-Type\": \"application/json\" },\n }),\n logId,\n };\n }\n\n // Binary or unknown — log size, pass through.\n const buf = await upstream.arrayBuffer();\n completeLog(logId, {\n status: \"completed\",\n output: `binary response (${contentType || \"unknown\"}, ${buf.byteLength} bytes)`,\n totalLatencyMs: Date.now() - started,\n });\n return {\n response: new Response(buf, {\n headers: { \"Content-Type\": contentType || \"application/octet-stream\" },\n }),\n logId,\n };\n}\n","import \"server-only\";\nimport type { SessionUser } from \"../auth\";\nimport { getCapability } from \"../capabilities\";\nimport { resolveVariantId, type UpstreamCallArgs } from \"../adapters\";\nimport { getVariant, type VariantContext } from \"../api-variants\";\nimport { getPreferences } from \"../preferences\";\nimport { badRequest, HttpError } from \"../response\";\nimport { resolveModel } from \"./index\";\nimport { completeLog, startLog } from \"./log\";\nimport { handleNonStream } from \"./non-stream\";\nimport type { ForwardResult } from \"./types\";\n\n/**\n * Multipart upstream forwarder for capabilities whose upstream wire\n * shape is `multipart/form-data` (audio.transcription, video create).\n *\n * The standard JSON pipeline in `forwardGeneration` doesn't apply\n * here — there's no canonical chat-completion body to merge, no\n * `transformRequest`, no `applyFieldFilter`. We resolve the model →\n * provider, post the FormData verbatim (letting fetch set the\n * Content-Type with the right boundary), and route the response\n * through the same `handleNonStream` path so logs stay uniform.\n *\n * `model` MUST be present as a form field — same contract as the\n * JSON gateway.\n */\nexport async function forwardMultipartGeneration(\n user: SessionUser,\n capabilityId: string,\n form: FormData,\n): Promise<ForwardResult> {\n const capability = getCapability(capabilityId);\n if (!capability) throw badRequest(`Unknown capability \"${capabilityId}\"`);\n\n const requestedModel = form.get(\"model\");\n if (typeof requestedModel !== \"string\" || !requestedModel) {\n throw badRequest(\"`model` form field is required\");\n }\n\n const { model, provider, adapter, meta, apiKey } = await resolveModel(requestedModel);\n\n const variantId = resolveVariantId(adapter, capability, model, meta);\n const variant = getVariant(variantId);\n if (!variant) throw badRequest(`No upstream variant registered for \"${variantId}\"`);\n if (variant.capability !== capability.id) {\n throw badRequest(\n `Variant \"${variantId}\" serves \"${variant.capability}\", not \"${capability.id}\"`,\n );\n }\n\n const ctx: VariantContext = { provider, model, meta, capability, stream: false };\n const callArgs: UpstreamCallArgs = { provider, model, meta, capability, variant, stream: false };\n\n // Re-stamp model with upstream id so providers / Azure deployment\n // routing stays consistent with the JSON path.\n const upstreamForm = new FormData();\n for (const [k, v] of form.entries()) {\n if (k === \"model\") continue;\n upstreamForm.append(k, v);\n }\n upstreamForm.append(\"model\", model.upstreamModelId);\n\n // Summarise BEFORE the upstream-id rewrite so logs reflect the\n // caller-facing model + any text prompt fields.\n const summary = summariseForm(form, capability.id);\n const logId = startLog({\n userId: user.id,\n modelName: model.name,\n capability: capability.id,\n requestBody: redactForm(form),\n inputSummary: summary?.slice(0, 1000) ?? null,\n });\n\n // Drop the JSON Content-Type the adapter would have set — fetch\n // generates `multipart/form-data; boundary=…` automatically when\n // body is FormData and Content-Type is absent.\n const headers = { ...adapter.upstreamHeaders(callArgs, apiKey) };\n delete headers[\"Content-Type\"];\n delete headers[\"content-type\"];\n\n const started = Date.now();\n // Multipart endpoints are non-stream (audio.speech / transcription\n // returns the full audio buffer, video create returns a job id),\n // so the operative timeout is a real wall-clock cap on the\n // upstream call. The user's preference wins over model.timeout —\n // see comment in forwardGeneration for the same priority logic.\n const userTimeoutSec = getPreferences(user.id).gateway_timeout_seconds;\n const timeoutMs = Math.max(1, userTimeoutSec || model.timeout) * 1000;\n let upstream: Response;\n try {\n upstream = await fetch(adapter.upstreamUrl(callArgs), {\n method: \"POST\",\n headers,\n body: upstreamForm,\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n completeLog(logId, { status: \"failed\", reason: message, totalLatencyMs: Date.now() - started });\n throw new HttpError(`Upstream request failed: ${message}`, 502);\n }\n\n if (!upstream.ok) {\n const text = await upstream.text().catch(() => upstream.statusText);\n completeLog(logId, {\n status: \"failed\",\n reason: `Upstream HTTP ${upstream.status}`,\n output: text.slice(0, 4000),\n totalLatencyMs: Date.now() - started,\n });\n return {\n response: new Response(text, {\n status: upstream.status,\n headers: { \"Content-Type\": upstream.headers.get(\"Content-Type\") ?? \"application/json\" },\n }),\n logId,\n };\n }\n\n return handleNonStream({ upstream, variant, ctx, opts: {}, started, logId });\n}\n\nfunction summariseForm(form: FormData, capabilityId: string): string | null {\n const prompt = form.get(\"prompt\");\n if (typeof prompt === \"string\" && prompt) return prompt;\n if (capabilityId === \"audio.transcription\") {\n const f = form.get(\"file\");\n const name = f instanceof File ? f.name : null;\n const size = f instanceof File ? f.size : null;\n if (name) return `audio file: ${name}${size ? ` (${size} bytes)` : \"\"}`;\n return \"audio input\";\n }\n return null;\n}\n\nfunction redactForm(form: FormData): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [k, v] of form.entries()) {\n if (v instanceof File) {\n out[k] = { _kind: \"file\", name: v.name, type: v.type, size: v.size };\n } else {\n const s = String(v);\n out[k] = s.length > 4000 ? `${s.slice(0, 4000)}…(+${s.length - 4000})` : s;\n }\n }\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Generic upstream proxy: used by polling/download/delete endpoints that hang\n// off the same provider as the create call (e.g. GET /videos/{id}, DELETE\n// /videos/{id}, GET /videos/{id}/content).\n// ---------------------------------------------------------------------------\n\ninterface ProxyArgs {\n user: SessionUser;\n /** Caller-facing model name so we can resolve which provider owns this resource. */\n modelName: string;\n /** Relative path appended to provider.baseUrl (must include leading slash). */\n path: string;\n method?: \"GET\" | \"DELETE\" | \"POST\";\n /** Optional query string (no leading `?`). */\n query?: string;\n body?: BodyInit;\n /** Override / supplement adapter headers. */\n headers?: Record<string, string>;\n}\n\n/**\n * Lightweight proxy for follow-up requests that ride on top of a\n * previously-created resource. No gateway pipeline, no log — the\n * resource creation was already logged at submit time.\n */\nexport async function gatewayProxy(args: ProxyArgs): Promise<Response> {\n const { provider, apiKey } = await resolveModel(args.modelName);\n if (!provider.enabled) throw badRequest(`Provider \"${provider.name}\" is disabled`);\n\n const baseUrl = provider.baseUrl.replace(/\\/$/, \"\");\n let url = `${baseUrl}${args.path}`;\n if (args.query) url += `?${args.query}`;\n\n const headers: Record<string, string> = {};\n if (apiKey) headers[\"Authorization\"] = `Bearer ${apiKey}`;\n Object.assign(headers, args.headers ?? {});\n if (args.body && !headers[\"Content-Type\"] && !(args.body instanceof FormData)) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n\n const res = await fetch(url, {\n method: args.method ?? \"GET\",\n headers,\n body: args.body,\n });\n\n // Pass-through: preserve content-type so binary downloads work.\n const passthroughHeaders: Record<string, string> = {\n \"Content-Type\": res.headers.get(\"Content-Type\") ?? \"application/octet-stream\",\n };\n const cl = res.headers.get(\"Content-Length\");\n if (cl) passthroughHeaders[\"Content-Length\"] = cl;\n const cd = res.headers.get(\"Content-Disposition\");\n if (cd) passthroughHeaders[\"Content-Disposition\"] = cd;\n\n return new Response(res.body, {\n status: res.status,\n statusText: res.statusText,\n headers: passthroughHeaders,\n });\n}\n"],"names":["INPUT_DATA_KEYS","Set","extractKwargs","body","out","k","v","Object","entries","has","B64_INLINE_THRESHOLD","BARE_B64_HEAD_PROBE","sanitizeStringForLog","s","length","startsWith","semi","indexOf","mime","slice","kb","Math","round","kind","test","sanitizeBodyForLog","value","Array","isArray","map","startLog","payload","id","sanitizedInput","requestBody","insert","generationLogs","values","userId","modelName","capability","status","input","inputSummary","generationKwargs","conversationId","messageId","run","completeLog","fields","update","set","output","reason","generation","promptTokens","completionTokens","totalTokens","firstTokenLatencyMs","totalLatencyMs","updatedAt","Date","toISOString","where"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
module.exports=[381305,a=>{"use strict";var b=a.i(187924),c=a.i(572131),d=a.i(182434),e=a.i(563588),f=a.i(883706);let g=(0,f.default)("palette",[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]]);var h=a.i(787654);let i=(0,f.default)("sliders-vertical",[["path",{d:"M10 8h4",key:"1sr2af"}],["path",{d:"M12 21v-9",key:"17s77i"}],["path",{d:"M12 8V3",key:"13r4qs"}],["path",{d:"M17 16h4",key:"h1uq16"}],["path",{d:"M19 12V3",key:"o1uvq1"}],["path",{d:"M19 21v-5",key:"qua636"}],["path",{d:"M3 14h4",key:"bcjad9"}],["path",{d:"M5 10V3",key:"cb8scm"}],["path",{d:"M5 21v-7",key:"1w1uti"}]]);var
|
|
1
|
+
module.exports=[381305,a=>{"use strict";var b=a.i(187924),c=a.i(572131),d=a.i(182434),e=a.i(563588),f=a.i(883706);let g=(0,f.default)("palette",[["path",{d:"M12 22a1 1 0 0 1 0-20 10 9 0 0 1 10 9 5 5 0 0 1-5 5h-2.25a1.75 1.75 0 0 0-1.4 2.8l.3.4a1.75 1.75 0 0 1-1.4 2.8z",key:"e79jfc"}],["circle",{cx:"13.5",cy:"6.5",r:".5",fill:"currentColor",key:"1okk4w"}],["circle",{cx:"17.5",cy:"10.5",r:".5",fill:"currentColor",key:"f64h9f"}],["circle",{cx:"6.5",cy:"12.5",r:".5",fill:"currentColor",key:"qy21gx"}],["circle",{cx:"8.5",cy:"7.5",r:".5",fill:"currentColor",key:"fotxhn"}]]);var h=a.i(787654);let i=(0,f.default)("sliders-vertical",[["path",{d:"M10 8h4",key:"1sr2af"}],["path",{d:"M12 21v-9",key:"17s77i"}],["path",{d:"M12 8V3",key:"13r4qs"}],["path",{d:"M17 16h4",key:"h1uq16"}],["path",{d:"M19 12V3",key:"o1uvq1"}],["path",{d:"M19 21v-5",key:"qua636"}],["path",{d:"M3 14h4",key:"bcjad9"}],["path",{d:"M5 10V3",key:"cb8scm"}],["path",{d:"M5 21v-7",key:"1w1uti"}]]),j=(0,f.default)("timer",[["line",{x1:"10",x2:"14",y1:"2",y2:"2",key:"14vaq8"}],["line",{x1:"12",x2:"15",y1:"14",y2:"11",key:"17fdiu"}],["circle",{cx:"12",cy:"14",r:"8",key:"1e1u0o"}]]);var k=a.i(546842),l=a.i(879808),m=a.i(823292),n=a.i(911394),o=a.i(483597),p=a.i(957407),q=a.i(340695),r=a.i(497895);let s=(0,f.default)("sun",[["circle",{cx:"12",cy:"12",r:"4",key:"4exip2"}],["path",{d:"M12 2v2",key:"tus03m"}],["path",{d:"M12 20v2",key:"1lh1kg"}],["path",{d:"m4.93 4.93 1.41 1.41",key:"149t6j"}],["path",{d:"m17.66 17.66 1.41 1.41",key:"ptbguv"}],["path",{d:"M2 12h2",key:"1t8f8n"}],["path",{d:"M20 12h2",key:"1q8mjw"}],["path",{d:"m6.34 17.66-1.41 1.41",key:"1m8zz5"}],["path",{d:"m19.07 4.93-1.41 1.41",key:"1shlcs"}]]),t=(0,f.default)("moon",[["path",{d:"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401",key:"kfwtm"}]]),u=(0,f.default)("monitor",[["rect",{width:"20",height:"14",x:"2",y:"3",rx:"2",key:"48i651"}],["line",{x1:"8",x2:"16",y1:"21",y2:"21",key:"1svkeh"}],["line",{x1:"12",x2:"12",y1:"17",y2:"21",key:"vw1qmm"}]]);var v=a.i(533441);a.i(506122),a.i(408119);var w=a.i(66315),x=a.i(644010),y=a.i(703130),z=a.i(205522),A=a.i(405784),B=a.i(587532),C=a.i(734020);function D({icon:a,title:c,description:d,action:e,children:f}){return(0,b.jsxs)(y.Card,{children:[(0,b.jsx)(y.CardHeader,{className:"pb-4",children:(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsx)("div",{className:"rounded-lg bg-primary/10 p-2",children:(0,b.jsx)(a,{className:"h-4 w-4 text-primary"})}),(0,b.jsxs)("div",{className:"flex-1 min-w-0",children:[(0,b.jsx)(y.CardTitle,{className:"text-base",children:c}),d&&(0,b.jsx)(y.CardDescription,{className:"text-sm",children:d})]}),e]})}),(0,b.jsx)(y.CardContent,{className:"space-y-4",children:f})]})}function E({label:a,description:c,children:d,stacked:e}){return e?(0,b.jsxs)("div",{className:"space-y-2",children:[(0,b.jsxs)("div",{className:"space-y-0.5",children:[(0,b.jsx)("span",{className:"text-sm font-medium",children:a}),c&&(0,b.jsx)("p",{className:"text-xs text-muted-foreground",children:c})]}),(0,b.jsx)("div",{children:d})]}):(0,b.jsxs)("div",{className:"flex flex-col justify-between gap-2 sm:flex-row sm:items-center sm:gap-4",children:[(0,b.jsxs)("div",{className:"shrink-0 space-y-0.5",children:[(0,b.jsx)("span",{className:"text-sm font-medium",children:a}),c&&(0,b.jsx)("p",{className:"text-xs text-muted-foreground",children:c})]}),(0,b.jsx)("div",{className:"w-full sm:max-w-[280px]",children:d})]})}let F=c.memo(function({value:a,onValueChange:d,models:e,isLoading:f,placeholder:g}){let[h,i]=c.useState(!1),[j,k]=c.useState(""),l=c.useRef(null),m=c.useMemo(()=>{if(!j)return e;let a=j.toLowerCase();return e.filter(b=>b.name.toLowerCase().includes(a))},[e,j]);return c.useEffect(()=>{if(!h)return;let a=a=>{l.current&&!l.current.contains(a.target)&&i(!1)};return document.addEventListener("mousedown",a),()=>document.removeEventListener("mousedown",a)},[h]),c.useEffect(()=>{h||k("")},[h]),(0,b.jsxs)("div",{ref:l,className:"relative",children:[(0,b.jsxs)("button",{type:"button",onClick:()=>!f&&i(!h),className:(0,r.cn)("flex h-9 w-full items-center justify-between rounded-md border bg-transparent px-3 text-sm","transition-colors hover:bg-muted/50",f&&"cursor-not-allowed opacity-50"),disabled:f,children:[(0,b.jsx)("span",{className:"truncate",children:a||g}),(0,b.jsx)(A.ChevronDown,{className:"h-4 w-4 shrink-0 opacity-50"})]}),h&&(0,b.jsxs)("div",{className:"absolute z-50 mt-1 w-full rounded-md border bg-popover shadow-md",children:[(0,b.jsx)("div",{className:"border-b p-2",children:(0,b.jsxs)("div",{className:"relative",children:[(0,b.jsx)(B.Search,{className:"absolute left-2 top-1.5 h-3.5 w-3.5 text-muted-foreground"}),(0,b.jsx)(z.Input,{placeholder:"Search...",className:"h-7 pl-7 text-xs",value:j,onChange:a=>k(a.target.value),autoFocus:!0})]})}),(0,b.jsx)("div",{className:"scrollbar-thin max-h-[240px] overflow-y-auto p-1",children:0===m.length?(0,b.jsx)("div",{className:"p-2 text-sm text-muted-foreground",children:"No models"}):m.map(c=>(0,b.jsxs)("button",{type:"button",onClick:()=>{d(c.name),i(!1)},className:(0,r.cn)("flex w-full items-center gap-2 rounded-sm px-2 py-1.5 text-left text-xs",a===c.name?"bg-accent":"hover:bg-muted/50"),children:[(0,b.jsx)(C.ProviderIcon,{providerName:c.provider||"?"}),(0,b.jsx)("span",{className:"truncate",children:c.name})]},c.name))})]})]})});function G({theme:a,active:c,onSelect:d}){let[e,f,g,h]=a.preview.swatches;return(0,b.jsxs)("button",{type:"button",onClick:d,className:(0,r.cn)("group relative flex items-stretch gap-3 overflow-hidden rounded-xl border bg-card p-3 text-left transition-all","hover:border-primary/50 hover:shadow-sm",c&&"border-primary ring-2 ring-primary/30"),children:[(0,b.jsxs)("div",{className:"relative flex h-16 w-16 shrink-0 items-center justify-center overflow-hidden rounded-lg border",style:{background:e,color:f},children:[(0,b.jsx)("span",{className:"text-xl font-semibold leading-none",children:a.preview.glyph??"Aa"}),(0,b.jsxs)("div",{className:"absolute bottom-1 left-1 right-1 flex h-1.5 gap-0.5",children:[(0,b.jsx)("div",{className:"flex-1 rounded-sm",style:{background:f}}),(0,b.jsx)("div",{className:"flex-1 rounded-sm",style:{background:g}}),(0,b.jsx)("div",{className:"flex-1 rounded-sm",style:{background:h}})]})]}),(0,b.jsxs)("div",{className:"min-w-0 flex-1",children:[(0,b.jsxs)("div",{className:"flex items-center gap-2",children:[(0,b.jsx)("span",{className:"text-sm font-medium",children:a.label}),(0,b.jsx)("span",{className:(0,r.cn)("rounded-full border px-1.5 py-0.5 text-[10px] font-medium uppercase tracking-wide","cool"===a.flair?"border-primary/30 bg-primary/10 text-primary":"border-border bg-muted text-muted-foreground"),children:a.flair})]}),(0,b.jsx)("p",{className:"mt-1 line-clamp-2 text-xs text-muted-foreground",children:a.description})]}),c&&(0,b.jsx)(v.Check,{className:"absolute right-2 top-2 h-4 w-4 text-primary"})]})}function H({value:a,onChange:c}){return(0,b.jsx)("div",{className:"inline-flex rounded-md border bg-muted/30 p-0.5",children:[{value:"light",label:"Light",icon:s},{value:"dark",label:"Dark",icon:t},{value:"system",label:"System",icon:u}].map(d=>{let e=d.icon,f=a===d.value;return(0,b.jsxs)("button",{type:"button",onClick:()=>c(d.value),className:(0,r.cn)("inline-flex items-center gap-1.5 rounded px-3 py-1.5 text-xs transition-colors",f?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground"),children:[(0,b.jsx)(e,{className:"h-3.5 w-3.5"}),d.label]},d.value)})})}function I({value:a,options:c,onChange:d}){return(0,b.jsx)("div",{className:"inline-flex w-full rounded-md border bg-muted/30 p-0.5 sm:w-auto",children:c.map(c=>{let e=a===c.value;return(0,b.jsx)("button",{type:"button",onClick:()=>d(c.value),className:(0,r.cn)("flex-1 rounded px-3 py-1.5 text-xs transition-colors sm:flex-initial",e?"bg-background text-foreground shadow-sm":"text-muted-foreground hover:text-foreground"),children:c.label},c.value)})})}var J=a.i(280281),K=a.i(546893),L=a.i(524634);let M=["👤","😀","😎","🤖","🦊","🐱","🐶","🦁","🐼","🐨","🐸","🦄","🌟","💫","🎯","🚀"];function N(){let{data:a}=n.preferences.useGet(),c=a??o.defaultUserPreferences,d=n.preferences.useUpdate(),e=a=>d.mutate(a,{onError:a=>m.toast.error(a.message||"Failed to save")});return(0,b.jsxs)(D,{icon:k.User,title:"User Profile",description:"The display name and avatar shown across the app.",children:[(0,b.jsx)(E,{label:"Display Name",description:"Shown in the header, chat messages, and conversation list.",children:(0,b.jsx)(z.Input,{value:c.user_name,onChange:a=>e({user_name:a.target.value}),placeholder:"Your name"})}),(0,b.jsx)(E,{label:"Avatar",description:"Pick an emoji avatar.",stacked:!0,children:(0,b.jsx)("div",{className:"flex flex-wrap gap-1.5",children:M.map(a=>(0,b.jsx)("button",{type:"button",onClick:()=>e({user_avatar:a}),className:(0,r.cn)("flex h-9 w-9 items-center justify-center rounded-lg border text-lg transition-all hover:bg-muted",c.user_avatar===a?"border-primary bg-primary/10 ring-2 ring-primary/20":"border-transparent"),children:a},a))})})]})}var O=a.i(915618),P=a.i(842698),Q=a.i(59848),R=a.i(596221),S=a.i(965733),T=a.i(917171);let U=`{
|
|
2
2
|
"type": "object",
|
|
3
3
|
"properties": {},
|
|
4
4
|
"required": []
|
|
5
|
-
}`;function U({open:a,onOpenChange:d,mode:e,tool:f}){let[g,h]=c.useState(""),[i,j]=c.useState(""),[k,m]=c.useState(T),[n,o]=c.useState(""),[q,r]=c.useState(!0),[s,t]=c.useState(null);c.useEffect(()=>{a&&(f?(h(f.name),j(f.description??""),m(JSON.stringify(f.parameters??{},null,2)),o(f.webhook_url??""),r(!1!==f.enabled)):(h(""),j(""),m(T),o(""),r(!0)),t(null))},[a,f]);let u=O.tools.useCreate({onSuccess:()=>{l.toast.success("Saved"),d(!1)},onError:a=>l.toast.error(a.message||"Save failed")}),v=O.tools.useUpdate({onSuccess:()=>{l.toast.success("Saved"),d(!1)},onError:a=>l.toast.error(a.message||"Save failed")}),w=u.isPending||v.isPending;return(0,b.jsx)(R.Dialog,{open:a,onOpenChange:d,children:(0,b.jsxs)(R.DialogContent,{className:"sm:max-w-[640px] max-h-[90vh] overflow-y-auto",onOpenAutoFocus:"edit"===e?a=>a.preventDefault():void 0,children:[(0,b.jsx)(R.DialogHeader,{children:(0,b.jsx)(R.DialogTitle,{children:"create"===e?"Add tool":"Edit"})}),(0,b.jsxs)("form",{onSubmit:a=>{if(a.preventDefault(),!g.trim())return l.toast.error("Name required");let b={};try{b=k.trim()?JSON.parse(k):{},t(null)}catch(a){t(a instanceof Error?a.message:"Invalid JSON");return}let c={name:g.trim(),description:i.trim(),parameters:b,webhook_url:n.trim()||null,enabled:q};"create"===e?u.mutate(c):f&&v.mutate({id:f.id,data:c})},className:"space-y-4",children:[(0,b.jsxs)("div",{className:"grid sm:grid-cols-2 gap-3",children:[(0,b.jsx)(V,{label:"Name",htmlFor:"t-name",children:(0,b.jsx)(y.Input,{id:"t-name",value:g,onChange:a=>h(a.target.value),placeholder:"get_weather",className:"h-9 text-sm font-mono"})}),(0,b.jsx)(V,{label:"Webhook URL",htmlFor:"t-webhook",children:(0,b.jsx)(y.Input,{id:"t-webhook",value:n,onChange:a=>o(a.target.value),placeholder:"https://…",className:"h-9 text-sm font-mono"})})]}),(0,b.jsx)(V,{label:"Description",htmlFor:"t-desc",children:(0,b.jsx)(y.Input,{id:"t-desc",value:i,onChange:a=>j(a.target.value),className:"h-9 text-sm"})}),(0,b.jsxs)(V,{label:"Parameters (JSON Schema)",htmlFor:"t-params",children:[(0,b.jsx)(J.Textarea,{id:"t-params",value:k,onChange:a=>m(a.target.value),rows:10,className:"text-xs font-mono"}),s&&(0,b.jsx)("span",{className:"text-xs text-destructive",children:s})]}),(0,b.jsxs)("div",{className:"flex items-center justify-between",children:[(0,b.jsx)(S.Label,{htmlFor:"t-enabled",className:"text-xs",children:"Enabled"}),(0,b.jsx)(I.Switch,{id:"t-enabled",checked:q,onCheckedChange:r})]}),(0,b.jsxs)("div",{className:"flex items-center justify-end gap-2 pt-2",children:[(0,b.jsx)(p.Button,{type:"button",variant:"outline",size:"sm",onClick:()=>d(!1),disabled:w,children:"Cancel"}),(0,b.jsxs)(p.Button,{type:"submit",size:"sm",disabled:w,children:[w&&(0,b.jsx)(Q.Loader2,{className:"mr-2 h-4 w-4 animate-spin"}),"Save"]})]})]})]})})}function V({label:a,htmlFor:c,children:d}){return(0,b.jsxs)("div",{className:"grid gap-1.5 min-w-0",children:[(0,b.jsx)(S.Label,{htmlFor:c,className:"text-xs",children:a}),d]})}var W=a.i(699464),X=a.i(781560),Y=a.i(254161),Z=a.i(158880),$=a.i(649865);function _({tools:a,onEdit:c,onDelete:d}){let e=!!c||!!d;return(0,b.jsxs)(Z.DataTableShell,{children:[(0,b.jsx)(Z.DataTableHeader,{children:(0,b.jsxs)(Z.DataTableHeaderRow,{children:[(0,b.jsx)(Z.DataTableHead,{children:"Name"}),(0,b.jsx)(Z.DataTableHead,{children:"Description"}),(0,b.jsx)(Z.DataTableHead,{children:"Webhook"}),(0,b.jsx)(Z.DataTableHead,{children:"Status"}),e&&(0,b.jsx)(Z.DataTableHead,{className:"w-[88px] text-right",children:"Actions"})]})}),(0,b.jsx)($.DataTableBody,{children:0===a.length?(0,b.jsx)(Z.DataTableEmpty,{colSpan:e?5:4,children:"No tools registered yet."}):a.map(a=>(0,b.jsxs)(Z.DataTableRow,{children:[(0,b.jsx)(Z.DataTableCell,{className:"font-mono text-xs max-w-[200px] truncate",title:a.name,children:a.name}),(0,b.jsx)(Z.DataTableCell,{className:"text-xs text-muted-foreground max-w-[320px] truncate",title:a.description,children:a.description||"—"}),(0,b.jsx)(Z.DataTableCell,{className:"text-xs font-mono text-muted-foreground max-w-[260px] truncate",title:a.webhook_url??void 0,children:a.webhook_url??(0,b.jsx)("span",{className:"italic",children:"none"})}),(0,b.jsx)(Z.DataTableCell,{children:(0,b.jsx)(Y.Badge,{variant:a.enabled?"default":"secondary",className:"text-[10px] uppercase",children:a.enabled?"on":"off"})}),e&&(0,b.jsx)(Z.DataTableCell,{className:"text-right",children:(0,b.jsxs)("div",{className:"flex items-center justify-end gap-1",children:[c&&(0,b.jsx)(p.Button,{variant:"ghost",size:"icon",className:"h-7 w-7",onClick:()=>c(a),title:"Edit",children:(0,b.jsx)(W.Pencil,{className:"h-3.5 w-3.5"})}),d&&(0,b.jsx)(p.Button,{variant:"ghost",size:"icon",className:"h-7 w-7 text-destructive hover:text-destructive",onClick:()=>d(a),title:"Delete",children:(0,b.jsx)(X.Trash2,{className:"h-3.5 w-3.5"})})]})})]},a.id))})]})}let aa=[{id:"profile",label:"Profile",icon:j.User,Component:M},{id:"appearance",label:"Appearance",icon:g,Component:function(){let{data:a}=m.preferences.useGet(),d=a??n.defaultUserPreferences,e=m.preferences.useUpdate(),f=c.useMemo(()=>(0,v.getAllThemes)(),[]),h=a=>e.mutate(a,{onError:a=>l.toast.error(a.message||"Failed to save")});return(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)(C,{icon:g,title:"Theme",description:"Pick a visual preset for the whole app.",children:[(0,b.jsx)("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:f.map(a=>(0,b.jsx)(F,{theme:a,active:d.theme_id===a.id,onSelect:()=>h({theme_id:a.id})},a.id))}),(0,b.jsx)(D,{label:"Color Scheme",description:"Light, dark, or follow the OS preference.",children:(0,b.jsx)(G,{value:d.theme_scheme,onChange:a=>h({theme_scheme:a})})})]}),(0,b.jsxs)(C,{icon:g,title:"Chat Rendering",description:"How streamed assistant messages animate and lay out.",children:[(0,b.jsx)(D,{label:"Render Mode",description:"Instant: no cursor. Stream: live + blinking cursor. Typewriter: smooth char-by-char.",stacked:!0,children:(0,b.jsx)(H,{value:d.chat_render_mode,options:[{value:"instant",label:"Instant"},{value:"stream",label:"Stream"},{value:"typewriter",label:"Typewriter"}],onChange:a=>h({chat_render_mode:a})})}),"typewriter"===d.chat_render_mode&&(0,b.jsx)(D,{label:"Typewriter Speed",description:`${d.typewriter_cps} characters per second.`,stacked:!0,children:(0,b.jsx)(w.Slider,{value:[d.typewriter_cps],min:20,max:400,step:10,onValueChange:([a])=>h({typewriter_cps:a})})}),(0,b.jsx)(D,{label:"Message Layout",description:"Plain: feed style. Bubble: aligned chat bubbles. Minimal: text only.",stacked:!0,children:(0,b.jsx)(H,{value:d.chat_bubble_style,options:[{value:"plain",label:"Plain"},{value:"bubble",label:"Bubble"},{value:"minimal",label:"Minimal"}],onChange:a=>h({chat_bubble_style:a})})})]})]})}},{id:"models",label:"Models",icon:d.Bot,Component:function(){let{data:a}=m.preferences.useGet(),e=a??n.defaultUserPreferences,f=m.preferences.useUpdate(),{data:g,isLoading:h}=K.models.useList(),i=c.useMemo(()=>Array.isArray(g)?g.map(a=>({name:a.name,provider:a.provider??void 0})):[],[g]),j=a=>f.mutate(a,{onError:a=>l.toast.error(a.message||"Failed to save")});return(0,b.jsxs)(C,{icon:d.Bot,title:"Default Models",description:"Models used when a conversation does not override them.",children:[(0,b.jsx)(D,{label:"Chat Model",description:"Default model for new conversations.",children:(0,b.jsx)(E,{value:e.default_model,onValueChange:a=>j({default_model:a}),models:i,isLoading:h,placeholder:h?"Loading...":"Select model"})}),(0,b.jsx)(D,{label:"Summary Model",description:"Model for titles and summaries.",children:(0,b.jsx)(E,{value:e.default_summary_model,onValueChange:a=>j({default_summary_model:a}),models:i,isLoading:h,placeholder:h?"Loading...":"Select model"})})]})}},{id:"chat",label:"Chat",icon:e.MessageSquare,Component:function(){let{data:a}=m.preferences.useGet(),c=a??n.defaultUserPreferences,d=m.preferences.useUpdate(),f=a=>d.mutate(a,{onError:a=>l.toast.error(a.message||"Failed to save")});return(0,b.jsxs)(C,{icon:e.MessageSquare,title:"Chat Defaults",children:[(0,b.jsx)(D,{label:"System Prompt",stacked:!0,children:(0,b.jsx)(J.Textarea,{value:c.default_system_prompt,onChange:a=>f({default_system_prompt:a.target.value}),rows:3,className:"resize-none"})}),(0,b.jsx)(D,{label:"History Limit",children:(0,b.jsx)(y.Input,{type:"number",value:c.default_history_limit,onChange:a=>f({default_history_limit:Number(a.target.value)}),min:1,max:50})})]})}},{id:"behavior",label:"Behavior",icon:i,Component:function(){let a=(0,o.useDeviceSettingsStore)(a=>a.sendOnEnter),c=(0,o.useDeviceSettingsStore)(a=>a.showTimestamps),d=(0,o.useDeviceSettingsStore)(a=>a.compactMode),e=(0,o.useDeviceSettingsStore)(a=>a.updateDeviceSettings);return(0,b.jsxs)(C,{icon:i,title:"Device Behavior",description:"Local-only switches — stored in this browser, never synced.",children:[(0,b.jsx)(D,{label:"Send on Enter",description:"Press Enter to send messages.",children:(0,b.jsx)(I.Switch,{checked:a,onCheckedChange:a=>e({sendOnEnter:a})})}),(0,b.jsx)(D,{label:"Show Timestamps",description:"Display message timestamps.",children:(0,b.jsx)(I.Switch,{checked:c,onCheckedChange:a=>e({showTimestamps:a})})}),(0,b.jsx)(D,{label:"Compact Mode",description:"Reduce spacing in chat view.",children:(0,b.jsx)(I.Switch,{checked:d,onCheckedChange:a=>e({compactMode:a})})})]})}},{id:"tools",label:"Tools",icon:k.Wrench,Component:function(){let{data:a}=O.tools.useList(),[d,e]=c.useState({open:!1,mode:"create"}),[f,g]=c.useState(null),h=O.tools.useDelete({onSuccess:()=>{l.toast.success("Tool deleted"),g(null)},onError:a=>l.toast.error(a.message||"Delete failed")});return(0,b.jsxs)(C,{icon:k.Wrench,title:"Custom tools",action:(0,b.jsxs)(p.Button,{size:"sm",variant:"secondary",onClick:()=>e({open:!0,mode:"create"}),children:[(0,b.jsx)(N.Plus,{className:"h-3.5 w-3.5 mr-1"}),"Add tool"]}),children:[(0,b.jsx)("div",{className:"border rounded-lg overflow-hidden",children:(0,b.jsx)(_,{tools:a??[],onEdit:a=>e({open:!0,mode:"edit",tool:a}),onDelete:g})}),(0,b.jsx)(U,{open:d.open,onOpenChange:a=>e(b=>({...b,open:a})),mode:d.mode,tool:d.tool}),(0,b.jsx)(P.ConfirmDialog,{open:!!f,onOpenChange:a=>!a&&g(null),title:"Delete tool?",description:(0,b.jsxs)(b.Fragment,{children:["This will delete ",(0,b.jsx)("b",{children:f?.name}),"."]}),confirmLabel:"Delete",destructive:!0,isLoading:h.isPending,onConfirm:()=>f&&h.mutate(f.id)})]})}}],ab="appearance";function ac({active:a,onSelect:c}){return(0,b.jsx)("nav",{"aria-label":"Settings sections",className:(0,q.cn)("shrink-0 md:w-44","scrollbar-none -mx-4 flex gap-1 overflow-x-auto px-4 md:mx-0 md:flex-col md:gap-0.5 md:overflow-visible md:px-0"),children:aa.map(d=>{let e=d.icon,f=a===d.id;return(0,b.jsxs)("button",{type:"button",onClick:()=>c(d.id),className:(0,q.cn)("inline-flex shrink-0 items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors","md:w-full md:justify-start",f?"bg-muted font-medium text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),children:[(0,b.jsx)(e,{className:"h-4 w-4 shrink-0"}),d.label]},d.id)})})}a.s(["default",0,function(){let[a,d]=function(){let[a,b]=c.useState(ab);return c.useEffect(()=>{let a=()=>{let a;return b((a=window.location.hash.replace(/^#/,""),aa.some(b=>b.id===a)?a:ab))};return a(),window.addEventListener("hashchange",a),()=>window.removeEventListener("hashchange",a)},[]),[a,c.useCallback(a=>{},[])]}(),e=m.preferences.useUpdate(),f=(0,o.useDeviceSettingsStore)(a=>a.resetDeviceSettings),g=aa.find(b=>b.id===a)?.Component??M,i=aa.find(b=>b.id===a)?.label??"Settings";return(0,b.jsx)("div",{className:"h-full overflow-y-auto scrollbar-thin",children:(0,b.jsxs)("div",{className:"mx-auto max-w-5xl space-y-6 p-4 md:p-6",children:[(0,b.jsxs)("header",{className:"flex items-center justify-between gap-2",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-lg font-semibold leading-none",children:"Settings"}),(0,b.jsx)("p",{className:"mt-1 text-sm text-muted-foreground",children:i})]}),(0,b.jsxs)(p.Button,{variant:"outline",size:"sm",onClick:()=>{e.mutate(n.defaultUserPreferences,{onSuccess:()=>{f(),l.toast.success("Settings reset")},onError:a=>l.toast.error(a.message||"Failed to reset")})},disabled:e.isPending,children:[(0,b.jsx)(h.RotateCcw,{className:"mr-2 h-4 w-4"}),"Reset"]})]}),(0,b.jsxs)("div",{className:"flex flex-col gap-4 md:flex-row md:gap-6",children:[(0,b.jsx)(ac,{active:a,onSelect:d}),(0,b.jsx)("div",{className:"min-w-0 flex-1",children:(0,b.jsx)(g,{})})]})]})})}],381305)}];
|
|
5
|
+
}`;function V({open:a,onOpenChange:d,mode:e,tool:f}){let[g,h]=c.useState(""),[i,j]=c.useState(""),[k,l]=c.useState(U),[n,o]=c.useState(""),[p,r]=c.useState(!0),[s,t]=c.useState(null);c.useEffect(()=>{a&&(f?(h(f.name),j(f.description??""),l(JSON.stringify(f.parameters??{},null,2)),o(f.webhook_url??""),r(!1!==f.enabled)):(h(""),j(""),l(U),o(""),r(!0)),t(null))},[a,f]);let u=P.tools.useCreate({onSuccess:()=>{m.toast.success("Saved"),d(!1)},onError:a=>m.toast.error(a.message||"Save failed")}),v=P.tools.useUpdate({onSuccess:()=>{m.toast.success("Saved"),d(!1)},onError:a=>m.toast.error(a.message||"Save failed")}),w=u.isPending||v.isPending;return(0,b.jsx)(S.Dialog,{open:a,onOpenChange:d,children:(0,b.jsxs)(S.DialogContent,{className:"sm:max-w-[640px] max-h-[90vh] overflow-y-auto",onOpenAutoFocus:"edit"===e?a=>a.preventDefault():void 0,children:[(0,b.jsx)(S.DialogHeader,{children:(0,b.jsx)(S.DialogTitle,{children:"create"===e?"Add tool":"Edit"})}),(0,b.jsxs)("form",{onSubmit:a=>{if(a.preventDefault(),!g.trim())return m.toast.error("Name required");let b={};try{b=k.trim()?JSON.parse(k):{},t(null)}catch(a){t(a instanceof Error?a.message:"Invalid JSON");return}let c={name:g.trim(),description:i.trim(),parameters:b,webhook_url:n.trim()||null,enabled:p};"create"===e?u.mutate(c):f&&v.mutate({id:f.id,data:c})},className:"space-y-4",children:[(0,b.jsxs)("div",{className:"grid sm:grid-cols-2 gap-3",children:[(0,b.jsx)(W,{label:"Name",htmlFor:"t-name",children:(0,b.jsx)(z.Input,{id:"t-name",value:g,onChange:a=>h(a.target.value),placeholder:"get_weather",className:"h-9 text-sm font-mono"})}),(0,b.jsx)(W,{label:"Webhook URL",htmlFor:"t-webhook",children:(0,b.jsx)(z.Input,{id:"t-webhook",value:n,onChange:a=>o(a.target.value),placeholder:"https://…",className:"h-9 text-sm font-mono"})})]}),(0,b.jsx)(W,{label:"Description",htmlFor:"t-desc",children:(0,b.jsx)(z.Input,{id:"t-desc",value:i,onChange:a=>j(a.target.value),className:"h-9 text-sm"})}),(0,b.jsxs)(W,{label:"Parameters (JSON Schema)",htmlFor:"t-params",children:[(0,b.jsx)(K.Textarea,{id:"t-params",value:k,onChange:a=>l(a.target.value),rows:10,className:"text-xs font-mono"}),s&&(0,b.jsx)("span",{className:"text-xs text-destructive",children:s})]}),(0,b.jsxs)("div",{className:"flex items-center justify-between",children:[(0,b.jsx)(T.Label,{htmlFor:"t-enabled",className:"text-xs",children:"Enabled"}),(0,b.jsx)(J.Switch,{id:"t-enabled",checked:p,onCheckedChange:r})]}),(0,b.jsxs)("div",{className:"flex items-center justify-end gap-2 pt-2",children:[(0,b.jsx)(q.Button,{type:"button",variant:"outline",size:"sm",onClick:()=>d(!1),disabled:w,children:"Cancel"}),(0,b.jsxs)(q.Button,{type:"submit",size:"sm",disabled:w,children:[w&&(0,b.jsx)(R.Loader2,{className:"mr-2 h-4 w-4 animate-spin"}),"Save"]})]})]})]})})}function W({label:a,htmlFor:c,children:d}){return(0,b.jsxs)("div",{className:"grid gap-1.5 min-w-0",children:[(0,b.jsx)(T.Label,{htmlFor:c,className:"text-xs",children:a}),d]})}var X=a.i(699464),Y=a.i(781560),Z=a.i(254161),$=a.i(158880),_=a.i(649865);function aa({tools:a,onEdit:c,onDelete:d}){let e=!!c||!!d;return(0,b.jsxs)($.DataTableShell,{children:[(0,b.jsx)($.DataTableHeader,{children:(0,b.jsxs)($.DataTableHeaderRow,{children:[(0,b.jsx)($.DataTableHead,{children:"Name"}),(0,b.jsx)($.DataTableHead,{children:"Description"}),(0,b.jsx)($.DataTableHead,{children:"Webhook"}),(0,b.jsx)($.DataTableHead,{children:"Status"}),e&&(0,b.jsx)($.DataTableHead,{className:"w-[88px] text-right",children:"Actions"})]})}),(0,b.jsx)(_.DataTableBody,{children:0===a.length?(0,b.jsx)($.DataTableEmpty,{colSpan:e?5:4,children:"No tools registered yet."}):a.map(a=>(0,b.jsxs)($.DataTableRow,{children:[(0,b.jsx)($.DataTableCell,{className:"font-mono text-xs max-w-[200px] truncate",title:a.name,children:a.name}),(0,b.jsx)($.DataTableCell,{className:"text-xs text-muted-foreground max-w-[320px] truncate",title:a.description,children:a.description||"—"}),(0,b.jsx)($.DataTableCell,{className:"text-xs font-mono text-muted-foreground max-w-[260px] truncate",title:a.webhook_url??void 0,children:a.webhook_url??(0,b.jsx)("span",{className:"italic",children:"none"})}),(0,b.jsx)($.DataTableCell,{children:(0,b.jsx)(Z.Badge,{variant:a.enabled?"default":"secondary",className:"text-[10px] uppercase",children:a.enabled?"on":"off"})}),e&&(0,b.jsx)($.DataTableCell,{className:"text-right",children:(0,b.jsxs)("div",{className:"flex items-center justify-end gap-1",children:[c&&(0,b.jsx)(q.Button,{variant:"ghost",size:"icon",className:"h-7 w-7",onClick:()=>c(a),title:"Edit",children:(0,b.jsx)(X.Pencil,{className:"h-3.5 w-3.5"})}),d&&(0,b.jsx)(q.Button,{variant:"ghost",size:"icon",className:"h-7 w-7 text-destructive hover:text-destructive",onClick:()=>d(a),title:"Delete",children:(0,b.jsx)(Y.Trash2,{className:"h-3.5 w-3.5"})})]})})]},a.id))})]})}let ab=[{id:"profile",label:"Profile",icon:k.User,Component:N},{id:"appearance",label:"Appearance",icon:g,Component:function(){let{data:a}=n.preferences.useGet(),d=a??o.defaultUserPreferences,e=n.preferences.useUpdate(),f=c.useMemo(()=>(0,w.getAllThemes)(),[]),h=a=>e.mutate(a,{onError:a=>m.toast.error(a.message||"Failed to save")});return(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)(D,{icon:g,title:"Theme",description:"Pick a visual preset for the whole app.",children:[(0,b.jsx)("div",{className:"grid grid-cols-1 gap-3 sm:grid-cols-2",children:f.map(a=>(0,b.jsx)(G,{theme:a,active:d.theme_id===a.id,onSelect:()=>h({theme_id:a.id})},a.id))}),(0,b.jsx)(E,{label:"Color Scheme",description:"Light, dark, or follow the OS preference.",children:(0,b.jsx)(H,{value:d.theme_scheme,onChange:a=>h({theme_scheme:a})})})]}),(0,b.jsxs)(D,{icon:g,title:"Chat Rendering",description:"How streamed assistant messages animate and lay out.",children:[(0,b.jsx)(E,{label:"Render Mode",description:"Instant: no cursor. Stream: live + blinking cursor. Typewriter: smooth char-by-char.",stacked:!0,children:(0,b.jsx)(I,{value:d.chat_render_mode,options:[{value:"instant",label:"Instant"},{value:"stream",label:"Stream"},{value:"typewriter",label:"Typewriter"}],onChange:a=>h({chat_render_mode:a})})}),"typewriter"===d.chat_render_mode&&(0,b.jsx)(E,{label:"Typewriter Speed",description:`${d.typewriter_cps} characters per second.`,stacked:!0,children:(0,b.jsx)(x.Slider,{value:[d.typewriter_cps],min:20,max:400,step:10,onValueChange:([a])=>h({typewriter_cps:a})})}),(0,b.jsx)(E,{label:"Message Layout",description:"Plain: feed style. Bubble: aligned chat bubbles. Minimal: text only.",stacked:!0,children:(0,b.jsx)(I,{value:d.chat_bubble_style,options:[{value:"plain",label:"Plain"},{value:"bubble",label:"Bubble"},{value:"minimal",label:"Minimal"}],onChange:a=>h({chat_bubble_style:a})})})]})]})}},{id:"models",label:"Models",icon:d.Bot,Component:function(){let{data:a}=n.preferences.useGet(),e=a??o.defaultUserPreferences,f=n.preferences.useUpdate(),{data:g,isLoading:h}=L.models.useList(),i=c.useMemo(()=>Array.isArray(g)?g.map(a=>({name:a.name,provider:a.provider??void 0})):[],[g]),j=a=>f.mutate(a,{onError:a=>m.toast.error(a.message||"Failed to save")});return(0,b.jsxs)(D,{icon:d.Bot,title:"Default Models",description:"Models used when a conversation does not override them.",children:[(0,b.jsx)(E,{label:"Chat Model",description:"Default model for new conversations.",children:(0,b.jsx)(F,{value:e.default_model,onValueChange:a=>j({default_model:a}),models:i,isLoading:h,placeholder:h?"Loading...":"Select model"})}),(0,b.jsx)(E,{label:"Summary Model",description:"Model for titles and summaries.",children:(0,b.jsx)(F,{value:e.default_summary_model,onValueChange:a=>j({default_summary_model:a}),models:i,isLoading:h,placeholder:h?"Loading...":"Select model"})})]})}},{id:"chat",label:"Chat",icon:e.MessageSquare,Component:function(){let{data:a}=n.preferences.useGet(),c=a??o.defaultUserPreferences,d=n.preferences.useUpdate(),f=a=>d.mutate(a,{onError:a=>m.toast.error(a.message||"Failed to save")});return(0,b.jsxs)(D,{icon:e.MessageSquare,title:"Chat Defaults",children:[(0,b.jsx)(E,{label:"System Prompt",stacked:!0,children:(0,b.jsx)(K.Textarea,{value:c.default_system_prompt,onChange:a=>f({default_system_prompt:a.target.value}),rows:3,className:"resize-none"})}),(0,b.jsx)(E,{label:"History Limit",children:(0,b.jsx)(z.Input,{type:"number",value:c.default_history_limit,onChange:a=>f({default_history_limit:Number(a.target.value)}),min:1,max:50})})]})}},{id:"timeouts",label:"Timeouts",icon:j,Component:function(){let{data:a}=n.preferences.useGet(),d=a??o.defaultUserPreferences,e=n.preferences.useUpdate(),[f,g]=c.useState(String(d.gateway_timeout_seconds)),[h,i]=c.useState(String(d.mcp_connect_timeout_seconds));c.useEffect(()=>{g(String(d.gateway_timeout_seconds))},[d.gateway_timeout_seconds]),c.useEffect(()=>{i(String(d.mcp_connect_timeout_seconds))},[d.mcp_connect_timeout_seconds]);let k=(a,b)=>{let c=b.trim();if(!c)return;let f=Number(c);if(!Number.isFinite(f)||f<1||f>86400)return void m.toast.error("Timeout must be between 1 and 86400 seconds");let g=Math.floor(f);g!==d[a]&&e.mutate({[a]:g},{onError:a=>m.toast.error(a.message||"Failed to save")})};return(0,b.jsxs)(D,{icon:j,title:"Timeouts",description:"Wall-clock budgets for upstream calls. Bumped from the legacy 60 s defaults — slow networks and reasoning models routinely need minutes.",children:[(0,b.jsx)(E,{label:"Gateway request (seconds)",description:"Chat, image, embedding, audio, rerank, video — every API call the gateway forwards.",children:(0,b.jsx)(z.Input,{type:"number",min:1,max:86400,value:f,onChange:a=>g(a.target.value),onBlur:a=>k("gateway_timeout_seconds",a.target.value),onKeyDown:a=>{"Enter"===a.key&&a.target.blur()},className:"w-32 text-right"})}),(0,b.jsx)(E,{label:"MCP connect (seconds)",description:"JSON-RPC initialize handshake — includes `npx`/`uvx`/`bunx` package download on cold cache. Applies to the re-check button you trigger from MCP details.",children:(0,b.jsx)(z.Input,{type:"number",min:1,max:86400,value:h,onChange:a=>i(a.target.value),onBlur:a=>k("mcp_connect_timeout_seconds",a.target.value),onKeyDown:a=>{"Enter"===a.key&&a.target.blur()},className:"w-32 text-right"})})]})}},{id:"behavior",label:"Behavior",icon:i,Component:function(){let a=(0,p.useDeviceSettingsStore)(a=>a.sendOnEnter),c=(0,p.useDeviceSettingsStore)(a=>a.showTimestamps),d=(0,p.useDeviceSettingsStore)(a=>a.compactMode),e=(0,p.useDeviceSettingsStore)(a=>a.updateDeviceSettings);return(0,b.jsxs)(D,{icon:i,title:"Device Behavior",description:"Local-only switches — stored in this browser, never synced.",children:[(0,b.jsx)(E,{label:"Send on Enter",description:"Press Enter to send messages.",children:(0,b.jsx)(J.Switch,{checked:a,onCheckedChange:a=>e({sendOnEnter:a})})}),(0,b.jsx)(E,{label:"Show Timestamps",description:"Display message timestamps.",children:(0,b.jsx)(J.Switch,{checked:c,onCheckedChange:a=>e({showTimestamps:a})})}),(0,b.jsx)(E,{label:"Compact Mode",description:"Reduce spacing in chat view.",children:(0,b.jsx)(J.Switch,{checked:d,onCheckedChange:a=>e({compactMode:a})})})]})}},{id:"tools",label:"Tools",icon:l.Wrench,Component:function(){let{data:a}=P.tools.useList(),[d,e]=c.useState({open:!1,mode:"create"}),[f,g]=c.useState(null),h=P.tools.useDelete({onSuccess:()=>{m.toast.success("Tool deleted"),g(null)},onError:a=>m.toast.error(a.message||"Delete failed")});return(0,b.jsxs)(D,{icon:l.Wrench,title:"Custom tools",action:(0,b.jsxs)(q.Button,{size:"sm",variant:"secondary",onClick:()=>e({open:!0,mode:"create"}),children:[(0,b.jsx)(O.Plus,{className:"h-3.5 w-3.5 mr-1"}),"Add tool"]}),children:[(0,b.jsx)("div",{className:"border rounded-lg overflow-hidden",children:(0,b.jsx)(aa,{tools:a??[],onEdit:a=>e({open:!0,mode:"edit",tool:a}),onDelete:g})}),(0,b.jsx)(V,{open:d.open,onOpenChange:a=>e(b=>({...b,open:a})),mode:d.mode,tool:d.tool}),(0,b.jsx)(Q.ConfirmDialog,{open:!!f,onOpenChange:a=>!a&&g(null),title:"Delete tool?",description:(0,b.jsxs)(b.Fragment,{children:["This will delete ",(0,b.jsx)("b",{children:f?.name}),"."]}),confirmLabel:"Delete",destructive:!0,isLoading:h.isPending,onConfirm:()=>f&&h.mutate(f.id)})]})}}],ac="appearance";function ad({active:a,onSelect:c}){return(0,b.jsx)("nav",{"aria-label":"Settings sections",className:(0,r.cn)("shrink-0 md:w-44","scrollbar-none -mx-4 flex gap-1 overflow-x-auto px-4 md:mx-0 md:flex-col md:gap-0.5 md:overflow-visible md:px-0"),children:ab.map(d=>{let e=d.icon,f=a===d.id;return(0,b.jsxs)("button",{type:"button",onClick:()=>c(d.id),className:(0,r.cn)("inline-flex shrink-0 items-center gap-2 rounded-md px-3 py-2 text-sm transition-colors","md:w-full md:justify-start",f?"bg-muted font-medium text-foreground":"text-muted-foreground hover:bg-muted/50 hover:text-foreground"),children:[(0,b.jsx)(e,{className:"h-4 w-4 shrink-0"}),d.label]},d.id)})})}a.s(["default",0,function(){let[a,d]=function(){let[a,b]=c.useState(ac);return c.useEffect(()=>{let a=()=>{let a;return b((a=window.location.hash.replace(/^#/,""),ab.some(b=>b.id===a)?a:ac))};return a(),window.addEventListener("hashchange",a),()=>window.removeEventListener("hashchange",a)},[]),[a,c.useCallback(a=>{},[])]}(),e=n.preferences.useUpdate(),f=(0,p.useDeviceSettingsStore)(a=>a.resetDeviceSettings),g=ab.find(b=>b.id===a)?.Component??N,i=ab.find(b=>b.id===a)?.label??"Settings";return(0,b.jsx)("div",{className:"h-full overflow-y-auto scrollbar-thin",children:(0,b.jsxs)("div",{className:"mx-auto max-w-5xl space-y-6 p-4 md:p-6",children:[(0,b.jsxs)("header",{className:"flex items-center justify-between gap-2",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-lg font-semibold leading-none",children:"Settings"}),(0,b.jsx)("p",{className:"mt-1 text-sm text-muted-foreground",children:i})]}),(0,b.jsxs)(q.Button,{variant:"outline",size:"sm",onClick:()=>{e.mutate(o.defaultUserPreferences,{onSuccess:()=>{f(),m.toast.success("Settings reset")},onError:a=>m.toast.error(a.message||"Failed to reset")})},disabled:e.isPending,children:[(0,b.jsx)(h.RotateCcw,{className:"mr-2 h-4 w-4"}),"Reset"]})]}),(0,b.jsxs)("div",{className:"flex flex-col gap-4 md:flex-row md:gap-6",children:[(0,b.jsx)(ad,{active:a,onSelect:d}),(0,b.jsx)("div",{className:"min-w-0 flex-1",children:(0,b.jsx)(g,{})})]})]})})}],381305)}];
|
|
6
6
|
|
|
7
7
|
//# sourceMappingURL=app_%28dashboard%29_settings_page_tsx_1hwv4x8._.js.map
|