API Reference
This page is a quick, task-oriented reference to the public API. For the exhaustive, always-current API — every method, field, and trait bound — see the generated docs on docs.rs/kova-sdk.
Everything below assumes:
use kova_sdk::prelude::*;AgentBuilder
Section titled “AgentBuilder”AgentBuilder::new() .provider(Arc<dyn LlmProvider>) // required .system_prompt(impl Into<String>) // optional .inference_config(InferenceConfig) // optional .tool(Arc<dyn Tool>) // optional, repeatable .tool_registry(ToolRegistry) // optional (composes with .tool()) .mcp_client(Arc<McpClient>, &str).await? // optional, async .context_budget(u32) // optional (max prompt tokens; heuristic guard) .max_iterations(usize) // optional (default 10) .max_concurrent_tools(usize) // optional (default 10) .retry_config(RetryConfig) // optional (default 2 retries) .metrics(Arc<MetricsCollector>) // optional .with_approval_handler(Arc<dyn ToolApprovalHandler>) // optional .with_lifecycle_hook(Arc<dyn ToolLifecycleHook>) // optional .build()? // -> Result<Agent, KovaError>| Method | Required | Default | Notes |
|---|---|---|---|
provider | yes | — | The only required piece |
system_prompt | no | None | Prepended to every turn |
inference_config | no | all-None | model, max_tokens, temperature, top_p, stop_sequences, response_format |
tool | no | — | Repeatable; merged into the registry on build |
tool_registry | no | empty | Composes with tool |
mcp_client | no | — | Async; discovers tools at build time |
context_budget | no | None | Max prompt tokens per call (heuristic); over-budget fails with ContextBudgetExceeded before the request |
max_iterations | no | 10 | Cap on tool-call loop rounds |
max_concurrent_tools | no | 10 | Semaphore cap for parallel tools |
retry_config | no | 2 retries, exp backoff | RetryConfig::disabled() to turn off |
metrics | no | None | Auto-records latency/tokens/errors/tool durations |
with_approval_handler | no | None | Gate before each tool execution |
with_lifecycle_hook | no | None | Observe tool start/end |
The agent is stateless — you own the conversation history. There is no
session/memory API; pass a &[ConversationMessage] in, persist new_messages.
// One agentic turn over caller-owned history.agent.run(messages: &[ConversationMessage]) -> Result<AgentResponse, KovaError>
// With per-call InferenceConfig overrides (unset fields fall back to defaults).agent.run_with_config(messages, overrides: InferenceConfig) -> Result<AgentResponse, KovaError>
// Constrain the final text to a JSON schema and parse it into T.agent.run_structured::<T>(messages, format: ResponseFormat) -> Result<(T, AgentResponse), KovaError>
// Pull-based streaming (see AgentEvent below).agent.run_stream(messages) -> impl Stream<Item = Result<AgentEvent, KovaError>>
// Cancellable variants — the token aborts mid-provider-call / mid-tool with// KovaError::Cancelled, producing no messages.agent.run_cancellable(messages, cancel: CancellationToken) -> Result<AgentResponse, KovaError>agent.run_stream_cancellable(messages, cancel: CancellationToken) -> impl Stream<…>
// Input tokens reported for the most recently completed turn (0 until the first).agent.last_turn_input_tokens() -> u32AgentResponse
Section titled “AgentResponse”pub struct AgentResponse { pub text: String, // final assistant text pub new_messages: Vec<ConversationMessage>, // everything the turn produced — persist this pub stop_reason: StopReason, pub usage: UsageStats, // summed across all calls in the turn pub llm_calls: u64, pub thinking: Option<String>,}AgentEvent (pull-based streaming)
Section titled “AgentEvent (pull-based streaming)”pub enum AgentEvent { TextDelta { text: String }, ThinkingDelta { text: String }, ToolCallStarted { id: String, name: String, input: serde_json::Value }, ToolCallFinished { id: String, name: String, result: String, is_error: bool }, TurnCompleted { response: AgentResponse },}Providers
Section titled “Providers”All implement LlmProvider and are wrapped in Arc before
AgentBuilder::provider. Config surfaces are covered in
Configuring a Provider.
// Anthropic (native Messages API; prompt caching + adaptive thinking)kova_sdk::provider::anthropic::{AnthropicProvider, AnthropicProviderConfig}// OpenAI-compatiblekova_sdk::provider::openai::{OpenAiCompatibleProvider, OpenAiProviderConfig}// AWS Bedrock (BedrockProvider::new is async)kova_sdk::provider::bedrock::{BedrockProvider, BedrockProviderConfig}// Google Geminikova_sdk::provider::gemini::{GeminiProvider, GeminiProviderConfig}// Ollamakova_sdk::provider::ollama::{OllamaProvider, OllamaProviderConfig, OllamaThink}The LlmProvider trait:
#[async_trait]pub trait LlmProvider: Send + Sync { async fn chat_completion(&self, messages: &[ConversationMessage], tools: &[ToolDefinition], config: &InferenceConfig) -> Result<ModelResponse, KovaError>; async fn chat_completion_stream(&self, messages: &[ConversationMessage], tools: &[ToolDefinition], config: &InferenceConfig) -> Result<Pin<Box<dyn Stream<Item = Result<StreamEvent, KovaError>> + Send>>, KovaError>; async fn list_models(&self) -> Result<Vec<ModelInfo>, KovaError>; // Default: offline ~4-chars/token heuristic; Anthropic overrides it natively. async fn count_tokens(&self, messages: &[ConversationMessage], tools: &[ToolDefinition]) -> Result<u32, KovaError>;}Structured output
Section titled “Structured output”use kova_sdk::models::ResponseFormat;
let format = ResponseFormat::named("route", schema_value); // or ResponseFormat::new(schema_value)let (value, response) = agent.run_structured::<MyType>(&messages, format).await?;Mapped natively per provider (OpenAI/Anthropic/Gemini/Ollama); Bedrock rejects
response_format. See Structured Output.
#[async_trait]pub trait Tool: Send + Sync { fn name(&self) -> &str; fn description(&self) -> &str; fn parameters_schema(&self) -> serde_json::Value; async fn execute(&self, args: serde_json::Value) -> Result<ToolResult, KovaError>;}
// Registry (Arc<RwLock<HashMap>> under the hood; synchronous methods)let registry = ToolRegistry::new();registry.register(Arc::new(MyTool)).await;registry.get("my_tool").await; // Option<Arc<dyn Tool>>registry.list().await; // Vec<String>registry.tool_definitions().await; // Vec<ToolDefinition> (cached)Built-in tools (tools / web-tools features)
Section titled “Built-in tools (tools / web-tools features)”use kova_sdk::tools::{ToolPolicy, WebPolicy, register_all_tools, register_all_tools_with_policy, fetch_text};
pub struct ToolPolicy { pub workspace_root: Option<PathBuf>, pub protected_paths: Vec<PathBuf>, pub shell_timeout: Duration, pub web: WebPolicy,}See Built-in Tools & ToolPolicy.
Approvals & lifecycle
Section titled “Approvals & lifecycle”pub enum ApprovalDecision { Approved, ApprovedForSession, Denied, DeniedWithReason(String), DeniedAlways }
#[async_trait]pub trait ToolApprovalHandler: Send + Sync { async fn approve(&self, tool_name: &str, args: &Value) -> ApprovalDecision;}
// ToolLifecycleHook — observe tool start/end (register with .with_lifecycle_hook)Conversations
Section titled “Conversations”The agent holds no history — you own a Vec<ConversationMessage>, pass it to
run, and persist response.new_messages. There is no MemoryStore. See
Conversations & History.
Embeddings
Section titled “Embeddings”use kova_sdk::embedding::EmbeddingProvider; // prelude re-exportuse kova_sdk::embedding::openai::OpenAiEmbeddingProvider; // feature `openai`use kova_sdk::embedding::ollama::OllamaEmbeddingProvider; // feature `ollama`
#[async_trait]pub trait EmbeddingProvider: Send + Sync { async fn embed(&self, texts: &[String]) -> Result<Vec<Vec<f32>>, KovaError>; fn dimensions(&self) -> Option<usize> { None }}
OpenAiEmbeddingProvider::new(base_url, model)?.with_api_key(key).with_dimensions(256);OllamaEmbeddingProvider::new(base_url, model)?;See Embeddings.
use kova_sdk::mcp::{McpClient, McpTransport, TokenProvider};
McpTransport::Stdio { command: String, args: Vec<String>, env: HashMap<String, String> }McpTransport::HttpSse { url: String, headers: HashMap<String, String> }McpTransport::StreamableHttp { url: String, headers: HashMap<String, String>, auth: Option<Arc<dyn TokenProvider>> }
McpClient::connect(transport).await?McpClient::connect_with_timeout(transport, Duration).await?client.tools_list().await? // cached until reconnectclient.tools_call(name, args).await? // (content, is_error); auto-reconnects once on Connectionclient.tools_call_with_timeout(name, args, Duration).await?client.reconnect().await? // re-establish + clear tools/list cacheStreaming
Section titled “Streaming”Pull-based only — run_stream / run_stream_cancellable yield AgentEvents
(see above). No handler to register. See Streaming.
Telemetry
Section titled “Telemetry”use kova_sdk::telemetry::{TelemetryConfig, ExporterConfig, OtlpProtocol, MetricsCollector};
TelemetryConfig::builder() .service_name("my-agent") .log_level(tracing::Level::INFO) .exporter(ExporterConfig::Otlp { endpoint, protocol: OtlpProtocol::Grpc }) // needs `telemetry` .sampling_rate(0.5) .build() .init()?;
let m = MetricsCollector::new(); // always availablem.record_llm_request(latency_ms, in_tokens, out_tokens);m.record_tool_invocation(duration_ms, success);m.record_llm_error();m.llm_request_count(); m.total_tokens(); m.error_count();Data types
Section titled “Data types”| Type | Shape |
|---|---|
Role | User · Assistant · System · Tool |
ContentBlock | Text { text } · ToolUse { id, name, input, provider_metadata } · ToolResult { tool_use_id, content, is_error } · Thinking { thinking, signature } |
ConversationMessage | { role: Role, content: Vec<ContentBlock> } |
ModelResponse | { content, stop_reason, usage: Option<UsageStats>, thinking: Option<String> } |
StopReason | EndTurn · ToolUse · MaxTokens · Unknown(String) (as_str() for logging) |
UsageStats | { input_tokens, output_tokens, total_tokens, thinking_tokens, cache_read_tokens, cache_creation_tokens: Option<u32> } |
InferenceConfig | { model, max_tokens, temperature, top_p, stop_sequences, response_format } — all Option |
ResponseFormat | { name: Option<String>, schema: Value } — ::named(name, schema) / ::new(schema) |
ToolDefinition | { name, description, parameters: Value } |
ToolResult | { content: String, is_error: bool } |
StreamEvent | ContentDelta · ThinkingDelta · ThinkingBlock { thinking, signature } · ToolUseDelta { index, .. } · UsageEvent { input_tokens, output_tokens, thinking_tokens, cache_read_tokens, cache_creation_tokens } · StopEvent · Error |
ModelInfo | { id, object, created, owned_by } |
ProviderErrorClass | AuthInvalid · AuthForbidden · RateLimited { retry_after } · Overloaded · InvalidRequest · NotFound · Other |
KovaError | see Error Types |