fix: skip tool id sanitization for openai responses
This commit is contained in:
@@ -27,6 +27,7 @@ Docs: https://docs.clawd.bot
|
|||||||
- Auto-reply: only report a model switch when session state is available. (#1465) Thanks @robbyczgw-cla.
|
- Auto-reply: only report a model switch when session state is available. (#1465) Thanks @robbyczgw-cla.
|
||||||
- Control UI: resolve local avatar URLs with basePath across injection + identity RPC. (#1457) Thanks @dlauer.
|
- Control UI: resolve local avatar URLs with basePath across injection + identity RPC. (#1457) Thanks @dlauer.
|
||||||
- Agents: surface concrete API error details instead of generic AI service errors.
|
- Agents: surface concrete API error details instead of generic AI service errors.
|
||||||
|
- Agents: avoid sanitizing tool call IDs for OpenAI responses to preserve Pi pairing.
|
||||||
- Docs: fix gog auth services example to include docs scope. (#1454) Thanks @zerone0x.
|
- Docs: fix gog auth services example to include docs scope. (#1454) Thanks @zerone0x.
|
||||||
- macOS: prefer linked channels in gateway summary to avoid false “not linked” status.
|
- macOS: prefer linked channels in gateway summary to avoid false “not linked” status.
|
||||||
|
|
||||||
|
|||||||
@@ -320,7 +320,7 @@ describe("sanitizeSessionHistory (google thinking)", () => {
|
|||||||
expect(assistant.content?.map((block) => block.type)).toEqual(["thinking"]);
|
expect(assistant.content?.map((block) => block.type)).toEqual(["thinking"]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("sanitizes tool call ids for OpenAI-compatible APIs", async () => {
|
it("sanitizes tool call ids for Google APIs", async () => {
|
||||||
const sessionManager = SessionManager.inMemory();
|
const sessionManager = SessionManager.inMemory();
|
||||||
const longId = `call_${"a".repeat(60)}`;
|
const longId = `call_${"a".repeat(60)}`;
|
||||||
const input = [
|
const input = [
|
||||||
@@ -338,17 +338,21 @@ describe("sanitizeSessionHistory (google thinking)", () => {
|
|||||||
|
|
||||||
const out = await sanitizeSessionHistory({
|
const out = await sanitizeSessionHistory({
|
||||||
messages: input,
|
messages: input,
|
||||||
modelApi: "openai-responses",
|
modelApi: "google-antigravity",
|
||||||
sessionManager,
|
sessionManager,
|
||||||
sessionId: "session:openai",
|
sessionId: "session:google",
|
||||||
});
|
});
|
||||||
|
|
||||||
const assistant = out[0] as Extract<AgentMessage, { role: "assistant" }>;
|
const assistant = out.find(
|
||||||
|
(msg) => (msg as { role?: unknown }).role === "assistant",
|
||||||
|
) as Extract<AgentMessage, { role: "assistant" }>;
|
||||||
const toolCall = assistant.content?.[0] as { id?: string };
|
const toolCall = assistant.content?.[0] as { id?: string };
|
||||||
expect(toolCall.id).toBeDefined();
|
expect(toolCall.id).toBeDefined();
|
||||||
expect(toolCall.id?.length).toBeLessThanOrEqual(40);
|
expect(toolCall.id?.length).toBeLessThanOrEqual(40);
|
||||||
|
|
||||||
const toolResult = out[1] as Extract<AgentMessage, { role: "toolResult" }>;
|
const toolResult = out.find(
|
||||||
|
(msg) => (msg as { role?: unknown }).role === "toolResult",
|
||||||
|
) as Extract<AgentMessage, { role: "toolResult" }>;
|
||||||
expect(toolResult.toolCallId).toBe(toolCall.id);
|
expect(toolResult.toolCallId).toBe(toolCall.id);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ describe("sanitizeSessionHistory", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("does not sanitize tool call ids for non-Google, non-OpenAI APIs", async () => {
|
it("does not sanitize tool call ids for non-Google APIs", async () => {
|
||||||
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
||||||
|
|
||||||
await sanitizeSessionHistory({
|
await sanitizeSessionHistory({
|
||||||
@@ -92,6 +92,25 @@ describe("sanitizeSessionHistory", () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("does not sanitize tool call ids for openai-responses", async () => {
|
||||||
|
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
||||||
|
|
||||||
|
await sanitizeSessionHistory({
|
||||||
|
messages: mockMessages,
|
||||||
|
modelApi: "openai-responses",
|
||||||
|
provider: "openai",
|
||||||
|
sessionManager: mockSessionManager,
|
||||||
|
sessionId: "test-session",
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(helpers.isGoogleModelApi).toHaveBeenCalledWith("openai-responses");
|
||||||
|
expect(helpers.sanitizeSessionMessagesImages).toHaveBeenCalledWith(
|
||||||
|
mockMessages,
|
||||||
|
"session:history",
|
||||||
|
expect.objectContaining({ sanitizeToolCallIds: false }),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it("keeps reasoning-only assistant messages for openai-responses", async () => {
|
it("keeps reasoning-only assistant messages for openai-responses", async () => {
|
||||||
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
vi.mocked(helpers.isGoogleModelApi).mockReturnValue(false);
|
||||||
|
|
||||||
|
|||||||
@@ -40,12 +40,6 @@ const GOOGLE_SCHEMA_UNSUPPORTED_KEYWORDS = new Set([
|
|||||||
"minProperties",
|
"minProperties",
|
||||||
"maxProperties",
|
"maxProperties",
|
||||||
]);
|
]);
|
||||||
const OPENAI_TOOL_CALL_ID_APIS = new Set([
|
|
||||||
"openai",
|
|
||||||
"openai-completions",
|
|
||||||
"openai-responses",
|
|
||||||
"openai-codex-responses",
|
|
||||||
]);
|
|
||||||
const MISTRAL_MODEL_HINTS = [
|
const MISTRAL_MODEL_HINTS = [
|
||||||
"mistral",
|
"mistral",
|
||||||
"mixtral",
|
"mixtral",
|
||||||
@@ -67,7 +61,7 @@ function isValidAntigravitySignature(value: unknown): value is string {
|
|||||||
|
|
||||||
function shouldSanitizeToolCallIds(modelApi?: string | null): boolean {
|
function shouldSanitizeToolCallIds(modelApi?: string | null): boolean {
|
||||||
if (!modelApi) return false;
|
if (!modelApi) return false;
|
||||||
return isGoogleModelApi(modelApi) || OPENAI_TOOL_CALL_ID_APIS.has(modelApi);
|
return isGoogleModelApi(modelApi);
|
||||||
}
|
}
|
||||||
|
|
||||||
function isMistralModel(params: { provider?: string | null; modelId?: string | null }): boolean {
|
function isMistralModel(params: { provider?: string | null; modelId?: string | null }): boolean {
|
||||||
|
|||||||
Reference in New Issue
Block a user