kaynine-runtime 0.1.0

Runtime actors, durable runs, approval flows, and policy chains for Kaynine
Documentation

Kaynine

Kaynine is a host-agnostic, single-agent framework for Rust applications. It provides the agent loop, model adapters, tools, policy enforcement, event streaming, and durable sessions without coupling your product to a UI stack.

Features

  • OpenAI Responses, Anthropic Messages, and OpenAI-compatible providers
  • Streaming responses, tool calls, cancellation, steering, and approval flows
  • SQLite-backed session recovery, branching, and context compaction
  • Composable prompts, product context, and prompt-only skills

Core integration

The host owns credentials, tools, policy, and presentation. The following example creates a durable session, connects an OpenAI-compatible provider, and streams one run. Subscribe before starting the run so no live event is missed.

Add the facade crate and every Kaynine module is available under one dependency:

kaynine = "0.1"
use async_trait::async_trait;
use kaynine::core::{
    budget::BudgetPolicy,
    error::CredentialError,
    event::RealtimeEvent,
    ids::{ModelId, SessionId},
    message::ContentBlock,
    policy::AllowAllPolicy,
    provider::{
        CredentialProvider, CredentialRequest, Credentials, ModelCapabilities,
    },
    store::CreateSessionRequest,
};
use kaynine::providers::openai_compatible::OpenAiCompatibleProvider;
use kaynine::runtime::{AgentRuntime, StartRunRequest, SubscriptionItem};
use kaynine::store::sqlite::SqliteStore;
use std::{path::Path, sync::Arc, time::Duration};

struct EnvCredentials;

#[async_trait]
impl CredentialProvider for EnvCredentials {
    async fn resolve(
        &self,
        _request: CredentialRequest,
    ) -> Result<Credentials, CredentialError> {
        Ok(Credentials {
            bearer: std::env::var("KAYNINE_API_KEY").ok(),
            headers: Vec::new(),
        })
    }
}

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let store = Arc::new(SqliteStore::open(Path::new("kaynine.db"))?);
    let runtime = AgentRuntime::new(store);
    let session_id = SessionId::generate();
    let model = ModelId::from("your-model");

    runtime
        .create_session(CreateSessionRequest {
            command: None,
            session_id: session_id.clone(),
            definition_id: "my-agent".into(),
            definition_version: 1,
            default_model: model.clone(),
            metadata: serde_json::json!({}),
        })
        .await?;
    let branch_id = runtime.list_branches(&session_id).await?.remove(0).branch_id;
    let mut events = runtime.watch_session(&session_id).await?;

    let capabilities = ModelCapabilities {
        context_tokens: 128_000,
        max_output_tokens: 8_192,
        supports_tools: true,
        supports_images: false,
        supports_reasoning: true,
    };
    let provider = Arc::new(OpenAiCompatibleProvider::new(
        "openai-compatible",
        "http://localhost:8080/v1",
        serde_json::json!({ "your-model": capabilities }),
    )?);

    runtime
        .start_run(StartRunRequest {
            command_id: uuid::Uuid::new_v4().to_string(),
            session_id: session_id.clone(),
            branch_id,
            content: vec![ContentBlock::Text {
                text: "Hello from Kaynine".into(),
            }],
            model_override: None,
            reasoning_override: None,
            capabilities,
            system_prompt: "You are a helpful assistant.".into(),
            provider: provider.clone(),
            token_counter: provider,
            credentials: Arc::new(EnvCredentials),
            tools: Vec::new(),
            budget: BudgetPolicy::default(),
            max_turns: Some(8),
            policy: Arc::new(AllowAllPolicy), // Use a stricter policy for tools.
            approval_timeout: None,
            prompt: None,
            compaction: None,
            compaction_selector: None,
        })
        .await?;

    while let Some(item) = events.next().await {
        if let SubscriptionItem::Event(event) = item {
            match event.payload {
                RealtimeEvent::TextDelta { text, .. } => print!("{text}"),
                RealtimeEvent::RunCompleted | RealtimeEvent::RunCancelled => break,
                RealtimeEvent::RunFailed { reason } => {
                    return Err(std::io::Error::other(format!("{reason:?}")).into());
                }
                _ => {}
            }
        }
    }

    runtime.shutdown(Duration::from_secs(2)).await?;
    Ok(())
}

See examples/host-demo for a headless host and examples/tauri-minimal for a Tauri v2 integration.

Crates

Crate Responsibility
kaynine Facade crate re-exporting everything below as one dependency
kaynine-core Domain types, extension traits, and the agent loop
kaynine-runtime Sessions, runs, subscriptions, and the host facade
kaynine-providers Model provider adapters
kaynine-store SQLite persistence
kaynine-tools Sandboxed file and process tools