PlayKit.ai

Core Concepts

Understand the core architecture and design patterns of PlayKit Unity SDK

Core Concepts

SDK Architecture

The PlayKit Unity SDK uses a modular design with the following core components:

  • PlayKitSDK: The SDK entry point, using singleton pattern to manage global configuration and initialization
  • Client Factory: Creates different types of AI clients through factory methods
  • Service Providers: Handle communication with the PlayKit API
  • Authentication Manager: Manages developer and player identity authentication

Singleton Pattern

PlayKitSDK uses the singleton pattern to ensure only one SDK instance exists throughout the application. You can access the instance via PlayKitSDK.Instance, but in most cases static methods are sufficient:

await PlayKitSDK.InitializeAsync();
bool isReady = PlayKitSDK.IsReady();
var playerClient = PlayKitSDK.GetPlayerClient();

The SDK auto-initializes at runtime using [RuntimeInitializeOnLoadMethod] — no prefab placement required.

Client Types

The SDK provides multiple clients to handle different AI features:

PlayKit_AIChatClient

Used for AI text generation and conversation. Supports basic chat, streaming responses, and structured output.

var chatClient = PlayKitSDK.Factory.CreateChatClient();
var chatClient = PlayKitSDK.Factory.CreateChatClient("gpt-4o");

Learn more: Text Generation

PlayKit_AIImageClient

Used for AI image generation. Supports multiple sizes and aspect ratios.

var imageClient = PlayKitSDK.Factory.CreateImageClient();
var imageClient = PlayKitSDK.Factory.CreateImageClient("dall-e-3");

Learn more: Image Generation

PlayKit_AudioTranscriptionClient

Used for converting audio to text (speech recognition).

var transcriptionClient = PlayKitSDK.Factory.CreateTranscriptionClient("whisper-1");

Learn more: Speech Recognition

PlayKit_NPC

A specialized client for simplifying NPC dialogue. Used as a MonoBehaviour component, automatically manages conversation history.

var npc = gameObject.AddComponent<PlayKit_NPC>();
PlayKitSDK.Populate.CreateNpc(recipient, "gpt-4o");

Learn more: NPC Conversations

PlayKit_PlayerClient

Manages player information, authentication, and credits.

var playerClient = PlayKitSDK.GetPlayerClient();
var info = playerClient.GetCachedPlayerInfo();
Debug.Log($"Remaining credits: {info.Credits}");

Learn more: Authentication

PlayKit_AIChatClient vs PlayKit_NPC

The SDK gives you two ways to build AI conversations. Picking the right one avoids a lot of unnecessary wiring.

PlayKit_AIChatClient — developer-facing

PlayKit_AIChatClient is a low-level building block. It exposes exactly what you need and nothing more: you hand it a message list, it returns a response. History, parsing, and output format are entirely yours to own.

var chatClient = PlayKitSDK.Factory.CreateChatClient();
var config = new PlayKit_ChatConfig(messages) { Temperature = 0.7f };
var result = await chatClient.TextGenerationAsync(config, token);
// you decide what to do with result.Response

Use it for: custom chat UIs, in-game consoles, structured data generation (GenerateStructuredAsync), tool/function calling, or any pipeline where you control the shape of the conversation.

PlayKit_NPC — game-designer-facing

PlayKit_NPC is an opinionated game-character system. You write a SetCharacterDesign() prompt; the SDK handles history, memory, reply predictions, and voice integration. The API surface is deliberately small so a designer can configure it without touching engine code.

npc.SetCharacterDesign("You are a gruff blacksmith named Arn...");
string reply = await npc.Talk("I need a sword", token);

Use it for: interactive NPCs, companion characters, dialogue scenes.

Why NPC uses Actions instead of structured output

PlayKit_NPC has no structured output method by design. The alternative is the Actions system, for two reasons:

Speed. Structured output adds tokens and a post-processing step — the model must produce valid JSON before anything happens in-game. Actions are embedded inline in the dialogue and execute the moment the model signals them, with no parsing overhead.

