Skip to content

A C# implementation of asynchronous tool execution buffering for Anthropic's Claude API. This library enables **true parallel conversation and tool execution** - users can continue chatting while long-running tools execute in the background.

License

Notifications You must be signed in to change notification settings

johnbrodowski/AnthropicToolUseBuffer

Repository files navigation

About this code

This example was extracted from AGPA β€” my fully autonomous general-purpose agent (closed-source, ~150k LOC).

AnthropicToolUseBuffer

A C# implementation of asynchronous tool execution buffering for Anthropic's Claude API. This library enables true parallel conversation and tool execution - users can continue chatting while long-running tools execute in the background.

πŸš€ What Makes This Special

Traditional AI tool implementations block the conversation while tools execute:

User: "Run this analysis"
AI: [calls analysis tool]
[User must wait 2 minutes...]
AI: "Here are the results"

AnthropicToolUseBuffer enables parallel execution:

User: "Run this analysis"
AI: [calls analysis tool - buffers it]
User: "What's the weather like?"
AI: "Sunny and 72Β°F" [continues conversation while tool runs]
[Tool completes in background]
AI: "The analysis is complete. Here are the results..."

✨ Key Features

🎯 Core Innovation: Tool Use Buffering

  • Asynchronous tool execution - Conversation continues while tools run
  • Queue-based message pairing - Multiple concurrent tool calls supported
  • ID-based matching - Each tool_use automatically paired with its tool_result by ID
  • Thread-safe buffering - Concurrent tool execution without race conditions
  • Timeout handling - Configurable timeout prevents stale buffers (default: 5 minutes)
  • Smart ping exclusion - Cache-alive pings don't pollute message history

πŸ› οΈ Universal Tool Builder

  • Write once, use everywhere - Define tools once, convert to any provider format
  • Type-safe tool definitions - Strongly-typed parameter definitions
  • Nested object support - Complex parameter structures
  • Provider agnostic - Same interface works across all AI providers

πŸ’Ύ Advanced Features

  • Streaming responses - Real-time SSE parsing with delta handling
  • Prompt caching - Automatic keep-alive timer before 5-minute expiry
  • Message persistence - SQLite database with conversation history
  • Permission system - Control which tools can call other tools (tool chaining)
  • Message validation - Automatic alternation validation and placeholder injection

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    FormAnthropicDemo                        β”‚
β”‚                     (WinForms UI)                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                             β”‚
                β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
                β”‚                         β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  AnthropicApiClass   β”‚   β”‚  Tool Buffer       β”‚
    β”‚  (API Client)        β”‚   β”‚  (Message Pairing) β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                β”‚                         β”‚
    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚  Streaming Parser    β”‚   β”‚  MessageDatabase   β”‚
    β”‚  (SSE Handling)      β”‚   β”‚  (SQLite)          β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

    β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
    β”‚       Universal Tool Builder System          β”‚
    β”‚  (Provider-agnostic tool definitions)        β”‚
    β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ“¦ Project Structure

AnthropicToolUseBuffer/
β”œβ”€β”€ AIClassesAnthropic/          # Message and response classes
β”‚   β”œβ”€β”€ MessageClass.cs          # Core message structures
β”‚   β”œβ”€β”€ ContentClass.cs          # Message content types
β”‚   β”œβ”€β”€ DeltaClass.cs            # Streaming delta handling
β”‚   └── StreamBufferParser.cs    # SSE stream parser
β”œβ”€β”€ ToolBuilder/                 # Universal tool definition system
β”‚   β”œβ”€β”€ UniversalToolBuilder.cs  # Provider-agnostic builder
β”‚   β”œβ”€β”€ ToolTransformerBuilderAnthropic.cs
β”‚   β”œβ”€β”€ LoadTools.cs             # Tool registration
β”‚   └── USAGE_EXAMPLE.cs         # Usage examples
β”œβ”€β”€ ToolClasses/                 # Tool implementations
β”‚   β”œβ”€β”€ Tool.cs                  # Base tool class
β”‚   β”œβ”€β”€ ToolClass.cs             # Tool metadata
β”‚   └── ToolBufferDemo.cs        # Demo tool
β”œβ”€β”€ ApiAnthropic.cs              # Main API client
β”œβ”€β”€ FormAnthropicDemo.cs         # WinForms UI implementation
β”œβ”€β”€ MessageDatabase.cs           # SQLite persistence
β”œβ”€β”€ AppSettings.cs               # Configuration management
└── NonBlockingTimerClass.cs     # Cache-alive timer

🚦 Getting Started

Prerequisites

Installation

  1. Clone the repository:
git clone https://github.com/johnbrodowski/AnthropicToolUseBuffer.git
  1. Create appsettings.json in the project root:
{
  "anthropic": {
    "apiKey": "YOUR_API_KEY_HERE",
    "defaultModel": "claude-sonnet-4-5",
    "cacheAliveIntervalMinutes": 4.75
  },
  "general": {
    "useTools": true,
    "toolPairTimeoutMinutes": 5
  },
  "database": {
    "defaultDatabaseName": "ToolBufferDemoMessageDatabase.db"
  }
}
  1. Build and run:
dotnet build
dotnet run

πŸ’‘ How Tool Buffering Works

The Problem

Traditional implementations send messages immediately:

// Traditional approach - blocks conversation
User message β†’ API β†’ Assistant with tool_use β†’ Wait for tool β†’ Send tool_result β†’ API β†’ Continue

The Solution

AnthropicToolUseBuffer uses a queue-based buffer that supports multiple concurrent tool calls:

