From 14092b08be2f45590f6855eea0206b6ac5f4cd5e Mon Sep 17 00:00:00 2001 From: dal Date: Fri, 8 Aug 2025 13:29:59 -0600 Subject: [PATCH] move everything over to gpt5 --- .../analysis-type-router-step.ts | 13 ++-- packages/ai/src/steps/create-todos-step.ts | 11 ++-- .../src/steps/extract-values-search-step.ts | 10 ++- .../ai/src/steps/generate-chat-title-step.ts | 10 ++- packages/ai/src/utils/models/gpt-5-mini.ts | 62 +++++++++++++++++++ packages/ai/src/utils/models/gpt-5-nano.ts | 62 +++++++++++++++++++ 6 files changed, 158 insertions(+), 10 deletions(-) create mode 100644 packages/ai/src/utils/models/gpt-5-mini.ts create mode 100644 packages/ai/src/utils/models/gpt-5-nano.ts diff --git a/packages/ai/src/steps/analyst-agent/analysis-type-router-step/analysis-type-router-step.ts b/packages/ai/src/steps/analyst-agent/analysis-type-router-step/analysis-type-router-step.ts index b0b84fe7f..d29652cbd 100644 --- a/packages/ai/src/steps/analyst-agent/analysis-type-router-step/analysis-type-router-step.ts +++ b/packages/ai/src/steps/analyst-agent/analysis-type-router-step/analysis-type-router-step.ts @@ -5,7 +5,7 @@ import { generateObject } from 'ai'; import { wrapTraced } from 'braintrust'; import { z } from 'zod'; import { thinkAndPrepWorkflowInputSchema } from '../../../schemas/workflow-schemas'; -import { Haiku35 } from '../../../utils/models/haiku-3-5'; +import { GPT5Nano } from '../../../utils/models/gpt-5-nano'; import { appendToConversation, standardizeMessages } from '../../../utils/standardizeMessages'; import type { AnalystRuntimeContext } from '../../../workflows/analyst-workflow'; import { formatAnalysisTypeRouterPrompt } from './format-analysis-type-router-prompt'; @@ -68,7 +68,7 @@ const execution = async ({ const tracedAnalysisType = wrapTraced( async () => { const { object } = await generateObject({ - model: Haiku35, + model: GPT5Nano, schema: analysisTypeSchema, messages: [ { @@ -77,8 +77,13 @@ const execution = async ({ }, ...messages, ], - temperature: 0, - maxTokens: 500, + temperature: 1, + providerOptions: { + openai: { + parallelToolCalls: false, + reasoningEffort: 'minimal', + }, + }, }); return object; diff --git a/packages/ai/src/steps/create-todos-step.ts b/packages/ai/src/steps/create-todos-step.ts index 2d9612370..a78ca5437 100644 --- a/packages/ai/src/steps/create-todos-step.ts +++ b/packages/ai/src/steps/create-todos-step.ts @@ -8,7 +8,7 @@ import { thinkAndPrepWorkflowInputSchema } from '../schemas/workflow-schemas'; import { createTodoList } from '../tools/planning-thinking-tools/create-todo-item-tool'; import { ChunkProcessor } from '../utils/database/chunk-processor'; import { ReasoningHistorySchema } from '../utils/memory/types'; -import { Sonnet4 } from '../utils/models/sonnet-4'; +import { GPT5 } from '../utils/models/gpt-5'; import { RetryWithHealingError, isRetryWithHealingError } from '../utils/retry'; import { appendToConversation, standardizeMessages } from '../utils/standardizeMessages'; import { createOnChunkHandler } from '../utils/streaming'; @@ -188,14 +188,17 @@ The TODO list should break down each aspect of the user request into tasks, base const DEFAULT_OPTIONS = { maxSteps: 1, - temperature: 0, - maxTokens: 300, + temperature: 1, + openai: { + parallelToolCalls: false, + reasoningEffort: 'minimal', + }, }; export const todosAgent = new Agent({ name: 'Create Todos', instructions: todosInstructions, - model: Sonnet4, + model: GPT5, tools: { createTodoList, }, diff --git a/packages/ai/src/steps/extract-values-search-step.ts b/packages/ai/src/steps/extract-values-search-step.ts index c5e38aae7..0790f1f6f 100644 --- a/packages/ai/src/steps/extract-values-search-step.ts +++ b/packages/ai/src/steps/extract-values-search-step.ts @@ -7,6 +7,7 @@ import type { CoreMessage } from 'ai'; import { wrapTraced } from 'braintrust'; import { z } from 'zod'; import { thinkAndPrepWorkflowInputSchema } from '../schemas/workflow-schemas'; +import { GPT5Mini } from '../utils/models/gpt-5-mini'; import { Haiku35 } from '../utils/models/haiku-3-5'; import { appendToConversation, standardizeMessages } from '../utils/standardizeMessages'; import type { AnalystRuntimeContext } from '../workflows/analyst-workflow'; @@ -265,7 +266,7 @@ const extractValuesSearchStepExecution = async ({ const tracedValuesExtraction = wrapTraced( async () => { const { object } = await generateObject({ - model: Haiku35, + model: GPT5Mini, schema: llmOutputSchema, messages: [ { @@ -274,6 +275,13 @@ const extractValuesSearchStepExecution = async ({ }, ...messages, ], + temperature: 1, + providerOptions: { + openai: { + parallelToolCalls: false, + reasoningEffort: 'minimal', + }, + }, }); return object; diff --git a/packages/ai/src/steps/generate-chat-title-step.ts b/packages/ai/src/steps/generate-chat-title-step.ts index b43ae9f11..e216337fe 100644 --- a/packages/ai/src/steps/generate-chat-title-step.ts +++ b/packages/ai/src/steps/generate-chat-title-step.ts @@ -9,6 +9,7 @@ import { thinkAndPrepWorkflowInputSchema } from '../schemas/workflow-schemas'; import { Haiku35 } from '../utils/models/haiku-3-5'; import { appendToConversation, standardizeMessages } from '../utils/standardizeMessages'; import type { AnalystRuntimeContext } from '../workflows/analyst-workflow'; +import { GPT5Mini } from '../utils/models/gpt-5-mini'; const inputSchema = thinkAndPrepWorkflowInputSchema; @@ -67,7 +68,7 @@ const generateChatTitleExecution = async ({ const tracedChatTitle = wrapTraced( async () => { const { object } = await generateObject({ - model: Haiku35, + model: GPT5Mini, schema: llmOutputSchema, messages: [ { @@ -76,6 +77,13 @@ const generateChatTitleExecution = async ({ }, ...messages, ], + temperature: 1, + providerOptions: { + openai: { + parallelToolCalls: false, + reasoningEffort: 'minimal', + }, + }, }); return object; diff --git a/packages/ai/src/utils/models/gpt-5-mini.ts b/packages/ai/src/utils/models/gpt-5-mini.ts new file mode 100644 index 000000000..f39c902f3 --- /dev/null +++ b/packages/ai/src/utils/models/gpt-5-mini.ts @@ -0,0 +1,62 @@ +import type { LanguageModelV1 } from '@ai-sdk/provider'; +import { createFallback } from './ai-fallback'; +import { openaiModel } from './providers/openai'; + +// Lazy initialization to allow mocking in tests +let _gpt5Instance: ReturnType | null = null; + +function initializeGPT5() { + if (_gpt5Instance) { + return _gpt5Instance; + } + + // Build models array based on available credentials + const models: LanguageModelV1[] = []; + + // Only include OpenAI if API key is available + if (process.env.OPENAI_API_KEY) { + try { + models.push(openaiModel('gpt-5-mini-2025-08-07')); + console.info('GPT5: OpenAI model added to fallback chain'); + } catch (error) { + console.warn('GPT5: Failed to initialize OpenAI model:', error); + } + } + + // Ensure we have at least one model + if (models.length === 0) { + throw new Error('No AI models available. Please set OPENAI_API_KEY environment variable.'); + } + + console.info(`GPT5: Initialized with ${models.length} model(s) in fallback chain`); + + _gpt5Instance = createFallback({ + models, + modelResetInterval: 60000, + retryAfterOutput: true, + onError: (err) => console.error(`FALLBACK. Here is the error: ${err}`), + }); + + return _gpt5Instance; +} + +// Export a proxy that initializes on first use +export const GPT5Mini = new Proxy({} as ReturnType, { + get(_target, prop) { + const instance = initializeGPT5(); + // Direct property access without receiver to avoid proxy conflicts + return instance[prop as keyof typeof instance]; + }, + has(_target, prop) { + const instance = initializeGPT5(); + return prop in instance; + }, + ownKeys(_target) { + const instance = initializeGPT5(); + return Reflect.ownKeys(instance); + }, + getOwnPropertyDescriptor(_target, prop) { + const instance = initializeGPT5(); + return Reflect.getOwnPropertyDescriptor(instance, prop); + }, +}); diff --git a/packages/ai/src/utils/models/gpt-5-nano.ts b/packages/ai/src/utils/models/gpt-5-nano.ts new file mode 100644 index 000000000..4552d35fe --- /dev/null +++ b/packages/ai/src/utils/models/gpt-5-nano.ts @@ -0,0 +1,62 @@ +import type { LanguageModelV1 } from '@ai-sdk/provider'; +import { createFallback } from './ai-fallback'; +import { openaiModel } from './providers/openai'; + +// Lazy initialization to allow mocking in tests +let _gpt5Instance: ReturnType | null = null; + +function initializeGPT5() { + if (_gpt5Instance) { + return _gpt5Instance; + } + + // Build models array based on available credentials + const models: LanguageModelV1[] = []; + + // Only include OpenAI if API key is available + if (process.env.OPENAI_API_KEY) { + try { + models.push(openaiModel('gpt-5-nano-2025-08-07')); + console.info('GPT5: OpenAI model added to fallback chain'); + } catch (error) { + console.warn('GPT5: Failed to initialize OpenAI model:', error); + } + } + + // Ensure we have at least one model + if (models.length === 0) { + throw new Error('No AI models available. Please set OPENAI_API_KEY environment variable.'); + } + + console.info(`GPT5: Initialized with ${models.length} model(s) in fallback chain`); + + _gpt5Instance = createFallback({ + models, + modelResetInterval: 60000, + retryAfterOutput: true, + onError: (err) => console.error(`FALLBACK. Here is the error: ${err}`), + }); + + return _gpt5Instance; +} + +// Export a proxy that initializes on first use +export const GPT5Nano = new Proxy({} as ReturnType, { + get(_target, prop) { + const instance = initializeGPT5(); + // Direct property access without receiver to avoid proxy conflicts + return instance[prop as keyof typeof instance]; + }, + has(_target, prop) { + const instance = initializeGPT5(); + return prop in instance; + }, + ownKeys(_target) { + const instance = initializeGPT5(); + return Reflect.ownKeys(instance); + }, + getOwnPropertyDescriptor(_target, prop) { + const instance = initializeGPT5(); + return Reflect.getOwnPropertyDescriptor(instance, prop); + }, +});