![]() |
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
(Objective-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
#import <CkoJsonObject.h> #import <CkoAi.h> #import <NSString.h> #import <CkoStringBuilder.h> BOOL success = NO; // 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" // } // } // } // } // ] // } CkoJsonObject *jsonTools = [[CkoJsonObject alloc] init]; int toolIdx = 0; jsonTools.I = [NSNumber numberWithInt: toolIdx]; [jsonTools UpdateString: @"tools[i].name" value: @"get_horoscope"]; [jsonTools UpdateString: @"tools[i].description" value: @"Get today's horoscope for an astrological sign."]; [jsonTools UpdateString: @"tools[i].parameters.properties.sign.type" value: @"string"]; [jsonTools UpdateString: @"tools[i].parameters.properties.sign.description" value: @"An astrological sign like Taurus or Aquarius"]; // More tools can be added as desired.. jsonTools.EmitCompact = NO; NSLog(@"%@",[jsonTools Emit]); CkoAi *ai = [[CkoAi alloc] init]; // 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.Provider = @"openai"; // Use your provider's API key. ai.ApiKey = @"MY_API_KEY"; // Choose a model. ai.Model = @"gpt-5-mini"; // Tool function calling must always occur within a conversation. NSString *conversation_name = @"convo_astrology"; NSString *sysMessage = @"You are a helpful astrologer"; NSString *devMessage = @"Respond only with markdown."; [ai NewConvo: conversation_name sysMsg: sysMessage devMsg: devMessage]; // Provide inputs [ai InputAddText: @"What is my horoscope? I am an Aquarius."]; // Get the response in streaming mode. ai.Streaming = YES; // 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. CkoStringBuilder *sbEventName = [[CkoStringBuilder alloc] init]; CkoStringBuilder *sbDelta = [[CkoStringBuilder alloc] init]; CkoStringBuilder *sbFullResponse = [[CkoStringBuilder alloc] init]; // 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; CkoJsonObject *jsonFn = [[CkoJsonObject alloc] init]; BOOL finished = NO; 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 == NO) { NSLog(@"%@",ai.LastErrorText); return; } BOOL madeFunctionCalls = NO; BOOL streamingDone = NO; while (!streamingDone) { int result = [[ai PollAi: NO] intValue]; if (result < 0) { NSLog(@"%@",ai.LastErrorText); NSLog(@"%@",@"Failed."); return; } if (result > 0) { // We have an event.. success = [ai NextAiEvent: [NSNumber numberWithInt: maxWaitMs] sbName: sbEventName sbDelta: sbDelta]; if (success == NO) { NSLog(@"%@",ai.LastErrorText); return; } // Is this an event where the AI is requesting a function call? if ([sbEventName ContentsEqual: @"function_call" caseSensitive: YES]) { [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"] intValue]; int fn_idx = 0; while ((fn_idx < numFnCalls)) { jsonFn.I = [NSNumber numberWithInt: fn_idx]; CkoStringBuilder *sbFnName = [[CkoStringBuilder alloc] init]; [jsonFn StringOfSb: @"function_call[i].name" sb: sbFnName]; NSString *callId = [jsonFn StringOf: @"function_call[i].call_id"]; if ([sbFnName ContentsEqual: @"get_horoscope" caseSensitive: YES] == YES) { // The get_horoscope function (as defined above) has one argument named "sign". NSString *zodiac_sign = [jsonFn StringOf: @"function_call[i].args.sign"]; NSLog(@"%@%@",@"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: NSString *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 fnResult: applicationFnCallResult]; madeFunctionCalls = YES; } // Your application would add code to check for and handle each possible function call. fn_idx = fn_idx + 1; } } else { if (![sbEventName ContentsEqual: @"empty" caseSensitive: YES]) { [sbFullResponse AppendSb: sbDelta]; if ([sbEventName ContentsEqual: @"null_terminator" caseSensitive: YES]) { streamingDone = YES; } } } } else { // No event arrived, so wait a short time rather than spin in a loop.. [ai SleepMs: [NSNumber numberWithInt: 100]]; } } if (!madeFunctionCalls) { finished = YES; } numAsks = numAsks + 1; } NSLog(@"%@",@"Full Response:"); NSLog(@"%@",[sbFullResponse GetAsString]); |
||||
© 2000-2026 Chilkat Software, Inc. All Rights Reserved.