Unity SDK

Add NPC conversations to your Unity game with the Foil Engine UPM package.

Installation

Install via Unity Package Manager using a git URL. In Unity, go to Window → Package Manager → + → Add package from git URL and enter:

https://github.com/py1218/foilengine-unity.git
💡Tip
Requires Unity 2021.3 or later. The SDK depends on Newtonsoft.Json (included with Unity 2020+).

Quick Start (Async/Await)

Unity 2023+ supports async/await natively:

using FoilEngine;
using FoilEngine.Models;

var client = new FoilEngineClient("pk_live_...");

// Discover your personas
Persona[] personas = await client.Personas.ListAsync();
Debug.Log(personas[0].Name); // "Grumpy Barista"

// Initialize a session
SessionInit session = await client.Chat.InitSessionAsync(
    personaId: personas[0].Id,
    userSessionId: "player-001",
    playerName: "Alex",
    playerGender: "non-binary"
);
Debug.Log(session.Message); // NPC's greeting

// Send a message
ChatResponse response = await client.Chat.SendMessageAsync(
    personaId: personas[0].Id,
    message: "What do you recommend?",
    userSessionId: "player-001"
);
Debug.Log(response.Message);      // NPC's reply
Debug.Log(response.CurrentState); // State machine state
Debug.Log(response.Score);        // Session score

Quick Start (Coroutines)

For Unity 2021–2022 or if you prefer coroutines:

using UnityEngine;
using FoilEngine;
using FoilEngine.Models;

public class NPCManager : MonoBehaviour
{
    private FoilEngineClient client;

    void Start()
    {
        client = new FoilEngineClient("pk_live_...");
        StartCoroutine(client.Personas.List(
            onSuccess: personas => {
                Debug.Log(personas[0].Name);
                StartCoroutine(InitChat(personas[0].Id));
            },
            onError: err => Debug.LogError(err.Message)
        ));
    }

    IEnumerator InitChat(string personaId)
    {
        yield return client.Chat.InitSession(
            personaId: personaId,
            userSessionId: "player-001",
            playerName: "Alex",
            playerGender: "non-binary",
            onSuccess: session => Debug.Log(session.Message),
            onError: err => Debug.LogError(err.Message)
        );
    }
}

Configuration

var client = new FoilEngineClient(
    apiKey: "pk_live_...",                          // required
    baseUrl: "http://localhost:8000",               // default: https://api.foilengine.io
    timeoutSeconds: 30,                             // default: 30
    maxRetries: 3                                   // default: 3
);

Available Methods

Personas

AsyncCoroutineDescription
client.Personas.ListAsync()client.Personas.List(onSuccess, onError)List all published personas

Machines

AsyncCoroutineDescription
client.Machines.ListAsync(personaId, userSessionId)client.Machines.List(personaId, userSessionId, onSuccess, onError)List available machines for a player

Chat

AsyncCoroutineDescription
InitSessionAsync(...)InitSession(..., onSuccess, onError)Start a new conversation
SendMessageAsync(...)SendMessage(..., onSuccess, onError)Send a message, get NPC reply
GetSessionAsync(...)GetSession(..., onSuccess, onError)Check if a session exists
GetHistoryAsync(...)GetHistory(..., onSuccess, onError)Get full message history
ResetAsync(...)Reset(..., onSuccess, onError)Delete a session

Error Handling

Async/Await

using FoilEngine;

try
{
    var session = await client.Chat.GetSessionAsync(personaId, "player-001");
}
catch (NotFoundException)
{
    // No existing session — initialize one
    var session = await client.Chat.InitSessionAsync(personaId, "player-001", "Alex", "non-binary");
}
catch (RateLimitException e)
{
    Debug.Log($"Retry after {e.RetryAfter}s");
}
catch (AuthenticationException)
{
    Debug.LogError("Invalid API key");
}

Coroutines

StartCoroutine(client.Chat.GetSession(
    personaId: personaId,
    userSessionId: "player-001",
    onSuccess: session => Debug.Log(session.Exists),
    onError: err => {
        if (err is NotFoundException)
            StartCoroutine(InitNewSession());
        else
            Debug.LogError(err.Message);
    }
));
ExceptionStatusWhen
BadRequestException400Invalid UUID, missing fields
AuthenticationException401Missing or invalid API key
ForbiddenException403Not owner or persona unpublished
NotFoundException404Resource not found
RateLimitException429Rate limit exceeded
ServerException500Internal server error
💡Tip
The SDK automatically retries on 429 and 5xx errors with exponential backoff (up to 3 retries). Uses UnityWebRequest for full platform compatibility (WebGL, mobile, console).

Multi-Machine Example

// Discover available machines for a player
MachineInfo[] machines = await client.Machines.ListAsync(personaId, "player-001");

foreach (var m in machines)
{
    string status = m.HasSession ? "active" : "available";
    string linked = m.IsLinked ? " (linked)" : "";
    Debug.Log($"  {m.Name}: {status}{linked}");
}

// Start a specific machine
SessionInit session = await client.Chat.InitSessionAsync(
    personaId: personaId,
    userSessionId: "player-001",
    playerName: "Alex",
    playerGender: "non-binary",
    machineId: machines[1].MachineId  // target a specific scenario
);