plungeai-sdk-setup
Per-language detail — the four One API SDKs
Shared by all four: the key comes from PLUNGEAIAPIKEY; base URL https://api.plungeai.com; retries 2 with exponential backoff honouring Retry-After on connection errors, timeouts, 408, 429 and ≥ 500 — never on 409 or 424 (semantic answers: approvalrequired, duplicateexecutionid, a missing…
Shared by all four: the key comes from PLUNGEAI_API_KEY; base URL https://api.plungeai.com; retries 2 with
exponential backoff honouring Retry-After on connection errors, timeouts, 408, 429 and ≥ 500 — never on 409 or
424 (semantic answers: approval_required, duplicate_execution_id, a missing connection; a retried execute
would start a second run); 10-minute timeout; the idempotency key is sent as x-trace-id, becomes the run's
execution id, is re-sent on every retry of the call, and a replay answers 409 duplicate_execution_id. Agent and
tool ids below (calculator-agent) are illustrative — discover real ids with discovery.search first.
Error statuses map the same way in TypeScript and Python:
| Status | Error class |
|---|---|
| 400 | BadRequestError |
| 401 | AuthenticationError |
| 403 | PermissionDeniedError |
| 404 | NotFoundError |
| 409 | ConflictError |
| 422 | UnprocessableEntityError |
| 424 | FailedDependencyError — connect: { provider, method, link } says where to connect the missing account |
| 429 | RateLimitError |
| ≥ 500 | InternalServerError |
| no response | APIConnectionError (timeout: TS APIConnectionTimeoutError, Python APITimeoutError) |
code is the envelope's error.code; the request id is the x-request-id header.
TypeScript — @plungeai/one-api
import PlungeAI from '@plungeai/one-api'
const client = new PlungeAI({ apiKey: process.env['PLUNGEAI_API_KEY'] }) // the default; can be omitted
const stream = await client.workflows.executeInlineStream({ workflow }) // workflow: CNL YAML string
for await (const event of stream) {
if (event.event === 'token') process.stdout.write((event.data as { delta: string }).delta)
}
for await (const w of client.workflows.list({ kind: 'bot' })) console.log(w) // walks every page
let page = await client.workflows.list({ limit: 50 })
while (page.hasNextPage()) page = await page.getNextPage()
try {
await client.agents.execute('calculator-agent', { prompt: '6*7' }, { maxRetries: 5 })
} catch (err) {
if (err instanceof PlungeAI.FailedDependencyError) console.log(err.connect?.link)
else if (err instanceof PlungeAI.APIError) console.log(err.status, err.code, err.requestID)
else throw err
}
const { data, request_id } = await client.whoami().withResponse()- Streams:
breakorstream.controller.abort()aborts the request;stream.tee(),stream.toReadableStream().stream: trueonclient.agents.execute/client.chat.completions.createreturns the sameStream. - Options per request:
maxRetries,timeout(ms),idempotencyKey. Client:new PlungeAI({ maxRetries: 0, timeout: 20_000 }). - Raw:
.withResponse()→{ data, response, request_id };.asResponse()→ the rawResponse, body unread. - Error classes are exported by name and as statics on
PlungeAI. - Runtimes: Node.js 20+, Deno, Bun, Cloudflare Workers, Vercel Edge. Browsers refused unless
dangerouslyAllowBrowser: true.
Python — plungeai
from plungeai import PlungeAI, APIError, FailedDependencyError
client = PlungeAI() # PlungeAI(api_key="ozk_…", max_retries=0, timeout=20.0)
for event in client.workflows.execute_inline_stream(workflow=workflow):
if event.event == "token":
print(event.json()["delta"], end="")
for w in client.workflows.list(kind="bot"): # walks every page
print(w)
page = client.workflows.list(limit=50) # page.data, page.has_more
while page.has_next_page():
page = page.get_next_page()
try:
client.agents.execute("calculator-agent", prompt="6*7", max_retries=5)
except FailedDependencyError as err:
print(err.connect["link"])
except APIError as err:
print(err.status_code, err.code, err.request_id)
response = client.agents.with_raw_response.execute("calculator-agent", prompt="6*7")
print(response.status_code, response.headers["x-request-id"]); run = response.parse()- Async:
AsyncPlungeAI()has every method with the same signature, awaited; streams iterate withasync for event in await …. snake_casemethods; request fields are keyword arguments typed asTypedDicts (plungeai.types); responses are plaindicts. Path parameters come first, positionally:client.workflows.versions.restore(workflow_id, version).- Streams:
event.dataraw string,event.json()parsed; leaving the loop closes the response.stream=Trueonagents.execute/chat.completions.createreturns aStream. - Per-call options:
extra_headers,extra_query,timeout(seconds),max_retries,idempotency_key.client.get(path, query=…),client.post(path, body=…)reach routes outside the generated layer;executions.continueiscontinue_. - Python 3.10+, one runtime dependency (
httpx), shipspy.typed.
Go — github.com/PlungeAI/plungeai-go
client := plungeai.NewClient() // plungeai.NewClient(plungeai.WithAPIKey("ozk_…"), plungeai.WithMaxRetries(0))
stream, err := client.Workflows.ExecuteInlineStream(ctx, plungeai.WorkflowExecuteInlineStreamParams{Workflow: workflow})
if err != nil {
return err
}
defer stream.Close()
for stream.Next() {
ev := stream.Current() // ev.Event, ev.Data (raw string), ev.JSON(&v)
}
err = stream.Err()
pager := client.Workflows.ListAutoPaging(ctx, plungeai.WorkflowListParams{Kind: "bot"}) // walks every page
for pager.Next() {
fmt.Println(pager.Current())
}
var raw *http.Response
_, err = client.Agents.Execute(ctx, "calculator-agent", plungeai.AgentExecuteParams{Prompt: "6*7"}, plungeai.WithResponseInto(&raw))
var apiErr *plungeai.Error
if errors.As(err, &apiErr) && apiErr.StatusCode == 424 {
fmt.Println(apiErr.Connect.Link)
}- Every method:
ctx, path parameters, a params struct (plungeai.<Resource><Method>Params), then options. Nested resources are fields:client.Workflows.Versions.List(ctx, workflowID). - Options (client or per call):
WithAPIKey,WithBaseURL,WithMaxRetries,WithRequestTimeout,WithHeader,WithQuery,WithIdempotencyKey,WithResponseInto. A deadline onctxbounds the whole call, retries included. - Streaming twins:
Agents.ExecuteStreaming,Chat.Completions.CreateStreaming; list twins:…AutoPaging; manual pages:page.Data,page.HasNextPage(),page.GetNextPage(ctx). - Errors: one type
*plungeai.Error(StatusCode,Code,Message,RequestID,Connecton 424); no response → the transport error (errors.Is(err, context.DeadlineExceeded)on timeout); no key →plungeai.ErrMissingAPIKey. client.Get(ctx, path, params, &out),client.Post(ctx, path, body, &out)reach routes outside the generated layer; the rootPOST /v1/executeisclient.ExecuteCall.- Go 1.24+, standard library only; module published from
github.com/PlungeAI/plungeai-go, sourcesdk/one-api-go/.
Rust — plungeai
use futures_util::StreamExt;
use plungeai::{types::*, Client, RequestOptions};
let client = Client::builder().max_retries(0).build()?; // or Client::new()?
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?; // event.event, event.data, event.json::<T>()
}
let mut items = client.workflows().list(&Default::default()).await?.into_stream(); // walks every page
while let Some(w) = items.next().await {
println!("{:?}", w?);
}
match client.with_options(RequestOptions::new().max_retries(5)).agents().execute("calculator-agent", ¶ms).await {
Err(plungeai::Error::Api(err)) if err.status == 424 => println!("{:?}", err.connect.map(|c| c.link)),
other => { other?; }
}
let response = client.agents().execute_raw("calculator-agent", ¶ms).await?;
println!("{} {:?}", response.status, response.request_id); // response.parse::<AgentExecuteResponse>()?- Resources are methods (
client.agents(),client.workflows().versions()); path parameters first, then a reference to theDefaultparams struct. Optional fieldsOption<T>; response enums carryUnknown. client.with_options(RequestOptions::new()…)(header,query,timeout,max_retries,idempotency_key) returns a client carrying those options; every JSON operation has a…_rawtwin (status,headers,request_id,parse::<T>()); streaming twins…_stream(agents().execute_stream,chat().completions().create_stream); pagesdata,has_next_page(),next_page(),into_stream().- Errors:
Error::Api(Box<ApiError>)(status,code,message,request_id,connect),Connection,Timeout,Decode; predicatesstatus(),is_not_found(),is_rate_limit(). client.get(path),client.post(path, &body)reach routes outside the generated layer.- Rust 1.85+ (edition 2021),
tokioruntime, TLS through rustls.
Models plane
Every SDK covers the OpenAI-compatible routes (chat.completions.create, embeddings, models); the OpenAI SDK
works too with base URL https://api.plungeai.com/v1 and the same key — see plungeai-models.