![]() |
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
(Unicode 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 <CkJsonObjectW.h> #include <CkAiW.h> #include <CkStringBuilderW.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" // } // } // } // } // ] // } CkJsonObjectW jsonTools; int toolIdx = 0; jsonTools.put_I(toolIdx); jsonTools.UpdateString(L"tools[i].name",L"get_horoscope"); jsonTools.UpdateString(L"tools[i].description",L"Get today's horoscope for an astrological sign."); jsonTools.UpdateString(L"tools[i].parameters.properties.sign.type",L"string"); jsonTools.UpdateString(L"tools[i].parameters.properties.sign.description",L"An astrological sign like Taurus or Aquarius"); // More tools can be added as desired.. jsonTools.put_EmitCompact(false); wprintf(L"%s\n",jsonTools.emit()); CkAiW 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(L"openai"); // Use your provider's API key. ai.put_ApiKey(L"MY_API_KEY"); // Choose a model. ai.put_Model(L"gpt-5-mini"); // Tool function calling must always occur within a conversation. const wchar_t *conversation_name = L"convo_astrology"; const wchar_t *sysMessage = L"You are a helpful astrologer"; const wchar_t *devMessage = L"Respond only with markdown."; ai.NewConvo(conversation_name,sysMessage,devMessage); // Provide inputs ai.InputAddText(L"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. CkStringBuilderW sbEventName; CkStringBuilderW sbDelta; CkStringBuilderW 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; CkJsonObjectW 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(L"text"); if (success == false) { wprintf(L"%s\n",ai.lastErrorText()); return; } bool madeFunctionCalls = false; bool streamingDone = false; while (!streamingDone) { int result = ai.PollAi(false); if (result < 0) { wprintf(L"%s\n",ai.lastErrorText()); wprintf(L"Failed.\n"); return; } if (result > 0) { // We have an event.. success = ai.NextAiEvent(maxWaitMs,sbEventName,sbDelta); if (success == false) { wprintf(L"%s\n",ai.lastErrorText()); return; } // Is this an event where the AI is requesting a function call? if (sbEventName.ContentsEqual(L"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(L"function_call"); int fn_idx = 0; while ((fn_idx < numFnCalls)) { jsonFn.put_I(fn_idx); CkStringBuilderW sbFnName; jsonFn.StringOfSb(L"function_call[i].name",sbFnName); const wchar_t *callId = jsonFn.stringOf(L"function_call[i].call_id"); if (sbFnName.ContentsEqual(L"get_horoscope",true) == true) { // The get_horoscope function (as defined above) has one argument named "sign". const wchar_t *zodiac_sign = jsonFn.stringOf(L"function_call[i].args.sign"); wprintf(L"zodiac_sign = %s\n",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: const wchar_t *applicationFnCallResult = L"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(L"empty",true)) { sbFullResponse.AppendSb(sbDelta); if (sbEventName.ContentsEqual(L"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; } wprintf(L"Full Response:\n"); wprintf(L"%s\n",sbFullResponse.getAsString()); } |
||||||
© 2000-2026 Chilkat Software, Inc. All Rights Reserved.