Skip to content

[ENHANCEMENT] Decouple internal message types from @anthropic-ai/sdk #337

@edelauna

Description

@edelauna

Problem (one or two sentences)

All API providers — including OpenAI, Gemini, Bedrock, and every third-party router — import `Anthropic.Messages.MessageParam` from `@anthropic-ai/sdk` as their internal message type, even though those providers never call Anthropic's API. This creates an unnecessary coupling: any breaking change to the SDK's type definitions would cascade across all ~60 provider and integration files.

Context (who is affected and when)

Affects contributors adding or maintaining non-Anthropic providers. Every new provider must import `@anthropic-ai/sdk` just to satisfy the `createMessage` signature, even if the provider has no relationship with Anthropic. It's also confusing for new contributors who see an Anthropic import in, say, `opencode-go.ts` or `vscode-lm.ts` and reasonably wonder why.

Desired behavior (conceptual, not technical)

The codebase should define a neutral internal message type (e.g. `MessageParam` in `@roo-code/types`) that is structurally equivalent to the current Anthropic type. Non-Anthropic providers import from that internal type; only the Anthropic provider imports from `@anthropic-ai/sdk`.

Constraints / preferences

  • The internal type should be structurally compatible with `Anthropic.Messages.MessageParam` so the Anthropic provider requires no conversion.
  • The change is purely internal — no user-facing behaviour should change.
  • Ideally done incrementally (e.g. define the type first, migrate providers file-by-file) to keep PRs reviewable.

Acceptance criteria

Given a non-Anthropic provider (e.g. `opencode-go.ts`, `openrouter.ts`, `vscode-lm.ts`)
When you inspect its imports
Then `@anthropic-ai/sdk` does not appear

Given the Anthropic provider (`anthropic.ts`, `bedrock.ts`, `vertex.ts`)
When you inspect its imports
Then `@anthropic-ai/sdk` still appears (it legitimately uses the SDK)

Given the internal `MessageParam` type in `@roo-code/types`
When assigned to an `Anthropic.Messages.MessageParam`-typed variable
Then TypeScript accepts it without a cast (structural compatibility)

Proposed approach

  1. Add a `MessageParam` (and related types like `ContentBlock`, `TextBlockParam`, etc.) to `packages/types` that mirrors the Anthropic SDK shape.
  2. Update `base-provider.ts`, `router-provider.ts`, and the shared transform utilities to use the internal type.
  3. Migrate each non-Anthropic provider to import from `@roo-code/types` instead of `@anthropic-ai/sdk`.
  4. The Anthropic, Bedrock, and Vertex providers can continue importing from the SDK directly.

Trade-offs / risks

  • Maintaining the internal type means manually syncing it if Anthropic ever changes the SDK shape — though in practice these core message types are very stable.
  • ~60 files to touch; best done as a standalone refactor PR to keep it reviewable and bisectable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions