Skip to content

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

Merged
kitlangton merged 2 commits intodevfrom
kit/remove-as-any-3
Apr 16, 2026
Merged

fix: remove 10 more unnecessary as any casts in opencode core#22882
kitlangton merged 2 commits intodevfrom
kit/remove-as-any-3

Conversation

@kitlangton
Copy link
Copy Markdown
Contributor

Summary

Follow-up to #22877. Removes 10 more as any casts from packages/opencode/src/.

Changes

  • session/prompt.ts — the id: ... as any inside tool({...}) was bogus. The id field on the AI SDK Tool type only exists for type: 'provider' tools (with a ${string}.${string} template literal format); for user-defined tools you register them under an id key on the outer tools object, not inside the tool itself. Dropping those fields removes 2 casts. The inputSchema: jsonSchema(... as any) casts were unnecessary: the ProviderTransform.schema(...) call already returns JSONSchema7 (removing 1 cast), and the other site now imports JSONSchema7 from @ai-sdk/provider instead of widening to any.
  • server/instance/experimental.ts — replace zodToJsonSchema (from zod-to-json-schema, which expects the zod v3 ZodSchema<any>) with z.toJSONSchema from the existing zod v4 import. This kills the (t.parameters as any)?._def ? zodToJsonSchema(t.parameters as any) : t.parameters dead fallback — every Tool.Def.parameters is a z.ZodType by construction, so the "is this a Zod schema?" branch was unreachable.
  • config/config.ts — inline { config?: Record<string, unknown> } for the .well-known/opencode JSON response.
  • lsp/server.ts — inline { assets?: { name?: string; browser_download_url?: string }[] } for the GitHub releases response (matching the existing shape used further down in the same file at line 1580). Tightens the release.assets.find((a: any) => ...) callback to drop its own a: any and adds a browser_download_url presence check before use.
  • cli/cmd/tui/routes/session/index.tsx:
    • WebFetch — remove 2 casts by accessing props.input.url directly (ToolProps<typeof WebFetchTool> already gives us the shape).
    • CodeSearch / WebSearch — change ToolProps<any> to ToolProps<typeof CodeSearchTool> / ToolProps<typeof WebSearchTool> so props.input.query is typed. The metadata casts are retained but narrowed from any to { results?: number } / { numResults?: number } (true type would require touching the tool metadata schemas — deferred).
    • Task — narrow x.state.title access via the status === "running" || status === "completed" discriminant (Pending/Error states don't have title).

Remaining

~15 as any casts still in packages/opencode/src/, all at genuine type boundaries or dynamic dispatch sites:

  • plugin/plugin.ts (3) — dynamic hook dispatch (internal bus payload ↔ SDK Event, plugin config type mismatch)
  • lsp/client.ts (2) — Node child process stream ↔ vscode-languageserver-protocol stream
  • util/filesystem.ts (1) — DOM ↔ Node ReadableStream bridge
  • util/effect-zod.ts (1) — symbol key on interface with only string index signature
  • provider/provider.ts (1) — internal Auth.Info ↔ plugin SDK Auth
  • tool/registry.ts (1) — plugin args boundary (runtime-validated unknown ↔ user-defined Zod shape)
  • cli/cmd/tui/routes/session/index.tsx (1) — SolidJS <Dynamic> component/props inference

Verification

  • bun turbo typecheck passes (all 13 tasks).
  • bun run lint passes (oxlint warnings only, no errors).
  • bun test test/session/structured-output-integration.test.ts passes (checks the createStructuredOutputTool path).

- session/prompt.ts: drop the bogus `id: ... as any` from tool() calls (id is only for type: 'provider' tools); use jsonSchema(schema) and jsonSchema(toolSchema as JSONSchema7) directly
- server/instance/experimental.ts: replace zodToJsonSchema (zod v3) with z.toJSONSchema from the existing zod v4 import; drop the dead zod-detection branch
- config/config.ts: inline { config?: Record<string, unknown> } shape for well-known response
- lsp/server.ts: inline { assets?: {...}[] } shape for GitHub release API; tighten the find callback to remove a stray `a: any` and check browser_download_url before use
- cli/cmd/tui/routes/session/index.tsx: type CodeSearch/WebSearch with their proper tool types; type WebFetch input.url directly; narrow Task's state.title access via status discriminant
The test was asserting `tool.id === "StructuredOutput"` on an internal
implementation detail. The AI SDK's user-defined tool type has no `id`
field (that field only exists on `type: 'provider'` tools). Tools are
registered under their key on the outer `tools` object, not via an
inner `id`, so the field was ornamental and unread.

The previous `id: ... as any` cast was papering over this \u2014 dropping
both the cast and the assertion aligns the test with the AI SDK's
actual contract.
@kitlangton kitlangton merged commit 1c33b86 into dev Apr 16, 2026
10 checks passed
@kitlangton kitlangton deleted the kit/remove-as-any-3 branch April 16, 2026 20:11
xywsxp pushed a commit to xywsxp/opencode that referenced this pull request Apr 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant