Skip to content

Conversation

@DeJeune
Copy link
Collaborator

@DeJeune DeJeune commented Nov 27, 2025

CheckList

Provider isSupported Screenshot
OpenAICompatible Yes image
Anthropic Yes image
AnthropicCompatible Yes image
OpenAI Yes image
Gemini Yes image
Gemini 3 Pro Yes image
OpenRouter Yes image
OpenRouter-Gemini 3 Pro Yes image
Copilot No Cell
Azure OpenAI No Plan image

Summary

This PR implements a Proxy API Server that exposes Cherry Studio's configured AI providers as an Anthropic-compatible API endpoint. This allows external tools and applications to use any AI provider configured in Cherry Studio through a standardized Anthropic Messages API.

image

Key Features

  • Provider API host formatting utilities to handle differences between Cherry Studio and AI SDK
  • Support for all AI SDK providers including OpenAI, Anthropic, Google Gemini, Azure OpenAI, Vertex AI, Amazon Bedrock, OpenRouter, DeepSeek, xAI (Grok), and more
  • AI SDK configuration utilities for converting Cherry Studio providers to AI SDK configurations
  • Streaming and non-streaming message generation using the unified AI SDK pipeline
  • Tool calling support with proper Anthropic format conversion

What this PR does

Before this PR:

  • Cherry Studio's AI providers are only accessible through the app's internal chat interface
  • Users cannot use their configured providers with external tools (like Claude Code, Cursor, or custom scripts)
  • Each provider requires different API endpoints and authentication methods

After this PR:

  • Any AI provider configured in Cherry Studio can be accessed via a local Anthropic-compatible API
  • External tools can connect to http://localhost:<port>/v1/messages and use any provider
  • Model format: <provider-id>:<model-id> (e.g., my-openai:gpt-4o, gemini:gemini-2.0-flash)
  • Supports streaming responses, tool calling, and multi-turn conversations

Why we need it and why it was done in this way

User Scenario:
Developers and power users who want to use their existing Cherry Studio provider configurations with external AI tools (Claude Code, Cursor, Continue, custom scripts, etc.) without re-configuring API keys in multiple places.

Feature Value:

  1. Single source of truth - Configure providers once in Cherry Studio, use everywhere
  2. Cost management - Use cheaper providers through a standard interface
  3. Privacy - Keep API keys in one secure location (Cherry Studio)
  4. Flexibility - Switch providers without changing external tool configurations

Implementation Approach:

  • Uses Vercel AI SDK for unified provider handling
  • Converts between Anthropic Messages API format and AI SDK format
  • Leverages existing Cherry Studio provider configurations from Redux store
  • Shares provider resolution logic with the renderer process for consistency

Tradeoffs:

  • Added complexity in message format conversion
  • Some provider-specific features may not be fully supported through the unified API

Alternatives Considered:

  • OpenAI-compatible API: Chosen Anthropic format because it has better tool calling support and is more expressive
  • Direct provider passthrough: Would require implementing each provider's API separately

Breaking changes

None. This is a new feature that doesn't affect existing functionality.

Special notes for your reviewer

  1. The Proxy API Server is opt-in and must be enabled in settings
  2. All enabled providers in Cherry Studio are available through the API
  3. Token counting is estimated (approximately 4 chars per token for English)

Checklist

Release note

feat: Add Proxy API Server - expose Cherry Studio providers as Anthropic-compatible API for use with external tools