// Queue-based buffering - supports concurrent tools
User: "Run analysis A"     β†’ API β†’ Assistant text saved
                                 β†’ tool_use A buffered by ID
                                 β†’ Tool A starts (30 sec)
User: "Run analysis B"     β†’ API β†’ Assistant text saved
                                 β†’ tool_use B buffered by ID
                                 β†’ Tool B starts (20 sec)
User: "What's the status?" β†’ API continues conversation
                                 ↓
Tool B completes (20 sec)  β†’ tool_result B buffered
                           β†’ Match found! Flush pair B
                           β†’ API receives results for B
                                 ↓
Tool A completes (30 sec)  β†’ tool_result A buffered
                           β†’ Match found! Flush pair A
                           β†’ API receives results for A

Implementation

// Queue-based buffering (thread-safe)
private readonly object _toolBufferLock = new object();

// Dictionaries indexed by tool_use ID for concurrent support
private readonly Dictionary<string, (MessageAnthropic message, DateTime timestamp)> _pendingToolUseMessages = new();
private readonly Dictionary<string, MessageAnthropic> _pendingToolResults = new();

// When tool_use received: buffer by ID
_pendingToolUseMessages[toolUseId] = (message, DateTime.Now);

// When tool_result received: find matching tool_use by ID
if (_pendingToolUseMessages.ContainsKey(toolUseId))
{
    // Match found - flush this pair only
    FlushPair(toolUseId);
}

πŸ”§ Tool Definition Example

Define tools once using the Universal Tool Builder:

var weatherTool = new UniversalToolBuilder()
    .AddToolName("get_weather")
    .AddDescription("Retrieves current weather information.")
    .AddNestedObject("weather_params", "Weather query parameters", isRequired: true)
        .AddProperty("location", "string", "City name or coordinates", isRequired: true)
        .AddProperty("units", "string", "Temperature units (celsius/fahrenheit)", isRequired: false)
    .EndNestedObject()
    .EndObject()
    .Build();

// Convert to Anthropic format
var anthropicTool = weatherTool.ToAnthropic();

See ToolBuilder/USAGE_EXAMPLE.cs for more comprehensive examples.

🎯 Use Cases

  • Long-running analysis tools - Run data analysis while user continues conversation
  • Concurrent API calls - Multiple API requests running simultaneously without blocking
  • Parallel data processing - Process multiple datasets concurrently
  • Multi-step workflows - Execute complex tool chains asynchronously
  • Enterprise chatbots - Production-grade Claude integrations with concurrent tool support
  • AI agent frameworks - Building blocks for autonomous agents with parallel task execution

βš™οΈ Configuration

App Settings

All configuration is in appsettings.json:

Setting Description Default
anthropic.apiKey Your Anthropic API key Required
anthropic.defaultModel Claude model to use claude-sonnet-4-5
anthropic.cacheAliveIntervalMinutes Keep-alive ping interval 4.75
general.useTools Enable tool support true
general.toolPairTimeoutMinutes Tool buffer timeout 5
database.defaultDatabaseName SQLite database name ToolBufferDemoMessageDatabase.db

Tool Permissions

Control which tools can call other tools:

_toolPermissions.RegisterTool(
    toolName: "tool_buffer_demo",
    canInitiateToolChain: true,
    allowedTools: new[] { "tool_buffer_demo" }
);

πŸ§ͺ Demo Tool

The included tool_buffer_demo demonstrates async tool execution:

User: "Try the tool_buffer_demo"
AI: "I'll call the tool_buffer_demo function for you."
[Tool starts executing - 10 second delay]

User: "Is it working?"
AI: "Yes! The tool is still running in the background..."

[Tool completes]
AI: "The tool has completed! The test was successful."

πŸ“Š Message Flow

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ User Input  β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ FlushMatchedToolPairβ”‚ ◄──── Check for pending pairs (all IDs)
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Send to API      β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Stream Response    β”‚
β”‚ (SSE Parsing)      β”‚
β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
       β”‚
       β”œβ”€β–Ί text delta        β†’ Display immediately
       β”œβ”€β–Ί thinking delta    β†’ Show thinking process
       β”œβ”€β–Ί tool_use          β†’ Buffer in _pendingToolUseMessages[toolUseId]
       └─► tool_result       β†’ Buffer in _pendingToolResults[toolUseId]

       When IDs match:
       └─► FlushMatchedToolPair β†’ Find matching pairs by ID
                                 β†’ Flush matched pairs only
                                 β†’ Keep unmatched pairs in queue

πŸ” Security Notes

  • Never commit API keys - Use environment variables or secure configuration
  • Validate tool inputs - Always sanitize user-provided tool parameters
  • Permission system - Use tool permissions to control tool chaining
  • Database security - Encrypt sensitive data in message database

🀝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

πŸ“ License

This project is licensed under the Apache License 2.0 - see the LICENSE.txt file for details.

πŸ™ Acknowledgments

  • Built for Anthropic's Claude API
  • Inspired by the need for better async tool execution in AI applications

πŸ“§ Contact & Author

Author: John Brodowski Project Link: https://github.com/johnbrodowski/AnthropicToolUseBuffer Release Date: December 25, 2025


Note: This is a demonstration implementation extracted from a larger project. The tool buffering mechanism represents a novel approach to handling Claude's tool use capabilities and is being open-sourced to benefit the AI development community.

About

A C# implementation of asynchronous tool execution buffering for Anthropic's Claude API. This library enables **true parallel conversation and tool execution** - users can continue chatting while long-running tools execute in the background.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages