فهرست منبع

fix: remove 10 more unnecessary `as any` casts in opencode core (#22882)

Kit Langton 4 ماه پیش
والد
کامیت
1c33b866ba

+ 20 - 15
packages/opencode/src/cli/cmd/tui/routes/session/index.tsx

@@ -44,6 +44,8 @@ import type { GrepTool } from "@/tool/grep"
 import type { EditTool } from "@/tool/edit"
 import type { ApplyPatchTool } from "@/tool/apply_patch"
 import type { WebFetchTool } from "@/tool/webfetch"
+import type { CodeSearchTool } from "@/tool/codesearch"
+import type { WebSearchTool } from "@/tool/websearch"
 import type { TaskTool } from "@/tool/task"
 import type { QuestionTool } from "@/tool/question"
 import type { SkillTool } from "@/tool/skill"
@@ -1934,28 +1936,26 @@ function Grep(props: ToolProps<typeof GrepTool>) {
 
 function WebFetch(props: ToolProps<typeof WebFetchTool>) {
   return (
-    <InlineTool icon="%" pending="Fetching from the web..." complete={(props.input as any).url} part={props.part}>
-      WebFetch {(props.input as any).url}
+    <InlineTool icon="%" pending="Fetching from the web..." complete={props.input.url} part={props.part}>
+      WebFetch {props.input.url}
     </InlineTool>
   )
 }
 
-function CodeSearch(props: ToolProps<any>) {
-  const input = props.input as any
-  const metadata = props.metadata as any
+function CodeSearch(props: ToolProps<typeof CodeSearchTool>) {
+  const metadata = props.metadata as { results?: number }
   return (
-    <InlineTool icon="◇" pending="Searching code..." complete={input.query} part={props.part}>
-      Exa Code Search "{input.query}" <Show when={metadata.results}>({metadata.results} results)</Show>
+    <InlineTool icon="◇" pending="Searching code..." complete={props.input.query} part={props.part}>
+      Exa Code Search "{props.input.query}" <Show when={metadata.results}>({metadata.results} results)</Show>
     </InlineTool>
   )
 }
 
-function WebSearch(props: ToolProps<any>) {
-  const input = props.input as any
-  const metadata = props.metadata as any
+function WebSearch(props: ToolProps<typeof WebSearchTool>) {
+  const metadata = props.metadata as { numResults?: number }
   return (
-    <InlineTool icon="◈" pending="Searching web..." complete={input.query} part={props.part}>
-      Exa Web Search "{input.query}" <Show when={metadata.numResults}>({metadata.numResults} results)</Show>
+    <InlineTool icon="◈" pending="Searching web..." complete={props.input.query} part={props.part}>
+      Exa Web Search "{props.input.query}" <Show when={metadata.numResults}>({metadata.numResults} results)</Show>
     </InlineTool>
   )
 }
@@ -1979,7 +1979,9 @@ function Task(props: ToolProps<typeof TaskTool>) {
     )
   })
 
-  const current = createMemo(() => tools().findLast((x) => (x.state as any).title))
+  const current = createMemo(() =>
+    tools().findLast((x) => (x.state.status === "running" || x.state.status === "completed") && x.state.title),
+  )
 
   const isRunning = createMemo(() => props.part.state.status === "running")
 
@@ -1996,8 +1998,11 @@ function Task(props: ToolProps<typeof TaskTool>) {
 
     if (isRunning() && tools().length > 0) {
       // content[0] += ` · ${tools().length} toolcalls`
-      if (current()) content.push(`↳ ${Locale.titlecase(current()!.tool)} ${(current()!.state as any).title}`)
-      else content.push(`↳ ${tools().length} toolcalls`)
+      if (current()) {
+        const state = current()!.state
+        const title = state.status === "running" || state.status === "completed" ? state.title : undefined
+        content.push(`↳ ${Locale.titlecase(current()!.tool)} ${title}`)
+      } else content.push(`↳ ${tools().length} toolcalls`)
     }
 
     if (props.part.state.status === "completed") {

+ 1 - 1
packages/opencode/src/config/config.ts

@@ -517,7 +517,7 @@ export const layer = Layer.effect(
           if (!response.ok) {
             throw new Error(`failed to fetch remote config from ${url}: ${response.status}`)
           }
-          const wellknown = (yield* Effect.promise(() => response.json())) as any
+          const wellknown = (yield* Effect.promise(() => response.json())) as { config?: Record<string, unknown> }
           const remoteConfig = wellknown.config ?? {}
           if (!remoteConfig.$schema) remoteConfig.$schema = "https://opencode.ai/config.json"
           const source = `${url}/.well-known/opencode`

+ 5 - 3
packages/opencode/src/lsp/server.ts

@@ -611,7 +611,9 @@ export const Zls: Info = {
         return
       }
 
-      const release = (await releaseResponse.json()) as any
+      const release = (await releaseResponse.json()) as {
+        assets?: { name?: string; browser_download_url?: string }[]
+      }
 
       const platform = process.platform
       const arch = process.arch
@@ -646,8 +648,8 @@ export const Zls: Info = {
         return
       }
 
-      const asset = release.assets.find((a: any) => a.name === assetName)
-      if (!asset) {
+      const asset = release.assets?.find((a) => a.name === assetName)
+      if (!asset?.browser_download_url) {
         log.error(`Could not find asset ${assetName} in latest zls release`)
         return
       }

+ 1 - 3
packages/opencode/src/server/instance/experimental.ts

@@ -12,7 +12,6 @@ import { Config } from "../../config"
 import { ConsoleState } from "../../config/console-state"
 import { Account, AccountID, OrgID } from "../../account"
 import { AppRuntime } from "../../effect/app-runtime"
-import { zodToJsonSchema } from "zod-to-json-schema"
 import { errors } from "../error"
 import { lazy } from "../../util/lazy"
 import { Effect, Option } from "effect"
@@ -226,8 +225,7 @@ export const ExperimentalRoutes = lazy(() =>
           tools.map((t) => ({
             id: t.id,
             description: t.description,
-            // Handle both Zod schemas and plain JSON schemas
-            parameters: (t.parameters as any)?._def ? zodToJsonSchema(t.parameters as any) : t.parameters,
+            parameters: z.toJSONSchema(t.parameters),
           })),
         )
       },

+ 3 - 4
packages/opencode/src/session/prompt.ts

@@ -10,6 +10,7 @@ import { Agent } from "../agent/agent"
 import { Provider } from "../provider"
 import { ModelID, ProviderID } from "../provider/schema"
 import { type Tool as AITool, tool, jsonSchema, type ToolExecutionOptions, asSchema } from "ai"
+import type { JSONSchema7 } from "@ai-sdk/provider"
 import { SessionCompaction } from "./compaction"
 import { Bus } from "../bus"
 import { ProviderTransform } from "../provider"
@@ -407,9 +408,8 @@ NOTE: At any point in time through this workflow you should feel free to ask the
         })) {
           const schema = ProviderTransform.schema(input.model, z.toJSONSchema(item.parameters))
           tools[item.id] = tool({
-            id: item.id as any,
             description: item.description,
-            inputSchema: jsonSchema(schema as any),
+            inputSchema: jsonSchema(schema),
             execute(args, options) {
               return run.promise(
                 Effect.gen(function* () {
@@ -1827,9 +1827,8 @@ NOTE: At any point in time through this workflow you should feel free to ask the
     const { $schema: _, ...toolSchema } = input.schema
 
     return tool({
-      id: "StructuredOutput" as any,
       description: STRUCTURED_OUTPUT_DESCRIPTION,
-      inputSchema: jsonSchema(toolSchema as any),
+      inputSchema: jsonSchema(toolSchema as JSONSchema7),
       async execute(args) {
         // AI SDK validates args against inputSchema before calling execute()
         input.onSuccess(args)

+ 0 - 10
packages/opencode/test/session/structured-output.test.ts

@@ -157,16 +157,6 @@ describe("structured-output.AssistantMessage", () => {
 })
 
 describe("structured-output.createStructuredOutputTool", () => {
-  test("creates tool with correct id", () => {
-    const tool = SessionPrompt.createStructuredOutputTool({
-      schema: { type: "object", properties: { name: { type: "string" } } },
-      onSuccess: () => {},
-    })
-
-    // AI SDK tool type doesn't expose id, but we set it internally
-    expect((tool as any).id).toBe("StructuredOutput")
-  })
-
   test("creates tool with description", () => {
     const tool = SessionPrompt.createStructuredOutputTool({
       schema: { type: "object" },