- Added provider API host formatting utilities to handle differences between Cherry Studio and AI SDK.
- Introduced functions for formatting provider API hosts, including support for Azure OpenAI and Vertex AI.
- Created a simple API key rotator for managing API key rotation.
- Developed shared provider initialization and mapping utilities for resolving provider IDs.
- Implemented AI SDK configuration utilities for converting Cherry Studio providers to AI SDK configurations.
- Added support for various providers including OpenRouter, Google Vertex AI, and Amazon Bedrock.
- Enhanced error handling and logging in the unified messages service for better debugging.
- Introduced functions for streaming and generating unified messages using AI SDK.
@DeJeune DeJeune marked this pull request as draft November 27, 2025 07:31
@DeJeune DeJeune marked this pull request as ready for review November 27, 2025 13:13
@DeJeune DeJeune requested a review from 0xfullex as a code owner November 27, 2025 13:13
@DeJeune DeJeune added this to the v1.7.1 milestone Nov 27, 2025
Copy link
Collaborator

@0xfullex 0xfullex left a comment

Choose a reason for hiding this comment

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

Note

This review was translated by Claude.

PR Review Summary

Thank you for submitting this PR. After careful review, I found some issues that need to be fixed, including several critical bugs that would cause core functionality to not work.


❓ Need Additional Explanation

Please provide a detailed description of the problem this PR solves:

  1. User Scenario: Who is the target audience for this Proxy API Server? What problems are they encountering?
  2. Feature Value: Why do we need to expose any AI provider as an Anthropic-compatible API? What are the specific use cases?
  3. Relationship with Existing Features: How does this feature differ from Cherry Studio's existing API Server? Is it a supplement or a replacement?
  4. Breaking Changes: Will this PR affect existing users' experience?

The following parts of the PR template need to be filled:

  • "Before this PR" / "After this PR"
  • "Why we need it and why it was done in this way"
  • "Fixes #" (if there are related issues)

🔴 Critical Issues (Must Fix)

1. Tool result content is cleared

Location: `src/main/apiServer/services/unified-messages.ts:187-190`

```typescript
// After the values array is correctly populated...
return {
type: 'content',
value: [] // ❌ Should be value: values
}
```

The `values` array is built but never used, causing all tool_result content to be lost. This would completely break the tool calling chain.

2. Pure tool_result messages generate empty user messages

Location: `src/main/apiServer/services/unified-messages.ts:308-327`

When messages only contain `tool_result`, the code first pushes a `role: 'tool'` message, then unconditionally continues to push a `role: 'user'` message, where both `textParts` and `imageParts` are empty arrays:

```typescript
messages.push({
role: 'user',
content: [...textParts, ...imageParts] // Empty array []
})
```

AI SDK/models usually reject empty messages, causing the tool chain to break.

3. Provider filtering contradicts feature declaration

Location: `src/main/apiServer/utils/index.ts:32-34`

```typescript
const supportedProviders = providers.filter(
(p: Provider) => p.enabled && (p.type === 'openai' || p.type === 'anthropic')
)
```

The PR description claims to support "any AI provider supported by AI SDK", but the code only allows `openai` and `anthropic` types. Providers like gemini/vertexai/bedrock cannot be used, which contradicts the claimed functionality.


⚠️ Important Issues

4. Missing test coverage

About 1500 lines of new code in `packages/shared/` have no unit tests:

  • `AiSdkToAnthropicSSE.ts` (649 lines)
  • `sdk-config.ts` (240 lines)
  • `api/index.ts` (177 lines)

It's recommended to add at least tests for core conversion logic.

5. Duplicate code

The `/count_tokens` endpoint has two nearly identical implementations in router and providerRouter (`messages.ts:568-715`). Consider extracting shared logic.

6. Token estimation is too simple

```typescript
// ~4 characters per token for English text
const estimatedTokens = Math.ceil(totalChars / 4) + messages.length * 3
```
Estimation is inaccurate for non-English text (like Chinese), and doesn't handle tool token counting.


📝 Minor Suggestions

  1. Type Safety: `AiSdkToAnthropicSSE.ts:180` uses `as any`, consider improving type definitions
  2. Hardcoded Values: There are hardcoded `APP-Code` and API hosts in `aihubmix.ts`

Summary

Please:

  1. Complete the PR description, explaining the feature's purpose and use cases
  2. Fix Critical Issues, especially tool calling related bugs
  3. Add tests, at least covering core conversion logic
  4. Run `yarn build:check` to ensure everything passes

