From 81a8c15da8ff240141d15c719e89bc429eeab531 Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Fri, 11 Jul 2025 16:47:33 +1000 Subject: [PATCH 01/10] wip --- examples/chat-ui/src/App.tsx | 1 + examples/chat-ui/src/types/models.ts | 10 +++++----- examples/chat-ui/src/utils/auth.ts | 3 ++- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/chat-ui/src/App.tsx b/examples/chat-ui/src/App.tsx index f390de7..90b40c4 100644 --- a/examples/chat-ui/src/App.tsx +++ b/examples/chat-ui/src/App.tsx @@ -6,6 +6,7 @@ function App() { return ( + } /> } /> } /> } /> diff --git a/examples/chat-ui/src/types/models.ts b/examples/chat-ui/src/types/models.ts index 73c4d16..bfcbd10 100644 --- a/examples/chat-ui/src/types/models.ts +++ b/examples/chat-ui/src/types/models.ts @@ -67,12 +67,12 @@ export const providers: Record = { baseUrl: 'https://api.groq.com/openai/v1', logo: '🚀', documentationUrl: 'https://console.groq.com/docs', - authType: 'apiKey', apiKeyHeader: 'Authorization', - // oauth: { - // authorizeUrl: 'http://localhost:3000/keys/request', - // tokenUrl: 'https://openrouter.ai/api/v1/auth/keys' - // }, + authType: 'oauth', + oauth: { + authorizeUrl: 'http://localhost:3000/keys/request', + tokenUrl: 'http://localhost:3000/keys/request/exchange', + }, }, anthropic: { id: 'anthropic', diff --git a/examples/chat-ui/src/utils/auth.ts b/examples/chat-ui/src/utils/auth.ts index d476cfe..762f4e4 100644 --- a/examples/chat-ui/src/utils/auth.ts +++ b/examples/chat-ui/src/utils/auth.ts @@ -152,7 +152,7 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str // Retrieve PKCE state let pkceState: PKCEState - if (state === 'no-state' && providerId === 'openrouter') { + if (state === 'no-state' && (providerId === 'openrouter' || providerId === 'groq')) { // OpenRouter doesn't use state, find the most recent PKCE state for this provider const allKeys = Object.keys(sessionStorage) const pkceKeys = allKeys.filter((key) => key.startsWith(`pkce_${providerId}_`)) @@ -222,6 +222,7 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str const requestBody = new URLSearchParams({ grant_type: 'authorization_code', code, + // TODO: state?? redirect_uri: getRedirectUri(providerId), code_verifier: pkceState.code_verifier, }) From d612d5aecf44dac3230dc2d817a17b9274283faf Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Fri, 11 Jul 2025 20:42:38 +1000 Subject: [PATCH 02/10] Successfully getting a token from Groq! --- .../chat-ui/src/components/OAuthCallback.tsx | 6 +- examples/chat-ui/src/utils/auth.ts | 142 +++++++++++------- 2 files changed, 92 insertions(+), 56 deletions(-) diff --git a/examples/chat-ui/src/components/OAuthCallback.tsx b/examples/chat-ui/src/components/OAuthCallback.tsx index 01beae1..370dd56 100644 --- a/examples/chat-ui/src/components/OAuthCallback.tsx +++ b/examples/chat-ui/src/components/OAuthCallback.tsx @@ -34,9 +34,9 @@ const OAuthCallback: React.FC = ({ provider }) => { throw new Error('Missing authorization code') } - // OpenRouter doesn't use state parameter, but other providers might - const stateToUse = state || 'no-state' - await completeOAuthFlow(provider, code, stateToUse) + // TODO: Add state parameter handling back if needed later + // const stateToUse = state || 'no-state' + await completeOAuthFlow(provider, code) setStatus('success') // Close popup after successful authentication diff --git a/examples/chat-ui/src/utils/auth.ts b/examples/chat-ui/src/utils/auth.ts index 762f4e4..0ce1204 100644 --- a/examples/chat-ui/src/utils/auth.ts +++ b/examples/chat-ui/src/utils/auth.ts @@ -11,7 +11,8 @@ export interface OAuthToken { // Types for PKCE flow interface PKCEState { code_verifier: string - state: string + // TODO: Add state support back if needed later + // state: string } // Generate a random code verifier for PKCE @@ -35,15 +36,15 @@ async function generateCodeChallenge(verifier: string): Promise { .replace(/=/g, '') } -// Generate random state parameter -function generateState(): string { - const array = new Uint8Array(16) - crypto.getRandomValues(array) - return btoa(String.fromCharCode(...array)) - .replace(/\+/g, '-') - .replace(/\//g, '_') - .replace(/=/g, '') -} +// TODO: Add state generation back if needed later +// function generateState(): string { +// const array = new Uint8Array(16) +// crypto.getRandomValues(array) +// return btoa(String.fromCharCode(...array)) +// .replace(/\+/g, '-') +// .replace(/\//g, '_') +// .replace(/=/g, '') +// } // API Key functions (existing functionality) export function hasApiKey(providerId: SupportedProvider): boolean { @@ -111,11 +112,17 @@ export async function beginOAuthFlow(providerId: SupportedProvider): Promise { - console.log('DEBUG: Starting OAuth completion for', providerId, 'with code:', code?.substring(0, 10) + '...', 'state:', state) +export async function completeOAuthFlow(providerId: SupportedProvider, code: string): Promise { + console.log('DEBUG: Starting OAuth completion for', providerId, 'with code:', code?.substring(0, 10) + '...') + console.log('DEBUG: Full code for debugging:', code) + console.log('DEBUG: Provider config:', providers[providerId]) const provider = providers[providerId] if (!provider.oauth) { throw new Error(`Provider ${providerId} does not support OAuth`) } - // Retrieve PKCE state - let pkceState: PKCEState + // Retrieve PKCE state (find the most recent one since we don't use state parameter) + const allKeys = Object.keys(sessionStorage) + const pkceKeys = allKeys.filter((key) => key.startsWith(`pkce_${providerId}_`)) - if (state === 'no-state' && (providerId === 'openrouter' || providerId === 'groq')) { - // OpenRouter doesn't use state, find the most recent PKCE state for this provider - const allKeys = Object.keys(sessionStorage) - const pkceKeys = allKeys.filter((key) => key.startsWith(`pkce_${providerId}_`)) + console.log('DEBUG: Found PKCE keys:', pkceKeys) - console.log('DEBUG: Found PKCE keys:', pkceKeys) + if (pkceKeys.length === 0) { + throw new Error('PKCE state not found. Please try again.') + } - if (pkceKeys.length === 0) { - throw new Error('PKCE state not found. Please try again.') - } + // Use the most recent one (sort by timestamp) + const sortedKeys = pkceKeys.sort((a, b) => { + const aTime = parseInt(a.split('_').pop() || '0') + const bTime = parseInt(b.split('_').pop() || '0') + return bTime - aTime // Most recent first + }) - // Use the most recent one (sort by timestamp) - const sortedKeys = pkceKeys.sort((a, b) => { - const aTime = parseInt(a.split('_').pop() || '0') - const bTime = parseInt(b.split('_').pop() || '0') - return bTime - aTime // Most recent first - }) + const pkceStateJson = sessionStorage.getItem(sortedKeys[0])! + const pkceState: PKCEState = JSON.parse(pkceStateJson) - const pkceStateJson = sessionStorage.getItem(sortedKeys[0])! - pkceState = JSON.parse(pkceStateJson) + console.log('DEBUG: Using PKCE state:', { key: sortedKeys[0], state: pkceState }) + console.log('DEBUG: Code verifier length:', pkceState.code_verifier.length) + console.log('DEBUG: Code verifier sample:', pkceState.code_verifier.substring(0, 20) + '...') - console.log('DEBUG: Using PKCE state:', { key: sortedKeys[0], state: pkceState }) + // Test: regenerate challenge from verifier to verify it matches server expectation + const recomputedChallenge = await generateCodeChallenge(pkceState.code_verifier) + console.log('DEBUG: Recomputed challenge from verifier:', recomputedChallenge) + console.log('DEBUG: Server reported challenge was: dW2iEvNljlkhcRcryo3Z0GITcJM1liKcHlB5v8CDEu8') - // Clean up the state - sessionStorage.removeItem(sortedKeys[0]) - } else { - const pkceStateJson = sessionStorage.getItem(`pkce_${providerId}_${state}`) - if (!pkceStateJson) { - throw new Error('PKCE state not found. Please try again.') - } - pkceState = JSON.parse(pkceStateJson) - console.log('DEBUG: Using PKCE state for state', state, ':', pkceState) - } + // Clean up the state + sessionStorage.removeItem(sortedKeys[0]) // Exchange code for token let tokenResponse: Response @@ -218,19 +224,23 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str duration: `${endTime - startTime}ms`, }) } else { - // Standard OAuth2 flow for other providers + // Standard OAuth2 flow for other providers (Groq) const requestBody = new URLSearchParams({ grant_type: 'authorization_code', code, - // TODO: state?? redirect_uri: getRedirectUri(providerId), code_verifier: pkceState.code_verifier, }) - console.log('DEBUG: Standard OAuth token request:', { + + console.log('DEBUG: Groq token request:', { url: provider.oauth.tokenUrl, body: Object.fromEntries(requestBody.entries()), + codeVerifierLength: pkceState.code_verifier.length, + codeVerifierSample: pkceState.code_verifier.substring(0, 20) + '...', + fullCodeVerifier: pkceState.code_verifier, // For debugging }) + const startTime = performance.now() tokenResponse = await fetch(provider.oauth.tokenUrl, { method: 'POST', headers: { @@ -238,11 +248,13 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str }, body: requestBody, }) + const endTime = performance.now() - console.log('DEBUG: Standard OAuth token response:', { + console.log('DEBUG: Groq token response:', { status: tokenResponse.status, statusText: tokenResponse.statusText, headers: Object.fromEntries(tokenResponse.headers.entries()), + duration: `${endTime - startTime}ms`, }) } @@ -276,10 +288,7 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str setOAuthToken(providerId, token) - // Clean up PKCE state (already cleaned up above for OpenRouter) - if (state !== 'no-state') { - sessionStorage.removeItem(`pkce_${providerId}_${state}`) - } + // PKCE state already cleaned up above } // Get authentication headers for API calls @@ -319,3 +328,30 @@ function getRedirectUri(providerId: SupportedProvider): string { const baseUrl = window.location.origin return `${baseUrl}/oauth/${providerId}/callback` } + +// Test function to verify PKCE implementation with known values +export async function testPKCEImplementation(): Promise { + console.log('=== TESTING PKCE IMPLEMENTATION ===') + + // Test with a known code verifier (from RFC 7636 example) + const testVerifier = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' + const expectedChallenge = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM' + + const computedChallenge = await generateCodeChallenge(testVerifier) + + console.log('DEBUG: Test verifier:', testVerifier) + console.log('DEBUG: Expected challenge:', expectedChallenge) + console.log('DEBUG: Computed challenge:', computedChallenge) + console.log('DEBUG: Challenges match:', computedChallenge === expectedChallenge) + + // Test with current implementation + const currentVerifier = generateCodeVerifier() + const currentChallenge = await generateCodeChallenge(currentVerifier) + + console.log('DEBUG: Current verifier:', currentVerifier) + console.log('DEBUG: Current challenge:', currentChallenge) + console.log('DEBUG: Verifier length:', currentVerifier.length) + console.log('DEBUG: Challenge length:', currentChallenge.length) + + console.log('=== END PKCE TEST ===') +} From 730ba7b0c5018bf2019646cdab5b07e0d30aaf94 Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Fri, 11 Jul 2025 20:57:13 +1000 Subject: [PATCH 03/10] Simplify PKCE flow to use single key per provider Previously, the PKCE flow stored multiple keys with timestamps (pkce_${providerId}_${timestamp}) and had complex logic to find the most recent key. This simplified implementation: - Changes storage key format from `pkce_${providerId}_${timestamp}` to `pkce_${providerId}` - Removes timestamp-based key sorting logic in completeOAuthFlow() - Ensures only one PKCE key is stored per provider at any time - Eliminates potential race conditions with multiple concurrent auth flows - Simplifies debugging by having predictable key names This applies to both OpenRouter and Groq OAuth flows. Also fixes TypeScript build error by removing unused 'state' variable in OAuthCallback component. Amp-Thread: https://ampcode.com/threads/T-12223468-a950-40a8-9d44-2e1a66e6efbe Co-authored-by: Amp --- examples/chat-ui/src/components/ChatApp.tsx | 2 + .../chat-ui/src/components/ModelSelector.tsx | 2 + .../chat-ui/src/components/OAuthCallback.tsx | 58 +++++++++++++++---- examples/chat-ui/src/utils/auth.ts | 30 +++++----- 4 files changed, 64 insertions(+), 28 deletions(-) diff --git a/examples/chat-ui/src/components/ChatApp.tsx b/examples/chat-ui/src/components/ChatApp.tsx index 6db7a43..0dc1760 100644 --- a/examples/chat-ui/src/components/ChatApp.tsx +++ b/examples/chat-ui/src/components/ChatApp.tsx @@ -33,7 +33,9 @@ const ChatApp: React.FC = () => { // Handle OAuth success messages from popups useEffect(() => { const handleMessage = (event: MessageEvent) => { + console.log('DEBUG: Received message in parent window:', event.data) if (event.data.type === 'oauth_success') { + console.log('DEBUG: OAuth success message received, triggering API key update') handleApiKeyUpdate() } } diff --git a/examples/chat-ui/src/components/ModelSelector.tsx b/examples/chat-ui/src/components/ModelSelector.tsx index 973e6b1..b87592c 100644 --- a/examples/chat-ui/src/components/ModelSelector.tsx +++ b/examples/chat-ui/src/components/ModelSelector.tsx @@ -39,7 +39,9 @@ const ModelSelector: React.FC = ({ selectedModel, onModelCha // Handle OAuth success - show provider models when OAuth completes useEffect(() => { const handleMessage = (event: MessageEvent) => { + console.log('DEBUG: ModelSelector received message:', event.data) if (event.data.type === 'oauth_success' && event.data.provider) { + console.log('DEBUG: ModelSelector opening provider models modal for:', event.data.provider) const provider = providers[event.data.provider as keyof typeof providers] if (provider) { setProviderModelsModal({ isOpen: true, provider }) diff --git a/examples/chat-ui/src/components/OAuthCallback.tsx b/examples/chat-ui/src/components/OAuthCallback.tsx index 370dd56..9355bb3 100644 --- a/examples/chat-ui/src/components/OAuthCallback.tsx +++ b/examples/chat-ui/src/components/OAuthCallback.tsx @@ -23,7 +23,6 @@ const OAuthCallback: React.FC = ({ provider }) => { try { const code = searchParams.get('code') - const state = searchParams.get('state') const error = searchParams.get('error') if (error) { @@ -39,17 +38,49 @@ const OAuthCallback: React.FC = ({ provider }) => { await completeOAuthFlow(provider, code) setStatus('success') + console.log('DEBUG: OAuth flow completed successfully') + console.log('DEBUG: window.opener exists:', !!window.opener) + console.log('DEBUG: window.opener closed:', window.opener?.closed) + console.log('DEBUG: window.parent exists:', !!window.parent) + console.log('DEBUG: window.parent === window:', window.parent === window) + + // Try multiple approaches to communicate with parent + const sendSuccessMessage = () => { + const message = { type: 'oauth_success', provider } + + // Try window.opener first + if (window.opener && !window.opener.closed) { + console.log('DEBUG: Sending message via window.opener') + window.opener.postMessage(message, '*') + } + + // Also try window.parent as fallback + if (window.parent && window.parent !== window) { + console.log('DEBUG: Sending message via window.parent') + window.parent.postMessage(message, '*') + } + + // Also try top window + if (window.top && window.top !== window) { + console.log('DEBUG: Sending message via window.top') + window.top.postMessage(message, '*') + } + } + + // Send success message immediately + sendSuccessMessage() + // Close popup after successful authentication - // Give extra time for debugging in development - setTimeout(() => { - if (window.opener) { - window.opener.postMessage({ type: 'oauth_success', provider }, '*') + if (window.opener && !window.opener.closed) { + console.log('DEBUG: Closing popup in 100ms') + setTimeout(() => { + console.log('DEBUG: Attempting to close popup') window.close() - } else { - // Redirect to main page if not in popup - window.location.href = '/' - } - }, 3000) + }, 100) + } else { + console.log('DEBUG: No valid opener, showing success message and manual close') + // Don't redirect immediately, let user see success and close manually + } } catch (err) { console.error('OAuth callback error:', err) setError(err instanceof Error ? err.message : 'Unknown error') @@ -86,7 +117,12 @@ const OAuthCallback: React.FC = ({ provider }) => {

Authentication Successful!

Successfully connected to {provider}. You can now close this window.

+

Successfully connected to {provider}.

+
+ + {window.opener && ( + + )} +
)} diff --git a/examples/chat-ui/src/utils/auth.ts b/examples/chat-ui/src/utils/auth.ts index 23383d4..b1f46ff 100644 --- a/examples/chat-ui/src/utils/auth.ts +++ b/examples/chat-ui/src/utils/auth.ts @@ -144,14 +144,18 @@ export async function beginOAuthFlow(providerId: SupportedProvider): Promise { @@ -272,6 +276,12 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str access_token: tokenData.key, token_type: 'Bearer', } + } else if (providerId === 'groq') { + // Groq returns { api_key: "..." } + token = { + access_token: tokenData.api_key, + token_type: 'Bearer', + } } else { // Standard OAuth2 response token = { @@ -282,6 +292,7 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str } } + console.log('DEBUG: Saving token for', providerId, ':', token) setOAuthToken(providerId, token) // PKCE state already cleaned up above From aae9e985343101dea152dc6eee764472d6758acb Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Fri, 11 Jul 2025 21:25:27 +1000 Subject: [PATCH 05/10] Able to run inference against staging Groq --- .../chat-ui/src/components/OAuthCallback.tsx | 36 +++++-------------- .../chat-ui/src/hooks/useStreamResponse.ts | 2 +- examples/chat-ui/src/types/models.ts | 11 +++++- 3 files changed, 20 insertions(+), 29 deletions(-) diff --git a/examples/chat-ui/src/components/OAuthCallback.tsx b/examples/chat-ui/src/components/OAuthCallback.tsx index 4fcc6e1..8e0e6eb 100644 --- a/examples/chat-ui/src/components/OAuthCallback.tsx +++ b/examples/chat-ui/src/components/OAuthCallback.tsx @@ -67,19 +67,13 @@ const OAuthCallback: React.FC = ({ provider }) => { // Try to send success message const messageSent = sendSuccessMessage() + console.log({ messageSent }) - // Close popup if we have a valid opener, otherwise redirect to main page - if (window.opener && !window.opener.closed) { - console.log('DEBUG: Closing popup in 100ms') - setTimeout(() => { - console.log('DEBUG: Attempting to close popup') - window.close() - }, 100) - } else { - console.log('DEBUG: No valid opener, showing success message') - // Just show success message, let user navigate back manually - // or provide a link to go back - } + console.log('DEBUG: Closing popup in 100ms') + setTimeout(() => { + console.log('DEBUG: Attempting to close popup') + window.close() + }, 100) } catch (err) { console.error('OAuth callback error:', err) setError(err instanceof Error ? err.message : 'Unknown error') @@ -118,25 +112,13 @@ const OAuthCallback: React.FC = ({ provider }) => {
- {window.opener && ( - - )}
)} diff --git a/examples/chat-ui/src/hooks/useStreamResponse.ts b/examples/chat-ui/src/hooks/useStreamResponse.ts index dbfdec0..f8e9b6b 100644 --- a/examples/chat-ui/src/hooks/useStreamResponse.ts +++ b/examples/chat-ui/src/hooks/useStreamResponse.ts @@ -90,7 +90,7 @@ export const useStreamResponse = ({ switch (model.provider.id) { case 'groq': { const apiKey = authHeaders.Authorization?.replace('Bearer ', '') - const groqProvider = createGroq({ apiKey }) + const groqProvider = createGroq({ apiKey, baseURL: model.provider.baseUrl }) baseModel = groqProvider(model.modelId) break } diff --git a/examples/chat-ui/src/types/models.ts b/examples/chat-ui/src/types/models.ts index bfcbd10..937476d 100644 --- a/examples/chat-ui/src/types/models.ts +++ b/examples/chat-ui/src/types/models.ts @@ -61,10 +61,19 @@ export interface Model { } export const providers: Record = { + // groq: { + // id: 'groq', + // name: 'Groq', + // baseUrl: 'https://api.groq.com/openai/v1', + // logo: '🚀', + // documentationUrl: 'https://console.groq.com/docs', + // apiKeyHeader: 'Authorization', + // authType: 'apiKey', + // }, groq: { id: 'groq', name: 'Groq', - baseUrl: 'https://api.groq.com/openai/v1', + baseUrl: 'http://localhost:8000/api/openai/v1', logo: '🚀', documentationUrl: 'https://console.groq.com/docs', apiKeyHeader: 'Authorization', From 255711ab84cc9b8a50e36a54821f15971e32f04d Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Fri, 11 Jul 2025 21:27:04 +1000 Subject: [PATCH 06/10] The old oauth callback got clobbered, try to restore it --- examples/chat-ui/src/App.tsx | 8 ++++---- .../components/{OAuthCallback.tsx => PkceCallback.tsx} | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) rename examples/chat-ui/src/components/{OAuthCallback.tsx => PkceCallback.tsx} (98%) diff --git a/examples/chat-ui/src/App.tsx b/examples/chat-ui/src/App.tsx index 90b40c4..4c56287 100644 --- a/examples/chat-ui/src/App.tsx +++ b/examples/chat-ui/src/App.tsx @@ -1,14 +1,14 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' import ChatApp from './components/ChatApp' -import OAuthCallback from './components/OAuthCallback' +import PkceCallback from './components/PkceCallback.tsx' function App() { return ( - } /> - } /> - } /> + } /> + } /> + } /> } /> diff --git a/examples/chat-ui/src/components/OAuthCallback.tsx b/examples/chat-ui/src/components/PkceCallback.tsx similarity index 98% rename from examples/chat-ui/src/components/OAuthCallback.tsx rename to examples/chat-ui/src/components/PkceCallback.tsx index 8e0e6eb..0502ef3 100644 --- a/examples/chat-ui/src/components/OAuthCallback.tsx +++ b/examples/chat-ui/src/components/PkceCallback.tsx @@ -7,7 +7,7 @@ interface OAuthCallbackProps { provider: SupportedProvider } -const OAuthCallback: React.FC = ({ provider }) => { +const PkceCallback: React.FC = ({ provider }) => { const [searchParams] = useSearchParams() const [status, setStatus] = useState<'loading' | 'success' | 'error'>('loading') const [error, setError] = useState(null) @@ -150,4 +150,4 @@ const OAuthCallback: React.FC = ({ provider }) => { ) } -export default OAuthCallback +export default PkceCallback From a37724e80b2d29931e1deab77301bcea8ab07331 Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Fri, 11 Jul 2025 21:34:41 +1000 Subject: [PATCH 07/10] Restored, but still buggy --- examples/chat-ui/src/App.tsx | 3 ++- .../chat-ui/src/components/OAuthCallback.tsx | 22 +++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 examples/chat-ui/src/components/OAuthCallback.tsx diff --git a/examples/chat-ui/src/App.tsx b/examples/chat-ui/src/App.tsx index 4c56287..59c2878 100644 --- a/examples/chat-ui/src/App.tsx +++ b/examples/chat-ui/src/App.tsx @@ -1,6 +1,7 @@ import { BrowserRouter as Router, Routes, Route } from 'react-router-dom' import ChatApp from './components/ChatApp' import PkceCallback from './components/PkceCallback.tsx' +import { OAuthCallback } from './components/OAuthCallback.tsx' function App() { return ( @@ -8,7 +9,7 @@ function App() { } /> } /> - } /> + } /> } />
diff --git a/examples/chat-ui/src/components/OAuthCallback.tsx b/examples/chat-ui/src/components/OAuthCallback.tsx new file mode 100644 index 0000000..d6f57fa --- /dev/null +++ b/examples/chat-ui/src/components/OAuthCallback.tsx @@ -0,0 +1,22 @@ +import { useEffect } from 'react' +import { onMcpAuthorization } from 'use-mcp' + +export function OAuthCallback() { + useEffect(() => { + onMcpAuthorization() + }, []) + + return ( +
+
+

Authenticating...

+

Please wait while we complete your authentication.

+

This window should close automatically.

+ +
+
+
+
+
+ ) +} From 25a3bdc8d21a6354dbf946a86d716a09fee9806c Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Wed, 16 Jul 2025 22:03:23 +1000 Subject: [PATCH 08/10] updated data --- examples/chat-ui/src/data/models.json | 1876 ++++++++++++++++++++----- 1 file changed, 1540 insertions(+), 336 deletions(-) diff --git a/examples/chat-ui/src/data/models.json b/examples/chat-ui/src/data/models.json index d40234c..e1ff4f7 100644 --- a/examples/chat-ui/src/data/models.json +++ b/examples/chat-ui/src/data/models.json @@ -1,86 +1,86 @@ { "anthropic": { - "claude-3-haiku-20240307": { - "id": "claude-3-haiku-20240307", - "name": "Claude Haiku 3", + "claude-3-5-haiku-20241022": { + "id": "claude-3-5-haiku-20241022", + "name": "Claude Haiku 3.5", "attachment": true, "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2023-08-31", - "release_date": "2024-03-13", - "last_updated": "2024-03-13", + "knowledge": "2024-07-31", + "release_date": "2024-10-22", + "last_updated": "2024-10-22", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 0.25, - "output": 1.25, - "cache_read": 0.03, - "cache_write": 0.3 + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 }, "limit": { "context": 200000, - "output": 4096 + "output": 8192 } }, - "claude-3-opus-20240229": { - "id": "claude-3-opus-20240229", - "name": "Claude Opus 3", + "claude-3-5-sonnet-20241022": { + "id": "claude-3-5-sonnet-20241022", + "name": "Claude Sonnet 3.5 v2", "attachment": true, "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2023-08-31", - "release_date": "2024-02-29", - "last_updated": "2024-02-29", + "knowledge": "2024-04-30", + "release_date": "2024-10-22", + "last_updated": "2024-10-22", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 15, - "output": 75, - "cache_read": 1.5, - "cache_write": 18.75 + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 }, "limit": { "context": 200000, - "output": 4096 + "output": 8192 } }, - "claude-3-5-haiku-20241022": { - "id": "claude-3-5-haiku-20241022", - "name": "Claude Haiku 3.5", + "claude-sonnet-4-20250514": { + "id": "claude-sonnet-4-20250514", + "name": "Claude Sonnet 4", "attachment": true, - "reasoning": false, + "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2024-07-31", - "release_date": "2024-10-22", - "last_updated": "2024-10-22", + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 0.8, - "output": 4, - "cache_read": 0.08, - "cache_write": 1 + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 }, "limit": { "context": 200000, - "output": 8192 + "output": 64000 } }, - "claude-sonnet-4-20250514": { - "id": "claude-sonnet-4-20250514", - "name": "Claude Sonnet 4", + "claude-opus-4-20250514": { + "id": "claude-opus-4-20250514", + "name": "Claude Opus 4", "attachment": true, "reasoning": true, "temperature": true, @@ -94,36 +94,36 @@ }, "open_weights": false, "cost": { - "input": 3, - "output": 15, - "cache_read": 0.3, - "cache_write": 3.75 + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 }, "limit": { "context": 200000, - "output": 64000 + "output": 32000 } }, - "claude-3-sonnet-20240229": { - "id": "claude-3-sonnet-20240229", - "name": "Claude Sonnet 3", + "claude-3-opus-20240229": { + "id": "claude-3-opus-20240229", + "name": "Claude Opus 3", "attachment": true, "reasoning": false, "temperature": true, "tool_call": true, "knowledge": "2023-08-31", - "release_date": "2024-03-04", - "last_updated": "2024-03-04", + "release_date": "2024-02-29", + "last_updated": "2024-02-29", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 3, - "output": 15, - "cache_read": 0.3, - "cache_write": 0.3 + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 }, "limit": { "context": 200000, @@ -156,42 +156,42 @@ "output": 8192 } }, - "claude-opus-4-20250514": { - "id": "claude-opus-4-20250514", - "name": "Claude Opus 4", + "claude-3-haiku-20240307": { + "id": "claude-3-haiku-20240307", + "name": "Claude Haiku 3", "attachment": true, - "reasoning": true, + "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2025-03-31", - "release_date": "2025-05-22", - "last_updated": "2025-05-22", + "knowledge": "2023-08-31", + "release_date": "2024-03-13", + "last_updated": "2024-03-13", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 15, - "output": 75, - "cache_read": 1.5, - "cache_write": 18.75 + "input": 0.25, + "output": 1.25, + "cache_read": 0.03, + "cache_write": 0.3 }, "limit": { "context": 200000, - "output": 32000 + "output": 4096 } }, - "claude-3-5-sonnet-20241022": { - "id": "claude-3-5-sonnet-20241022", - "name": "Claude Sonnet 3.5 v2", + "claude-3-7-sonnet-20250219": { + "id": "claude-3-7-sonnet-20250219", + "name": "Claude Sonnet 3.7", "attachment": true, - "reasoning": false, + "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2024-04-30", - "release_date": "2024-10-22", - "last_updated": "2024-10-22", + "knowledge": "2024-10-31", + "release_date": "2025-02-19", + "last_updated": "2025-02-19", "modalities": { "input": ["text", "image"], "output": ["text"] @@ -205,19 +205,19 @@ }, "limit": { "context": 200000, - "output": 8192 + "output": 64000 } }, - "claude-3-7-sonnet-20250219": { - "id": "claude-3-7-sonnet-20250219", - "name": "Claude Sonnet 3.7", + "claude-3-sonnet-20240229": { + "id": "claude-3-sonnet-20240229", + "name": "Claude Sonnet 3", "attachment": true, - "reasoning": true, + "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2024-10-31", - "release_date": "2025-02-19", - "last_updated": "2025-02-19", + "knowledge": "2023-08-31", + "release_date": "2024-03-04", + "last_updated": "2024-03-04", "modalities": { "input": ["text", "image"], "output": ["text"] @@ -227,37 +227,37 @@ "input": 3, "output": 15, "cache_read": 0.3, - "cache_write": 3.75 + "cache_write": 0.3 }, "limit": { "context": 200000, - "output": 64000 + "output": 4096 } } }, "groq": { - "llama-3.3-70b-versatile": { - "id": "llama-3.3-70b-versatile", - "name": "Llama 3.3 70B Versatile", + "qwen-qwq-32b": { + "id": "qwen-qwq-32b", + "name": "Qwen QwQ 32B", "attachment": false, - "reasoning": false, + "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2023-12", - "release_date": "2024-12-06", - "last_updated": "2024-12-06", + "knowledge": "2024-09", + "release_date": "2024-11-27", + "last_updated": "2024-11-27", "modalities": { "input": ["text"], "output": ["text"] }, "open_weights": true, "cost": { - "input": 0.59, - "output": 0.79 + "input": 0.29, + "output": 0.39 }, "limit": { "context": 131072, - "output": 32768 + "output": 16384 } }, "llama-3.1-8b-instant": { @@ -331,33 +331,33 @@ "output": 8192 } }, - "llama3-8b-8192": { - "id": "llama3-8b-8192", - "name": "Llama 3 8B", + "mistral-saba-24b": { + "id": "mistral-saba-24b", + "name": "Mistral Saba 24B", "attachment": false, "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2023-03", - "release_date": "2024-04-18", - "last_updated": "2024-04-18", + "knowledge": "2024-08", + "release_date": "2025-02-06", + "last_updated": "2025-02-06", "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": true, + "open_weights": false, "cost": { - "input": 0.05, - "output": 0.08 + "input": 0.79, + "output": 0.79 }, "limit": { - "context": 8192, - "output": 8192 + "context": 32768, + "output": 32768 } }, - "llama3-70b-8192": { - "id": "llama3-70b-8192", - "name": "Llama 3 70B", + "llama3-8b-8192": { + "id": "llama3-8b-8192", + "name": "Llama 3 8B", "attachment": false, "reasoning": false, "temperature": true, @@ -371,8 +371,8 @@ }, "open_weights": true, "cost": { - "input": 0.59, - "output": 0.79 + "input": 0.05, + "output": 0.08 }, "limit": { "context": 8192, @@ -403,72 +403,72 @@ "output": 8192 } }, - "qwen-qwq-32b": { - "id": "qwen-qwq-32b", - "name": "Qwen QwQ 32B", + "llama-3.3-70b-versatile": { + "id": "llama-3.3-70b-versatile", + "name": "Llama 3.3 70B Versatile", "attachment": false, - "reasoning": true, + "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2024-09", - "release_date": "2024-11-27", - "last_updated": "2024-11-27", + "knowledge": "2023-12", + "release_date": "2024-12-06", + "last_updated": "2024-12-06", "modalities": { "input": ["text"], "output": ["text"] }, "open_weights": true, "cost": { - "input": 0.29, - "output": 0.39 + "input": 0.59, + "output": 0.79 }, "limit": { "context": 131072, - "output": 16384 + "output": 32768 } }, - "mistral-saba-24b": { - "id": "mistral-saba-24b", - "name": "Mistral Saba 24B", + "llama3-70b-8192": { + "id": "llama3-70b-8192", + "name": "Llama 3 70B", "attachment": false, "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2024-08", - "release_date": "2025-02-06", - "last_updated": "2025-02-06", + "knowledge": "2023-03", + "release_date": "2024-04-18", + "last_updated": "2024-04-18", "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 0.79, + "input": 0.59, "output": 0.79 }, "limit": { - "context": 32768, - "output": 32768 + "context": 8192, + "output": 8192 } }, - "qwen/qwen3-32b": { - "id": "qwen/qwen3-32b", - "name": "Qwen3 32B", + "moonshotai/kimi-k2-instruct": { + "id": "moonshotai/kimi-k2-instruct", + "name": "Kimi K2 Instruct", "attachment": false, - "reasoning": true, + "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2024-11-08", - "release_date": "2024-12-23", - "last_updated": "2024-12-23", + "knowledge": "2024-10", + "release_date": "2025-07-14", + "last_updated": "2025-07-14", "modalities": { "input": ["text"], "output": ["text"] }, "open_weights": true, "cost": { - "input": 0.29, - "output": 0.59 + "input": 1, + "output": 3 }, "limit": { "context": 131072, @@ -545,6 +545,30 @@ "context": 131072, "output": 128 } + }, + "qwen/qwen3-32b": { + "id": "qwen/qwen3-32b", + "name": "Qwen3 32B", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-11-08", + "release_date": "2024-12-23", + "last_updated": "2024-12-23", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0.29, + "output": 0.59 + }, + "limit": { + "context": 131072, + "output": 16384 + } } }, "openrouter": { @@ -573,29 +597,29 @@ "output": 32768 } }, - "openai/gpt-4.1": { - "id": "openai/gpt-4.1", - "name": "GPT-4.1", + "openai/o4-mini": { + "id": "openai/o4-mini", + "name": "o4 Mini", "attachment": true, - "reasoning": false, + "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2024-04", - "release_date": "2025-04-14", - "last_updated": "2025-04-14", + "knowledge": "2024-06", + "release_date": "2025-04-16", + "last_updated": "2025-04-16", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 2, - "output": 8, - "cache_read": 0.5 + "input": 1.1, + "output": 4.4, + "cache_read": 0.28 }, "limit": { - "context": 1047576, - "output": 32768 + "context": 200000, + "output": 100000 } }, "openai/gpt-4o-mini": { @@ -623,362 +647,1542 @@ "output": 16384 } }, - "openai/o4-mini": { - "id": "openai/o4-mini", - "name": "o4 Mini", + "openai/gpt-4.1": { + "id": "openai/gpt-4.1", + "name": "GPT-4.1", "attachment": true, - "reasoning": true, + "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2024-06", - "release_date": "2025-04-16", - "last_updated": "2025-04-16", + "knowledge": "2024-04", + "release_date": "2025-04-14", + "last_updated": "2025-04-14", "modalities": { "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 1.1, - "output": 4.4, - "cache_read": 0.28 + "input": 2, + "output": 8, + "cache_read": 0.5 }, "limit": { - "context": 200000, - "output": 100000 + "context": 1047576, + "output": 32768 } }, - "anthropic/claude-4-sonnet-20250522": { - "id": "anthropic/claude-4-sonnet-20250522", - "name": "Claude Sonnet 4", - "attachment": true, + "sarvamai/sarvam-m:free": { + "id": "sarvamai/sarvam-m:free", + "name": "Sarvam-M (free)", + "attachment": false, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2025-03-31", - "release_date": "2025-05-22", - "last_updated": "2025-05-22", + "knowledge": "2025-05", + "release_date": "2025-05-25", + "last_updated": "2025-05-25", "modalities": { - "input": ["text", "image"], + "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 3, - "output": 15, - "cache_read": 0.3, - "cache_write": 3.75 + "input": 0, + "output": 0 }, "limit": { - "context": 200000, - "output": 64000 + "context": 32768, + "output": 32768 } }, - "anthropic/claude-3.7-sonnet": { - "id": "anthropic/claude-3.7-sonnet", - "name": "Claude Sonnet 3.7", - "attachment": true, + "deepseek/deepseek-r1-distill-qwen-14b": { + "id": "deepseek/deepseek-r1-distill-qwen-14b", + "name": "DeepSeek R1 Distill Qwen 14B", + "attachment": false, "reasoning": true, "temperature": true, - "tool_call": true, - "knowledge": "2024-01", - "release_date": "2025-02-19", - "last_updated": "2025-02-19", + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2025-01-29", + "last_updated": "2025-01-29", "modalities": { - "input": ["text", "image"], + "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 15, - "output": 75, - "cache_read": 1.5, - "cache_write": 18.75 + "input": 0, + "output": 0 }, "limit": { - "context": 200000, - "output": 128000 + "context": 64000, + "output": 8192 } }, - "anthropic/claude-opus-4": { - "id": "anthropic/claude-opus-4", - "name": "Claude Opus 4", - "attachment": true, + "deepseek/deepseek-r1:free": { + "id": "deepseek/deepseek-r1:free", + "name": "R1 (free)", + "attachment": false, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2025-03-31", - "release_date": "2025-05-22", - "last_updated": "2025-05-22", + "knowledge": "2025-01", + "release_date": "2025-01-20", + "last_updated": "2025-01-20", "modalities": { - "input": ["text", "image"], + "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 15, - "output": 75, - "cache_read": 1.5, - "cache_write": 18.75 + "input": 0, + "output": 0 }, "limit": { - "context": 200000, - "output": 32000 + "context": 163840, + "output": 163840 } }, - "x-ai/grok-3-mini": { - "id": "x-ai/grok-3-mini", - "name": "Grok 3 Mini", + "deepseek/deepseek-r1-distill-llama-70b": { + "id": "deepseek/deepseek-r1-distill-llama-70b", + "name": "DeepSeek R1 Distill Llama 70B", "attachment": false, "reasoning": true, "temperature": true, - "tool_call": true, - "knowledge": "2024-11", - "release_date": "2025-02-17", - "last_updated": "2025-02-17", + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2025-01-23", + "last_updated": "2025-01-23", "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 0.3, - "output": 0.5, - "cache_read": 0.075, - "cache_write": 0.5 + "input": 0, + "output": 0 }, "limit": { - "context": 131072, + "context": 8192, "output": 8192 } }, - "x-ai/grok-3-mini-beta": { - "id": "x-ai/grok-3-mini-beta", - "name": "Grok 3 Mini Beta", + "deepseek/deepseek-r1-0528:free": { + "id": "deepseek/deepseek-r1-0528:free", + "name": "R1 0528 (free)", "attachment": false, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2024-11", - "release_date": "2025-02-17", - "last_updated": "2025-02-17", + "knowledge": "2025-05", + "release_date": "2025-05-28", + "last_updated": "2025-05-28", "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 0.3, - "output": 0.5, - "cache_read": 0.075, - "cache_write": 0.5 + "input": 0, + "output": 0 }, "limit": { - "context": 131072, - "output": 8192 + "context": 163840, + "output": 163840 } }, - "x-ai/grok-3": { - "id": "x-ai/grok-3", - "name": "Grok 3", + "deepseek/deepseek-v3-base:free": { + "id": "deepseek/deepseek-v3-base:free", + "name": "DeepSeek V3 Base (free)", "attachment": false, "reasoning": false, "temperature": true, - "tool_call": true, - "knowledge": "2024-11", - "release_date": "2025-02-17", - "last_updated": "2025-02-17", + "tool_call": false, + "knowledge": "2025-03", + "release_date": "2025-03-29", + "last_updated": "2025-03-29", "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 3, - "output": 15, - "cache_read": 0.75, - "cache_write": 15 + "input": 0, + "output": 0 }, "limit": { - "context": 131072, - "output": 8192 + "context": 163840, + "output": 163840 } }, - "x-ai/grok-3-beta": { - "id": "x-ai/grok-3-beta", - "name": "Grok 3 Beta", + "deepseek/deepseek-chat-v3-0324": { + "id": "deepseek/deepseek-chat-v3-0324", + "name": "DeepSeek V3 0324", "attachment": false, "reasoning": false, "temperature": true, - "tool_call": true, - "knowledge": "2024-11", - "release_date": "2025-02-17", - "last_updated": "2025-02-17", + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2025-03-24", + "last_updated": "2025-03-24", "modalities": { "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 3, - "output": 15, - "cache_read": 0.75, - "cache_write": 15 + "input": 0, + "output": 0 }, "limit": { - "context": 131072, + "context": 16384, "output": 8192 } }, - "google/gemini-2.5-pro-preview-05-06": { - "id": "google/gemini-2.5-pro-preview-05-06", - "name": "Gemini 2.5 Pro Preview 05-06", - "attachment": true, + "deepseek/deepseek-r1-0528-qwen3-8b:free": { + "id": "deepseek/deepseek-r1-0528-qwen3-8b:free", + "name": "Deepseek R1 0528 Qwen3 8B (free)", + "attachment": false, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2025-01", - "release_date": "2025-05-06", - "last_updated": "2025-05-06", + "knowledge": "2025-05", + "release_date": "2025-05-29", + "last_updated": "2025-05-29", "modalities": { - "input": ["text", "image", "audio", "video", "pdf"], + "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 1.25, - "output": 10, - "cache_read": 0.31 + "input": 0, + "output": 0 }, "limit": { - "context": 1048576, - "output": 65536 + "context": 131072, + "output": 131072 } }, - "google/gemini-2.5-pro-preview-06-05": { - "id": "google/gemini-2.5-pro-preview-06-05", - "name": "Gemini 2.5 Pro Preview 06-05", - "attachment": true, - "reasoning": true, + "cognitivecomputations/dolphin3.0-mistral-24b": { + "id": "cognitivecomputations/dolphin3.0-mistral-24b", + "name": "Dolphin3.0 Mistral 24B", + "attachment": false, + "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2025-01", - "release_date": "2025-06-05", - "last_updated": "2025-06-05", + "knowledge": "2024-10", + "release_date": "2025-02-13", + "last_updated": "2025-02-13", "modalities": { - "input": ["text", "image", "audio", "video", "pdf"], + "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 1.25, - "output": 10, - "cache_read": 0.31 + "input": 0, + "output": 0 }, "limit": { - "context": 1048576, - "output": 65536 + "context": 32768, + "output": 8192 } }, - "google/gemini-2.5-pro": { - "id": "google/gemini-2.5-pro", - "name": "Gemini 2.5 Pro", - "attachment": true, + "cognitivecomputations/dolphin3.0-r1-mistral-24b": { + "id": "cognitivecomputations/dolphin3.0-r1-mistral-24b", + "name": "Dolphin3.0 R1 Mistral 24B", + "attachment": false, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2025-01", - "release_date": "2025-03-20", - "last_updated": "2025-06-05", + "knowledge": "2024-10", + "release_date": "2025-02-13", + "last_updated": "2025-02-13", "modalities": { - "input": ["text", "image", "audio", "video", "pdf"], + "input": ["text"], "output": ["text"] }, - "open_weights": false, + "open_weights": true, "cost": { - "input": 1.25, - "output": 10, - "cache_read": 0.31 + "input": 0, + "output": 0 }, "limit": { - "context": 1048576, - "output": 65536 + "context": 32768, + "output": 8192 } }, - "google/gemini-2.5-flash-preview-04-17": { - "id": "google/gemini-2.5-flash-preview-04-17", - "name": "Gemini 2.5 Flash Preview 04-17", + "anthropic/claude-4-sonnet-20250522": { + "id": "anthropic/claude-4-sonnet-20250522", + "name": "Claude Sonnet 4", "attachment": true, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2025-01", - "release_date": "2025-04-17", - "last_updated": "2025-04-17", + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", "modalities": { - "input": ["text", "image", "audio", "video", "pdf"], + "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 0.15, - "output": 0.6, - "cache_read": 0.0375 + "input": 3, + "output": 15, + "cache_read": 0.3, + "cache_write": 3.75 }, "limit": { - "context": 1048576, - "output": 65536 + "context": 200000, + "output": 64000 } }, - "google/gemini-2.5-flash-preview-05-20": { - "id": "google/gemini-2.5-flash-preview-05-20", - "name": "Gemini 2.5 Flash Preview 05-20", + "anthropic/claude-3.5-haiku": { + "id": "anthropic/claude-3.5-haiku", + "name": "Claude Haiku 3.5", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-07-31", + "release_date": "2024-10-22", + "last_updated": "2024-10-22", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0.8, + "output": 4, + "cache_read": 0.08, + "cache_write": 1 + }, + "limit": { + "context": 200000, + "output": 8192 + } + }, + "anthropic/claude-3.7-sonnet": { + "id": "anthropic/claude-3.7-sonnet", + "name": "Claude Sonnet 3.7", "attachment": true, "reasoning": true, "temperature": true, "tool_call": true, - "knowledge": "2025-01", - "release_date": "2025-05-20", - "last_updated": "2025-05-20", + "knowledge": "2024-01", + "release_date": "2025-02-19", + "last_updated": "2025-02-19", "modalities": { - "input": ["text", "image", "audio", "video", "pdf"], + "input": ["text", "image"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 0.15, - "output": 0.6, - "cache_read": 0.0375 + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 }, "limit": { - "context": 1048576, - "output": 65536 + "context": 200000, + "output": 128000 } }, - "google/gemini-2.0-flash-001": { - "id": "google/gemini-2.0-flash-001", - "name": "Gemini 2.0 Flash", + "anthropic/claude-opus-4": { + "id": "anthropic/claude-opus-4", + "name": "Claude Opus 4", "attachment": true, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-03-31", + "release_date": "2025-05-22", + "last_updated": "2025-05-22", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 15, + "output": 75, + "cache_read": 1.5, + "cache_write": 18.75 + }, + "limit": { + "context": 200000, + "output": 32000 + } + }, + "featherless/qwerky-72b": { + "id": "featherless/qwerky-72b", + "name": "Qwerky 72B", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2025-03-20", + "last_updated": "2025-03-20", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "rekaai/reka-flash-3": { + "id": "rekaai/reka-flash-3", + "name": "Reka Flash 3", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2024-10", + "release_date": "2025-03-12", + "last_updated": "2025-03-12", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "moonshotai/kimi-dev-72b:free": { + "id": "moonshotai/kimi-dev-72b:free", + "name": "Kimi Dev 72b (free)", + "attachment": false, "reasoning": false, "temperature": true, "tool_call": true, - "knowledge": "2024-06", - "release_date": "2024-12-11", - "last_updated": "2024-12-11", + "knowledge": "2025-06", + "release_date": "2025-06-16", + "last_updated": "2025-06-16", "modalities": { - "input": ["text", "image", "audio", "video", "pdf"], + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "moonshotai/kimi-k2": { + "id": "moonshotai/kimi-k2", + "name": "Kimi K2", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-10", + "release_date": "2025-07-11", + "last_updated": "2025-07-11", + "modalities": { + "input": ["text"], "output": ["text"] }, "open_weights": false, "cost": { - "input": 0.1, - "output": 0.4, - "cache_read": 0.025 + "input": 0.57, + "output": 2.3 }, "limit": { - "context": 1048576, + "context": 131072, + "output": 32768 + } + }, + "x-ai/grok-3-mini": { + "id": "x-ai/grok-3-mini", + "name": "Grok 3 Mini", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075, + "cache_write": 0.5 + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "x-ai/grok-3": { + "id": "x-ai/grok-3", + "name": "Grok 3", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15 + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "x-ai/grok-3-beta": { + "id": "x-ai/grok-3-beta", + "name": "Grok 3 Beta", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15 + }, + "limit": { + "context": 131072, "output": 8192 } + }, + "x-ai/grok-4": { + "id": "x-ai/grok-4", + "name": "Grok 4", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-07", + "release_date": "2025-07-09", + "last_updated": "2025-07-09", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 3, + "output": 15, + "cache_read": 0.75, + "cache_write": 15 + }, + "limit": { + "context": 256000, + "output": 64000 + } + }, + "x-ai/grok-3-mini-beta": { + "id": "x-ai/grok-3-mini-beta", + "name": "Grok 3 Mini Beta", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2024-11", + "release_date": "2025-02-17", + "last_updated": "2025-02-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0.3, + "output": 0.5, + "cache_read": 0.075, + "cache_write": 0.5 + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "microsoft/mai-ds-r1:free": { + "id": "microsoft/mai-ds-r1:free", + "name": "MAI DS R1 (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-21", + "last_updated": "2025-04-21", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "openrouter/cypher-alpha:free": { + "id": "openrouter/cypher-alpha:free", + "name": "Cypher Alpha (free)", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-07", + "release_date": "2025-07-01", + "last_updated": "2025-07-01", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 1000000, + "output": 1000000 + } + }, + "meta-llama/llama-3.3-70b-instruct:free": { + "id": "meta-llama/llama-3.3-70b-instruct:free", + "name": "Llama 3.3 70B Instruct (free)", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-12", + "release_date": "2024-12-06", + "last_updated": "2024-12-06", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 65536, + "output": 65536 + } + }, + "meta-llama/llama-3.2-11b-vision-instruct": { + "id": "meta-llama/llama-3.2-11b-vision-instruct", + "name": "Llama 3.2 11B Vision Instruct", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": false, + "knowledge": "2023-12", + "release_date": "2024-09-25", + "last_updated": "2024-09-25", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "meta-llama/llama-4-scout:free": { + "id": "meta-llama/llama-4-scout:free", + "name": "Llama 4 Scout (free)", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-08", + "release_date": "2025-04-05", + "last_updated": "2025-04-05", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 64000, + "output": 64000 + } + }, + "google/gemma-3n-e4b-it:free": { + "id": "google/gemma-3n-e4b-it:free", + "name": "Gemma 3n 4B (free)", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-05", + "release_date": "2025-05-20", + "last_updated": "2025-05-20", + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "google/gemini-2.5-flash-preview-05-20": { + "id": "google/gemini-2.5-flash-preview-05-20", + "name": "Gemini 2.5 Flash Preview 05-20", + "attachment": true, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-01", + "release_date": "2025-05-20", + "last_updated": "2025-05-20", + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.0375 + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemma-3-27b-it": { + "id": "google/gemma-3-27b-it", + "name": "Gemma 3 27B IT", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-10", + "release_date": "2025-03-12", + "last_updated": "2025-03-12", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 96000, + "output": 8192 + } + }, + "google/gemini-2.5-pro-preview-06-05": { + "id": "google/gemini-2.5-pro-preview-06-05", + "name": "Gemini 2.5 Pro Preview 06-05", + "attachment": true, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-01", + "release_date": "2025-06-05", + "last_updated": "2025-06-05", + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.5-flash-preview-04-17": { + "id": "google/gemini-2.5-flash-preview-04-17", + "name": "Gemini 2.5 Flash Preview 04-17", + "attachment": true, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-01", + "release_date": "2025-04-17", + "last_updated": "2025-04-17", + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0.15, + "output": 0.6, + "cache_read": 0.0375 + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.0-flash-exp:free": { + "id": "google/gemini-2.0-flash-exp:free", + "name": "Gemini 2.0 Flash Experimental (free)", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-12", + "release_date": "2024-12-11", + "last_updated": "2024-12-11", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 1048576, + "output": 1048576 + } + }, + "google/gemma-2-9b-it:free": { + "id": "google/gemma-2-9b-it:free", + "name": "Gemma 2 9B (free)", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-06", + "release_date": "2024-06-28", + "last_updated": "2024-06-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "google/gemma-3-12b-it": { + "id": "google/gemma-3-12b-it", + "name": "Gemma 3 12B IT", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-10", + "release_date": "2025-03-13", + "last_updated": "2025-03-13", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 96000, + "output": 8192 + } + }, + "google/gemini-2.5-pro-preview-05-06": { + "id": "google/gemini-2.5-pro-preview-05-06", + "name": "Gemini 2.5 Pro Preview 05-06", + "attachment": true, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-01", + "release_date": "2025-05-06", + "last_updated": "2025-05-06", + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "google/gemini-2.0-flash-001": { + "id": "google/gemini-2.0-flash-001", + "name": "Gemini 2.0 Flash", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-06", + "release_date": "2024-12-11", + "last_updated": "2024-12-11", + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 0.1, + "output": 0.4, + "cache_read": 0.025 + }, + "limit": { + "context": 1048576, + "output": 8192 + } + }, + "google/gemma-3n-e4b-it": { + "id": "google/gemma-3n-e4b-it", + "name": "Gemma 3n E4B IT", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2025-05-20", + "last_updated": "2025-05-20", + "modalities": { + "input": ["text", "image", "audio"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "google/gemini-2.5-pro": { + "id": "google/gemini-2.5-pro", + "name": "Gemini 2.5 Pro", + "attachment": true, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-01", + "release_date": "2025-03-20", + "last_updated": "2025-06-05", + "modalities": { + "input": ["text", "image", "audio", "video", "pdf"], + "output": ["text"] + }, + "open_weights": false, + "cost": { + "input": 1.25, + "output": 10, + "cache_read": 0.31 + }, + "limit": { + "context": 1048576, + "output": 65536 + } + }, + "thudm/glm-z1-32b:free": { + "id": "thudm/glm-z1-32b:free", + "name": "GLM Z1 32B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-17", + "last_updated": "2025-04-17", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mistralai/mistral-small-3.1-24b-instruct": { + "id": "mistralai/mistral-small-3.1-24b-instruct", + "name": "Mistral Small 3.1 24B Instruct", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-10", + "release_date": "2025-03-17", + "last_updated": "2025-03-17", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 128000, + "output": 8192 + } + }, + "mistralai/devstral-small-2507": { + "id": "mistralai/devstral-small-2507", + "name": "Devstral Small 1.1", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-05", + "release_date": "2025-07-10", + "last_updated": "2025-07-10", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0.1, + "output": 0.3 + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/mistral-small-3.2-24b-instruct": { + "id": "mistralai/mistral-small-3.2-24b-instruct", + "name": "Mistral Small 3.2 24B Instruct", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-10", + "release_date": "2025-06-20", + "last_updated": "2025-06-20", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 96000, + "output": 8192 + } + }, + "mistralai/mistral-7b-instruct:free": { + "id": "mistralai/mistral-7b-instruct:free", + "name": "Mistral 7B Instruct (free)", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-05", + "release_date": "2024-05-27", + "last_updated": "2024-05-27", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mistralai/devstral-medium-2507": { + "id": "mistralai/devstral-medium-2507", + "name": "Devstral Medium", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-05", + "release_date": "2025-07-10", + "last_updated": "2025-07-10", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0.4, + "output": 2 + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/mistral-small-3.2-24b-instruct:free": { + "id": "mistralai/mistral-small-3.2-24b-instruct:free", + "name": "Mistral Small 3.2 24B (free)", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-06", + "release_date": "2025-06-20", + "last_updated": "2025-06-20", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 96000, + "output": 96000 + } + }, + "mistralai/devstral-small-2505:free": { + "id": "mistralai/devstral-small-2505:free", + "name": "Devstral Small 2505 (free)", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-05", + "release_date": "2025-05-21", + "last_updated": "2025-05-21", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "mistralai/mistral-nemo:free": { + "id": "mistralai/mistral-nemo:free", + "name": "Mistral Nemo (free)", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2024-07", + "release_date": "2024-07-19", + "last_updated": "2024-07-19", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "mistralai/devstral-small-2505": { + "id": "mistralai/devstral-small-2505", + "name": "Devstral Small", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-05", + "release_date": "2025-05-07", + "last_updated": "2025-05-07", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0.06, + "output": 0.12 + }, + "limit": { + "context": 128000, + "output": 128000 + } + }, + "nousresearch/deephermes-3-llama-3-8b-preview": { + "id": "nousresearch/deephermes-3-llama-3-8b-preview", + "name": "DeepHermes 3 Llama 3 8B Preview", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2024-04", + "release_date": "2025-02-28", + "last_updated": "2025-02-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 131072, + "output": 8192 + } + }, + "tngtech/deepseek-r1t2-chimera:free": { + "id": "tngtech/deepseek-r1t2-chimera:free", + "name": "DeepSeek R1T2 Chimera (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-07", + "release_date": "2025-07-08", + "last_updated": "2025-07-08", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 163840, + "output": 163840 + } + }, + "qwen/qwen3-30b-a3b:free": { + "id": "qwen/qwen3-30b-a3b:free", + "name": "Qwen3 30B A3B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-28", + "last_updated": "2025-04-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "qwen/qwen3-235b-a22b:free": { + "id": "qwen/qwen3-235b-a22b:free", + "name": "Qwen3 235B A22B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-28", + "last_updated": "2025-04-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 131072, + "output": 131072 + } + }, + "qwen/qwq-32b:free": { + "id": "qwen/qwq-32b:free", + "name": "QwQ 32B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-03", + "release_date": "2025-03-05", + "last_updated": "2025-03-05", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen/qwen-2.5-coder-32b-instruct": { + "id": "qwen/qwen-2.5-coder-32b-instruct", + "name": "Qwen2.5 Coder 32B Instruct", + "attachment": false, + "reasoning": false, + "temperature": true, + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2024-11-11", + "last_updated": "2024-11-11", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen3-8b:free": { + "id": "qwen/qwen3-8b:free", + "name": "Qwen3 8B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-28", + "last_updated": "2025-04-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "qwen/qwen3-14b:free": { + "id": "qwen/qwen3-14b:free", + "name": "Qwen3 14B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-28", + "last_updated": "2025-04-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 40960, + "output": 40960 + } + }, + "qwen/qwen2.5-vl-72b-instruct": { + "id": "qwen/qwen2.5-vl-72b-instruct", + "name": "Qwen2.5 VL 72B Instruct", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": false, + "knowledge": "2024-10", + "release_date": "2025-02-01", + "last_updated": "2025-02-01", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 8192 + } + }, + "qwen/qwen2.5-vl-72b-instruct:free": { + "id": "qwen/qwen2.5-vl-72b-instruct:free", + "name": "Qwen2.5 VL 72B Instruct (free)", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-02", + "release_date": "2025-02-01", + "last_updated": "2025-02-01", + "modalities": { + "input": ["text", "image"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 32768, + "output": 32768 + } + }, + "qwen/qwen2.5-vl-32b-instruct:free": { + "id": "qwen/qwen2.5-vl-32b-instruct:free", + "name": "Qwen2.5 VL 32B Instruct (free)", + "attachment": true, + "reasoning": false, + "temperature": true, + "tool_call": true, + "knowledge": "2025-03", + "release_date": "2025-03-24", + "last_updated": "2025-03-24", + "modalities": { + "input": ["text", "image", "video"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 8192, + "output": 8192 + } + }, + "qwen/qwen3-32b:free": { + "id": "qwen/qwen3-32b:free", + "name": "Qwen3 32B (free)", + "attachment": false, + "reasoning": true, + "temperature": true, + "tool_call": true, + "knowledge": "2025-04", + "release_date": "2025-04-28", + "last_updated": "2025-04-28", + "modalities": { + "input": ["text"], + "output": ["text"] + }, + "open_weights": true, + "cost": { + "input": 0, + "output": 0 + }, + "limit": { + "context": 40960, + "output": 40960 + } } } } From 9d996a3322e0caf873d5f36f863c93192e776e2d Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Wed, 16 Jul 2025 22:04:54 +1000 Subject: [PATCH 09/10] Pruning Groq models --- examples/chat-ui/src/data/models.json | 168 +------------------------- 1 file changed, 1 insertion(+), 167 deletions(-) diff --git a/examples/chat-ui/src/data/models.json b/examples/chat-ui/src/data/models.json index e1ff4f7..40397d9 100644 --- a/examples/chat-ui/src/data/models.json +++ b/examples/chat-ui/src/data/models.json @@ -236,101 +236,6 @@ } }, "groq": { - "qwen-qwq-32b": { - "id": "qwen-qwq-32b", - "name": "Qwen QwQ 32B", - "attachment": false, - "reasoning": true, - "temperature": true, - "tool_call": true, - "knowledge": "2024-09", - "release_date": "2024-11-27", - "last_updated": "2024-11-27", - "modalities": { - "input": ["text"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.29, - "output": 0.39 - }, - "limit": { - "context": 131072, - "output": 16384 - } - }, - "llama-3.1-8b-instant": { - "id": "llama-3.1-8b-instant", - "name": "Llama 3.1 8B Instant", - "attachment": false, - "reasoning": false, - "temperature": true, - "tool_call": true, - "knowledge": "2023-12", - "release_date": "2024-07-23", - "last_updated": "2024-07-23", - "modalities": { - "input": ["text"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.05, - "output": 0.08 - }, - "limit": { - "context": 131072, - "output": 8192 - } - }, - "llama-guard-3-8b": { - "id": "llama-guard-3-8b", - "name": "Llama Guard 3 8B", - "attachment": false, - "reasoning": false, - "temperature": true, - "tool_call": false, - "release_date": "2024-07-23", - "last_updated": "2024-07-23", - "modalities": { - "input": ["text"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.2, - "output": 0.2 - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, - "gemma2-9b-it": { - "id": "gemma2-9b-it", - "name": "Gemma 2 9B", - "attachment": false, - "reasoning": false, - "temperature": true, - "tool_call": true, - "knowledge": "2024-06", - "release_date": "2024-06-27", - "last_updated": "2024-06-27", - "modalities": { - "input": ["text"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.2, - "output": 0.2 - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, "mistral-saba-24b": { "id": "mistral-saba-24b", "name": "Mistral Saba 24B", @@ -355,30 +260,6 @@ "output": 32768 } }, - "llama3-8b-8192": { - "id": "llama3-8b-8192", - "name": "Llama 3 8B", - "attachment": false, - "reasoning": false, - "temperature": true, - "tool_call": true, - "knowledge": "2023-03", - "release_date": "2024-04-18", - "last_updated": "2024-04-18", - "modalities": { - "input": ["text"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.05, - "output": 0.08 - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, "deepseek-r1-distill-llama-70b": { "id": "deepseek-r1-distill-llama-70b", "name": "DeepSeek R1 Distill Llama 70B", @@ -427,30 +308,6 @@ "output": 32768 } }, - "llama3-70b-8192": { - "id": "llama3-70b-8192", - "name": "Llama 3 70B", - "attachment": false, - "reasoning": false, - "temperature": true, - "tool_call": true, - "knowledge": "2023-03", - "release_date": "2024-04-18", - "last_updated": "2024-04-18", - "modalities": { - "input": ["text"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.59, - "output": 0.79 - }, - "limit": { - "context": 8192, - "output": 8192 - } - }, "moonshotai/kimi-k2-instruct": { "id": "moonshotai/kimi-k2-instruct", "name": "Kimi K2 Instruct", @@ -523,34 +380,11 @@ "output": 8192 } }, - "meta-llama/llama-guard-4-12b": { - "id": "meta-llama/llama-guard-4-12b", - "name": "Llama Guard 4 12B", - "attachment": false, - "reasoning": false, - "temperature": true, - "tool_call": false, - "release_date": "2025-04-05", - "last_updated": "2025-04-05", - "modalities": { - "input": ["text", "image"], - "output": ["text"] - }, - "open_weights": true, - "cost": { - "input": 0.2, - "output": 0.2 - }, - "limit": { - "context": 131072, - "output": 128 - } - }, "qwen/qwen3-32b": { "id": "qwen/qwen3-32b", "name": "Qwen3 32B", "attachment": false, - "reasoning": false, + "reasoning": true, "temperature": true, "tool_call": true, "knowledge": "2024-11-08", From d80e9f44af2dbe1d4383c01f8cbc1baa3adf7213 Mon Sep 17 00:00:00 2001 From: Glen Maddern Date: Wed, 16 Jul 2025 22:10:01 +1000 Subject: [PATCH 10/10] deploying --- examples/chat-ui/src/components/ChatApp.tsx | 2 +- examples/chat-ui/src/types/models.ts | 30 ++++++++++----------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/examples/chat-ui/src/components/ChatApp.tsx b/examples/chat-ui/src/components/ChatApp.tsx index bfc0c1f..847ac3e 100644 --- a/examples/chat-ui/src/components/ChatApp.tsx +++ b/examples/chat-ui/src/components/ChatApp.tsx @@ -79,7 +79,7 @@ const ChatApp: React.FC = () => { return false } - let pollInterval: NodeJS.Timeout | null = null + let pollInterval: number | null = null const startPolling = () => { // Capture initial state diff --git a/examples/chat-ui/src/types/models.ts b/examples/chat-ui/src/types/models.ts index 937476d..2e373a6 100644 --- a/examples/chat-ui/src/types/models.ts +++ b/examples/chat-ui/src/types/models.ts @@ -61,28 +61,28 @@ export interface Model { } export const providers: Record = { - // groq: { - // id: 'groq', - // name: 'Groq', - // baseUrl: 'https://api.groq.com/openai/v1', - // logo: '🚀', - // documentationUrl: 'https://console.groq.com/docs', - // apiKeyHeader: 'Authorization', - // authType: 'apiKey', - // }, groq: { id: 'groq', name: 'Groq', - baseUrl: 'http://localhost:8000/api/openai/v1', + baseUrl: 'https://api.groq.com/openai/v1', logo: '🚀', documentationUrl: 'https://console.groq.com/docs', apiKeyHeader: 'Authorization', - authType: 'oauth', - oauth: { - authorizeUrl: 'http://localhost:3000/keys/request', - tokenUrl: 'http://localhost:3000/keys/request/exchange', - }, + authType: 'apiKey', }, + // groq: { + // id: 'groq', + // name: 'Groq', + // baseUrl: 'http://localhost:8000/api/openai/v1', + // logo: '🚀', + // documentationUrl: 'https://console.groq.com/docs', + // apiKeyHeader: 'Authorization', + // authType: 'oauth', + // oauth: { + // authorizeUrl: 'http://localhost:3000/keys/request', + // tokenUrl: 'http://localhost:3000/keys/request/exchange', + // }, + // }, anthropic: { id: 'anthropic', name: 'Anthropic',