![]() |
Chilkat HOME Android™ AutoIt C C# C++ Chilkat2-Python CkPython Classic ASP DataFlex Delphi DLL Go Java JavaScript Node.js Objective-C PHP Extension Perl PowerBuilder PowerShell PureBasic Ruby SQL Server Swift Tcl Unicode C Unicode C++ VB.NET VBScript Visual Basic 6.0 Visual FoxPro Xojo Plugin
(C++) Streaming AI with Manual AI Tool Function CallingSee more AI ExamplesDemonstrates how to get AI responses in streaming mode, including manual tool function calls.Note: This example requires Chilkat v11.4.0 or greater. For more information, see https://www.chilkatsoft.com/ai_tool_function_caling_briefly_explained.asp
#include <CkJsonObject.h> #include <CkAi.h> #include <CkStringBuilder.h> void ChilkatSample(void) { bool 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; 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); std::cout << jsonTools.emit() << "\r\n"; CkAi ai; // 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. const char *conversation_name = "convo_astrology"; const char *sysMessage = "You are a helpful astrologer"; const char *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; CkStringBuilder sbDelta; CkStringBuilder sbFullResponse; // 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; bool finished = false; int numAsks = 0; // Set a max # of followup Asks to prevent any unexpected infinite looping. while (!finished && (numAsks < 10)) { // Send the request to the AI model. success = ai.Ask("text"); if (success == false) { std::cout << ai.lastErrorText() << "\r\n"; return; } bool madeFunctionCalls = false; bool streamingDone = false; while (!streamingDone) { int result = ai.PollAi(false); if (result < 0) { std::cout << ai.lastErrorText() << "\r\n"; std::cout << "Failed." << "\r\n"; return; } if (result > 0) { // We have an event.. success = ai.NextAiEvent(maxWaitMs,sbEventName,sbDelta); if (success == false) { std::cout << ai.lastErrorText() << "\r\n"; 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; jsonFn.StringOfSb("function_call[i].name",sbFnName); const char *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". const char *zodiac_sign = jsonFn.stringOf("function_call[i].args.sign"); std::cout << "zodiac_sign = " << zodiac_sign << "\r\n"; // 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: const char *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; } std::cout << "Full Response:" << "\r\n"; std::cout << sbFullResponse.getAsString() << "\r\n"; } |
||||||
© 2000-2026 Chilkat Software, Inc. All Rights Reserved.