fix issue with tool schemas and google

This commit is contained in:
Dax Raad 2025-06-17 11:27:07 -04:00
parent 57b3051024
commit ee91f31313
15 changed files with 82 additions and 19 deletions

View file

@ -86,6 +86,9 @@
"sharp",
"esbuild",
],
"patchedDependencies": {
"ai@4.3.16": "patches/ai@4.3.16.patch",
},
"overrides": {
"zod": "3.24.2",
},

View file

@ -37,5 +37,8 @@
"esbuild",
"protobufjs",
"sharp"
]
],
"patchedDependencies": {
"ai@4.3.16": "patches/ai@4.3.16.patch"
}
}

View file

@ -93,8 +93,11 @@ const cli = yargs(hideBin(process.argv))
if (Installation.VERSION === latest) return
const method = await Installation.method()
if (method === "unknown") return
await Installation.upgrade(method, latest).catch(() => {})
Bus.publish(Installation.Event.Updated, { version: latest })
await Installation.upgrade(method, latest)
.then(() => {
Bus.publish(Installation.Event.Updated, { version: latest })
})
.catch(() => {})
})()
await proc.exited

View file

@ -117,6 +117,6 @@ export namespace Installation {
export async function latest() {
return fetch("https://api.github.com/repos/sst/opencode/releases/latest")
.then((res) => res.json())
.then((data) => data.tag_name.slice(1))
.then((data) => data.tag_name.slice(1) as string)
}
}

View file

@ -23,6 +23,7 @@ import { ModelsDev } from "./models"
import { NamedError } from "../util/error"
import { Auth } from "../auth"
import { TaskTool } from "../tool/task"
import { GlobalConfig } from "../global/config"
export namespace Provider {
const log = Log.create({ service: "provider" })
@ -257,7 +258,10 @@ export namespace Provider {
}
export async function defaultModel() {
const [provider] = await list().then((val) => Object.values(val))
const cfg = await GlobalConfig.get()
const provider = await list()
.then((val) => Object.values(val))
.then((x) => x.find((p) => !cfg.provider || cfg.provider === p.info.id))
if (!provider) throw new Error("no providers found")
const [model] = sort(Object.values(provider.info.models))
if (!model) throw new Error("no models found")
@ -285,11 +289,16 @@ export namespace Provider {
TaskTool,
TodoReadTool,
]
const TOOL_MAPPING: Record<string, Tool.Info[]> = {
anthropic: TOOLS.filter((t) => t.id !== "opencode.patch"),
openai: TOOLS,
openai: TOOLS.map((t) => ({
...t,
parameters: optionalToNullable(t.parameters),
})),
google: TOOLS,
}
export async function tools(providerID: string) {
/*
const cfg = await Config.get()
@ -301,6 +310,38 @@ export namespace Provider {
return TOOL_MAPPING[providerID] ?? TOOLS
}
function optionalToNullable(schema: z.ZodTypeAny): z.ZodTypeAny {
if (schema instanceof z.ZodObject) {
const shape = schema.shape
const newShape: Record<string, z.ZodTypeAny> = {}
for (const [key, value] of Object.entries(shape)) {
const zodValue = value as z.ZodTypeAny
if (zodValue instanceof z.ZodOptional) {
newShape[key] = zodValue.unwrap().nullable()
} else {
newShape[key] = optionalToNullable(zodValue)
}
}
return z.object(newShape)
}
if (schema instanceof z.ZodArray) {
return z.array(optionalToNullable(schema.element))
}
if (schema instanceof z.ZodUnion) {
return z.union(
schema.options.map((option: z.ZodTypeAny) =>
optionalToNullable(option),
) as [z.ZodTypeAny, z.ZodTypeAny, ...z.ZodTypeAny[]],
)
}
return schema
}
export const ModelNotFoundError = NamedError.create(
"ProviderModelNotFoundError",
z.object({

View file

@ -497,7 +497,7 @@ export namespace Session {
msgs.map(toUIMessage).filter((x) => x.parts.length > 0),
),
],
temperature: model.info.id === "codex-mini-latest" ? undefined : 0,
temperature: model.info.temperature ? 0 : undefined,
tools: {
...tools,
},

View file

@ -35,7 +35,7 @@ export const BashTool = Tool.define({
.min(0)
.max(MAX_TIMEOUT)
.describe("Optional timeout in milliseconds")
.nullable(),
.optional(),
description: z
.string()
.describe(

View file

@ -21,7 +21,7 @@ export const EditTool = Tool.define({
),
replaceAll: z
.boolean()
.nullable()
.optional()
.describe("Replace all occurences of old_string (default false)"),
}),
async execute(params, ctx) {

View file

@ -11,7 +11,7 @@ export const GlobTool = Tool.define({
pattern: z.string().describe("The glob pattern to match files against"),
path: z
.string()
.nullable()
.optional()
.describe(
`The directory to search in. If not specified, the current working directory will be used. IMPORTANT: Omit this field to use the default directory. DO NOT enter "undefined" or "null" - simply omit it for the default behavior. Must be a valid directory path if provided.`,
),

View file

@ -14,13 +14,13 @@ export const GrepTool = Tool.define({
.describe("The regex pattern to search for in file contents"),
path: z
.string()
.nullable()
.optional()
.describe(
"The directory to search in. Defaults to the current working directory.",
),
include: z
.string()
.nullable()
.optional()
.describe(
'File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")',
),

View file

@ -29,11 +29,11 @@ export const ListTool = Tool.define({
.describe(
"The absolute path to the directory to list (must be absolute, not relative)",
)
.nullable(),
.optional(),
ignore: z
.array(z.string())
.describe("List of glob patterns to ignore")
.nullable(),
.optional(),
}),
async execute(params) {
const app = App.info()

View file

@ -19,11 +19,11 @@ export const ReadTool = Tool.define({
offset: z
.number()
.describe("The line number to start reading from (0-based)")
.nullable(),
.optional(),
limit: z
.number()
.describe("The number of lines to read (defaults to 2000)")
.nullable(),
.optional(),
}),
async execute(params, ctx) {
let filePath = params.filePath

View file

@ -22,7 +22,7 @@ export const WebFetchTool = Tool.define({
.min(0)
.max(MAX_TIMEOUT / 1000)
.describe("Optional timeout in seconds (max 120)")
.nullable(),
.optional(),
}),
async execute(params, ctx) {
// Validate URL

View file

@ -9,7 +9,7 @@ describe("tool.glob", () => {
let result = await GlobTool.execute(
{
pattern: "./node_modules/**/*",
path: null,
path: undefined,
},
{
sessionID: "test",
@ -25,7 +25,7 @@ describe("tool.glob", () => {
let result = await GlobTool.execute(
{
pattern: "*.json",
path: null,
path: undefined,
},
{
sessionID: "test",

13
patches/ai@4.3.16.patch Normal file
View file

@ -0,0 +1,13 @@
diff --git a/dist/index.mjs b/dist/index.mjs
index 92a80377692488c4ba8801ce33e7736ad7055e43..add6281bbecaa1c03d3b48eb99aead4a7a7336b2 100644
--- a/dist/index.mjs
+++ b/dist/index.mjs
@@ -1593,7 +1593,7 @@ function prepareCallSettings({
return {
maxTokens,
// TODO v5 remove default 0 for temperature
- temperature: temperature != null ? temperature : 0,
+ temperature: temperature,
topP,
topK,
presencePenalty,