Skip to content

refactor: eliminate remaining 'any' types in ai.ts#17

Open
cosmicallycooked wants to merge 1 commit into1a35e1:mainfrom
cosmicallycooked:refactor/typed-ai-vendor-responses
Open

refactor: eliminate remaining 'any' types in ai.ts#17
cosmicallycooked wants to merge 1 commit into1a35e1:mainfrom
cosmicallycooked:refactor/typed-ai-vendor-responses

Conversation

@cosmicallycooked
Copy link
Copy Markdown
Contributor

Summary

Rebased on current main (post-#11 structured outputs). Replaces every remaining any type in src/lib/ai.ts with dedicated interfaces:

  • VendorErrorBody — typed error response shape (replaces 6× (err as any))
  • OpenAIResponsesResult / OpenAIResponsesContent — Responses API output chain (replaces 8× (b: any) / (c: any))
  • OpenAIChatCompletionResult — Chat Completions choices shape
  • AnthropicMessagesResult / AnthropicContentBlock — Messages API with tool_use blocks (replaces 3× (b: any))

No logic changes, no runtime behavior changes. Zero new type errors introduced.

Test plan

  • pnpm typecheck — zero new errors (pre-existing ink-text-input and vitest module errors unchanged)
  • grep -w any src/lib/ai.ts confirms no any type annotations remain
  • Reviewed all six response-handling blocks for correct type narrowing

🤖 Generated with Claude Code

Add typed interfaces for vendor response shapes (VendorErrorBody,
OpenAIResponsesResult, OpenAIChatCompletionResult, AnthropicMessagesResult)
and replace every explicit `any` cast and annotation. No logic changes.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 9, 2026

📝 Walkthrough

Walkthrough

Changes to src/lib/ai.ts introduce TypeScript interfaces for vendor error and response payloads, replace any-based optional chaining with typed error bodies, and tighten response parsing validation for OpenAI and Anthropic API endpoints across multiple AI-related functions.

Changes

Cohort / File(s) Summary
Type Safety & Error Handling
src/lib/ai.ts
Added TypeScript interfaces for OpenAI and Anthropic error/response payloads; replaced any-based optional chaining with typed VendorErrorBody for consistent error message extraction; tightened response parsing by treating OpenAI outputs/content as structured arrays with safe defaults and stricter Anthropic tool block validation requiring toolBlock?.input.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐰 With types now clear and errors caught,
The AI calls are safer wrought,
No any shadows lurking near,
Just structured payloads, bright and clear!
The vendors talk in harmony,
A TypeScript victory! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title directly and concisely describes the main change: eliminating 'any' types in ai.ts, which aligns with the changeset's primary objective.
Description check ✅ Passed The description is directly related to the changeset, providing clear context about the refactoring work, specific interfaces introduced, and testing validation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/lib/ai.ts (1)

241-247: Add runtime shape guards before asserting toolBlock.input types.

input is still unknown at runtime; direct assertions can silently pass malformed payloads downstream. A small type-guard step would make these paths resilient without changing happy-path behavior.

♻️ Suggested hardening diff
+function isGeneratedInterest(value: unknown): value is GeneratedInterest {
+  if (!value || typeof value !== 'object') return false
+  const v = value as Partial<GeneratedInterest>
+  return (
+    typeof v.name === 'string' &&
+    typeof v.description === 'string' &&
+    Array.isArray(v.keywords) &&
+    v.keywords.every((k) => typeof k === 'string') &&
+    Array.isArray(v.relatedTopics) &&
+    v.relatedTopics.every((t) => typeof t === 'string')
+  )
+}
+
+function isGeneratedReply(value: unknown): value is GeneratedReply {
+  return !!value && typeof value === 'object' && typeof (value as { reply?: unknown }).reply === 'string'
+}
-      return toolBlock.input as GeneratedInterest
+      if (!isGeneratedInterest(toolBlock.input)) {
+        throw new Error('Anthropic tool output did not match GeneratedInterest schema')
+      }
+      return toolBlock.input
-      return toolBlock.input as GeneratedReply
+      if (!isGeneratedReply(toolBlock.input)) {
+        throw new Error('Anthropic tool output did not match GeneratedReply schema')
+      }
+      return toolBlock.input
-        const wrapper = toolBlock.input as { suggestions: GeneratedInterest[] }
-        return wrapper.suggestions
+        const wrapper = toolBlock.input as { suggestions?: unknown }
+        if (!Array.isArray(wrapper.suggestions) || !wrapper.suggestions.every(isGeneratedInterest)) {
+          throw new Error('Anthropic tool output did not include valid suggestions')
+        }
+        return wrapper.suggestions

Also applies to: 338-344, 498-505

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/ai.ts` around lines 241 - 247, The code currently asserts
toolBlock.input as GeneratedInterest without runtime validation; add a small
runtime shape guard (e.g., isGeneratedInterest or validateToolInput) that checks
required fields and types on toolBlock.input before casting, and throw a clear
Error if validation fails; update the parsing sites that reference data,
toolBlock and the cast to GeneratedInterest (the block in src/lib/ai.ts around
the return of toolBlock.input and the similar places at the other two
occurrences) to call the guard and only then return the properly-typed value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/lib/ai.ts`:
- Around line 241-247: The code currently asserts toolBlock.input as
GeneratedInterest without runtime validation; add a small runtime shape guard
(e.g., isGeneratedInterest or validateToolInput) that checks required fields and
types on toolBlock.input before casting, and throw a clear Error if validation
fails; update the parsing sites that reference data, toolBlock and the cast to
GeneratedInterest (the block in src/lib/ai.ts around the return of
toolBlock.input and the similar places at the other two occurrences) to call the
guard and only then return the properly-typed value.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9755c839-968b-444d-b8f9-c04d88f6f687

📥 Commits

Reviewing files that changed from the base of the PR and between cfb6428 and 32c547e.

📒 Files selected for processing (1)
  • src/lib/ai.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant