Roo-Code/src/api/providers/base-provider.ts
Roo Code 4e61f778fe fix: ensure JSON Schema draft 2020-12 compliance for OpenAI-compatible providers
- Update convertToolSchemaForOpenAI in base-provider.ts to use normalizeToolSchema
  which properly converts type arrays (e.g., ["string", "null"]) to anyOf format
  required by JSON Schema draft 2020-12
- Update Cerebras stripUnsupportedSchemaFields to handle anyOf/oneOf/allOf arrays
- Add comprehensive tests for base-provider convertToolSchemaForOpenAI function

Fixes #10320
2025-12-24 05:35:39 +00:00

88 lines
2.8 KiB
TypeScript

import { Anthropic } from "@anthropic-ai/sdk"
import type { ModelInfo } from "@roo-code/types"
import type { ApiHandler, ApiHandlerCreateMessageMetadata } from "../index"
import { ApiStream } from "../transform/stream"
import { countTokens } from "../../utils/countTokens"
import { isMcpTool } from "../../utils/mcp-name"
import { normalizeToolSchema } from "../../utils/json-schema"
/**
* Base class for API providers that implements common functionality.
*/
export abstract class BaseProvider implements ApiHandler {
abstract createMessage(
systemPrompt: string,
messages: Anthropic.Messages.MessageParam[],
metadata?: ApiHandlerCreateMessageMetadata,
): ApiStream
abstract getModel(): { id: string; info: ModelInfo }
/**
* Converts an array of tools to be compatible with OpenAI's strict mode.
* Filters for function tools, applies schema conversion to their parameters,
* and ensures all tools have consistent strict: true values.
*/
protected convertToolsForOpenAI(tools: any[] | undefined): any[] | undefined {
if (!tools) {
return undefined
}
return tools.map((tool) => {
if (tool.type !== "function") {
return tool
}
// MCP tools use the 'mcp--' prefix - disable strict mode for them
// to preserve optional parameters from the MCP server schema
const isMcp = isMcpTool(tool.function.name)
return {
...tool,
function: {
...tool.function,
strict: !isMcp,
parameters: isMcp
? tool.function.parameters
: this.convertToolSchemaForOpenAI(tool.function.parameters),
},
}
})
}
/**
* Converts tool schemas to be compatible with OpenAI's strict mode and
* JSON Schema draft 2020-12 by:
* - Setting additionalProperties: false for object types (strict mode requirement)
* - Converting nullable types (["type", "null"]) to anyOf format (draft 2020-12 requirement)
* - Stripping unsupported format values for OpenAI Structured Outputs compatibility
* - Recursively processing nested schemas
*
* This uses normalizeToolSchema from json-schema.ts which handles all transformations.
* Required by third-party proxies that enforce JSON Schema draft 2020-12 (e.g., Claude API proxies).
*/
protected convertToolSchemaForOpenAI(schema: any): any {
if (!schema || typeof schema !== "object") {
return schema
}
return normalizeToolSchema(schema as Record<string, unknown>)
}
/**
* Default token counting implementation using tiktoken.
* Providers can override this to use their native token counting endpoints.
*
* @param content The content to count tokens for
* @returns A promise resolving to the token count
*/
async countTokens(content: Anthropic.Messages.ContentBlockParam[]): Promise<number> {
if (content.length === 0) {
return 0
}
return countTokens(content, { useWorker: true })
}
}