Character integrity. A structured-output call produces a JSON object, not a sentence — the character voice breaks. Actions let the NPC speak naturally and trigger game logic in the same response, without exposing a data format to the player.

// What the NPC can do is registered in the inspector or in code:
npc.OnActionTriggered += (actionName, args) => {
    if (actionName == "GiveItem")   GiveItemToPlayer(args["item_name"]);
    if (actionName == "OpenShop")   OpenShopUI();
};
// The NPC decides when to call them while replying naturally.

For structured data that lives outside the character (item stats, quest definitions, world state reads), use PlayKit_AIChatClient.GenerateStructuredAsync — not the NPC component.

At a glance

PlayKit_AIChatClientPlayKit_NPC
AudienceDevelopersGame designers
HistoryManualAutomatic
OutputRaw string / typed objectNatural dialogue + action calls
Structured dataGenerateStructuredAsyncUse Actions instead
Game logic integrationParse response manuallyAction system
MemorySetMemory / GetMemory
Save / restoreSaveHistory / LoadHistory

Factory Pattern

The SDK uses the factory pattern to create client instances. Factory methods are located in PlayKitSDK.Factory and PlayKitSDK.Populate:

var chat = PlayKitSDK.Factory.CreateChatClient();
var chat = PlayKitSDK.Factory.CreateChatClient("gpt-4o");
var image = PlayKitSDK.Factory.CreateImageClient();
var transcription = PlayKitSDK.Factory.CreateTranscriptionClient("whisper-1");
PlayKitSDK.Populate.CreateNpc(npcComponent, "gpt-4o");

If you don't specify a model name, the SDK will use the default model configured in the PlayKit SDK Settings window.

Async Operations

All SDK API calls are asynchronous, based on UniTask. UniTask is a Unity-optimized async library that's more efficient than standard Task.

Using async/await

using Cysharp.Threading.Tasks;

async void Start()
{
    var chatClient = PlayKitSDK.Factory.CreateChatClient();

    var result = await chatClient.TextGenerationAsync(
        config,
        this.GetCancellationTokenOnDestroy()
    );

    if (result.Success)
    {
        Debug.Log(result.Response);
    }
}

CancellationToken

All async methods accept a CancellationToken parameter for cancelling ongoing operations:

// Automatically cancel using Unity lifecycle
await chatClient.TextGenerationAsync(config, this.GetCancellationTokenOnDestroy());

// Manual cancellation control
var cts = new CancellationTokenSource();
var task = chatClient.TextGenerationAsync(config, cts.Token);

// Cancel after 5 seconds
await UniTask.Delay(5000);
cts.Cancel();

When using async operations in Unity, always pass a CancellationToken to avoid continuing execution after object destruction.

Conversation Message System

AI conversations use a message list to maintain context. Each message contains a Role and Content.

Message Roles

The SDK supports three message roles:

  • system: System instructions that define AI behavior and role
  • user: User or player messages
  • assistant: AI responses

Creating Conversation History

var messages = new List<PlayKit_ChatMessage>
{
    new PlayKit_ChatMessage
    {
        Role = "system",
        Content = "You are a friendly game NPC named Ellie. You run a magic shop."
    },
    new PlayKit_ChatMessage
    {
        Role = "user",
        Content = "Hello, what do you sell?"
    },
    new PlayKit_ChatMessage
    {
        Role = "assistant",
        Content = "Welcome! I have various magic potions and scrolls."
    },
    new PlayKit_ChatMessage
    {
        Role = "user",
        Content = "Do you have healing potions?"
    }
};

var config = new PlayKit_ChatConfig(messages) { Temperature = 0.7f };
var result = await chatClient.TextGenerationAsync(config, cancellationToken);

Managing Conversation History

You need to manually maintain conversation history, or use PlayKit_NPC for automatic management:

var history = new List<PlayKit_ChatMessage>
{
    new PlayKit_ChatMessage { Role = "system", Content = "You are a friendly assistant." },
    new PlayKit_ChatMessage { Role = "user", Content = "Hello" }
};

