mirror of
https://github.com/sst/opencode.git
synced 2025-07-07 16:14:59 +00:00
fix issue with tool schemas and google
This commit is contained in:
parent
57b3051024
commit
ee91f31313
15 changed files with 82 additions and 19 deletions
3
bun.lock
3
bun.lock
|
@ -86,6 +86,9 @@
|
||||||
"sharp",
|
"sharp",
|
||||||
"esbuild",
|
"esbuild",
|
||||||
],
|
],
|
||||||
|
"patchedDependencies": {
|
||||||
|
"ai@4.3.16": "patches/ai@4.3.16.patch",
|
||||||
|
},
|
||||||
"overrides": {
|
"overrides": {
|
||||||
"zod": "3.24.2",
|
"zod": "3.24.2",
|
||||||
},
|
},
|
||||||
|
|
|
@ -37,5 +37,8 @@
|
||||||
"esbuild",
|
"esbuild",
|
||||||
"protobufjs",
|
"protobufjs",
|
||||||
"sharp"
|
"sharp"
|
||||||
]
|
],
|
||||||
|
"patchedDependencies": {
|
||||||
|
"ai@4.3.16": "patches/ai@4.3.16.patch"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,8 +93,11 @@ const cli = yargs(hideBin(process.argv))
|
||||||
if (Installation.VERSION === latest) return
|
if (Installation.VERSION === latest) return
|
||||||
const method = await Installation.method()
|
const method = await Installation.method()
|
||||||
if (method === "unknown") return
|
if (method === "unknown") return
|
||||||
await Installation.upgrade(method, latest).catch(() => {})
|
await Installation.upgrade(method, latest)
|
||||||
|
.then(() => {
|
||||||
Bus.publish(Installation.Event.Updated, { version: latest })
|
Bus.publish(Installation.Event.Updated, { version: latest })
|
||||||
|
})
|
||||||
|
.catch(() => {})
|
||||||
})()
|
})()
|
||||||
|
|
||||||
await proc.exited
|
await proc.exited
|
||||||
|
|
|
@ -117,6 +117,6 @@ export namespace Installation {
|
||||||
export async function latest() {
|
export async function latest() {
|
||||||
return fetch("https://api.github.com/repos/sst/opencode/releases/latest")
|
return fetch("https://api.github.com/repos/sst/opencode/releases/latest")
|
||||||
.then((res) => res.json())
|
.then((res) => res.json())
|
||||||
.then((data) => data.tag_name.slice(1))
|
.then((data) => data.tag_name.slice(1) as string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import { ModelsDev } from "./models"
|
||||||
import { NamedError } from "../util/error"
|
import { NamedError } from "../util/error"
|
||||||
import { Auth } from "../auth"
|
import { Auth } from "../auth"
|
||||||
import { TaskTool } from "../tool/task"
|
import { TaskTool } from "../tool/task"
|
||||||
|
import { GlobalConfig } from "../global/config"
|
||||||
|
|
||||||
export namespace Provider {
|
export namespace Provider {
|
||||||
const log = Log.create({ service: "provider" })
|
const log = Log.create({ service: "provider" })
|
||||||
|
@ -257,7 +258,10 @@ export namespace Provider {
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function defaultModel() {
|
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")
|
if (!provider) throw new Error("no providers found")
|
||||||
const [model] = sort(Object.values(provider.info.models))
|
const [model] = sort(Object.values(provider.info.models))
|
||||||
if (!model) throw new Error("no models found")
|
if (!model) throw new Error("no models found")
|
||||||
|
@ -285,11 +289,16 @@ export namespace Provider {
|
||||||
TaskTool,
|
TaskTool,
|
||||||
TodoReadTool,
|
TodoReadTool,
|
||||||
]
|
]
|
||||||
|
|
||||||
const TOOL_MAPPING: Record<string, Tool.Info[]> = {
|
const TOOL_MAPPING: Record<string, Tool.Info[]> = {
|
||||||
anthropic: TOOLS.filter((t) => t.id !== "opencode.patch"),
|
anthropic: TOOLS.filter((t) => t.id !== "opencode.patch"),
|
||||||
openai: TOOLS,
|
openai: TOOLS.map((t) => ({
|
||||||
|
...t,
|
||||||
|
parameters: optionalToNullable(t.parameters),
|
||||||
|
})),
|
||||||
google: TOOLS,
|
google: TOOLS,
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function tools(providerID: string) {
|
export async function tools(providerID: string) {
|
||||||
/*
|
/*
|
||||||
const cfg = await Config.get()
|
const cfg = await Config.get()
|
||||||
|
@ -301,6 +310,38 @@ export namespace Provider {
|
||||||
return TOOL_MAPPING[providerID] ?? TOOLS
|
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(
|
export const ModelNotFoundError = NamedError.create(
|
||||||
"ProviderModelNotFoundError",
|
"ProviderModelNotFoundError",
|
||||||
z.object({
|
z.object({
|
||||||
|
|
|
@ -497,7 +497,7 @@ export namespace Session {
|
||||||
msgs.map(toUIMessage).filter((x) => x.parts.length > 0),
|
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: {
|
||||||
...tools,
|
...tools,
|
||||||
},
|
},
|
||||||
|
|
|
@ -35,7 +35,7 @@ export const BashTool = Tool.define({
|
||||||
.min(0)
|
.min(0)
|
||||||
.max(MAX_TIMEOUT)
|
.max(MAX_TIMEOUT)
|
||||||
.describe("Optional timeout in milliseconds")
|
.describe("Optional timeout in milliseconds")
|
||||||
.nullable(),
|
.optional(),
|
||||||
description: z
|
description: z
|
||||||
.string()
|
.string()
|
||||||
.describe(
|
.describe(
|
||||||
|
|
|
@ -21,7 +21,7 @@ export const EditTool = Tool.define({
|
||||||
),
|
),
|
||||||
replaceAll: z
|
replaceAll: z
|
||||||
.boolean()
|
.boolean()
|
||||||
.nullable()
|
.optional()
|
||||||
.describe("Replace all occurences of old_string (default false)"),
|
.describe("Replace all occurences of old_string (default false)"),
|
||||||
}),
|
}),
|
||||||
async execute(params, ctx) {
|
async execute(params, ctx) {
|
||||||
|
|
|
@ -11,7 +11,7 @@ export const GlobTool = Tool.define({
|
||||||
pattern: z.string().describe("The glob pattern to match files against"),
|
pattern: z.string().describe("The glob pattern to match files against"),
|
||||||
path: z
|
path: z
|
||||||
.string()
|
.string()
|
||||||
.nullable()
|
.optional()
|
||||||
.describe(
|
.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.`,
|
`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.`,
|
||||||
),
|
),
|
||||||
|
|
|
@ -14,13 +14,13 @@ export const GrepTool = Tool.define({
|
||||||
.describe("The regex pattern to search for in file contents"),
|
.describe("The regex pattern to search for in file contents"),
|
||||||
path: z
|
path: z
|
||||||
.string()
|
.string()
|
||||||
.nullable()
|
.optional()
|
||||||
.describe(
|
.describe(
|
||||||
"The directory to search in. Defaults to the current working directory.",
|
"The directory to search in. Defaults to the current working directory.",
|
||||||
),
|
),
|
||||||
include: z
|
include: z
|
||||||
.string()
|
.string()
|
||||||
.nullable()
|
.optional()
|
||||||
.describe(
|
.describe(
|
||||||
'File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")',
|
'File pattern to include in the search (e.g. "*.js", "*.{ts,tsx}")',
|
||||||
),
|
),
|
||||||
|
|
|
@ -29,11 +29,11 @@ export const ListTool = Tool.define({
|
||||||
.describe(
|
.describe(
|
||||||
"The absolute path to the directory to list (must be absolute, not relative)",
|
"The absolute path to the directory to list (must be absolute, not relative)",
|
||||||
)
|
)
|
||||||
.nullable(),
|
.optional(),
|
||||||
ignore: z
|
ignore: z
|
||||||
.array(z.string())
|
.array(z.string())
|
||||||
.describe("List of glob patterns to ignore")
|
.describe("List of glob patterns to ignore")
|
||||||
.nullable(),
|
.optional(),
|
||||||
}),
|
}),
|
||||||
async execute(params) {
|
async execute(params) {
|
||||||
const app = App.info()
|
const app = App.info()
|
||||||
|
|
|
@ -19,11 +19,11 @@ export const ReadTool = Tool.define({
|
||||||
offset: z
|
offset: z
|
||||||
.number()
|
.number()
|
||||||
.describe("The line number to start reading from (0-based)")
|
.describe("The line number to start reading from (0-based)")
|
||||||
.nullable(),
|
.optional(),
|
||||||
limit: z
|
limit: z
|
||||||
.number()
|
.number()
|
||||||
.describe("The number of lines to read (defaults to 2000)")
|
.describe("The number of lines to read (defaults to 2000)")
|
||||||
.nullable(),
|
.optional(),
|
||||||
}),
|
}),
|
||||||
async execute(params, ctx) {
|
async execute(params, ctx) {
|
||||||
let filePath = params.filePath
|
let filePath = params.filePath
|
||||||
|
|
|
@ -22,7 +22,7 @@ export const WebFetchTool = Tool.define({
|
||||||
.min(0)
|
.min(0)
|
||||||
.max(MAX_TIMEOUT / 1000)
|
.max(MAX_TIMEOUT / 1000)
|
||||||
.describe("Optional timeout in seconds (max 120)")
|
.describe("Optional timeout in seconds (max 120)")
|
||||||
.nullable(),
|
.optional(),
|
||||||
}),
|
}),
|
||||||
async execute(params, ctx) {
|
async execute(params, ctx) {
|
||||||
// Validate URL
|
// Validate URL
|
||||||
|
|
|
@ -9,7 +9,7 @@ describe("tool.glob", () => {
|
||||||
let result = await GlobTool.execute(
|
let result = await GlobTool.execute(
|
||||||
{
|
{
|
||||||
pattern: "./node_modules/**/*",
|
pattern: "./node_modules/**/*",
|
||||||
path: null,
|
path: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sessionID: "test",
|
sessionID: "test",
|
||||||
|
@ -25,7 +25,7 @@ describe("tool.glob", () => {
|
||||||
let result = await GlobTool.execute(
|
let result = await GlobTool.execute(
|
||||||
{
|
{
|
||||||
pattern: "*.json",
|
pattern: "*.json",
|
||||||
path: null,
|
path: undefined,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
sessionID: "test",
|
sessionID: "test",
|
||||||
|
|
13
patches/ai@4.3.16.patch
Normal file
13
patches/ai@4.3.16.patch
Normal 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,
|
Loading…
Add table
Add a link
Reference in a new issue