Start a run
From the CLI
Section titled “From the CLI”kindgi runs start --flow=acme.review-order --input='{"orderId":"A-200"}'kindgi runs start --flow=acme.review-order --input=@order.json--input is the run's input as JSON, or @ and a file to read it from. The
command waits for the run to finish and prints it. With --no-wait, it
prints the run as soon as it exists:
kindgi runs start --flow=acme.reserve-order --input='{"orderId":"A-300"}' --no-wait{ "id": "1b1f6486-3faf-4ab7-8506-c09f50f989bc", … "flowId": "acme.reserve-order", "flowVersion": "0.1.0", "status": "pending", "dryRun": false, …}kindgi runs get <run-id> shows it again, with its output once it's done.
From your app
Section titled “From your app”Create a client. With no arguments it reads the API's URL and a token from
KINDGI_API_URL and KINDGI_API_TOKEN, which you set in your env file
(.env / .env.local). In development, when they aren't set, it uses the
running kindgi dev, which writes both to .kindgirc.json, and warns once
that you should set them. In production (NODE_ENV or KINDGI_ENV set to
production) it never does, so set them there.
import { createClient } from '@kindgi/sdk/client';
const kindgi = createClient(); // KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi devfrom kindgi.client import Kindgi
kindgi = Kindgi() # KINDGI_API_URL, KINDGI_API_TOKEN, or the running kindgi devWait for the result
Section titled “Wait for the result”const run = await kindgi.runs.start({ flow: 'acme.review-order', input: { orderId: 'A-200' },});console.log(run.status, run.output);completed { status: 'held', orderId: 'A-200' }run = kindgi.runs.start(flow="acme.review-order", input={"orderId": "A-200"})print(run.status, run.output)completed {'status': 'held', 'orderId': 'A-200'}start returns when the run completes, fails or waits for something (a
person's approval, for example: status is then suspended). Use it when the
run is short and the caller needs the answer.
Start it in the background
Section titled “Start it in the background”With wait: false, start returns as soon as the run exists, with status
pending, and the run finishes on the server:
let run = await kindgi.runs.start({ flow: 'acme.reserve-order', input: { orderId: 'A-300' }, options: { wait: false },});console.log(run.id, run.status);
while (run.status === 'pending' || run.status === 'running') { await new Promise((resolve) => setTimeout(resolve, 1000)); run = await kindgi.runs.get(run.id);}console.log(run.status, run.output);dbcf7457-0d25-49b9-9112-b03c9b44e9e8 pendingcompleted { attempt: 3, orderId: 'A-300', reserved: true }import time
run = kindgi.runs.start( flow="acme.reserve-order", input={"orderId": "A-300"}, options={"wait": False})print(run.id, run.status)
while run.status in ("pending", "running"): time.sleep(1) run = kindgi.runs.get(run.id)print(run.status, run.output)0ed299be-e04d-47bb-84b8-2ff9a4286822 pendingcompleted {'attempt': 3, 'orderId': 'A-300', 'reserved': True}Polling works, but there are better ways to learn that a run ended: follow its events, or have Kindgi send your app a webhook when it finishes.
Agent runs take options: { wait: false } too: the turn then runs in the
background. Start an agent with agent instead of flow, and its input
({ "userMessage": "…" }, see
Give an agent its input).
What you get back
Section titled “What you get back”| Field | |
|---|---|
id |
The run's id: for get, cancel, the journal and the event stream. |
status |
pending, running, suspended, completed, failed or cancelled. |
output |
What the run returned, once it completed. |
failureMessage |
Why it failed. |
flowId, flowVersion |
The flow and the version the run is pinned to. An agent's turn reports agent.turn. |
dryRun |
Whether it was a dry run. |
publicAccessToken |
A read-only token for this run, for a browser, when the deployment issues them (details). Only start returns it. |
The client references have every field and option: TypeScript, Python, and the CLI.
When it fails
Section titled “When it fails”A run that fails is still a run: start returns it, with status: "failed"
and failureMessage. A request the API refuses (a flow that doesn't exist,
a malformed input) raises an error instead, and no run exists:
import { KindgiApiError } from '@kindgi/sdk/client';
const run = await kindgi.runs.start({ flow: 'acme.review-order', input: { orderId: 'Z-9' } });if (run.status === 'failed') console.log(run.failureMessage);
try { await kindgi.runs.start({ flow: 'acme.no-such-flow', input: {} });} catch (err) { if (err instanceof KindgiApiError) console.log(err.error.code, err.message);}handler-error: Tool "acme.get-order" handler threw: handler-throw: Handler for tool "acme.get-order" threw: Error: No order Z-9not-found No flow "acme.no-such-flow" is registered in this tenant.from kindgi.client import NotFoundError
run = kindgi.runs.start(flow="acme.review-order", input={"orderId": "Z-9"})if run.status == "failed": print(run.failure_message)
try: kindgi.runs.start(flow="acme.no-such-flow", input={})except NotFoundError as err: print(err)handler-error: Tool "acme.get-order" handler threw: handler-throw: Handler for tool "acme.get-order" threw: ValueError: No order Z-9No flow "acme.no-such-flow" is registered in this tenant.A request that times out on your side may have started the run anyway. Retry a start safely shows how to retry without starting it twice.