var result = await chatClient.TextGenerationAsync(new PlayKit_ChatConfig(history), token);

if (result.Success)
{
    history.Add(new PlayKit_ChatMessage { Role = "assistant", Content = result.Response });
}

Using PlayKit_NPC automatically manages conversation history without manual message adding.

Result Wrapper

The SDK uses PlayKit_AIResult<T> type to wrap API call results:

public class PlayKit_AIResult<T>
{
    public bool Success { get; }       // Whether operation succeeded
    public T Response { get; }         // Response data
    public string ErrorMessage { get; } // Error message (if failed)
}

Handling Results

var result = await chatClient.TextGenerationAsync(config, token);

if (result.Success)
{
    // Success: use result.Response
    Debug.Log($"AI response: {result.Response}");
    DisplayMessage(result.Response);
}
else
{
    // Failure: check result.ErrorMessage
    Debug.LogError($"Call failed: {result.ErrorMessage}");
    ShowErrorDialog(result.ErrorMessage);
}

Error Handling

The SDK provides clear error handling mechanisms.

Using Result Checking

The recommended approach is checking the PlayKit_AIResult's Success property:

var result = await chatClient.TextGenerationAsync(config, token);

if (!result.Success)
{
    Debug.LogError($"Error: {result.ErrorMessage}");
}

Catching Exceptions

For severe errors, the SDK throws exceptions:

using PlayKit_SDK;
using PlayKit_SDK.Public;

try
{
    var result = await chatClient.TextGenerationAsync(config, token);
}
catch (PlayKitApiErrorException ex)
{
    Debug.LogError($"API error: {ex.Message}");
}
catch (PlayKitImageSizeValidationException ex)
{
    Debug.LogError($"Invalid image size: {ex.Message}");
}
catch (PlayKitException ex)
{
    Debug.LogError($"SDK error: {ex.Message}");
}

Common Errors

  • SDK not initialized: Calling API before calling InitializeAsync()
  • Invalid Token: Developer Token expired or incorrect
  • Network error: Cannot connect to PlayKit API
  • Insufficient credits: Player account has insufficient credits
  • Parameter error: Invalid parameters passed (e.g., unsupported image size)

Configuration Options

Temperature

The temperature parameter controls AI response randomness, ranging from 0.0 to 2.0:

  • 0.0-0.3: High determinism, suitable for factual answers
  • 0.7: Balance creativity and consistency (default)
  • 1.5-2.0: Highly creative, suitable for creative content
var config = new PlayKit_ChatConfig(messages) { Temperature = 0.7f };

Default Models

You can configure default models in the PlayKit SDK Settings window:

  • Default Chat Model: Default chat model
  • Default Image Model: Default image generation model

Factory methods will use these defaults if no model is specified.

Debug Tools

The SDK provides some debugging helper methods:

PlayKit_AIChatClient.PrintPrettyChatMessages(messages, "Current Conversation");

Check SDK Status

if (PlayKitSDK.IsReady())
{
    Debug.Log("SDK is ready");
}
else
{
    Debug.LogWarning("SDK not initialized");
}

NPC Debugging

var npc = GetComponent<PlayKit_NPC>();

// Print NPC conversation history
npc.PrintPrettyChatMessages("NPC History");

// Check status
Debug.Log($"Is talking: {npc.IsTalking}");
Debug.Log($"History message count: {npc.GetHistoryLength()}");

Best Practices

  1. Always check IsReady(): Ensure SDK is initialized before calling APIs
  2. Use CancellationToken: Avoid continuing async operations after object destruction
  3. Check Success: Always check PlayKit_AIResult.Success instead of assuming success
  4. Limit history length: Long conversation history increases API costs and response time
  5. Set temperature appropriately: Choose suitable temperature values for your use case
  6. Use NPC Client: For game characters, prefer PlayKit_NPC over manual history management

Next Steps

Now that you understand the SDK's core concepts, continue learning specific features: