Skip to main content

Crate agents_kit

Crate agents_kit 

Source
Expand description

Portable agent runtimes over Codex App Server, OpenCode, and a provider-backed Custom implementation.

The public hierarchy is Agent → Workspace → Conversation. Supporting request and response values live in functional modules instead of being flattened onto the crate root.

Implement AgentBackend, WorkspaceBackend and ConversationBackend directly to supply a backend hierarchy. Associated children keep caller types concrete; the supplied opaque handles implement those same contracts.

Start with config and AgentBuilder, supplying AgentStorage at creation or explicit typed-ID reopen. workspace defines backend-host cwd, roots, policy and revision-checked replacement. conversation and prompt describe accepted work; notification covers durable acknowledgment and interactions. identity, model, tool and knowledge hold passive portable inputs, while error describes typed failure and cleanup context.

Custom retains direct caller ProviderBackend and ToolsetBackend values, using each toolset’s associated Handler without a Clone requirement. Unary and streaming prompts share one accepted-work owner. Dropping an observer neither cancels that work nor releases its admission slot; use abort or the consuming lifecycle operations and keep the async runtime alive through cleanup.

§Walkthroughs

GoalStart here
Build, close and reopen a supplied hierarchyThe local example below; AgentBuilder
Supply an exact native model and effortmodel and config
Observe output, resolve durable interactions and cancelconversation
Ingest local sources and choose retrieval scopeknowledge
Implement a caller-owned hierarchyAgentBackend’s complete composition example
Supply concrete Provider and non-Clone Toolset childrenAgentBuilder::with_provider

§Local construction, parent close and fresh-handle reopen

This runs locally with an owned embedded Lance StateStore directory. Provider construction is passive: submitting a prompt would require the configured Ollama service and exact model. The directory and all runtime handles belong to this example. Agent shutdown preserves quiescent durable records; closing an individual conversation instead permanently terminates that conversation.

Caller-built Local actions run in the caller process without Kit sandbox enforcement. Custom therefore requires FullAccess and Enabled when actions are configured, with read-write workspace roots; those roots do not confine the actions. This example’s ping action performs no filesystem or network I/O.

use std::{num::NonZeroUsize, time::Duration};
use agents_kit::{AgentBackend, AgentBuilder, AgentStorage, ConversationBackend, WorkspaceBackend};
use agents_kit::config::{AgentConfig, CustomAgentConfig, CustomLoopLimits, CustomToolApproval};
use agents_kit::conversation::NewConversation;
use agents_kit::{model::ModelSelector, tool::ToolSelection};
use agents_kit::workspace::{NewWorkspace, WorkspaceContext, WorkspaceDefaults,
    WorkspaceExecutionPolicy, WorkspaceNetworkAccess, WorkspaceRoot,
    WorkspaceRootAccess, WorkspaceSandboxMode};
use providers_kit::{Provider, ProviderConfig,
    config::{OllamaConfig, ProviderKind, TransportConfig}};
use storage_kit::{StateStore,
    state::config::{LanceStateStoreConfig, StateStoreConfig}};
use tools_kit::{Toolset, declaration::{ToolInfo, ToolName}, execution::ToolResult,
    local::ToolRegistration, schema::JsonSchema};

let directory = std::env::temp_dir().join(format!("agent-rustdoc-{}", uuid::Uuid::new_v4()));
std::fs::create_dir(&directory)?;
let store_config = StateStoreConfig::Lance(
    LanceStateStoreConfig::directory(directory.clone()));
let provider_config = ProviderConfig::new(
    ProviderKind::Ollama(OllamaConfig::local()), TransportConfig::default());
let config = AgentConfig::new(
    CustomAgentConfig::new(ModelSelector::new("exact-model")?, ToolSelection::Auto,
        CustomLoopLimits::new(4, 4, 1)?, CustomToolApproval::Deny)?.into(),
    Duration::from_secs(10), NonZeroUsize::MIN)?;
