mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-11 18:43:43 +00:00
fix(tools): strip xAI-unsupported JSON Schema keywords from tool definitions
xAI rejects minLength, maxLength, minItems, maxItems, minContains, and maxContains in tool schemas with a 502 error instead of ignoring them. This causes all requests to fail when any tool definition includes these validation-constraint keywords (e.g. sessions_spawn uses maxLength and maxItems on its attachment fields). Add stripXaiUnsupportedKeywords() in schema/clean-for-xai.ts, mirroring the existing cleanSchemaForGemini() pattern. Apply it in normalizeToolParameters() when the provider is xai directly, or openrouter with an x-ai/* model id. Fixes tool calls for x-ai/grok-* models both direct and via OpenRouter.
This commit is contained in:
committed by
Peter Steinberger
parent
da05395c2a
commit
00347bda75
@@ -1,5 +1,6 @@
|
||||
import type { AnyAgentTool } from "./pi-tools.types.js";
|
||||
import { cleanSchemaForGemini } from "./schema/clean-for-gemini.js";
|
||||
import { isXaiProvider, stripXaiUnsupportedKeywords } from "./schema/clean-for-xai.js";
|
||||
|
||||
function extractEnumValues(schema: unknown): unknown[] | undefined {
|
||||
if (!schema || typeof schema !== "object") {
|
||||
@@ -64,7 +65,7 @@ function mergePropertySchemas(existing: unknown, incoming: unknown): unknown {
|
||||
|
||||
export function normalizeToolParameters(
|
||||
tool: AnyAgentTool,
|
||||
options?: { modelProvider?: string },
|
||||
options?: { modelProvider?: string; modelId?: string },
|
||||
): AnyAgentTool {
|
||||
const schema =
|
||||
tool.parameters && typeof tool.parameters === "object"
|
||||
@@ -79,6 +80,7 @@ export function normalizeToolParameters(
|
||||
// - OpenAI rejects function tool schemas unless the *top-level* is `type: "object"`.
|
||||
// (TypeBox root unions compile to `{ anyOf: [...] }` without `type`).
|
||||
// - Anthropic expects full JSON Schema draft 2020-12 compliance.
|
||||
// - xAI rejects validation-constraint keywords (minLength, maxLength, etc.) outright.
|
||||
//
|
||||
// Normalize once here so callers can always pass `tools` through unchanged.
|
||||
|
||||
@@ -86,13 +88,24 @@ export function normalizeToolParameters(
|
||||
options?.modelProvider?.toLowerCase().includes("google") ||
|
||||
options?.modelProvider?.toLowerCase().includes("gemini");
|
||||
const isAnthropicProvider = options?.modelProvider?.toLowerCase().includes("anthropic");
|
||||
const isXai = isXaiProvider(options?.modelProvider, options?.modelId);
|
||||
|
||||
function applyProviderCleaning(s: unknown): unknown {
|
||||
if (isGeminiProvider && !isAnthropicProvider) {
|
||||
return cleanSchemaForGemini(s);
|
||||
}
|
||||
if (isXai) {
|
||||
return stripXaiUnsupportedKeywords(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// If schema already has type + properties (no top-level anyOf to merge),
|
||||
// clean it for Gemini compatibility (but only if using Gemini, not Anthropic)
|
||||
// clean it for Gemini/xAI compatibility as appropriate.
|
||||
if ("type" in schema && "properties" in schema && !Array.isArray(schema.anyOf)) {
|
||||
return {
|
||||
...tool,
|
||||
parameters: isGeminiProvider && !isAnthropicProvider ? cleanSchemaForGemini(schema) : schema,
|
||||
parameters: applyProviderCleaning(schema),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -107,10 +120,7 @@ export function normalizeToolParameters(
|
||||
const schemaWithType = { ...schema, type: "object" };
|
||||
return {
|
||||
...tool,
|
||||
parameters:
|
||||
isGeminiProvider && !isAnthropicProvider
|
||||
? cleanSchemaForGemini(schemaWithType)
|
||||
: schemaWithType,
|
||||
parameters: applyProviderCleaning(schemaWithType),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -184,10 +194,7 @@ export function normalizeToolParameters(
|
||||
// - OpenAI rejects schemas without top-level `type: "object"`.
|
||||
// - Anthropic accepts proper JSON Schema with constraints.
|
||||
// Merging properties preserves useful enums like `action` while keeping schemas portable.
|
||||
parameters:
|
||||
isGeminiProvider && !isAnthropicProvider
|
||||
? cleanSchemaForGemini(flattenedSchema)
|
||||
: flattenedSchema,
|
||||
parameters: applyProviderCleaning(flattenedSchema),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user