# Chidori TypeScript API Reference

Chidori runs TypeScript agents in a Rust runtime. Agents use normal async
TypeScript for orchestration, while all side effects go through the injected
`chidori` host object so the runtime can log, replay, stream, pause, and resume
work.

This file is optimized as an LLM-facing reference for generating Chidori agents
and tools.

## Agent Shape

An agent is a `.ts` file that exports `agent(input, chidori)`:

```ts
import type { Chidori } from "chidori";

export async function agent(input: { document: string }, chidori: Chidori) {
  const summary = await chidori.prompt(
    "Summarize in three bullets:\n\n" + input.document,
    { type: "final" },
  );
  return { summary };
}
```

Rules:

- Export `async function agent(input, chidori)`.
- Return JSON-compatible values only.
- Use `chidori.*` for LLMs, tools, HTTP, input, memory, templates, logging, and
  sandboxed code execution.
- Prefer deterministic code. Durable runs use fixed `Date` and seeded
  `Math.random` policies by default.
- Local TypeScript imports are governed by runtime policy. Dynamic imports are
  rejected.

## CLI

```bash
chidori check agents/my_agent.ts
chidori run agents/my_agent.ts --input key=value
chidori run agents/my_agent.ts --input '{"document": "text"}'
chidori run agents/my_agent.ts --stream
chidori run agents/my_agent.ts --trace
chidori serve agents/webhook.ts --port 8080
chidori trace <run_id>
chidori snapshot <run_id>
```

`chidori snapshot <run_id>` prints `runtime.snapshot.json` metadata without
printing raw VM snapshot bytes.

## Host Object

The runtime injects a `chidori` object with these methods.

### prompt

```ts
const text = await chidori.prompt("Write a concise answer", {
  type: "final",
  model: "claude-sonnet",
  maxTokens: 500,
  temperature: 0.2,
  tools: ["web_search"],
});
```

Options:

- `type`: label for streamed prompt output, such as `"progress"`, `"draft"`,
  `"subagent"`, or `"final"`.
- `model`: provider model override.
- `maxTokens` or `max_tokens`: output token cap.
- `temperature`: sampling temperature.
- `tools`: registered tool names available to provider tool-use loops.

When streaming is enabled, prompt events include `prompt_type`, `stream_id`,
and `seq` so UIs can filter progress streams separately from final-answer
streams.

### input

```ts
const answer = await chidori.input("Approve this request?", {
  type: "approval",
  choices: ["yes", "no"],
  default: "no",
});
```

In server mode, `input()` pauses the session. Resume it with
`POST /sessions/{id}/resume` or `AgentClient.resume(id, response)`.

### tool

```ts
const result = await chidori.tool("web_search", { query: "snapshot runtime" });
```

Tools discovered from disk are TypeScript `.ts` modules or MCP-backed remote
tools. Archived Starlark tools under `examples/legacy-starlark/` are kept for
migration reference and are no longer loaded by tool directory discovery.

### callAgent

```ts
const child = await chidori.callAgent("child.ts", { topic: "snapshots" });
```

Sub-agents share the parent runtime context and call log. Runtime dispatch now
accepts TypeScript `.ts` sub-agents only; archived `.star` examples are kept
for migration reference.

### parallel

```ts
const [a, b] = await chidori.parallel([
  () => chidori.prompt("Draft option A", { type: "draft" }),
  () => chidori.prompt("Draft option B", { type: "draft" }),
]);
```

The current TypeScript helper uses `Promise.all` semantics. True durable
parallel host execution is gated on host-backed promises and branch snapshots.

### http

```ts
const response = await chidori.http("https://example.com/webhook", {
  method: "POST",
  headers: { "content-type": "application/json" },
  query: { source: "chidori" },
  body: { ok: true },
  timeoutMs: 10_000,
});
```

HTTP calls are policy-checked, logged, and replayed from the call log when
available.

### template

```ts
const prompt = await chidori.template("prompts/summary.jinja", {
  document: input.document,
});
```

Use templates for reusable prompt text. Inline templates are also supported.

### memory

```ts
await chidori.memory("set", "draft", { text: "..." });
const draft = await chidori.memory("get", "draft");
const keys = await chidori.memory("list");
await chidori.memory("delete", "draft");
await chidori.memory("clear");
```

Memory actions are logged and replay-aware.

### checkpoint

```ts
await chidori.checkpoint("after-draft", { tokens: 120 });
```

`checkpoint()` records an explicit call-log marker. Persisted runs also refresh
snapshot manifest metadata at durable host safepoints.

### log

```ts
await chidori.log("Fetched candidates", { count: 3 });
```

Use structured logs for progress and debugging. Logs are call-log records.

### retry and tryCall

```ts
const value = await chidori.retry(
  () => chidori.http("https://example.com"),
  { attempts: 3, delayMs: 250, backoff: "exponential" },
);

const result = await chidori.tryCall(() => chidori.tool("maybe_fails", {}));
if (!result.ok) {
  await chidori.log("Tool failed", { error: result.error });
}
```