🤖 Review by Claude Code

- Fix tool result content bug: return `values` array instead of empty array
- Fix empty message bug: skip pushing user/assistant messages when content is empty
- Expand provider support: remove type restrictions to support all AI SDK providers
- Add missing alias for @cherrystudio/ai-sdk-provider in main process config

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@DeJeune DeJeune requested a review from 0xfullex November 27, 2025 14:31
DeJeune and others added 3 commits November 27, 2025 22:41
Extract duplicated token estimation code from both count_tokens endpoints
into a shared `estimateTokenCount` function to improve maintainability.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
@beyondkmp

This comment was marked as resolved.

… cache service

- Deleted the old ReasoningCache class and its instance.
- Introduced CacheService for managing reasoning caches.
- Updated unified-messages service to utilize new googleReasoningCache and openRouterReasoningCache.
- Added AiSdkToAnthropicSSE adapter to handle streaming events and integrate with new cache service.
- Reorganized shared adapters to include the new AiSdkToAnthropicSSE adapter.
- Created openrouter adapter with detailed reasoning schemas for better type safety and validation.
Copilot AI review requested due to automatic review settings December 4, 2025 13:39
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR implements a comprehensive Proxy API Server that exposes Cherry Studio's configured AI providers through an Anthropic-compatible API endpoint. This enables external tools like Claude Code and Cursor to use any AI provider configured in Cherry Studio via a standardized interface.

Key Changes:

  • Extracted shared provider utilities to packages/shared for code reuse between renderer and main processes
  • Implemented AiSdkToAnthropicSSE adapter to convert AI SDK responses to Anthropic SSE format
  • Created unified message processing service supporting both streaming and non-streaming modes
  • Added support for PPIO provider's Anthropic-compatible models
  • Enhanced Claude Code integration to work with any provider via the unified adapter

Reviewed changes

Copilot reviewed 64 out of 65 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
packages/shared/provider/* Shared provider utilities for detection, mapping, formatting, and SDK configuration
packages/shared/middleware/* Shared AI SDK middlewares (Gemini thought signature, OpenRouter reasoning)
packages/shared/api/* Shared API URL formatting and validation utilities
packages/shared/anthropic/* Enhanced Anthropic SDK utilities with sanitization
src/main/apiServer/adapters/* AI SDK to Anthropic SSE conversion adapter
src/main/apiServer/services/unified-messages.ts Core unified message processing service
src/main/apiServer/routes/messages.ts Enhanced message routing with unified processing
src/main/services/agents/services/claudecode/* Claude Code integration improvements
src/renderer/src/aiCore/provider/* Refactored to use shared utilities

No critical issues found. The implementation is well-structured with proper error handling and type safety. The code follows established patterns and includes comprehensive documentation.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +142 to +156
new TransformStream<LanguageModelV2StreamPart, LanguageModelV2StreamPart>({
transform(
chunk: LanguageModelV2StreamPart,
controller: TransformStreamDefaultController<LanguageModelV2StreamPart>
) {
if (chunk.type === 'reasoning-delta' && chunk.delta.includes(REDACTED_BLOCK)) {
controller.enqueue({
...chunk,
delta: chunk.delta.replace(REDACTED_BLOCK, '')
})
} else {
controller.enqueue(chunk)
}
}
})
Copy link

Copilot AI Dec 4, 2025

Choose a reason for hiding this comment

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

Superfluous argument passed to function TransformStream.

Copilot uses AI. Check for mistakes.
@EurFelux
Copy link
Collaborator

EurFelux commented Dec 7, 2025

[!NOTE]

This comment was translated by Claude.

If it doesn't make it for 1.7.2, we'll let #11738 into main first


Original Content

如果赶不上1.7.2,我们就先让 #11738 进main

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.

[Bug]: Cannot add other models for agent

6 participants