# TypeScript

The Python surface, mirrored — async resource methods, typed errors, and the same result shapes with n and ci95.

The TypeScript SDK mirrors the [Python surface](/docs/sdks/python/) method
for method. `new Roborama()` reads `ROBORAMA_API_KEY` from the environment,
every method returns a promise, and the package ships type definitions for
every request and result shape.

```bash
npm i roborama
```

*Example: first call*

**Python**

```python
import roborama  # reads ROBORAMA_API_KEY from the environment

run = roborama.run(
    robot="g1-edu-pro@fw2.3",
    environment="kitchen-std@v1.2",
    task="pick_place@v1",
    episodes="auto(ci=0.95, moe=0.03)",
)
print(run.result())  # n=612  rate=0.874  ci95=(0.846, 0.898)
```

**TypeScript**

```typescript
import Roborama from "@roborama/sdk"; // reads ROBORAMA_API_KEY

const roborama = new Roborama();

const run = await roborama.runs.create({
  robot: "g1-edu-pro@fw2.3",
  environment: "kitchen-std@v1.2",
  task: "pick_place@v1",
  episodes: "auto(ci=0.95, moe=0.03)",
});

console.log(await run.result()); // n=612  rate=0.874  ci95=(0.846, 0.898)
```

**cURL**

```bash
curl https://api.roborama.com/v1/runs \
  -H "Authorization: Bearer $ROBORAMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "run",
    "robot": "g1-edu-pro@fw2.3",
    "environment": "kitchen-std@v1.2",
    "task": "pick_place@v1",
    "episodes": "auto(ci=0.95, moe=0.03)"
  }'
```

**Agent (tool-use payload)**

```json
{
  "type": "tool_use",
  "name": "roborama_run",
  "input": {
    "robot": "g1-edu-pro@fw2.3",
    "environment": "kitchen-std@v1.2",
    "task": "pick_place@v1",
    "episodes": "auto(ci=0.95, moe=0.03)"
  }
}
```

## The shape of the SDK

`roborama.runs.create()` is the workhorse: its `kind` field selects the
primitive — `run` is the default; `eval`, `verify`, `matrix`, `threshold`,
`compare`, and `transfer` are the rest — mirroring `POST /v1/runs` exactly.
Everything else is resource-style: `roborama.robots.list()`,
`roborama.quote()`, `roborama.gates.create()`. Field names stay snake_case on
both sides of the wire (`max_budget_usd`, `success_rate`, `ci95`), so
examples translate between the tabs on this site one field at a time.

Live progress is an async iterator:

```ts
import Roborama from "@roborama/sdk"; // reads ROBORAMA_API_KEY

const roborama = new Roborama();
const run = await roborama.runs.get("run_8842");

for await (const event of run.watch()) {
  console.log(event.episode, event.status);
}
```

## Results

`await run.result()` resolves once the run completes, with the same fields
every tab shows: `n`, `success_rate`, `ci95`, `failure_clusters`, both
meters, and `cost_usd` — the canonical first run comes back as n=612, rate
0.874, ci95 (0.846, 0.898). Episode artifacts hang off `run.episodes`
(`video_url`, `mcap_url`, `replay_spec`), and `run.export()` and
`run.report()` match their Python equivalents.

## Typed errors

One error class, `RoboramaError`, with a `.code` that matches
[the error reference](/docs/errors/). Switch on the code, not the message —
messages are for humans and may improve without notice.

*Example: typed errors*

**Python**

```python
import roborama  # reads ROBORAMA_API_KEY from the environment

try:
    run = roborama.run(
        robot="g1-edu-pro@fw2.3",
        environment="kitchen-std@v1.2",
        task="pick_place@v1",
        episodes=600,
        max_budget_usd=500,   # deliberately too small for 600 episodes
    )
    print(run.result())
except roborama.BudgetExceeded as err:
    # budget_exceeded: the hard stop fired mid-run; partial results are kept
    print(err.code, err.run_id)
    partial = err.partial_result
    print(partial.n, partial.success_rate, partial.ci95)
```

**TypeScript**

```typescript
// auth: reads ROBORAMA_API_KEY from the environment
import Roborama, { RoboramaError } from "@roborama/sdk";

const roborama = new Roborama();

try {
  const run = await roborama.runs.create({
    robot: "g1-edu-pro@fw2.3",
    environment: "kitchen-std@v1.2",
    task: "pick_place@v1",
    episodes: 600,
    max_budget_usd: 500, // deliberately too small for 600 episodes
  });
  console.log(await run.result());
} catch (err) {
  if (err instanceof RoboramaError && err.code === "budget_exceeded") {
    // the hard stop fired mid-run; partial results are kept
    console.log(err.code, err.run_id);
    console.log(err.partial_result);
  } else {
    throw err;
  }
}
```

**cURL**

```bash
# A run that hits its max_budget_usd hard stop returns 402 with
# code=budget_exceeded and the partial result attached.
curl -i https://api.roborama.com/v1/runs \
  -H "Authorization: Bearer $ROBORAMA_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "kind": "run",
    "robot": "g1-edu-pro@fw2.3",
    "environment": "kitchen-std@v1.2",
    "task": "pick_place@v1",
    "episodes": 600,
    "max_budget_usd": 500
  }'
```

**Agent (tool-use payload)**

```json
{
  "type": "tool_use",
  "name": "roborama_run",
  "input": {
    "robot": "g1-edu-pro@fw2.3",
    "environment": "kitchen-std@v1.2",
    "task": "pick_place@v1",
    "episodes": 600,
    "max_budget_usd": 500
  }
}
```

## Where the rest of the docs live

This page is short on purpose. Every example on this site has a TypeScript
tab generated from the same source as the Python tab, so the primitive pages
are the real TypeScript documentation. Start at
[`run()`](/docs/primitives/run/) or the [quickstart](/docs/quickstart/); the
[REST page](/docs/sdks/rest/) documents the wire format underneath all of it.