### Sandboxed Execution

```ts
const js = await chidori.execJs("return input.x + 1", { timeoutMs: 1000 });
const py = await chidori.execPython("result = input['x'] + 1", { timeoutMs: 1000 });
const wasm = await chidori.execWasm(wasmBytesBase64, {
  function: "add",
  args: [1, 2],
  memoryPages: 1,
});
```

Generated or untrusted code should run through sandbox helpers, not directly in
the agent runtime.

## TypeScript Tool Shape

A TypeScript tool exports JSON-compatible metadata and an async
`run(args, chidori)` function. Tool discovery evaluates the exported `tool`
value in a restricted metadata VM context before registration.

```ts
import type { Chidori, ToolDefinition } from "chidori";

export const tool: ToolDefinition = {
  name: "web_search",
  description: "Search the web for a short query.",
  parameters: {
    type: "object",
    properties: {
      query: { type: "string", description: "Search query" },
    },
    required: ["query"],
  },
};

export async function run(args: { query: string }, chidori: Chidori) {
  await chidori.log("Running web_search", { query: args.query });
  return { query: args.query, results: [] };
}
```

Tool metadata must be JSON-compatible. The `parameters` field is a JSON Schema
object and is used for provider tool calling.

## Streaming

CLI:

```bash
chidori run examples/agents/streaming_progress.ts --stream
```

HTTP:

```ts
for await (const event of client.stream({ topic: "snapshots" })) {
  if (event.type === "prompt_delta" && event.prompt_type === "progress") {
    process.stdout.write(event.delta);
  }
}
```

Stream event types:

- `call`: a host call record.
- `prompt_start`: prompt stream started.
- `prompt_delta`: incremental token text.
- `prompt_end`: prompt stream ended.
- `done`: run completed, failed, or paused.

Prompt labels work inside sub-agents and parallel branches because prompt
events are emitted through the shared runtime context.

## Sessions

Start a server:

```bash
chidori serve examples/agents/webhook.ts --port 8080
```

Session endpoints:

- `POST /sessions`: create and run a session.
- `GET /sessions`: list sessions.
- `GET /sessions/{id}`: get session state.
- `GET /sessions/{id}/checkpoint`: get call log plus optional
  `snapshot_manifest`.
- `GET /sessions/{id}/snapshot`: get only snapshot manifest metadata.
- `POST /sessions/{id}/resume`: resume a paused `input()` session.
- `POST /sessions/{id}/replay`: replay from a call-log checkpoint.
- `POST /sessions/stream`: run with SSE events.

Use `CHIDORI_DB_PATH=/path/to/chidori.sqlite` to persist sessions across server
restarts.

## TypeScript SDK

```ts
import { AgentClient, Checkpoint } from "chidori";

const client = new AgentClient("http://localhost:8080");
const session = await client.run({ document: "Rust is a systems language." });

const checkpoint = await session.checkpoint();
const replayed = await client.replay(checkpoint);

if (checkpoint.snapshotManifest) {
  console.log(checkpoint.snapshotManifest.pending?.kind);
}

const manifest = await client.getSnapshotManifest(session.id);
```

`Checkpoint` contains the replay call log and optional snapshot manifest
metadata. It does not contain raw VM snapshot bytes.

## Runtime Policy

Durable TypeScript runs record policy in the snapshot manifest:

- `typescript_imports`: `none`, `relative`, or `project`.
- `date`: `disabled`, `fixed`, or `host`.
- `random`: `disabled`, `seeded`, or `host`.
- `maps_sets`: `reject` or `serialize`.

Environment overrides:

```bash
CHIDORI_TS_IMPORTS=relative
CHIDORI_TS_DATE=fixed
CHIDORI_TS_RANDOM=seeded
CHIDORI_SNAPSHOT_MAPS_SETS=reject
```

Durable snapshot runs reject host clock and host randomness.

For local smoke tests without provider credentials, set
`CHIDORI_TEST_LLM_RESPONSE` to a static response string. This registers a
catch-all test provider and avoids external network calls.

## Snapshot And Replay Notes

Current resume/replay uses the call log plus persisted host-promise metadata:
the agent re-executes and host calls return cached records. Persisted
TypeScript runs also write `runtime.snapshot` and `runtime.snapshot.json`
metadata. Direct live VM continuation from `runtime.snapshot` without replay is
still gated on the QuickJS runtime serializer and server `LiveQuickJsVm`
restore path.

Snapshot manifests record:

- ABI version and engine fork.
- Runtime policy.
- Entry source hash and imported module hashes.
- Pending host operation, if any.
- Host promise table records, including pending/resolved/rejected state.
- Call-log length and snapshot blob filename.

Resume rejects incompatible source hashes, policy, or ABI before trusting
snapshot metadata or raw VM snapshot bytes.
