ai icon indicating copy to clipboard operation
ai copied to clipboard

useChat sending message to Google ADK API

Open ram4444 opened this issue 11 months ago • 3 comments

Description

I found the return body of google adk is slightly different than other AI providers' endpoints. The content contains an array of parts and the role is inside the content

[
    {
        "content": {
            "parts": [
                {
                    "text": "Okay! 😊\n\nEaster is on April 25th or 26th. Christmas is on December 25th."
                }
            ],
            "role": "model"
        },
        "partial": false,
        "invocation_id": "e-73a5d2be-d454-4696-bf7a-86b831f0f7e1",
        "author": "ollama_agent",
        "actions": {
            "state_delta": {},
            "artifact_delta": {},
            "requested_auth_configs": {}
        },
        "id": "PgjeZkgs",
        "timestamp": 1745205698.571864
    }
]

Besides, I have some troubles to put the input to the useChat as it requires a body of

body: {
      app_name: "ollama_agent",
      user_id: "u_123",
      session_id: "s_123",
      new_message: {
          role: "user",
          parts: [{
          text: input
          }]
      },
      "streaming": false
    },

I am using react native. seems the handleInputChange handleSubmit do not put the input text to the body

<TextInput
                style={{ backgroundColor: 'white', padding: 8 }}
                placeholder="Say something..."
                value={input}
                onChange={e =>
                handleInputChange({
                    ...e,
                    target: {
                    ...e.target,
                    value: e.nativeEvent.text,
                    },
                } as unknown as React.ChangeEvent<HTMLInputElement>)
                }
                onSubmitEditing={e => {
                  //console.log('Submit', e);
                  handleSubmit(e);
                e.preventDefault();
                }}
                autoFocus={true}
            />

ram4444 avatar Apr 21 '25 19:04 ram4444

it would be easier if you shared more of the code you are using so it is repoducible

bernaferrari avatar Apr 23 '25 19:04 bernaferrari

I have update the input provided to be clear. And here is my code. Ctrl+F MyNote as my current issue

import { useEffect, useRef } from "react";

import { anthropic } from "@ai-sdk/anthropic";
import { streamText } from "ai";

import { Send, X } from "lucide-react-native";
import { View, TextInput, ScrollView, Text, SafeAreaView } from 'react-native';

import { generateAPIUrl } from "../utils/ai"
import { useChat } from "@ai-sdk/react"
import { fetch as expoFetch } from 'expo/fetch';

import type { UIMessage } from "ai";

import { z } from 'zod';


function Messages({ messages }: { messages: Array<UIMessage> }) {
  const messagesContainerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (messagesContainerRef.current) {
      messagesContainerRef.current.scrollTop =
        messagesContainerRef.current.scrollHeight;
    }
  }, [messages]);

  if (!messages.length) {
    return (
      
        <Text>"Ask me anything! I'm here to help."</Text>
      
    );
  }
  console.log('MSG', messages);

  return (
    <ScrollView style={{ flex: 1 }}>
        
        
      {messages.map(m => { 
        console.log('User said', m.content);
        try {
          if (m.role === "user") {
            return(<View key={m.id} style={{ marginVertical: 8 }}>
              <View>
                <Text style={{ fontWeight: 700 }}>{m.role}</Text>
                {m.toolInvocations ? (
                    <Text>{JSON.stringify(m.toolInvocations, null, 2)}</Text>
                ) : (
                    <Text>{m.content}</Text>
                )}
              </View>
            </View>
            )
          }
        } catch (e) {
          //console.log('Error', e)
          //console.log('Model Replied:', messages)
          {m.parts.map(part => { 
            return(<View key={m.id} style={{ marginVertical: 8 }}>
            
            <View>
              <Text style={{ fontWeight: 700 }}>{m.role}</Text>
                <Text>{part.text}</Text>
                {
                  /*
                  m.toolInvocations ? (
                      <Text>{JSON.stringify(m.toolInvocations, null, 2)}</Text>
                  ) : (
                      <Text>{m.content}</Text>
                  )
                    */
                }
            </View>
            </View>
          )})}
          
        }
      })}
        
    </ScrollView>
  )
  
}

const SYSTEM_PROMPT = `You are an AI for a music store.

There are products available for purchase. You can recommend a product to the user.
You can get a list of products by using the getProducts tool.

You also have access to a fulfillment server that can be used to purchase products.
You can get a list of products by using the getInventory tool.
You can purchase a product by using the purchase tool.

After purchasing a product tell the customer they've made a great choice and their order will be processed soon and they will be playing their new guitar in no time.
`;

export default function AIAssistant() {

  const { messages, error, handleInputChange, input, handleSubmit, data } = useChat({
    initialMessages: [],
    fetch: expoFetch as unknown as typeof globalThis.fetch,
    headers: { 
      'Content-Type': 'application/json',
      Connection: 'keep-alive',
      'Accept-Encoding': 'gzip, deflate, br',
      Accept: '*/*' },
    
    body: { // MyNote: In the doc, it is called the ADDITIONAL body to be sent
      app_name: "ollama_agent",
      user_id: "u_123",
      session_id: "s_123",
      new_message: {
          role: "user",
          parts: [{
          text: input //<----it shows error here as I put variable"input" of useChat.  Even I hard code it here, the value I have put here cannot be reflected on the server side log. So if I think Google ADK can recognise the body, but the useChat is fail to put the value of TextInput below. Now My workaround is using simply fetch POST without useChat
          }]
      },
      "streaming": false
    },
    
    api: "https://adkagentapi-dev.local/run",

    onToolCall: (call) => {
        if (call.toolCall.toolName === "recommendGuitar") {
          return "Handled by the UI";
        }
    },
    onResponse: (response) => {
      console.log('Response', response);
      //console.log('data', data)
    },
    onFinish: (response) => {
      console.log('Finnish', response);
    },  //console.log('data', data)
    onError: error => {
      console.error(error, 'ERROR for message: '+ input)
      console.log('data', data);
    },
  });

  

  return (
    <>
    <SafeAreaView style={{ height: '70vh' }}>
        <View
            style={{
            height: '60%',
            display: 'flex',
            flexDirection: 'column',
            paddingHorizontal: 8,
            }}
        >
            
            <Messages messages={messages} />
            <View style={{ marginTop: 8 }}>
            <TextInput
                style={{ backgroundColor: 'white', padding: 8 }}
                placeholder="Say something..."
                value={input}
                onChange={e =>
                handleInputChange({
                    ...e,
                    target: {
                    ...e.target,
                    value: e.nativeEvent.text,
                    },
                } as unknown as React.ChangeEvent<HTMLInputElement>)
                }
                onSubmitEditing={e => {
                  //console.log('Submit', e);
                  handleSubmit(e);
                e.preventDefault();
                }}
                autoFocus={true}
            />
            </View>
            <Send />
        </View>
    </SafeAreaView>
    </>
    
    
  );
}

ram4444 avatar Apr 24 '25 01:04 ram4444

I'm also facing this issue. The key point is how to pass incompatible AI protocols to useChat.

0Chan-smc avatar Apr 24 '25 01:04 0Chan-smc

in ai sdk 5 you can set up custom chat transports and modify the api calls when messages are submitted.

lgrammel avatar Jun 26 '25 14:06 lgrammel