diff --git a/package-lock.json b/package-lock.json index cd491bf..450d9ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,17 @@ { "name": "dyad", - "version": "0.15.0-beta.2", + "version": "0.16.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "dyad", - "version": "0.15.0-beta.2", + "version": "0.16.0", "license": "MIT", "dependencies": { "@ai-sdk/anthropic": "^1.2.8", "@ai-sdk/google": "^1.2.19", - "@ai-sdk/openai": "^1.3.7", + "@ai-sdk/openai": "^1.3.24", "@ai-sdk/openai-compatible": "^0.2.13", "@biomejs/biome": "^1.9.4", "@dyad-sh/supabase-management-js": "v1.0.0", @@ -171,13 +171,13 @@ } }, "node_modules/@ai-sdk/openai": { - "version": "1.3.21", - "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.3.21.tgz", - "integrity": "sha512-ipAhkRKUd2YaMmn7DAklX3N7Ywx/rCsJHVyb0V/lKRqPcc612qAFVbjg+Uve8QYJlbPxgfsM4s9JmCFp6PSdYw==", + "version": "1.3.24", + "resolved": "https://registry.npmjs.org/@ai-sdk/openai/-/openai-1.3.24.tgz", + "integrity": "sha512-GYXnGJTHRTZc4gJMSmFRgEQudjqd4PUN0ZjQhPwOAYH1yOAvQoG/Ikqs+HyISRbLPCrhbZnPKCNHuRU4OfpW0Q==", "license": "Apache-2.0", "dependencies": { "@ai-sdk/provider": "1.1.3", - "@ai-sdk/provider-utils": "2.2.7" + "@ai-sdk/provider-utils": "2.2.8" }, "engines": { "node": ">=18" @@ -202,6 +202,23 @@ "zod": "^3.0.0" } }, + "node_modules/@ai-sdk/openai/node_modules/@ai-sdk/provider-utils": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider-utils/-/provider-utils-2.2.8.tgz", + "integrity": "sha512-fqhG+4sCVv8x7nFzYnFo19ryhAa3w096Kmc3hWxMQfW/TubPOmt3A6tYZhl4mUfQWWQMsuSkLrtjlWuXBVSGQA==", + "license": "Apache-2.0", + "dependencies": { + "@ai-sdk/provider": "1.1.3", + "nanoid": "^3.3.8", + "secure-json-parse": "^2.7.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "zod": "^3.23.8" + } + }, "node_modules/@ai-sdk/provider": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", diff --git a/package.json b/package.json index e46bad9..e520f83 100644 --- a/package.json +++ b/package.json @@ -85,7 +85,7 @@ "dependencies": { "@ai-sdk/anthropic": "^1.2.8", "@ai-sdk/google": "^1.2.19", - "@ai-sdk/openai": "^1.3.7", + "@ai-sdk/openai": "^1.3.24", "@ai-sdk/openai-compatible": "^0.2.13", "@biomejs/biome": "^1.9.4", "@dyad-sh/supabase-management-js": "v1.0.0", diff --git a/src/ipc/handlers/chat_stream_handlers.ts b/src/ipc/handlers/chat_stream_handlers.ts index dd9b63b..6a54f81 100644 --- a/src/ipc/handlers/chat_stream_handlers.ts +++ b/src/ipc/handlers/chat_stream_handlers.ts @@ -38,7 +38,7 @@ import * as path from "path"; import * as os from "os"; import * as crypto from "crypto"; import { readFile, writeFile, unlink } from "fs/promises"; -import { getMaxTokens } from "../utils/token_utils"; +import { getMaxTokens, getTemperature } from "../utils/token_utils"; import { MAX_CHAT_TURNS_IN_CONTEXT } from "@/constants/settings_constants"; import { validateChatContext } from "../utils/context_paths_utils"; import { GoogleGenerativeAIProviderOptions } from "@ai-sdk/google"; @@ -58,6 +58,7 @@ import { } from "../utils/dyad_tag_parser"; import { fileExists } from "../utils/file_utils"; import { FileUploadsState } from "../utils/file_uploads_state"; +import { OpenAIResponsesProviderOptions } from "@ai-sdk/openai"; type AsyncIterableStream = AsyncIterable & ReadableStream; @@ -593,7 +594,7 @@ This conversation includes one or more image attachments. When the user uploads } return streamText({ maxTokens: await getMaxTokens(settings.selectedModel), - temperature: 0, + temperature: await getTemperature(settings.selectedModel), maxRetries: 2, model: modelClient.model, providerOptions: { @@ -609,6 +610,9 @@ This conversation includes one or more image attachments. When the user uploads includeThoughts: true, }, } satisfies GoogleGenerativeAIProviderOptions, + openai: { + reasoningSummary: "auto", + } satisfies OpenAIResponsesProviderOptions, }, system: systemPrompt, messages: chatMessages.filter((m) => m.content), diff --git a/src/ipc/ipc_types.ts b/src/ipc/ipc_types.ts index 2d0a380..4699af8 100644 --- a/src/ipc/ipc_types.ts +++ b/src/ipc/ipc_types.ts @@ -183,6 +183,7 @@ export type LanguageModel = tag?: string; maxOutputTokens?: number; contextWindow?: number; + temperature?: number; type: "custom"; } | { @@ -192,6 +193,7 @@ export type LanguageModel = tag?: string; maxOutputTokens?: number; contextWindow?: number; + temperature?: number; type: "local" | "cloud"; }; diff --git a/src/ipc/shared/language_model_helpers.ts b/src/ipc/shared/language_model_helpers.ts index bcb6178..de2a201 100644 --- a/src/ipc/shared/language_model_helpers.ts +++ b/src/ipc/shared/language_model_helpers.ts @@ -15,6 +15,7 @@ export interface ModelOption { name: string; displayName: string; description: string; + temperature?: number; tag?: string; maxOutputTokens?: number; contextWindow?: number; @@ -22,6 +23,39 @@ export interface ModelOption { export const MODEL_OPTIONS: Record = { openai: [ + // https://platform.openai.com/docs/models/gpt-5 + { + name: "gpt-5", + displayName: "GPT 5", + description: "OpenAI's flagship model", + // Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens + maxOutputTokens: undefined, + contextWindow: 400_000, + // Requires temperature to be default value (1) + temperature: 1, + }, + // https://platform.openai.com/docs/models/gpt-5-mini + { + name: "gpt-5-mini", + displayName: "GPT 5 Mini", + description: "OpenAI's lightweight, but intelligent model", + // Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens + maxOutputTokens: undefined, + contextWindow: 400_000, + // Requires temperature to be default value (1) + temperature: 1, + }, + // https://platform.openai.com/docs/models/gpt-5-nano + { + name: "gpt-5-nano", + displayName: "GPT 5 Nano", + description: "Fastest, most cost-efficient version of GPT-5", + // Technically it's 128k but OpenAI errors if you set max_tokens instead of max_completion_tokens + maxOutputTokens: undefined, + contextWindow: 400_000, + // Requires temperature to be default value (1) + temperature: 1, + }, // https://platform.openai.com/docs/models/gpt-4.1 { name: "gpt-4.1", @@ -29,6 +63,7 @@ export const MODEL_OPTIONS: Record = { description: "OpenAI's flagship model", maxOutputTokens: 32_768, contextWindow: 1_047_576, + temperature: 0, }, // https://platform.openai.com/docs/models/gpt-4.1-mini { @@ -37,6 +72,7 @@ export const MODEL_OPTIONS: Record = { description: "OpenAI's lightweight, but intelligent model", maxOutputTokens: 32_768, contextWindow: 1_047_576, + temperature: 0, }, // https://platform.openai.com/docs/models/o3-mini { @@ -46,6 +82,7 @@ export const MODEL_OPTIONS: Record = { // See o4-mini comment below for why we set this to 32k maxOutputTokens: 32_000, contextWindow: 200_000, + temperature: 0, }, // https://platform.openai.com/docs/models/o4-mini { @@ -57,6 +94,7 @@ export const MODEL_OPTIONS: Record = { // the max output tokens is *included* in the context window limit. maxOutputTokens: 32_000, contextWindow: 200_000, + temperature: 0, }, ], // https://docs.anthropic.com/en/docs/about-claude/models/all-models#model-comparison-table @@ -68,6 +106,7 @@ export const MODEL_OPTIONS: Record = { // See comment below for Claude 3.7 Sonnet for why we set this to 16k maxOutputTokens: 16_000, contextWindow: 200_000, + temperature: 0, }, { name: "claude-3-7-sonnet-latest", @@ -79,6 +118,7 @@ export const MODEL_OPTIONS: Record = { // https://docs.anthropic.com/en/docs/build-with-claude/extended-thinking#max-tokens-and-context-window-size-with-extended-thinking maxOutputTokens: 16_000, contextWindow: 200_000, + temperature: 0, }, { name: "claude-3-5-sonnet-20241022", @@ -86,6 +126,7 @@ export const MODEL_OPTIONS: Record = { description: "Good coder, excellent at following instructions", maxOutputTokens: 8_000, contextWindow: 200_000, + temperature: 0, }, { name: "claude-3-5-haiku-20241022", @@ -93,6 +134,7 @@ export const MODEL_OPTIONS: Record = { description: "Lightweight coder", maxOutputTokens: 8_000, contextWindow: 200_000, + temperature: 0, }, ], google: [ @@ -105,6 +147,7 @@ export const MODEL_OPTIONS: Record = { maxOutputTokens: 65_536 - 1, // Gemini context window = input token + output token contextWindow: 1_048_576, + temperature: 0, }, // https://ai.google.dev/gemini-api/docs/models#gemini-2.5-flash-preview { @@ -115,6 +158,7 @@ export const MODEL_OPTIONS: Record = { maxOutputTokens: 65_536 - 1, // Gemini context window = input token + output token contextWindow: 1_048_576, + temperature: 0, }, ], openrouter: [ @@ -124,6 +168,7 @@ export const MODEL_OPTIONS: Record = { description: "Qwen's best coding model", maxOutputTokens: 32_000, contextWindow: 262_000, + temperature: 0, }, // https://openrouter.ai/deepseek/deepseek-chat-v3-0324:free { @@ -132,6 +177,7 @@ export const MODEL_OPTIONS: Record = { description: "Use for free (data may be used for training)", maxOutputTokens: 32_000, contextWindow: 128_000, + temperature: 0, }, // https://openrouter.ai/moonshotai/kimi-k2 { @@ -140,6 +186,7 @@ export const MODEL_OPTIONS: Record = { description: "Powerful cost-effective model", maxOutputTokens: 32_000, contextWindow: 131_000, + temperature: 0, }, { name: "deepseek/deepseek-r1-0528", @@ -147,6 +194,7 @@ export const MODEL_OPTIONS: Record = { description: "Good reasoning model with excellent price for performance", maxOutputTokens: 32_000, contextWindow: 128_000, + temperature: 0, }, ], auto: [ @@ -160,6 +208,7 @@ export const MODEL_OPTIONS: Record = { // and smart auto. maxOutputTokens: 32_000, contextWindow: 1_000_000, + temperature: 0, }, ], }; diff --git a/src/ipc/utils/get_model_client.ts b/src/ipc/utils/get_model_client.ts index 9caa614..a696828 100644 --- a/src/ipc/utils/get_model_client.ts +++ b/src/ipc/utils/get_model_client.ts @@ -183,7 +183,7 @@ function getRegularModelClient( const provider = createOpenAI({ apiKey }); return { modelClient: { - model: provider(model.name), + model: provider.responses(model.name), builtinProviderId: providerId, }, backupModelClients: [], diff --git a/src/ipc/utils/thinking_utils.ts b/src/ipc/utils/thinking_utils.ts index 31be916..c27f8f2 100644 --- a/src/ipc/utils/thinking_utils.ts +++ b/src/ipc/utils/thinking_utils.ts @@ -23,6 +23,11 @@ export function getExtraProviderOptions( if (!providerId) { return {}; } + if (providerId === "openai") { + return { + reasoning_effort: "medium", + }; + } if (PROVIDERS_THAT_SUPPORT_THINKING.includes(providerId)) { const budgetTokens = getThinkingBudgetTokens(settings?.thinkingBudget); return { diff --git a/src/ipc/utils/token_utils.ts b/src/ipc/utils/token_utils.ts index e3e38de..d497a9d 100644 --- a/src/ipc/utils/token_utils.ts +++ b/src/ipc/utils/token_utils.ts @@ -24,10 +24,16 @@ export async function getContextWindow() { return modelOption?.contextWindow || DEFAULT_CONTEXT_WINDOW; } -// Most models support at least 8000 output tokens so we use it as a default value. -const DEFAULT_MAX_TOKENS = 8_000; - -export async function getMaxTokens(model: LargeLanguageModel) { +export async function getMaxTokens( + model: LargeLanguageModel, +): Promise { const modelOption = await findLanguageModel(model); - return modelOption?.maxOutputTokens || DEFAULT_MAX_TOKENS; + return modelOption?.maxOutputTokens ?? undefined; +} + +export async function getTemperature( + model: LargeLanguageModel, +): Promise { + const modelOption = await findLanguageModel(model); + return modelOption?.temperature ?? 0; }