Skip to content

[JS] Context not propagated to Tools when using session.chat().send() #2611

Open
@sbruhat

Description

@sbruhat

Bug Report: Context not propagated to Tools when using session.chat().send()

Description

When using Genkit's session management (ai.loadSession, ai.createSession) with a custom SessionStore and the session.chat().send() pattern for conversation turns, context provided during the chat.send() call does not seem to be propagated to the context object received by Tool functions invoked by the LLM during that turn.

Code Snippets:

  1. Tool Definition (Attempting to access context):

    // Example: ajouterPlante tool
    import { z } from 'zod';
    import { ai } from './config'; // Assuming 'ai' is initialized genkit instance
    import { getFirestore, FieldValue } from 'firebase-admin/firestore';
    const db = getFirestore();
    
    const ajouterPlante = ai.defineTool({
        name: "ajouterPlante",
        description: "Adds a plant to the user's personal garden.",
        inputSchema: z.object({ nom: z.string(), /* other fields */ }),
        outputSchema: z.string(),
      },
      async (input, { context }) => { // Destructuring context
        console.log("Tool context received:", JSON.stringify(context, null, 2));
        const userId = context?.auth?.uid; // Attempting to access userId via recommended structure
    
        if (!userId) {
          console.error("ajouterPlante tool: userId (context.auth.uid) not found!", context);
          // Returning error message instead of throwing to see LLM response
          return "Sorry, I could not identify the user to add the plant.";
        }
    
        console.log(`[${userId}] Tool ajouterPlante:`, input);
        try {
            await db.collection("users").doc(userId).collection("plantes").add({
              ...input,
              ajoutéeLe: FieldValue.serverTimestamp(),
            });
            return `Plant "${input.nom}" successfully added to your garden.`;
        } catch (toolError) {
            console.error(`[${userId}] Firestore Error in ajouterPlante:`, toolError);
            return `Sorry, I couldn't add the plant "${input.nom}" right now.`;
        }
      }
    );
  2. Chatbot Function (Calling chat.send with context):

    import { onDocumentCreated } from "firebase-functions/v2/firestore";
    import { ai, jardinAgentConfig, MyFirestoreSessionStore, db } from './config'; // Assuming these are defined/imported
    
    export const chatbot = onDocumentCreated("messages/{messageId}", async (event) => {
      const userId = event.data?.data()?.userId;
      const userMessageText = event.data?.data()?.text;
      // ... (guard clauses for invalid message) ...
      if (!userId || !userMessageText) return;
    
      const sessionId = `user_${userId}`;
      const myFirestoreStore = new MyFirestoreSessionStore(db, 'genkitSessionsJardinier');
      let session;
    
      try {
        session = await ai.loadSession(sessionId, { store: myFirestoreStore });
        if (!session) {
           const notFoundError = new Error(`Session not found`);
           (notFoundError as any).code = 5; // Simulate NOT_FOUND code
           throw notFoundError;
        }
      } catch (error) {
        if (error.code === 5) { // Check for NOT_FOUND
          session = await ai.createSession({
            id: sessionId,
            store: myFirestoreStore,
            agent: jardinAgentConfig,
          });
        } else {
          throw error; // Re-throw other errors
        }
      }
    
      if (!session) { throw new Error("Failed to load or create session"); }
    
      const chat = session.chat({ // Get chat interface
        model: jardinAgentConfig.model,
        tools: jardinAgentConfig.tools,
        system: jardinAgentConfig.system,
      });
    
      if (!chat || typeof chat.send !== 'function') { throw new Error("Invalid chat object"); }
    
      // Attempt to send message with context
      const result = await chat.send({
          message: userMessageText,
          context: {
              auth: { // Using recommended structure
                  uid: userId
              }
          }
      });
    
      const botResponseText = result?.message?.content?.[0]?.text;
      // ... (save response) ...
    
    });

Expected Behavior:

Based on the Genkit documentation regarding context propagation ("Context passed to the generate() method is available to tools called within the generation loop"), it was expected that the context object passed to chat.send() would be available within the tool function's second argument ({ context }), allowing access to context.auth.uid.

Actual Behavior:

Logs confirm that when the ajouterPlante tool is invoked by the LLM following the chat.send call, the context object received by the tool function is minimal and does not contain the auth object or userId passed to chat.send. The typical logged context is similar to:
{ metadata: undefined, context: {}, sendChunk: [Function: ...], interrupt: [Function ...] }
This results in the tool being unable to identify the user and failing. Attempts to pass context via metadata in chat.send or session.chat also failed.

Conclusion:

There appears to be an issue with context propagation to tools when using the Session -> Chat -> send -> Tool workflow in Firebase Functions (2nd Gen) with the specified Genkit beta versions. Either the documentation needs clarification on how to achieve this, or there is a bug preventing the context from being passed correctly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingjs

    Type

    No type

    Projects

    Status

    No status

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions