Skip to content

Conversation

@shrey150
Copy link
Contributor

@shrey150 shrey150 commented Dec 19, 2025

why

what changed

test plan


Summary by cubic

Adds Deepseek chat completion support and fixes provider routing. Improves JSON-only responses, schema validation, and standardizes executionModel typing.

  • New Features

    • Implement Deepseek client and integrate into LLMProvider.
    • Add models: deepseek/deepseek-chat and deepseek/deepseek-reasoner.
  • Bug Fixes

    • Route via modelToProviderMap before AISDK fallback.
    • Clarify JSON-only response instructions and safely parse content.
    • Use toJsonSchema for Zod v3/v4 compatibility.

Written for commit 460b19c. Summary will update automatically on new commits.

JerryWu1234 and others added 11 commits November 7, 2025 16:46
# what changed
- Introduced a new `DeepseekAIClient` class for handling chat completions with the Deepseek API.
- Updated `LLMProvider` to include support for the Deepseek model, allowing it to instantiate `DeepseekAIClient` based on the model name.
- Modified the `AvailableModel` type to include "deepseek" as a valid model provider.

# test plan
- Ensure that the new client correctly handles chat completion requests and integrates seamlessly with existing LLM functionality.
…rove data extraction safety

# what changed
- Modified the instruction for JSON responses to clarify that the response must be in JSON format.
- Added optional chaining to safely access the message content in the response, preventing potential runtime errors.

# test plan
- Verify that the updated JSON response instructions are correctly interpreted by the client.
- Ensure that the optional chaining prevents errors when the message content is undefined.
…appings

# what changed
- Updated the LLMProvider constructor to accept a `manual` boolean option.
- Adjusted the logic in `getModelProvider` to conditionally handle model names based on the `manual` flag.
- Removed deprecated Deepseek model entries and added support for "deepseek/deepseek-reasoner" in the AvailableModel type.
- Introduced a new `manual` option in the V3Options interface.

# test plan
- Verify that the LLMProvider correctly initializes with the manual option.
- Ensure that model provider mappings function as expected with the new logic.
- Test the integration of the new "deepseek/deepseek-reasoner" model.
# what changed
- Added an optional `manual` parameter to the V3Evaluator class constructor.
- Updated the LLMProvider constructor to accept a `manual` boolean option, allowing for more flexible model handling.
- Adjusted the logic in the getClient method to utilize the new manual parameter.

# test plan
- Verify that the V3Evaluator initializes correctly with the manual option.
- Ensure that the LLMProvider functions as expected with the manual flag.
# what changed
- Added spaces in catch blocks for consistency.
- Introduced optional chaining for the manual option in LLMProvider initialization.
- Minor formatting adjustments to enhance readability.

# test plan
- Ensure that the V3 class functions correctly with the updated formatting and optional chaining.
# Conflicts:
#	packages/core/package.json
@changeset-bot
Copy link

changeset-bot bot commented Dec 19, 2025

🦋 Changeset detected

Latest commit: 460b19c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@browserbasehq/stagehand Patch
@browserbasehq/stagehand-evals Patch
@browserbasehq/stagehand-server Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

- Use .filter() with type guards instead of .map().join() for message formatting
- Remove duplicate requestId logging from response to match OpenAI
- Maintains type safety and consistency across LLM clients
The manual flag was a workaround for the routing bug where deepseek models
bypassed DeepseekAIClient. Since we fixed the routing by checking
modelToProviderMap first, the manual flag is no longer needed.
Completes removal of unused manual flag workaround from all locations.
@shrey150 shrey150 changed the title Deepseek fix Add support for DeepSeek Dec 19, 2025
@shrey150 shrey150 marked this pull request as ready for review December 19, 2025 23:21
Copy link
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

No issues found across 12 files

Architecture diagram
sequenceDiagram
    participant Agent as V3AgentHandler
    participant Provider as LLMProvider
    participant DSClient as DeepSeekAIClient
    participant Tools as Agent Tools (Act/Extract)
    participant API as DeepSeek API

    Note over Agent,API: Scenario: Agent execution using new DeepSeek integration

    %% Initialization & Routing Phase
    Agent->>Provider: getClient("deepseek/deepseek-chat")
    
    Note right of Provider: CHANGED: Routing Fix<br/>Checks explicit map before generic "/" fallback
    
    alt Model in modelToProviderMap (NEW)
        Provider->>DSClient: NEW: Instantiate DeepSeekAIClient
        DSClient-->>Provider: Client Instance
    else Generic Model (e.g. custom/other)
        Provider->>Provider: Use generic AI SDK fallback
    end
    
    Provider-->>Agent: Return LLMClient

    %% Execution Phase
    loop Agent Step
        Agent->>Tools: Initialize Tool (e.g., act, extract)
        Note right of Agent: CHANGED: executionModel passed as<br/>ModelConfiguration object (was string)
        
        Agent->>DSClient: createChatCompletion(messages, schema)
        
        opt Schema Validation (NEW)
            DSClient->>DSClient: Convert Zod to JSON Schema
            Note right of DSClient: Ensures compatibility with<br/>DeepSeek JSON mode
        end

        DSClient->>API: POST /chat/completions
        API-->>DSClient: 200 OK (JSON string)

        DSClient->>DSClient: NEW: Safe JSON Parse & Validation
        
        DSClient-->>Agent: Structured Response
    end
Loading

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Dec 19, 2025

Greptile Summary

This PR adds DeepSeek chat completion support by implementing DeepSeekAIClient and integrating it into the LLM provider system. The implementation also standardizes executionModel typing across agent tools from string to ModelConfiguration.

