Function

Execute C# functions through agent tool calls.

Basic Function Tools

Simple Function

// Define function
int Add(int a, int b) => a + b;

// Register as tool
agent.AddTool("add", Add);

// Agent can now call: add(5, 3) → 8

With Description

agent.AddTool(
    name: "calculate_damage",
    description: "Calculate damage dealt to enemy based on attack and defense stats",
    function: (int attack, int defense) =>
    {
        int damage = Mathf.Max(0, attack - defense);
        return $"Dealt {damage} damage";
    }
);

Lambda Functions

Inline Implementation

// Simple lambda
agent.AddTool("get_time", () => DateTime.Now.ToString("HH:mm:ss"));

// Multi-line lambda
agent.AddTool("spawn_enemies", (string type, int count) =>
{
    for (int i = 0; i < count; i++)
    {
        SpawnEnemy(type);
    }
    return $"Spawned {count} {type}";
});

Closure Variables

int score = 0;

agent.AddTool("add_score", (int points) =>
{
    score += points;
    return $"Score: {score}";
});

agent.AddTool("get_score", () => $"Current score: {score}");

Method References

Instance Methods

public class GameManager : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    
    void Start()
    {
        agent.AddTool("save_game", SaveGame);
        agent.AddTool("load_game", LoadGame);
        agent.AddTool("get_stats", GetPlayerStats);
    }
    
    string SaveGame()
    {
        // Save logic
        PlayerPrefs.Save();
        return "Game saved successfully";
    }
    
    string LoadGame(int slot)
    {
        // Load logic
        return $"Loaded save slot {slot}";
    }
    
    string GetPlayerStats()
    {
        return JsonUtility.ToJson(new
        {
            level = player.Level,
            health = player.Health
        });
    }
}

Static Methods

public static class GameUtilities
{
    public static string GetSystemInfo()
    {
        return $"OS: {SystemInfo.operatingSystem}\n" +
               $"CPU: {SystemInfo.processorType}\n" +
               $"RAM: {SystemInfo.systemMemorySize} MB";
    }
    
    public static float CalculateDistance(Vector3 a, Vector3 b)
    {
        return Vector3.Distance(a, b);
    }
}

// Register
agent.AddTool("get_system_info", GameUtilities.GetSystemInfo);
agent.AddTool("calculate_distance", GameUtilities.CalculateDistance);

Async Functions

Async/Await

async UniTask<string> FetchDataAsync(string url)
{
    using var request = UnityWebRequest.Get(url);
    await request.SendWebRequest();
    
    if (request.result == UnityWebRequest.Result.Success)
    {
        return request.downloadHandler.text;
    }
    else
    {
        return $"Error: {request.error}";
    }
}

// Register async function
agent.AddTool("fetch_data", FetchDataAsync);

Long-Running Operations

async UniTask<string> ProcessLargeDataset(string datasetName)
{
    var data = LoadDataset(datasetName);
    
    int progress = 0;
    int total = data.Count;
    
    foreach (var item in data)
    {
        await ProcessItem(item);
        progress++;
        
        if (progress % 10 == 0)
        {
            Debug.Log($"Progress: {progress}/{total}");
        }
    }
    
    return $"Processed {total} items";
}

agent.AddTool("process_dataset", ProcessLargeDataset);

Parameter Types

Primitive Types

// Int, float, string, bool
agent.AddTool("set_volume", (float volume) =>
{
    AudioListener.volume = volume;
    return $"Volume set to {volume}";
});

agent.AddTool("toggle_feature", (bool enabled) =>
{
    gameManager.FeatureEnabled = enabled;
    return $"Feature {(enabled ? "enabled" : "disabled")}";
});

Complex Types

[System.Serializable]
public class SpawnConfig
{
    public string enemyType;
    public int count;
    public Vector3 position;
}

agent.AddTool("spawn_with_config", (SpawnConfig config) =>
{
    for (int i = 0; i < config.count; i++)
    {
        SpawnEnemyAt(config.enemyType, config.position);
    }
    return $"Spawned {config.count} {config.enemyType}";
});

Optional Parameters

agent.AddTool("search_files", (string query, int maxResults = 10) =>
{
    var results = SearchFiles(query).Take(maxResults);
    return $"Found {results.Count()} results";
});

Return Types

agent.AddTool("get_info", () => "Information text");

JSON Objects

agent.AddTool("get_player_data", () =>
{
    var data = new
    {
        name = player.Name,
        level = player.Level,
        health = player.Health,
        position = player.transform.position
    };
    
    return JsonUtility.ToJson(data);
});

Collections

agent.AddTool("list_inventory", () =>
{
    var items = player.Inventory.GetAllItems();
    return JsonUtility.ToJson(new { items, count = items.Count });
});

Error Handling

Try-Catch

agent.AddTool("risky_operation", (string input) =>
{
    try
    {
        var result = PerformRiskyOperation(input);
        return $"Success: {result}";
    }
    catch (ArgumentException ex)
    {
        return $"Error: Invalid input - {ex.Message}";
    }
    catch (Exception ex)
    {
        Debug.LogException(ex);
        return $"Error: {ex.Message}";
    }
});

