Compare commits
2 Commits
main
...
vincentkoc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
001121ee7a | ||
|
|
b2d78fa63c |
@ -412,6 +412,49 @@ describe("applyExtraParamsToAgent", () => {
|
|||||||
expect(payloads[0]).not.toHaveProperty("reasoning_effort");
|
expect(payloads[0]).not.toHaveProperty("reasoning_effort");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("removes unsupported function.strict from xAI tool payloads", () => {
|
||||||
|
const payloads: Record<string, unknown>[] = [];
|
||||||
|
const baseStreamFn: StreamFn = (_model, _context, options) => {
|
||||||
|
const payload: Record<string, unknown> = {
|
||||||
|
tools: [
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: "write",
|
||||||
|
parameters: { type: "object", properties: {} },
|
||||||
|
strict: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
options?.onPayload?.(payload, _model);
|
||||||
|
payloads.push(payload);
|
||||||
|
return {} as ReturnType<StreamFn>;
|
||||||
|
};
|
||||||
|
const agent = { streamFn: baseStreamFn };
|
||||||
|
|
||||||
|
applyExtraParamsToAgent(agent, undefined, "xai", "grok-4.1-fast");
|
||||||
|
|
||||||
|
const model = {
|
||||||
|
api: "openai-completions",
|
||||||
|
provider: "xai",
|
||||||
|
id: "grok-4.1-fast",
|
||||||
|
} as Model<"openai-completions">;
|
||||||
|
const context: Context = { messages: [] };
|
||||||
|
void agent.streamFn?.(model, context, {});
|
||||||
|
|
||||||
|
expect(payloads).toHaveLength(1);
|
||||||
|
expect(payloads[0]?.tools).toEqual([
|
||||||
|
{
|
||||||
|
type: "function",
|
||||||
|
function: {
|
||||||
|
name: "write",
|
||||||
|
parameters: { type: "object", properties: {} },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
it("injects parallel_tool_calls for openai-completions payloads when configured", () => {
|
it("injects parallel_tool_calls for openai-completions payloads when configured", () => {
|
||||||
const payload = runParallelToolCallsPayloadMutationCase({
|
const payload = runParallelToolCallsPayloadMutationCase({
|
||||||
applyProvider: "nvidia-nim",
|
applyProvider: "nvidia-nim",
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import type { SimpleStreamOptions } from "@mariozechner/pi-ai";
|
|||||||
import { streamSimple } from "@mariozechner/pi-ai";
|
import { streamSimple } from "@mariozechner/pi-ai";
|
||||||
import type { ThinkLevel } from "../../auto-reply/thinking.js";
|
import type { ThinkLevel } from "../../auto-reply/thinking.js";
|
||||||
import type { OpenClawConfig } from "../../config/config.js";
|
import type { OpenClawConfig } from "../../config/config.js";
|
||||||
|
import { isXaiProvider } from "../schema/clean-for-xai.js";
|
||||||
import {
|
import {
|
||||||
createAnthropicBetaHeadersWrapper,
|
createAnthropicBetaHeadersWrapper,
|
||||||
createAnthropicFastModeWrapper,
|
createAnthropicFastModeWrapper,
|
||||||
@ -321,6 +322,40 @@ function createParallelToolCallsWrapper(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function stripXaiStrictToolSchemas(payload: unknown): void {
|
||||||
|
if (!payload || typeof payload !== "object") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const payloadObj = payload as { tools?: unknown };
|
||||||
|
if (!Array.isArray(payloadObj.tools)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (const tool of payloadObj.tools) {
|
||||||
|
if (!tool || typeof tool !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const functionDef = (tool as { function?: unknown }).function;
|
||||||
|
if (!functionDef || typeof functionDef !== "object") {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
delete (functionDef as Record<string, unknown>).strict;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function createXaiToolSchemaWrapper(baseStreamFn: StreamFn | undefined): StreamFn {
|
||||||
|
const underlying = baseStreamFn ?? streamSimple;
|
||||||
|
return (model, context, options) => {
|
||||||
|
const originalOnPayload = options?.onPayload;
|
||||||
|
return underlying(model, context, {
|
||||||
|
...options,
|
||||||
|
onPayload: (payload) => {
|
||||||
|
stripXaiStrictToolSchemas(payload);
|
||||||
|
return originalOnPayload?.(payload, model);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply extra params (like temperature) to an agent's streamFn.
|
* Apply extra params (like temperature) to an agent's streamFn.
|
||||||
* Also adds OpenRouter app attribution headers when using the OpenRouter provider.
|
* Also adds OpenRouter app attribution headers when using the OpenRouter provider.
|
||||||
@ -437,6 +472,11 @@ export function applyExtraParamsToAgent(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isXaiProvider(provider, modelId)) {
|
||||||
|
log.debug(`removing unsupported function.strict tool fields for ${provider}/${modelId}`);
|
||||||
|
agent.streamFn = createXaiToolSchemaWrapper(agent.streamFn);
|
||||||
|
}
|
||||||
|
|
||||||
// Guard Google payloads against invalid negative thinking budgets emitted by
|
// Guard Google payloads against invalid negative thinking budgets emitted by
|
||||||
// upstream model-ID heuristics for Gemini 3.1 variants.
|
// upstream model-ID heuristics for Gemini 3.1 variants.
|
||||||
agent.streamFn = createGoogleThinkingPayloadWrapper(agent.streamFn, thinkingLevel);
|
agent.streamFn = createGoogleThinkingPayloadWrapper(agent.streamFn, thinkingLevel);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user