Host Functions

Host functions are the only way a Chidori agent interacts with anything outside its own code. They live on the injected chidori object and are the one and only side-effect boundary — every call is logged, cacheable, and replayable. This page is the reference.

chidori.prompt(text, options?) → string | object

Send a message to an LLM. Returns the response as a string, or as parsed JSON when type labels a structured stream such as "json".

// Simple
const answer = await chidori.prompt("What is 2+2?");

// Full options
const result = await chidori.prompt("Analyze this data: " + data, {
  type: "json",
  model: "claude-opus",
  temperature: 0.2,
  maxTokens: 4000,
  tools: ["web_search", "calc"],
});

type labels streamed output (e.g. "progress", "draft", "subagent", "final", "json"). When tools: [...] is set, the LLM can autonomously invoke those tools.

chidori.template(strOrPath, vars) → string

Render a Jinja2 template with minijinja. Accepts either an inline string or a path ending in .jinja / .j2:

let text = await chidori.template("Hello {{ name }}!", { name: "Alice" });
text = await chidori.template("prompts/analysis.jinja", { items, role: "analyst" });

const answer = await chidori.prompt(
  await chidori.template("prompts/research.jinja", { topic, sources }),
);

Supports the full Jinja feature set: conditionals, loops, filters, includes, inheritance.

chidori.tool(name, args) → any

Invoke a registered tool. Tools live in tools/*.ts — each module exports tool metadata and a run function (see Composition):

const results = await chidori.tool("web_search", { query: "rust programming", maxResults: 5 });
const data    = await chidori.tool("fetch_url", { url: "https://example.com" });

chidori.callAgent(path, input) → any

Call another .ts agent as a sub-agent. It shares the parent runtime context and call log:

const summary = await chidori.callAgent("summarizer.ts", { document: longText });
const checked = await chidori.callAgent("fact_checker.ts", { claims: summary });

chidori.parallel(fns) → array

Run an array of functions concurrently (Promise.all semantics), preserving result order:

const results = await chidori.parallel(
  queries.map((q) => () => chidori.tool("web_search", { query: q })),
);

chidori.input(message, options?) → string

Pause execution and wait for a human response. Used for approval flows, clarification, or any human-in-the-loop step. The runtime saves a checkpoint and suspends the run; resume by POSTing to /sessions/{id}/resume.

const approved = await chidori.input("Proceed with this plan?", {
  type: "approval",
  choices: ["yes", "no"],
  default: plan,
});
if (approved === "yes") {
  await execute(plan);
}

Options include type, choices, and default.

chidori.execJs / execPython / execWasm(code, options?) → any

Run arbitrary code in a sandbox. Typically used to execute code an LLM generated at runtime. There are dedicated entry points per runtime:

const code = await chidori.prompt("Write Python to analyze this CSV:\n" + data, {
  type: "draft",
});
const result = await chidori.execPython(code, { timeoutMs: 30000 });

execJs, execPython, and execWasm (which takes base64 bytes) each accept limits such as { timeoutMs }. The sandbox has no filesystem, network, or host access.

chidori.http(url, options?) → object

Make an HTTP request:

const resp = await chidori.http("https://api.example.com/data", {
  method: "GET",
  headers: { Authorization: "Bearer " + token },
});
const submitted = await chidori.http("https://api.example.com/submit", {
  method: "POST",
  body: { key: "value" },
});

Options: method, headers, query, body, timeoutMs.

chidori.memory(action, ...) → any

Persistent storage that survives across agent runs. Supports key-value and vector storage. Actions: "set", "get", "list", "delete", "clear":

await chidori.memory("set", "user_pref", "dark mode");
const pref = await chidori.memory("get", "user_pref");

const keys = await chidori.memory("list");

chidori.log(message, data?) → void

Structured logging. Appears in traces and stderr under --verbose:

chidori.log("Processing batch", { count: items.length, batchId: id });

chidori.env(name) → string | undefined

Read an environment variable. Returns undefined if unset:

const apiKey = chidori.env("MY_API_KEY");

chidori.retry(fn, options) → any

Retry a function on failure with configurable backoff:

const result = await chidori.retry(
  () => chidori.prompt("Translate to French:\n" + text),
  { attempts: 3, delayMs: 500, backoff: "exponential" },
);

Options: attempts, delayMs, backoff.

chidori.tryCall(fn){ ok, error }

Execute a function and capture errors as values instead of throwing:

const result = await chidori.tryCall(() => chidori.tool("flaky_api", { query: text }));
if (!result.ok) {
  chidori.log("API failed", { error: result.error });
}

chidori.checkpoint(name, metadata?) → void

Write an explicit marker into the call log to make a run easier to inspect and branch:

chidori.checkpoint("after_search", { count: results.length });

The closed set

That's the surface. Every interaction with the outside world flows through a chidori host call — which is exactly the property that makes checkpointing, replay, and deterministic testing possible.

Was this page helpful?