Validation

agent.AddTool("set_difficulty", (int level) =>
{
    if (level < 1 || level > 10)
    {
        return "Error: Difficulty must be between 1 and 10";
    }
    
    gameManager.SetDifficulty(level);
    return $"Difficulty set to {level}";
});

Game-Specific Functions

Player Actions

public class PlayerActions : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    [SerializeField] private Player player;
    
    void Start()
    {
        RegisterPlayerTools();
    }
    
    void RegisterPlayerTools()
    {
        agent.AddTool("heal_player", HealPlayer);
        agent.AddTool("give_item", GiveItem);
        agent.AddTool("teleport", TeleportPlayer);
        agent.AddTool("set_health", SetHealth);
    }
    
    string HealPlayer(int amount)
    {
        int oldHealth = player.Health;
        player.Heal(amount);
        int newHealth = player.Health;
        
        return $"Healed {newHealth - oldHealth} HP (now at {newHealth})";
    }
    
    string GiveItem(string itemName, int quantity)
    {
        bool success = player.Inventory.AddItem(itemName, quantity);
        
        if (success)
        {
            return $"Added {quantity}x {itemName} to inventory";
        }
        else
        {
            return $"Failed to add {itemName} (inventory full?)";
        }
    }
    
    string TeleportPlayer(float x, float y, float z)
    {
        Vector3 position = new Vector3(x, y, z);
        player.transform.position = position;
        
        return $"Teleported to {position}";
    }
    
    string SetHealth(int health)
    {
        health = Mathf.Clamp(health, 0, player.MaxHealth);
        player.Health = health;
        
        return $"Health set to {health}/{player.MaxHealth}";
    }
}

World Interaction

public class WorldTools : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    
    void Start()
    {
        agent.AddTool("find_nearest", FindNearest);
        agent.AddTool("get_distance", GetDistance);
        agent.AddTool("list_objects", ListObjects);
    }
    
    string FindNearest(string tag)
    {
        var objects = GameObject.FindGameObjectsWithTag(tag);
        if (objects.Length == 0)
        {
            return $"No objects found with tag '{tag}'";
        }
        
        var player = GameObject.FindGameObjectWithTag("Player");
        var nearest = objects
            .OrderBy(obj => Vector3.Distance(player.transform.position, obj.transform.position))
            .First();
        
        float distance = Vector3.Distance(player.transform.position, nearest.transform.position);
        
        return $"Nearest {tag}: {nearest.name} at {distance:F1}m";
    }
    
    string GetDistance(string objectName)
    {
        var obj = GameObject.Find(objectName);
        if (obj == null)
        {
            return $"Object '{objectName}' not found";
        }
        
        var player = GameObject.FindGameObjectWithTag("Player");
        float distance = Vector3.Distance(player.transform.position, obj.transform.position);
        
        return $"Distance to {objectName}: {distance:F1}m";
    }
    
    string ListObjects(string tag)
    {
        var objects = GameObject.FindGameObjectsWithTag(tag);
        
        if (objects.Length == 0)
        {
            return $"No objects with tag '{tag}'";
        }
        
        var names = objects.Select(obj => obj.name);
        return $"Found {objects.Length} objects: {string.Join(", ", names)}";
    }
}

UI Functions

UI Manipulation

public class UITools : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    [SerializeField] private GameObject inventoryPanel;
    [SerializeField] private GameObject settingsPanel;
    
    void Start()
    {
        agent.AddTool("show_inventory", () =>
        {
            inventoryPanel.SetActive(true);
            return "Inventory opened";
        });
        
        agent.AddTool("show_settings", () =>
        {
            settingsPanel.SetActive(true);
            return "Settings opened";
        });
        
        agent.AddTool("show_message", ShowMessage);
    }
    
    string ShowMessage(string title, string message)
    {
        // Show message dialog
        DialogManager.Instance.Show(title, message);
        return "Message displayed";
    }
}

Data Access Functions

Database Queries

public class DataTools : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    private IDatabase database;
    
    void Start()
    {
        agent.AddTool("query_users", QueryUsers);
        agent.AddTool("get_user", GetUser);
        agent.AddTool("count_records", CountRecords);
    }
    
    async UniTask<string> QueryUsers(string searchTerm)
    {
        var users = await database.QueryAsync<User>(
            $"SELECT * FROM Users WHERE Name LIKE '%{searchTerm}%'"
        );
        
        return JsonUtility.ToJson(new
        {
            count = users.Count,
            users = users.Take(10) // Limit results
        });
    }
    
    async UniTask<string> GetUser(int userId)
    {
        var user = await database.GetAsync<User>(userId);
        
        if (user == null)
        {
            return $"User {userId} not found";
        }
        
        return JsonUtility.ToJson(user);
    }
    
    async UniTask<string> CountRecords(string tableName)
    {
        int count = await database.CountAsync(tableName);
        return $"{tableName}: {count} records";
    }
}

Testing Functions

Debug Tools

