clanker-agent/packages/ai/test/google-tool-call-missing-args.test.ts
Harivansh Rathi 0250f72976 move pi-mono into companion-cloud as apps/companion-os
- Copy all pi-mono source into apps/companion-os/
- Update Dockerfile to COPY pre-built binary instead of downloading from GitHub Releases
- Update deploy-staging.yml to build pi from source (bun compile) before Docker build
- Add apps/companion-os/** to path triggers
- No more cross-repo dispatch needed

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-07 09:22:50 -08:00

107 lines
2.9 KiB
TypeScript

import { Type } from "@sinclair/typebox";
import { afterEach, describe, expect, it, vi } from "vitest";
import { streamGoogleGeminiCli } from "../src/providers/google-gemini-cli.js";
import type { Context, Model, ToolCall } from "../src/types.js";
const emptySchema = Type.Object({});
const originalFetch = global.fetch;
afterEach(() => {
global.fetch = originalFetch;
vi.restoreAllMocks();
});
describe("google providers tool call missing args", () => {
it("defaults arguments to empty object when provider omits args field", async () => {
// Simulate a tool call response where args is missing (no-arg tool)
const sse = `${[
`data: ${JSON.stringify({
response: {
candidates: [
{
content: {
role: "model",
parts: [
{
functionCall: {
name: "get_status",
// args intentionally omitted
},
},
],
},
finishReason: "STOP",
},
],
usageMetadata: {
promptTokenCount: 10,
candidatesTokenCount: 5,
totalTokenCount: 15,
},
},
})}`,
].join("\n\n")}\n\n`;
const encoder = new TextEncoder();
const dataStream = new ReadableStream<Uint8Array>({
start(controller) {
controller.enqueue(encoder.encode(sse));
controller.close();
},
});
const fetchMock = vi.fn(async () => {
return new Response(dataStream, {
status: 200,
headers: { "content-type": "text/event-stream" },
});
});
global.fetch = fetchMock as typeof fetch;
const model: Model<"google-gemini-cli"> = {
id: "gemini-2.5-flash",
name: "Gemini 2.5 Flash",
api: "google-gemini-cli",
provider: "google-gemini-cli",
baseUrl: "https://cloudcode-pa.googleapis.com",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 8192,
};
const context: Context = {
messages: [
{ role: "user", content: "Check status", timestamp: Date.now() },
],
tools: [
{
name: "get_status",
description: "Get current status",
parameters: emptySchema,
},
],
};
const stream = streamGoogleGeminiCli(model, context, {
apiKey: JSON.stringify({ token: "token", projectId: "project" }),
});
for await (const _ of stream) {
// consume stream
}
const result = await stream.result();
expect(result.stopReason).toBe("toolUse");
expect(result.content).toHaveLength(1);
const toolCall = result.content[0] as ToolCall;
expect(toolCall.type).toBe("toolCall");
expect(toolCall.name).toBe("get_status");
expect(toolCall.arguments).toEqual({});
});
});