Semantic Kernel with Caddey
Integrate Caddey tools into a Semantic Kernel C# agent.
Caddey exposes app features as tools, and Semantic Kernel agents can dynamically choose and call these tools via two generic functions: ListCaddeyTools
and ExecuteCaddeyTool
.
Prerequisites
- Caddey API key (obtain when you create your Caddey agent)
- .NET 7.0 SDK and a C# project
- Semantic Kernel and OpenAI Connector
dotnet add package Microsoft.SemanticKernel
dotnet add package Microsoft.SemanticKernel.Connectors.OpenAI
Security tip: Store secrets in environment variables or user secrets (never commit them).
Approach: Dynamic Tool Loading
Provide two generic skill methods that let the agent fetch and execute Caddey tools at runtime.
using System;
using System.Net.Http;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using Microsoft.SemanticKernel;
using Microsoft.SemanticKernel.Plugins.Core;
public class CaddeyDynamicSkill
{
private readonly HttpClient _http = new();
private readonly string _apiKey;
private const string BaseUrl = "https://api.caddey.ai";
public CaddeyDynamicSkill(string apiKey) => _apiKey = apiKey;
[KernelFunction("ListCaddeyTools")]
[Description("List Caddey tools with optional pagination and searchTerm (JSON input).")]
public async Task<string> ListCaddeyToolsAsync(string inputJson)
{
var options = string.IsNullOrWhiteSpace(inputJson)
? new { pageNumber = 0, pageSize = 20 }
: JsonSerializer.Deserialize<JsonElement>(inputJson).EnumerateObject()
.ToDictionary(p => p.Name, p => p.Value);
var query = new StringBuilder($"pageNumber={options.GetValueOrDefault("pageNumber", 0)}&pageSize={options.GetValueOrDefault("pageSize", 20)}");
if (options.TryGetValue("searchTerm", out var term))
{
query.Append($"&search={Uri.EscapeDataString(term.GetString())}");
}
var request = new HttpRequestMessage(HttpMethod.Get, $"{BaseUrl}/tools/query?{query}")
{
Headers = { { "X-API-KEY", _apiKey } }
};
var response = await _http.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
[KernelFunction("ExecuteCaddeyTool")]
[Description("Execute a Caddey tool by ID with JSON input (must include tool_id and input object).")]
public async Task<string> ExecuteCaddeyToolAsync(string inputJson)
{
var doc = JsonDocument.Parse(inputJson).RootElement;
var toolId = doc.GetProperty("tool_id").GetString();
var payload = JsonSerializer.Serialize(doc.GetProperty("input").GetRawText());
var request = new HttpRequestMessage(HttpMethod.Post, $"{BaseUrl}/tools/{toolId}/execute")
{
Headers = { { "X-API-KEY", _apiKey } },
Content = new StringContent(payload, Encoding.UTF8, "application/json")
};
var response = await _http.SendAsync(request);
response.EnsureSuccessStatusCode();
return await response.Content.ReadAsStringAsync();
}
}
Register the Skill and Initialize the Agent
var builder = Kernel.Builder;
builder.WithOpenAIChatCompletionService("gpt-4", Environment.GetEnvironmentVariable("OPENAI_API_KEY"));
builder.Plugins.AddFromType<CaddeyDynamicSkill>(
"Caddey", new object[] { Environment.GetEnvironmentVariable("CADDEY_API_KEY") });
IKernel kernel = builder.Build();
var chat = kernel.ChatCompletion.CreateNewChat(
"You are an assistant with access to Caddey tools via ListCaddeyTools and ExecuteCaddeyTool.");
var response = await kernel.RunAsync(
"ListCaddeyTools",
"{}" // default: first page, 20 items
);
Console.WriteLine(response);
Using Your Agent
Simply prompt the agent in natural language, and it will pick the appropriate tool under the hood.
Examples:
- Create a reminder to call Bob tomorrow at 3 PM.
- Fetch the list of available tools.
- Send an email to [email protected] with subject “Project Update” and body “The report is ready.”
The agent will automatically invoke the listing or execution of tools as needed.
For additional support, visit the Support Section.