From e6281ab724a958add8298b70de650913aa2680d1 Mon Sep 17 00:00:00 2001 From: Abhishek Chauhan Date: Thu, 23 Jul 2026 19:48:33 +0530 Subject: [PATCH] fix(ts-oss): forward responseFormat to Gemini in generateResponse (#6468) --- mem0-ts/src/oss/src/llms/google.ts | 9 +++++++ mem0-ts/src/oss/tests/google-llm.test.ts | 31 ++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/mem0-ts/src/oss/src/llms/google.ts b/mem0-ts/src/oss/src/llms/google.ts index 6c8eb3e64..ecab15ef1 100644 --- a/mem0-ts/src/oss/src/llms/google.ts +++ b/mem0-ts/src/oss/src/llms/google.ts @@ -59,6 +59,15 @@ export class GoogleLLM implements LLM { ]; } + // Honor a requested JSON response format (parity with the Python SDK's + // mem0/llms/gemini.py). Gemini's structured output is opt-in via + // responseMimeType — without it the model is never told to emit JSON, so + // callers passing json_object silently get free-form text and depend on a + // fragile markdown-fence strip downstream. + if (responseFormat?.type === "json_object") { + config.responseMimeType = "application/json"; + } + const completion = await this.google.models.generateContent({ contents, model: this.model, diff --git a/mem0-ts/src/oss/tests/google-llm.test.ts b/mem0-ts/src/oss/tests/google-llm.test.ts index 373229665..018a94204 100644 --- a/mem0-ts/src/oss/tests/google-llm.test.ts +++ b/mem0-ts/src/oss/tests/google-llm.test.ts @@ -185,6 +185,37 @@ describe("GoogleLLM (unit)", () => { expect(response.toolCalls[1].name).toBe("add_graph_memory"); }); + // Regression: generateResponse accepted a responseFormat argument but never + // forwarded it, so Gemini was never told to emit JSON (parity with the Python + // SDK's mem0/llms/gemini.py, which sets response_mime_type/response_schema). + it("forwards json_object responseFormat as responseMimeType", async () => { + mockGenerateContent.mockResolvedValueOnce({ + text: '{"facts": ["fact1"]}', + functionCalls: null, + }); + + const llm = new GoogleLLM({ apiKey: "test-key" }); + await llm.generateResponse([{ role: "user", content: "Extract facts" }], { + type: "json_object", + }); + + const callArgs = mockGenerateContent.mock.calls[0][0]; + expect(callArgs.config.responseMimeType).toBe("application/json"); + }); + + it("does not set responseMimeType when no responseFormat is given", async () => { + mockGenerateContent.mockResolvedValueOnce({ + text: "plain text", + functionCalls: null, + }); + + const llm = new GoogleLLM({ apiKey: "test-key" }); + await llm.generateResponse([{ role: "user", content: "Hello" }]); + + const callArgs = mockGenerateContent.mock.calls[0][0]; + expect(callArgs.config.responseMimeType).toBeUndefined(); + }); + it("formats generateChat messages and joins Gemini response parts", async () => { mockGenerateContent.mockResolvedValueOnce({ candidates: [