Android™
Android™
Streaming AI with Manual AI Tool Function Calling
See more AI Examples
Demonstrates how to get AI responses in streaming mode, including manual tool function calls.Chilkat Android™ Downloads
// Important: Don't forget to include the call to System.loadLibrary
// as shown at the bottom of this code sample.
package com.test;
import android.app.Activity;
import com.chilkatsoft.*;
import android.widget.TextView;
import android.os.Bundle;
public class SimpleActivity extends Activity {
private static final String TAG = "Chilkat";
// Called when the activity is first created.
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
boolean success = false;
// Create the following JSON to define tool functions available for the AI to use.
// Note: You'll use the following JSON format regardless of the AI provider, whether
// it be ChatGPT, Gemini, Claude, Grok, etc. Chilkat automatically converts to the required
// format needed for a given AI provider.
// In this example, the application is providing a single function the AI may choose to call.
// {
// "tools": [
// {
// "name": "get_horoscope",
// "description": "Get today's horoscope for an astrological sign.",
// "parameters": {
// "properties": {
// "sign": {
// "type": "string",
// "description": "An astrological sign like Taurus or Aquarius"
// }
// }
// }
// }
// ]
// }
CkJsonObject jsonTools = new CkJsonObject();
int toolIdx = 0;
jsonTools.put_I(toolIdx);
jsonTools.UpdateString("tools[i].name","get_horoscope");
jsonTools.UpdateString("tools[i].description","Get today's horoscope for an astrological sign.");
jsonTools.UpdateString("tools[i].parameters.properties.sign.type","string");
jsonTools.UpdateString("tools[i].parameters.properties.sign.description","An astrological sign like Taurus or Aquarius");
// More tools can be added as desired..
jsonTools.put_EmitCompact(false);
Log.i(TAG, jsonTools.emit());
CkAi ai = new CkAi();
// Register the tools that will be made available to the AI.
ai.RegisterManualTools(jsonTools);
// The provider can be "openai", "google", "claude", "grok", "mistral", "custom", etc.
ai.put_Provider("openai");
// Use your provider's API key.
ai.put_ApiKey("MY_API_KEY");
// Choose a model.
ai.put_Model("gpt-5-mini");
// Tool function calling must always occur within a conversation.
String conversation_name = "convo_astrology";
String sysMessage = "You are a helpful astrologer";
String devMessage = "Respond only with markdown.";
ai.NewConvo(conversation_name,sysMessage,devMessage);
// Provide inputs
ai.InputAddText("What is my horoscope? I am an Aquarius.");
// Get the response in streaming mode.
ai.put_Streaming(true);
// In streaming mode, if we receive an AI event that is a request for tool use,
// we'll need to make the call to the JavaScript and then continue with a followup Ask,
// until the final response is received.
CkStringBuilder sbEventName = new CkStringBuilder();
CkStringBuilder sbDelta = new CkStringBuilder();
CkStringBuilder sbFullResponse = new CkStringBuilder();
// When PollAi returns with an event, it's highly unlikely the
// call to NextAiEvent does not immediately return. Setting a max
// timeout is just a precaution..
int maxWaitMs = 5000;
CkJsonObject jsonFn = new CkJsonObject();
boolean finished = false;
int numAsks = 0;
// Set a max # of followup Asks to prevent any unexpected infinite looping.
while (!finished and (numAsks < 10)) {
// Send the request to the AI model.
success = ai.Ask("text");
if (success == false) {
Log.i(TAG, ai.lastErrorText());
return;
}
boolean madeFunctionCalls = false;
boolean streamingDone = false;
while (!streamingDone) {
int result = ai.PollAi(false);
if (result < 0) {
Log.i(TAG, ai.lastErrorText());
Log.i(TAG, "Failed.");
return;
}
if (result > 0) {
// We have an event..
success = ai.NextAiEvent(maxWaitMs,sbEventName,sbDelta);
if (success == false) {
Log.i(TAG, ai.lastErrorText());
return;
}
// Is this an event where the AI is requesting a function call?
if (sbEventName.ContentsEqual("function_call",true)) {
jsonFn.LoadSb(sbDelta);
// Note: Chilkat will convert responses from all AI providers to this format:
// {
// "function_call": [
// {
// "name": "get_horoscope",
// "call_id": "call_RYmeysYQFocFc7Z2ofkv61dW",
// "arguments": "{\"sign\":\"Aquarius\"}",
// "args": {
// "sign": "Aquarius"
// }
// }
// ]
// }
int numFnCalls = jsonFn.SizeOfArray("function_call");
int fn_idx = 0;
while ((fn_idx < numFnCalls)) {
jsonFn.put_I(fn_idx);
CkStringBuilder sbFnName = new CkStringBuilder();
jsonFn.StringOfSb("function_call[i].name",sbFnName);
String callId = jsonFn.stringOf("function_call[i].call_id");
if (sbFnName.ContentsEqual("get_horoscope",true) == true) {
// The get_horoscope function (as defined above) has one argument named "sign".
String zodiac_sign = jsonFn.stringOf("function_call[i].args.sign");
Log.i(TAG, "zodiac_sign = " + zodiac_sign);
// Insert application code here to call your app's get_horoscope function, passing the zodiac_sign to it..
// For this example, we'll pretend the app's get_horoscope function returned the following:
String applicationFnCallResult = "Aquarius: Next Tuesday you will befriend a baby otter.";
// Provide the tool call result as an input for the followup Ask.
ai.InputAddFnResult(callId,applicationFnCallResult);
madeFunctionCalls = true;
}
// Your application would add code to check for and handle each possible function call.
fn_idx = fn_idx + 1;
}
}
else {
if (!sbEventName.ContentsEqual("empty",true)) {
sbFullResponse.AppendSb(sbDelta);
if (sbEventName.ContentsEqual("null_terminator",true)) {
streamingDone = true;
}
}
}
}
else {
// No event arrived, so wait a short time rather than spin in a loop..
ai.SleepMs(100);
}
}
if (!madeFunctionCalls) {
finished = true;
}
numAsks = numAsks + 1;
}
Log.i(TAG, "Full Response:");
Log.i(TAG, sbFullResponse.getAsString());
}
static {
System.loadLibrary("chilkat");
// Note: If the incorrect library name is passed to System.loadLibrary,
// then you will see the following error message at application startup:
//"The application <your-application-name> has stopped unexpectedly. Please try again."
}
}