For AI agents: a documentation index is available at https://docs.plungeai.com/llms.txt. Append .md to any page URL, or send Accept: text/markdown, to get markdown. Setup instructions for agents are at https://docs.plungeai.com/agents.md. One ozk_ key opens every plane, models included.

Documentation Index: fetch the complete documentation index at /llms.txt. Use this file to discover all available pages before exploring further.

The official Rust SDK for the PlungeAI One API (https://api.plungeai.com). Targets One API 2.4.0; crate version 1.0.0. The resource methods and their types are generated from the API's own OpenAPI document (GET /v1/openapi.json). Async over reqwest (rustls) on the tokio runtime.

Release status: cargo search plungeai; until it answers, depend on the path sdk/one-api-rust/ in the platform repository.

Installation

cargo add plungeai tokio --features tokio/full

Usage

use plungeai::{types::*, Client};

#[tokio::main]
async fn main() -> Result<(), plungeai::Error> {
    let client = Client::new()?; // reads PLUNGEAI_API_KEY; or Client::builder().api_key("ozk_…").build()?

    let me = client.whoami().await?;
    let run = client
        .agents()
        .execute("calculator-agent", &AgentExecuteParams { prompt: Some("6*7".into()), ..Default::default() })
        .await?;
    let hits = client
        .discovery()
        .search(&DiscoverySearchParams { q: Some("web search".into()), kind: Some(DiscoverySearchParamsKind::Agents), ..Default::default() })
        .await?;
    Ok(())
}

Resources are methods on the client (client.agents(), client.workflows().versions()); every operation takes its path parameters first, then a reference to its params struct (plungeai::types::<Resource><Method>Params, all Default). Params and responses are serde structs under plungeai::types; optional fields are Option<T>; response enums carry an Unknown variant, so a new server value never breaks a client.

Streaming responses

use futures_util::StreamExt;

let mut stream = client
    .workflows()
    .execute_inline_stream(&WorkflowExecuteInlineStreamParams { workflow: workflow.into(), ..Default::default() })
    .await?;
while let Some(event) = stream.next().await {
    let event = event?;
    if event.event.as_deref() == Some("token") {
        let token: serde_json::Value = event.json()?;
        print!("{}", token["delta"]);
    }
}

event.data is the raw string of the server-sent event; event.json::<T>() parses it. Dropping the stream cancels the request. Methods that accept stream: true on the API have a …_stream twin (client.agents().execute_stream, client.chat().completions().create_stream) returning the same Stream.

Auto-pagination

let mut items = client.workflows().list(&WorkflowListParams { kind: Some(WorkflowListParamsKind::Bot), ..Default::default() }).await?.into_stream();
while let Some(w) = items.next().await {
    println!("{:?}", w?);
}

let mut page = client.workflows().list(&WorkflowListParams { limit: Some(50), ..Default::default() }).await?;
loop {
    for w in &page.data {
        println!("{w:?}");
    }
    if !page.has_next_page() {
        break;
    }
    page = page.next_page().await?;
}

Handling errors

match client.agents().execute("calculator-agent", &AgentExecuteParams { prompt: Some("6*7".into()), ..Default::default() }).await {
    Ok(run) => println!("{run:?}"),
    Err(plungeai::Error::Api(err)) if err.status == 424 => println!("{:?}", err.connect.map(|c| c.link)),
    Err(plungeai::Error::Api(err)) => println!("{} {:?} {:?}", err.status, err.code, err.request_id),
    Err(err) => return Err(err),
}

One enum, plungeai::Error: Api(Box<ApiError>) for a response with an error status (status, code — the envelope's error.code, message, request_id — the x-request-id header, and connect on 424 with provider, method, link), Connection for a request that never got a response, Timeout, and Decode for a body that does not match its type. Predicates err.status(), err.is_not_found(), err.is_rate_limit() and so on classify without matching.

Retries

Failed requests are retried 2 times by default with short exponential backoff (honouring Retry-After): connection errors, timeouts, 408, 429 and ≥ 500. 409 and 424 are never retried — on the One API they are semantic answers (approval_required, duplicate_execution_id, a missing connection), and a retried execute would start a second run. Set the count on the builder or per call:

let client = Client::builder().max_retries(0).build()?;
client.with_options(RequestOptions::new().max_retries(5)).agents().execute("calculator-agent", &params).await?;

RequestOptions::new().idempotency_key(key) is sent as x-trace-id, the API's idempotency key: it becomes the run's execution id, is re-sent on every retry of the call, and a replay answers 409 duplicate_execution_id.

Timeouts

Each attempt times out after 10 minutes by default and fails with Error::Timeout (retried as above). Set it on the builder or per call: Client::builder().timeout(Duration::from_secs(20)), RequestOptions::new().timeout(Duration::from_secs(5)).

Raw responses

let response = client.agents().execute_raw("calculator-agent", &params).await?;
println!("{} {:?}", response.status, response.request_id);
let run: AgentExecuteResponse = response.parse()?;

client.with_options(RequestOptions) (header, query, timeout, max_retries, idempotency_key) returns a client whose every call carries those options, and every JSON operation has a …_raw form returning the response with its status, headers, request_id and body bytes. client.get(path), client.post(path, &body) and friends reach routes the generated layer does not cover.

Models plane

client.chat().completions().create(...) (plus client.embeddings() and client.models()) covers the OpenAI-compatible routes here; any OpenAI client also works with base URL https://api.plungeai.com/v1 and the same key.

Requirements

Rust 1.85 or newer (edition 2021); tokio runtime. TLS through rustls — no system OpenSSL needed.

Planned: TI-33

Search is not available yet. Until it ships, use the page index or browse the sidebar.

Planned: TI-34

The docs assistant is not available yet. You can hand these docs to your own assistant instead.