let fresh_tools = || -> Result<Toolset, tools_kit::ToolError> {
    Toolset::local(vec![ToolRegistration::function(
        ToolInfo::new(ToolName::new("ping")?,
            JsonSchema::strict(serde_json::json!({"type": "object"}))),
        |_| async { Ok(ToolResult::text("pong")) },
    )])
};
let runtime = tokio::runtime::Builder::new_current_thread().enable_all().build()?;
let outcome = runtime.block_on(async {
    let store = StateStore::connect(store_config.clone()).await?;
    let agent = AgentBuilder::create(config.clone(), AgentStorage::new(store))
        .with_provider(Provider::from_config(provider_config.clone())?)
        .with_toolset(fresh_tools()?).build().await?;
    let agent_id = agent.id();
    let outcome = async {
        let cwd = std::env::current_dir()?;
        let context = WorkspaceContext::new(cwd.clone(),
            vec![WorkspaceRoot::new(cwd, WorkspaceRootAccess::ReadWrite)?],
            WorkspaceExecutionPolicy::new(WorkspaceSandboxMode::FullAccess,
                WorkspaceNetworkAccess::Enabled))?;
        let workspace = agent.new_workspace(
            NewWorkspace::new("docs", context, WorkspaceDefaults::empty())?).await?;
        let conversation = workspace.new_conversation(
            NewConversation::new(Some("Review".into()), None, Vec::new())?).await?;
        let ids = (workspace.id(), conversation.id());
        assert_eq!(conversation.info().await?.title(), Some("Review"));
        workspace.close().await?; // invalidates runtime children, preserves records
        drop(conversation);
        Ok::<_, Box<dyn std::error::Error>>(ids)
    }.await;
    let shutdown = agent.shutdown().await;
    let (workspace_id, conversation_id) = outcome?;
    shutdown?;

    // New handles: credentials, tools and storage are supplied again, not recovered.
    let store = StateStore::connect(store_config).await?;
    let reopened = AgentBuilder::reopen(config, AgentStorage::new(store), agent_id)
        .with_provider(Provider::from_config(provider_config)?)
        .with_toolset(fresh_tools()?).build().await?;
    let outcome = async {
        let workspace = reopened.get_workspace(workspace_id).await?;
        let conversation = workspace.get_conversation(conversation_id.clone()).await?;
        assert_eq!(conversation.id(), conversation_id);
        assert_eq!(conversation.info().await?.title(), Some("Review"));
        conversation.close().await?; // terminal conversation cleanup
        workspace.close().await?;
        Ok::<(), Box<dyn std::error::Error>>(())
    }.await;
    let shutdown = reopened.shutdown().await;
    outcome?;
    shutdown?;
});
// Retain data on failure; successful shutdown is required before deletion.
outcome?;
std::fs::remove_dir_all(directory)?;

Native Codex and OpenCode builders can select caller provider and tool types for static upper composition with AgentBuilder::create_for_backends or AgentBuilder::reopen_for_backends. Those methods retain no provider value; Custom receives its concrete provider only through AgentBuilder::with_provider.

Custom uses the selected Model’s associated continuation type directly. Returned assistant messages remain intact through one prompt’s tool turns; durable history contains only provider-neutral caller and final-assistant text, so reopen does not reconstruct provider replay state.

Re-exports§

pub use crate::conversation::Conversation;
pub use crate::conversation::ConversationBackend;
pub use crate::error::KitError;
pub use crate::workspace::Workspace;
pub use crate::workspace::WorkspaceBackend;

Modules§

config
Agent construction settings and backend runtime policies. Validated passive configuration for Agent construction.
conversation
Conversation handles, backend contracts, and conversation requests and responses. Conversation metadata, accepted prompts, exact file reads and durable interactions.
error
Portable, safely formatted failures for Agent operations.
identity
Validated identities and agent inventory information. Opaque durable identities and descriptive agent inventory.
knowledge
Knowledge sources, scopes, ingestion requests, and retrieval policies. Inputs for privately managed knowledge ingestion and retrieval policy.
model
Model inventory, opaque selectors, and reasoning settings. Backend-advertised model, personality, and reasoning selectors.
notification
Durable notifications, caller resolutions, and notification streams. Durable conversation facts, exclusive delivery, and caller interaction resolutions.
prompt
Prompt requests, responses, and incremental output streams. Prompt inputs, exact terminal responses, and transient output observation.
tool
Portable tool selection and managed tool inventory. Managed tool inventory and per-prompt selection.
workspace
Workspace handles, backend contracts, defaults, and workspace requests. Workspace contexts, durable snapshots, revision-checked requests, and live handles.

Structs§

Agent
A live handle to one durable agent and its workspace inventory.
AgentBuilder
Configures creation or reopening of one durable Agent.
AgentStorage
Coordinates durable agent identities through a caller-supplied state store.

Traits§

AgentBackend
Public implementation contract for a complete portable agent runtime.