agent.AddTool("debug_info", () =>
{
    return $@"FPS: {1f / Time.deltaTime:F0}
Memory: {System.GC.GetTotalMemory(false) / 1024 / 1024}MB
Active GameObjects: {FindObjectsOfType<GameObject>().Length}
Time: {Time.time:F2}s";
});

agent.AddTool("log_message", (string message) =>
{
    Debug.Log($"[Agent] {message}");
    return "Message logged";
});

agent.AddTool("trigger_event", (string eventName) =>
{
    EventBus.Trigger(eventName);
    return $"Triggered event: {eventName}";
});

Best Practices

1. Clear Naming

// ❌ Bad
agent.AddTool("do", DoSomething);

// ✅ Good
agent.AddTool("spawn_enemy_at_location", SpawnEnemyAtLocation);

2. Descriptive Returns

// ❌ Bad
return "ok";

// ✅ Good
return "Successfully spawned 5 enemies at (10, 0, 15)";

3. Input Validation

agent.AddTool("set_difficulty", (int level) =>
{
    // Validate input
    if (level < 1 || level > 5)
    {
        return "Error: Difficulty must be between 1 and 5";
    }
    
    // Execute
    SetDifficulty(level);
    return $"Difficulty set to {level}";
});

4. Meaningful Errors

try
{
    return ExecuteOperation();
}
catch (FileNotFoundException ex)
{
    return $"Error: File not found - {ex.FileName}";
}
catch (UnauthorizedAccessException)
{
    return "Error: Permission denied";
}

Complete Example

using UnityEngine;
using Glitch9.AIDevKit.Agents;
using Cysharp.Threading.Tasks;

public class GameFunctionTools : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    [SerializeField] private Player player;
    [SerializeField] private GameManager gameManager;
    
    void Start()
    {
        RegisterAllTools();
    }
    
    void RegisterAllTools()
    {
        // Player tools
        agent.AddTool("get_player_stats", GetPlayerStats);
        agent.AddTool("heal_player", HealPlayer);
        agent.AddTool("teleport_player", TeleportPlayer);
        
        // Game tools
        agent.AddTool("spawn_enemy", SpawnEnemy);
        agent.AddTool("set_difficulty", SetDifficulty);
        agent.AddTool("save_game", SaveGame);
        agent.AddTool("load_game", LoadGame);
        
        // Query tools
        agent.AddTool("find_nearest", FindNearest);
        agent.AddTool("count_enemies", CountEnemies);
        
        Debug.Log("✓ Registered 9 function tools");
    }
    
    // Player tools
    string GetPlayerStats()
    {
        return JsonUtility.ToJson(new
        {
            name = player.Name,
            health = player.Health,
            maxHealth = player.MaxHealth,
            level = player.Level,
            experience = player.Experience,
            position = player.transform.position
        });
    }
    
    string HealPlayer(int amount)
    {
        int healed = player.Heal(amount);
        return $"Healed {healed} HP. Current health: {player.Health}/{player.MaxHealth}";
    }
    
    string TeleportPlayer(float x, float y, float z)
    {
        player.transform.position = new Vector3(x, y, z);
        return $"Teleported to ({x}, {y}, {z})";
    }
    
    // Game tools
    string SpawnEnemy(string enemyType, int count)
    {
        if (count < 1 || count > 10)
        {
            return "Error: Count must be between 1 and 10";
        }
        
        for (int i = 0; i < count; i++)
        {
            gameManager.SpawnEnemy(enemyType);
        }
        
        return $"Spawned {count} {enemyType}";
    }
    
    string SetDifficulty(string difficulty)
    {
        if (!gameManager.IsValidDifficulty(difficulty))
        {
            return $"Error: Invalid difficulty. Valid options: Easy, Normal, Hard";
        }
        
        gameManager.SetDifficulty(difficulty);
        return $"Difficulty set to {difficulty}";
    }
    
    async UniTask<string> SaveGame()
    {
        try
        {
            await gameManager.SaveAsync();
            return "Game saved successfully";
        }
        catch (Exception ex)
        {
            return $"Failed to save: {ex.Message}";
        }
    }
    
    async UniTask<string> LoadGame(int slot)
    {
        try
        {
            await gameManager.LoadAsync(slot);
            return $"Loaded save slot {slot}";
        }
        catch (Exception ex)
        {
            return $"Failed to load: {ex.Message}";
        }
    }
    
    // Query tools
    string FindNearest(string tag)
    {
        var objects = GameObject.FindGameObjectsWithTag(tag);
        if (objects.Length == 0)
        {
            return $"No objects found with tag '{tag}'";
        }
        
        var nearest = objects
            .OrderBy(obj => Vector3.Distance(player.transform.position, obj.transform.position))
            .First();
        
        float distance = Vector3.Distance(player.transform.position, nearest.transform.position);
        return $"{nearest.name} at {distance:F1}m";
    }
    
    string CountEnemies()
    {
        int count = GameObject.FindGameObjectsWithTag("Enemy").Length;
        return $"Active enemies: {count}";
    }
}

Next Steps

Last updated