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
- Add a `MessageParam` (and related types like `ContentBlock`, `TextBlockParam`, etc.) to `packages/types` that mirrors the Anthropic SDK shape.
- Update `base-provider.ts`, `router-provider.ts`, and the shared transform utilities to use the internal type.
- Migrate each non-Anthropic provider to import from `@roo-code/types` instead of `@anthropic-ai/sdk`.
- 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.
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
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
Trade-offs / risks