Skip to Content
Platform
ReferenceRust SDK

Rust SDK

Run tasks against a deployed runtime from Rust and read what the agent did.

The Rust SDK has the same surface as the JavaScript SDK; this page shows the Rust calls and what differs.

Install

cargo add introspection-sdk futures serde_json cargo add tokio --features rt-multi-thread,macros
FeatureAdds
DefaultREST client (runtimes, runner, tasks, files, shares, conversations, events, metrics, experiments) and auth (from_service_account, token_exchange, authorization_code_token).
otelIntrospectionLogs for track, feedback, identify.
arrowArrow decoding for conversation and event reads.
testingIn-memory exporter and test helpers.

IntrospectionClient::new(ClientConfig::default()) reads INTROSPECTION_TOKEN and returns IntrospectionError::TokenRequired when nothing resolves. Other credentials: Authentication.

Run a task

use futures::StreamExt; use introspection_sdk::{AgUiEvent, ClientConfig, IntrospectionClient, RunRequest, RunnerIdentity}; let client = IntrospectionClient::new(ClientConfig::default())?; let runner = client .runtime("support-agent") .await? .run(RunRequest { identity: Some(RunnerIdentity { user_id: Some("user_123".into()), ..Default::default() }), ..Default::default() }) .await?; let handle = runner.tasks().start_prompt("Summarize the open tickets.").await?; println!("{}", handle.text().await?); let mut events = runner.tasks().start_prompt("Say hello.").await?.into_stream().await?; while let Some(event) = events.next().await { if let AgUiEvent::TextMessageContent(m) = event? { print!("{}", m.delta); } }

RunRequest fields are all optional: identity (user_id, anonymous_id, conversation_id, tags, metadata), caller, agent_name, ttl_seconds, scope. With no identity the task belongs to your credential’s own member (an API key’s agent member); see Run a task for an end user. runner.tasks().start(&TaskCreate { .. }) takes the full option set (title, agent, metadata, files, repositories, tags); follow-ups use runner.tasks().runs.create(&task_id, &TaskRunCreate { .. }). Close with runner.close() and client.shutdown()?.

Continue and control a task

  • Reattach. Read active_run_id or latest_run_id from the task’s metadata, then runner.tasks().runs.stream(&task_id, &run_id).await?. There is no since cursor; a reattach replays the run.
  • Stream options. runs.stream_with(&task_id, &run_id, opts) and handle.stream_with(opts) take StreamOptions (max_reconnects 5, backoff 500 ms, timeout 300 s, emit_reconnect_events) and return the stream directly. Semantics and the retry table: JavaScript.
  • Interrupts. Read ids from the RUN_FINISHED outcome["interrupts"], then resume (Ask the user):
use introspection_sdk::{ResumeEntry, TaskCancelOptions, TaskRunResume}; runner.tasks().runs.resume(&task_id, &TaskRunResume { resume: vec![ResumeEntry { interrupt_id, status: "resolved".into(), payload: Some(serde_json::json!({ "approved": true })), }], }).await?; handle.cancel().await?; // abort the turn, keep the sandbox warm handle.cancel_with(&TaskCancelOptions::Drain { drain_within_seconds: Some(60) }).await?;

Files and shares

use introspection_sdk::{FileType, FileUpload, TaskCreate, TaskFileRef}; let uploaded = runner.files().upload(FileUpload::from_path("notes.txt").with_file_type(FileType::Upload)).await?; runner.tasks().start(&TaskCreate { prompt: Some("Summarize the attached notes.".into()), files: Some(vec![TaskFileRef { id: uploaded.id.to_string(), ..Default::default() }]), ..Default::default() }).await?;

FileUpload::from_bytes, files().create_text, download, and download_stream cover the rest. runner.shares() has create (ShareCreate::new(resource_type, id) plus granted_member_id, granted_tag, visible_from), update (only visible_from), and delete. Rules: Sharing.

Conversations, events, and metrics

use introspection_sdk::{ConversationListParams, MetricSpec, MetricsQuery}; let mut pages = runner.conversations().list(&ConversationListParams::default())?; while let Some(page) = pages.next_page().await? { for c in &page.records { println!("{} {}", c.id, c.usage.total_tokens); } } let result = runner.metrics().query(&MetricsQuery { view: "conversations".into(), metrics: vec![MetricSpec::of("sum", "total_cost_usd")], lookback: Some("7d".into()), ..Default::default() }).await?;
  • conversations().items.list/get read the transcript; export_json, export_trajectory, export_stream, and export_arrow (feature arrow) sit on conversations().
  • events().list(&EventListParams::new(IntrospectionEventName::Feedback))? returns typed Event variants (annotation too); pass IntrospectionEventName::Unknown("introspection.track".into()) for track events.
  • MetricsQuery.lookback is a client-side convenience lowered to absolute timestamps; rows are typed MetricRows, and truncated() says whether the row limit was hit.
  • Paginator offers next_page(), collect_all(max_pages), and Stream.

Feedback

use introspection_sdk::otel::{FeedbackOptions, IntrospectionLogs}; let logs = IntrospectionLogs::builder().service_name("support-api").build()?; { let _c = logs.set_conversation_id(&task_id); logs.feedback("thumbs_up", FeedbackOptions::new().with_comments("Solved it")); } logs.shutdown()?;

Needs the otel feature. with_previous_response_id anchors feedback to one response. Name rules: Send feedback.

Experiments

client.experiments() has list, get, create, update, and delete (documents as in introspection experiments create). client.experiment(id, project) returns a handle with run, start, end, and cancel.

let created = client.experiments().create(&serde_json::json!({ "project": "my-project", "name": "candidate", "runtime": "support-agent", "arms": [{ "runtime_id": a, "arm_label": "baseline" }, { "runtime_id": b, "arm_label": "candidate" }], "goal_json": { "kind": "composite", "direction": "maximize", "components": [{ "source": "judge", "judge_id": judge_id, "weight": 1.0 }] } })).await?; client.experiment(created.id, "my-project").start().await?;

Environment variables and errors

Environment variables match JavaScript, except INTROSPECTION_LOG_LEVEL and INTROSPECTION_STRICT_TRACING. Calls return ApiResult<T> with IntrospectionAPIError: Http (accessors status(), code(), request_id(), body(), retry_after()), RunFailed and StreamIncomplete from streams, and Transport, Decode, Timeout, Io, InvalidConfig. Client setup returns IntrospectionError; IntrospectionLogs returns IntrospectionLogsError.

Next

Last updated on