Key Changes:

  • Implemented DeepSeekAIClient following the OpenAI client pattern with support for JSON mode responses
  • Fixed provider routing in LLMProvider.getClient() to check modelToProviderMap before falling back to AI SDK
  • Added deepseek/deepseek-chat and deepseek/deepseek-reasoner models to type definitions
  • Standardized executionModel parameter type from string to ModelConfiguration across all agent tools and handlers
  • Improved JSON schema instructions for response models using toJsonSchema() helper for Zod v3/v4 compatibility

Issues Found:

  • Missing error handling for JSON.parse() at DeepSeekAIClient:274 - could throw unhandled exception if API returns malformed JSON

Confidence Score: 4/5

  • This PR is safe to merge with one minor fix needed for error handling.
  • The implementation follows established patterns from other LLM clients and the type system improvements are sound. However, there's one logical error where JSON.parse is called without error handling, which could cause runtime crashes if DeepSeek returns malformed JSON. This is critical enough to fix before merging since it affects production stability.
  • Fix error handling in packages/core/lib/v3/llm/DeepSeekAIClient.ts at line 274 before merging

Important Files Changed

Filename Overview
packages/core/lib/v3/llm/DeepSeekAIClient.ts New DeepSeek client implementation following OpenAI pattern. Missing error handling for JSON.parse at line 274.
packages/core/lib/v3/llm/LLMProvider.ts Correctly integrates DeepSeek provider with proper routing logic via modelToProviderMap before falling back to AISDK.
packages/core/lib/v3/types/public/model.ts Added DeepSeek models to type definitions and ModelConfiguration type for better type safety.
packages/core/lib/v3/agent/tools/index.ts Updated interface to accept ModelConfiguration instead of string for executionModel.
packages/core/lib/v3/v3.ts Simplified executionModel passing to handler by directly passing the ModelConfiguration object.

Sequence Diagram

sequenceDiagram
    participant User
    participant V3
    participant LLMProvider
    participant DeepSeekAIClient
    participant OpenAI SDK
    participant DeepSeek API
    participant AISDK

    User->>V3: agent({ model: "deepseek/deepseek-chat" })
    V3->>LLMProvider: getClient("deepseek/deepseek-chat")
    
    Note over LLMProvider: Check modelToProviderMap
    LLMProvider->>LLMProvider: Find provider = "deepseek"
    
    LLMProvider->>DeepSeekAIClient: new DeepSeekAIClient()
    DeepSeekAIClient->>OpenAI SDK: new OpenAI({ baseURL: "https://api.deepseek.com/v1" })
    LLMProvider-->>V3: Return DeepSeekAIClient
    
    V3->>DeepSeekAIClient: createChatCompletion()
    
    alt With response_model (JSON mode)
        DeepSeekAIClient->>DeepSeekAIClient: Add JSON schema instructions
        DeepSeekAIClient->>DeepSeekAIClient: Set response_format: { type: "json_object" }
    end
    
    DeepSeekAIClient->>OpenAI SDK: chat.completions.create()
    OpenAI SDK->>DeepSeek API: POST /v1/chat/completions
    DeepSeek API-->>OpenAI SDK: Response
    OpenAI SDK-->>DeepSeekAIClient: Response
    
    alt With response_model
        DeepSeekAIClient->>DeepSeekAIClient: JSON.parse(content)
        DeepSeekAIClient->>DeepSeekAIClient: validateZodSchema()
        alt Validation fails
            DeepSeekAIClient->>DeepSeekAIClient: Retry with retries-1
        end
    end
    
    DeepSeekAIClient-->>V3: Return response
    V3-->>User: Agent execution result
    
    Note over V3,AISDK: For AI SDK integration (e.g., streamText)
    User->>V3: Use AI SDK methods
    V3->>DeepSeekAIClient: getLanguageModel()
    DeepSeekAIClient->>AISDK: createDeepSeek({ apiKey })
    AISDK-->>DeepSeekAIClient: DeepSeek provider
    DeepSeekAIClient-->>V3: LanguageModelV2
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

10 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

throw new CreateChatCompletionResponseError(errorMessage);
}

const parsedData = JSON.parse(extractedData);
Copy link
Contributor

Choose a reason for hiding this comment

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

logic: JSON.parse can throw an error if the response is malformed. Wrap in try-catch to handle gracefully (see GoogleClient:364-373 for reference pattern)

Suggested change
const parsedData = JSON.parse(extractedData);
let parsedData;
try {
parsedData = JSON.parse(extractedData);
} catch (e) {
logger({
category: "deepseek",
message: `Failed to parse JSON response: ${e.message}`,
level: 0,
});
if (retries > 0) {
return this.createChatCompletion({
options: options as ChatCompletionOptions,
logger,
retries: retries - 1,
});
}
throw new CreateChatCompletionResponseError("Failed to parse JSON response");
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/core/lib/v3/llm/DeepSeekAIClient.ts
Line: 274:274

Comment:
**logic:** `JSON.parse` can throw an error if the response is malformed. Wrap in try-catch to handle gracefully (see GoogleClient:364-373 for reference pattern)

```suggestion
      let parsedData;
      try {
        parsedData = JSON.parse(extractedData);
      } catch (e) {
        logger({
          category: "deepseek",
          message: `Failed to parse JSON response: ${e.message}`,
          level: 0,
        });
        if (retries > 0) {
          return this.createChatCompletion({
            options: options as ChatCompletionOptions,
            logger,
            retries: retries - 1,
          });
        }
        throw new CreateChatCompletionResponseError("Failed to parse JSON response");
      }
```

How can I resolve this? If you propose a fix, please make it concise.

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.

3 participants