Fixing reasoning on Qwen3
This commit is contained in:
parent
c260e971d9
commit
5b54994da7
7 changed files with 48 additions and 76 deletions
|
|
@ -455,7 +455,7 @@
|
|||
"id": "qwen/qwen3-32b",
|
||||
"name": "Qwen3 32B",
|
||||
"attachment": false,
|
||||
"reasoning": false,
|
||||
"reasoning": true,
|
||||
"temperature": true,
|
||||
"tool_call": true,
|
||||
"knowledge": "2024-11-08",
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { Model, providers, SupportedProvider, SUPPORTED_PROVIDERS, FAVORITES_KEY } from '../types/models'
|
||||
import { Model, providers, SUPPORTED_PROVIDERS, FAVORITES_KEY } from '../types/models'
|
||||
|
||||
// Load models data from generated JSON
|
||||
import modelsData from '../data/models.json'
|
||||
|
|
@ -31,7 +31,6 @@ export function useModels() {
|
|||
contextLimit: modelData.limit.context,
|
||||
outputLimit: modelData.limit.output,
|
||||
cost: modelData.cost,
|
||||
providerOptions: getProviderOptions(providerId, modelId),
|
||||
}
|
||||
allModels.push(model)
|
||||
}
|
||||
|
|
@ -114,27 +113,3 @@ export function useModels() {
|
|||
getToolSupportingModels,
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to get provider-specific options
|
||||
function getProviderOptions(providerId: SupportedProvider, modelId: string) {
|
||||
// Add any provider-specific options here
|
||||
switch (providerId) {
|
||||
case 'groq':
|
||||
// Handle specific Groq model options
|
||||
if (modelId === 'qwen/qwen3-32b') {
|
||||
return {
|
||||
groq: {
|
||||
reasoningFormat: 'parsed',
|
||||
},
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'anthropic':
|
||||
// Handle specific Anthropic model options
|
||||
break
|
||||
case 'openrouter':
|
||||
// Handle specific OpenRouter model options
|
||||
break
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { type Model } from '../types/models'
|
|||
import { getAuthHeaders } from '../utils/auth'
|
||||
import { type Tool } from 'use-mcp/react'
|
||||
import { useConversationUpdater } from './useConversationUpdater'
|
||||
import { getProviderOptions } from '../utils/modelOptions.ts'
|
||||
|
||||
// Type guard for messages with content
|
||||
const hasContent = (message: Message): message is UserMessage | AssistantMessage | SystemMessage => {
|
||||
|
|
@ -166,7 +167,7 @@ export const useStreamResponse = ({
|
|||
tools: Object.keys(aiTools).length > 0 ? aiTools : undefined,
|
||||
maxSteps: 5, // Allow up to 5 steps for tool calling
|
||||
abortSignal: controller.signal,
|
||||
...selectedModel.providerOptions,
|
||||
providerOptions: getProviderOptions(selectedModel.provider.id, selectedModel.modelId),
|
||||
})
|
||||
|
||||
// Use fullStream to get all events including tool calls, results, and text
|
||||
|
|
@ -229,19 +230,13 @@ export const useStreamResponse = ({
|
|||
} else {
|
||||
console.warn('Tool call event missing toolName:', event)
|
||||
}
|
||||
// @ts-expect-error I have no idea why this is suddenly failing...
|
||||
} else if (event.type === 'tool-result') {
|
||||
// @ts-expect-error wat
|
||||
if (event.toolName && event.toolCallId) {
|
||||
newMessage = {
|
||||
role: 'tool-result',
|
||||
// @ts-expect-error the
|
||||
toolName: event.toolName,
|
||||
// @ts-expect-error actual
|
||||
toolArgs: event.args || {},
|
||||
// @ts-expect-error goddamn
|
||||
toolResult: event.result,
|
||||
// @ts-expect-error fek
|
||||
callId: event.toolCallId,
|
||||
}
|
||||
scrollToBottom(true)
|
||||
|
|
|
|||
|
|
@ -39,8 +39,6 @@ export interface Provider {
|
|||
oauth?: {
|
||||
authorizeUrl: string
|
||||
tokenUrl: string
|
||||
clientId: string
|
||||
scopes: string[]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -60,7 +58,6 @@ export interface Model {
|
|||
cache_read?: number
|
||||
cache_write?: number
|
||||
}
|
||||
providerOptions?: any
|
||||
}
|
||||
|
||||
export const providers: Record<SupportedProvider, Provider> = {
|
||||
|
|
@ -72,6 +69,10 @@ export const providers: Record<SupportedProvider, Provider> = {
|
|||
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'
|
||||
// },
|
||||
},
|
||||
anthropic: {
|
||||
id: 'anthropic',
|
||||
|
|
@ -92,8 +93,6 @@ export const providers: Record<SupportedProvider, Provider> = {
|
|||
oauth: {
|
||||
authorizeUrl: 'https://openrouter.ai/auth',
|
||||
tokenUrl: 'https://openrouter.ai/api/v1/auth/keys',
|
||||
clientId: '', // OpenRouter doesn't use client_id
|
||||
scopes: [], // OpenRouter doesn't use scopes
|
||||
},
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,22 +122,16 @@ export async function beginOAuthFlow(providerId: SupportedProvider): Promise<voi
|
|||
let authUrl: URL
|
||||
|
||||
if (providerId === 'openrouter') {
|
||||
// OpenRouter uses a different OAuth flow
|
||||
// OpenRouter uses a different redirect name flow
|
||||
authUrl = new URL(provider.oauth.authorizeUrl)
|
||||
authUrl.searchParams.set('callback_url', getRedirectUri(providerId))
|
||||
authUrl.searchParams.set('code_challenge', codeChallenge)
|
||||
authUrl.searchParams.set('code_challenge_method', 'S256')
|
||||
} else {
|
||||
// Standard OAuth2 flow for other providers
|
||||
// Groq uses redirect_uri
|
||||
authUrl = new URL(provider.oauth.authorizeUrl)
|
||||
authUrl.searchParams.set('client_id', provider.oauth.clientId)
|
||||
authUrl.searchParams.set('redirect_uri', getRedirectUri(providerId))
|
||||
authUrl.searchParams.set('response_type', 'code')
|
||||
authUrl.searchParams.set('scope', provider.oauth.scopes.join(' '))
|
||||
authUrl.searchParams.set('state', state)
|
||||
authUrl.searchParams.set('code_challenge', codeChallenge)
|
||||
authUrl.searchParams.set('code_challenge_method', 'S256')
|
||||
}
|
||||
authUrl.searchParams.set('code_challenge', codeChallenge)
|
||||
authUrl.searchParams.set('code_challenge_method', 'S256')
|
||||
|
||||
// Open popup or redirect
|
||||
const popup = window.open(authUrl.toString(), `oauth_${providerId}`, 'width=600,height=700')
|
||||
|
|
@ -227,7 +221,6 @@ export async function completeOAuthFlow(providerId: SupportedProvider, code: str
|
|||
// Standard OAuth2 flow for other providers
|
||||
const requestBody = new URLSearchParams({
|
||||
grant_type: 'authorization_code',
|
||||
client_id: provider.oauth.clientId,
|
||||
code,
|
||||
redirect_uri: getRedirectUri(providerId),
|
||||
code_verifier: pkceState.code_verifier,
|
||||
|
|
|
|||
35
examples/chat-ui/src/utils/modelOptions.ts
Normal file
35
examples/chat-ui/src/utils/modelOptions.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { type SupportedProvider } from '../types/models'
|
||||
import modelsData from '../data/models.json'
|
||||
|
||||
// Helper function to check if a model supports reasoning
|
||||
export function supportsReasoning(providerId: SupportedProvider, modelId: string): boolean {
|
||||
const providerModels = modelsData[providerId] as Record<string, any>
|
||||
if (!providerModels) return false
|
||||
|
||||
const model = providerModels[modelId]
|
||||
return model?.reasoning === true
|
||||
}
|
||||
|
||||
// Helper function to get provider-specific options
|
||||
export function getProviderOptions(providerId: SupportedProvider, modelId: string): Record<string, any> | undefined {
|
||||
// Add any provider-specific options here
|
||||
switch (providerId) {
|
||||
case 'groq':
|
||||
// Handle specific Groq model options - set reasoningFormat for all reasoning models
|
||||
if (supportsReasoning(providerId, modelId)) {
|
||||
return {
|
||||
groq: {
|
||||
reasoningFormat: 'parsed',
|
||||
},
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'anthropic':
|
||||
// Handle specific Anthropic model options
|
||||
break
|
||||
case 'openrouter':
|
||||
// Handle specific OpenRouter model options
|
||||
break
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
|
@ -1,32 +1,8 @@
|
|||
import { type Model, providers, type SupportedProvider } from '../types/models'
|
||||
import { type Model, providers } from '../types/models'
|
||||
|
||||
// Import models data directly
|
||||
import modelsData from '../data/models.json'
|
||||
|
||||
// Helper function to get provider-specific options
|
||||
function getProviderOptions(providerId: SupportedProvider, modelId: string) {
|
||||
// Add any provider-specific options here
|
||||
switch (providerId) {
|
||||
case 'groq':
|
||||
// Handle specific Groq model options
|
||||
if (modelId === 'qwen/qwen3-32b') {
|
||||
return {
|
||||
groq: {
|
||||
reasoningFormat: 'parsed',
|
||||
},
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'anthropic':
|
||||
// Handle specific Anthropic model options
|
||||
break
|
||||
case 'openrouter':
|
||||
// Handle specific OpenRouter model options
|
||||
break
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
const MODEL_PREFERENCE_KEY = 'aiChatTemplate_selectedModel'
|
||||
|
||||
function getAvailableModels(): Model[] {
|
||||
|
|
@ -47,7 +23,6 @@ function getAvailableModels(): Model[] {
|
|||
contextLimit: modelData.limit.context,
|
||||
outputLimit: modelData.limit.output,
|
||||
cost: modelData.cost,
|
||||
providerOptions: getProviderOptions(providerId as any, modelId),
|
||||
}
|
||||
models.push(model)
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue