@1kbirds/chidori 0.1.24 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/README.md +115 -5
  2. package/dist/agent.d.ts +487 -0
  3. package/dist/agent.js +46 -0
  4. package/dist/index.d.ts +332 -0
  5. package/dist/index.js +318 -0
  6. package/package.json +27 -32
  7. package/src/agent.ts +548 -0
  8. package/src/index.ts +580 -0
  9. package/.pytest_cache/README.md +0 -8
  10. package/CHANGELOG.md +0 -33
  11. package/Cargo.toml +0 -83
  12. package/build/stage/v0.1.24/chidori-v0.1.24-node-v108-darwin-arm64-unknown.tar.gz +0 -0
  13. package/build/stage/v0.1.24/chidori-v0.1.24-node-v93-darwin-arm64-unknown.tar.gz +0 -0
  14. package/build.rs +0 -7
  15. package/package_node/index.d.ts +0 -0
  16. package/package_node/index.js +0 -130
  17. package/package_node/native/chidori.node +0 -0
  18. package/package_python/.idea/inspectionProfiles/profiles_settings.xml +0 -6
  19. package/package_python/.idea/misc.xml +0 -4
  20. package/package_python/.idea/modules.xml +0 -8
  21. package/package_python/.idea/package_python.iml +0 -8
  22. package/package_python/.idea/vcs.xml +0 -6
  23. package/package_python/chidori/__init__.py +0 -0
  24. package/package_python/chidori/__pycache__/__init__.cpython-310.pyc +0 -0
  25. package/package_python/chidori/__pycache__/test_chidori.cpython-310-pytest-7.4.0.pyc +0 -0
  26. package/package_python/chidori/__pycache__/test_promptgraph.cpython-310-pytest-7.4.0.pyc +0 -0
  27. package/package_python/chidori/chidori.pyi +0 -32
  28. package/package_python/chidori/py.typed +0 -0
  29. package/package_python/chidori/test_chidori.py +0 -36
  30. package/pyproject.toml +0 -33
  31. package/src/lib.rs +0 -23
  32. package/src/translations/mod.rs +0 -9
  33. package/src/translations/nodejs.rs +0 -739
  34. package/src/translations/python.rs +0 -920
  35. package/src/translations/rust.rs +0 -737
  36. package/src/translations/shared.rs +0 -49
  37. package/src/translations/wasm.rs +0 -1
  38. package/tests/nodejs/chidori.test.js +0 -41
  39. package/tests/nodejs/nodeHandle.test.js +0 -15
package/package.json CHANGED
@@ -1,38 +1,33 @@
1
1
  {
2
2
  "name": "@1kbirds/chidori",
3
- "version": "0.1.24",
4
- "description": "Chidori is a library for building and running reactive AI agents.",
5
- "main": "package_node/index.js",
6
- "scripts": {
7
- "build": "cargo-cp-artifact -nc ./package_node/native/chidori.node -- cargo build --message-format=json-render-diagnostics --features nodejs",
8
- "build-debug": "npm run build --",
9
- "build-release": "npm run build -- --release",
10
- "test-rust": "cargo test",
11
- "test-js": "jest tests/nodejs"
12
- },
13
- "os": [
14
- "darwin",
15
- "linux",
16
- "win32"
17
- ],
18
- "cpu": [
19
- "x64",
20
- "ia32",
21
- "arm64"
22
- ],
23
- "binary": {
24
- "module_name": "chidori",
25
- "module_path": "./package_node/native",
26
- "host": "https://github.com/thousandbirdsinc/chidori/releases/download/",
27
- "package_name": "{module_name}-v{version}-{node_abi}-{platform}-{arch}-{libc}.tar.gz",
28
- "remote_path": "v{version}"
3
+ "version": "3.3.0",
4
+ "description": "TypeScript SDK for the Chidori agent framework HTTP client plus agent authoring types.",
5
+ "publishConfig": { "access": "public" },
6
+ "homepage": "https://github.com/ThousandBirdsInc/chidori",
7
+ "repository": { "type": "git", "url": "https://github.com/ThousandBirdsInc/chidori.git" },
8
+ "license": "Apache-2.0",
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "types": "dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "import": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ },
17
+ "./agent": {
18
+ "import": "./dist/agent.js",
19
+ "types": "./dist/agent.d.ts"
20
+ }
29
21
  },
30
- "license": "MIT",
31
- "dependencies": {
32
- "@mapbox/node-pre-gyp": "^1.0.8"
22
+ "files": ["dist", "src", "README.md"],
23
+ "scripts": {
24
+ "build": "tsc",
25
+ "typecheck": "tsc --noEmit"
33
26
  },
34
27
  "devDependencies": {
35
- "cargo-cp-artifact": "^0.1.8",
36
- "jest": "^29.6.1"
28
+ "typescript": "^5.4.0"
29
+ },
30
+ "engines": {
31
+ "node": ">=18"
37
32
  }
38
- }
33
+ }
package/src/agent.ts ADDED
@@ -0,0 +1,548 @@
1
+ /**
2
+ * Type declarations for TypeScript agents executed inside the Chidori runtime.
3
+ *
4
+ * These are authoring-time types only. The runtime injects the concrete
5
+ * `chidori` host object when it evaluates an agent or tool module.
6
+ */
7
+
8
+ export type AgentJson =
9
+ | null
10
+ | boolean
11
+ | number
12
+ | string
13
+ | AgentJson[]
14
+ | { [key: string]: AgentJson };
15
+
16
+ export type JsonObject = { [key: string]: AgentJson };
17
+
18
+ export interface JsonSchema {
19
+ type?: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null";
20
+ description?: string;
21
+ properties?: Record<string, JsonSchema>;
22
+ items?: JsonSchema;
23
+ required?: string[];
24
+ enum?: AgentJson[];
25
+ default?: AgentJson;
26
+ additionalProperties?: boolean | JsonSchema;
27
+ [keyword: string]: unknown;
28
+ }
29
+
30
+ export interface ToolDefinition {
31
+ name: string;
32
+ description: string;
33
+ parameters: JsonSchema & { type: "object" };
34
+ }
35
+
36
+ export type PromptStreamType = "progress" | "draft" | "subagent" | "final" | (string & {});
37
+
38
+ /** Provider prompt-cache lifetime for a cached prefix. */
39
+ export type CacheTtl = "5m" | "1h";
40
+
41
+ export interface PromptOptions {
42
+ type?: PromptStreamType;
43
+ system?: string;
44
+ model?: string;
45
+ maxTokens?: number;
46
+ max_tokens?: number;
47
+ maxTurns?: number;
48
+ max_turns?: number;
49
+ temperature?: number;
50
+ tools?: string[];
51
+ format?: "json" | (string & {});
52
+ stream?: boolean;
53
+ /**
54
+ * Prompt-cache posture. Defaults to on (`"5m"`): the runtime marks the
55
+ * stable request head (system, tools, conversation prefix) so providers
56
+ * bill repeated prefixes at the cached rate. `false` disables marking for
57
+ * this call; `"1h"` (or `{ ttl: "1h" }`) requests the extended TTL.
58
+ * Caching never changes a response — only how it is billed.
59
+ */
60
+ cache?: boolean | CacheTtl | { ttl?: CacheTtl };
61
+ }
62
+
63
+ /** Structured response from `Context.respond()` — mirrors the provider turn. */
64
+ export interface LlmResponseJson {
65
+ content: string;
66
+ blocks: AgentJson[];
67
+ tool_calls: { id: string; name: string; input: AgentJson }[];
68
+ stop_reason: string;
69
+ input_tokens: number;
70
+ output_tokens: number;
71
+ cache_creation_tokens: number;
72
+ cache_read_tokens: number;
73
+ }
74
+
75
+ /** Options for `Context.compact()` — explicit, opt-in window compaction. */
76
+ export interface CompactOptions {
77
+ /** How many of the newest conversation turns to keep verbatim (default 2). */
78
+ keepTurns?: number;
79
+ /**
80
+ * Skip compaction (pure no-op, no host call) while `estimateTokens()` is at
81
+ * or under this budget — lets a loop call `compact()` unconditionally.
82
+ */
83
+ budgetTokens?: number;
84
+ /** Model for the summarization prompt (defaults like `prompt()`). */
85
+ model?: string;
86
+ /** System instructions for the summarizer (a faithful-brief default). */
87
+ instructions?: string;
88
+ /** `maxTokens` for the summarization prompt. */
89
+ maxTokens?: number;
90
+ /** Cache posture for the summarization prompt (see `PromptOptions.cache`). */
91
+ cache?: boolean | CacheTtl | { ttl?: CacheTtl };
92
+ /** TTL of the fresh cache breakpoint placed on the summary (default "5m"). */
93
+ ttl?: CacheTtl;
94
+ }
95
+
96
+ /**
97
+ * An immutable, content-addressed, turn-structured prompt context.
98
+ *
99
+ * Builder methods return a NEW context that structurally shares this one's
100
+ * segments — `base.user("a")` and `base.user("b")` are independent and share
101
+ * `base`'s prefix — which keeps cache prefixes stable and makes forks cheap.
102
+ * Only `prompt()` / `respond()` perform a durable host call.
103
+ *
104
+ * ```ts
105
+ * const base = chidori.context()
106
+ * .system("You are a policy analyst.")
107
+ * .doc("corpus", corpusText)
108
+ * .cacheBreakpoint("1h");
109
+ * let ctx = base;
110
+ * for (const q of questions) {
111
+ * ctx = ctx.user(q);
112
+ * const { text, context } = await ctx.prompt();
113
+ * ctx = context; // assistant turn appended, prefix still shared
114
+ * }
115
+ * ```
116
+ */
117
+ export interface Context {
118
+ system(text: string): Context;
119
+ /** Expose registered tools (by name, resolved like `prompt({ tools })`). */
120
+ tools(names: string[]): Context;
121
+ /** A large stable reference block, labelled for the trace. */
122
+ doc(label: string, text: string): Context;
123
+ user(text: string): Context;
124
+ assistant(text: string): Context;
125
+ toolResult(id: string, content: string, isError?: boolean): Context;
126
+ /**
127
+ * Freeze everything appended so far as a cacheable prefix (one provider
128
+ * cache breakpoint). Providers cap breakpoints, so marks are coalesced —
129
+ * latest wins. Most authors never need this: stable heads are auto-marked.
130
+ */
131
+ cacheBreakpoint(ttl?: CacheTtl): Context;
132
+ /** Send this context; returns the text and the context extended with the
133
+ * assistant turn (including any internal tool-use exchange). */
134
+ prompt(options?: PromptOptions): Promise<{ text: string; context: Context }>;
135
+ /** Single structured turn for author-driven tool loops. */
136
+ respond(options?: PromptOptions): Promise<{ response: LlmResponseJson; context: Context }>;
137
+ /**
138
+ * Summarize the older conversation turns into one durable summary segment
139
+ * (via a recorded `prompt` host call, so it replays deterministically) and
140
+ * return a new context: stable head + summary + fresh cache breakpoint +
141
+ * the kept newest turns. Never automatic — compaction changes what the
142
+ * model sees, so it is always an explicit author decision. Returns this
143
+ * context unchanged (without a host call) when there is nothing to compact
144
+ * or the context is within `budgetTokens`.
145
+ */
146
+ compact(options?: CompactOptions): Promise<Context>;
147
+ /** Stable content hash of the request this context would assemble. */
148
+ digest(options?: PromptOptions): string;
149
+ /** Rough local token estimate for window budgeting. */
150
+ estimateTokens(): number;
151
+ }
152
+
153
+ /** One recorded exchange in a {@link Conversation} transcript. */
154
+ export interface ConversationTurn {
155
+ role: "user" | "assistant";
156
+ text: string;
157
+ }
158
+
159
+ /** Options for `chidori.conversation()`. */
160
+ export interface ConversationOptions {
161
+ /** System prompt — frozen once as the conversation's cacheable prefix. */
162
+ system?: string;
163
+ /** Tool names available on every turn (resolved like `prompt({ tools })`). */
164
+ tools?: string[];
165
+ /** Default stream label for each turn's prompt (default `"final"`). */
166
+ type?: PromptStreamType;
167
+ /** Default model for each turn (a per-turn override still wins). */
168
+ model?: string;
169
+ /** Default output token cap for each turn. */
170
+ maxTokens?: number;
171
+ /** Default sampling temperature for each turn. */
172
+ temperature?: number;
173
+ /** Default cache posture for each turn (see {@link PromptOptions.cache}). */
174
+ cache?: boolean | CacheTtl | { ttl?: CacheTtl };
175
+ /** TTL of the cache breakpoint frozen over the system/tools head. */
176
+ cacheTtl?: CacheTtl;
177
+ /**
178
+ * Opt-in window management: when set, each turn first runs the same budgeted
179
+ * `Context.compact()` — a pure no-op until the running tail exceeds budget,
180
+ * then the older turns fold into one recorded summary segment.
181
+ */
182
+ compact?: CompactOptions;
183
+ }
184
+
185
+ /** Options for `Conversation.loop()` — an interactive `input()`-driven loop. */
186
+ export interface ConversationLoopOptions {
187
+ /** Prompt shown to the human each turn (or a function of the turn index). */
188
+ prompt?: string | ((turn: number) => string);
189
+ /** Extra options forwarded to `chidori.input()` (defaults to `{ type: "message" }`). */
190
+ inputOptions?: InputOptions;
191
+ /** Words that end the loop, case-insensitive (default `["exit", "quit"]`). */
192
+ exit?: string | string[];
193
+ /** Hard cap on the number of exchanges before returning. */
194
+ maxTurns?: number;
195
+ /** Skip blank input lines instead of sending them (default `true`). */
196
+ skipEmpty?: boolean;
197
+ /** Per-turn prompt options applied to every `say()` in the loop. */
198
+ turn?: PromptOptions;
199
+ /** Called with the assistant reply (and the user message) after each turn. */
200
+ onReply?: (reply: string, message: string) => void | Promise<void>;
201
+ /** Return `true` after a turn to end the loop (checked after `onReply`). */
202
+ until?: (message: string, reply: string) => boolean;
203
+ }
204
+
205
+ /**
206
+ * A small stateful wrapper over {@link Context} for the most common shape — a
207
+ * multi-turn chat assistant. It owns the running context (system + tools frozen
208
+ * as a cacheable prefix) and threads each turn through it, so you write
209
+ * `chat.say(message)` instead of re-plumbing `ctx = (await
210
+ * ctx.user(message).prompt()).context` by hand. Every turn is still one durable
211
+ * `prompt`/`respond` host call that replays for free.
212
+ *
213
+ * ```ts
214
+ * const chat = chidori.conversation({ system: "You are concise." });
215
+ * const a = await chat.say("Hi, who are you?");
216
+ * const b = await chat.say("What can you help with?");
217
+ * // or drive it interactively:
218
+ * const transcript = await chat.loop({ prompt: "you>" });
219
+ * ```
220
+ */
221
+ export interface Conversation {
222
+ /** The underlying immutable context, for dropping to the lower-level API. */
223
+ readonly context: Context;
224
+ /** Number of completed exchanges (user+assistant pairs) so far. */
225
+ readonly length: number;
226
+ /** The transcript so far as plain `{ role, text }` entries. */
227
+ history(): ConversationTurn[];
228
+ /** Send one user message; resolves to the assistant's reply text. */
229
+ say(message: string, options?: PromptOptions): Promise<string>;
230
+ /**
231
+ * Like `say()`, but resolves to the structured response (`tool_calls`,
232
+ * `blocks`) for author-driven tool loops. Append tool results with
233
+ * `chat.context.toolResult(...)`, then call `say()` again.
234
+ */
235
+ respond(message: string, options?: PromptOptions): Promise<LlmResponseJson>;
236
+ /**
237
+ * Drive an interactive loop: read a human message via `chidori.input()`
238
+ * (terminal stdin under `chidori run`, a paused session resume under `chidori
239
+ * serve`), reply with `say()`, and repeat until the user types an exit word
240
+ * or `until` returns true. Resolves to the full transcript.
241
+ */
242
+ loop(options?: ConversationLoopOptions): Promise<ConversationTurn[]>;
243
+ }
244
+
245
+ export interface InputOptions {
246
+ type?: string;
247
+ default?: string;
248
+ choices?: string[];
249
+ }
250
+
251
+ /**
252
+ * Who delivered a signal. `kind` distinguishes a human participant from a peer
253
+ * agent; `id` is the participant identity; `runId` is set when an agent sends
254
+ * (its own run id), so agent-to-agent coordination is attributable in the trace.
255
+ */
256
+ export interface SignalSender {
257
+ kind: "human" | "agent";
258
+ id: string;
259
+ runId?: string;
260
+ }
261
+
262
+ /**
263
+ * A named message delivered into a run mid-flight (`docs/signals.md` §6.1). The
264
+ * inverse of `input()`: an outside party (human or agent) pushes
265
+ * `{ name, payload, from }` at an agent-declared listen point. Every signal is
266
+ * recorded in the call log, so the multiplayer session replays deterministically.
267
+ */
268
+ export interface Signal<T = AgentJson> {
269
+ name: string;
270
+ payload: T;
271
+ from: SignalSender;
272
+ }
273
+
274
+ export interface SignalOptions {
275
+ /**
276
+ * Resolve to a {@link SignalTimeout} sentinel after this many milliseconds
277
+ * instead of waiting forever. The deadline is enforced by the supervising
278
+ * server while the run idles; the recorded result (signal or sentinel)
279
+ * replays deterministically. Discriminate with `"timedOut" in result`.
280
+ */
281
+ timeoutMs?: number;
282
+ }
283
+
284
+ /**
285
+ * The sentinel a `timeoutMs` listen point resolves to when the deadline passes
286
+ * with no matching delivery (`docs/signals.md` §16, pinned:
287
+ * resolve-to-sentinel rather than reject). `name` is the single awaited name,
288
+ * or `null` for a multi-name `signalAny`.
289
+ */
290
+ export interface SignalTimeout {
291
+ name: string | null;
292
+ payload: null;
293
+ from: null;
294
+ timedOut: true;
295
+ }
296
+
297
+ export interface ParallelOptions {
298
+ concurrency?: number;
299
+ }
300
+
301
+ /**
302
+ * One `chidori.branch` variant (`docs/branching-execution.md` §6.1). A branch
303
+ * runs its own continuation source module from the parent's anchored state —
304
+ * not a re-run of the parent agent — so `source` is required.
305
+ */
306
+ export interface BranchVariant {
307
+ /** Branch label, shown in outcomes and the trace. Defaults to `branch-<k>`. */
308
+ label?: string;
309
+ /** Branch source module path, resolved like `callAgent` paths. */
310
+ source: string;
311
+ /** State handed to the branch as its run input. Defaults to `{}`. */
312
+ input?: AgentJson;
313
+ }
314
+
315
+ export type BranchStatus = "completed" | "paused" | "failed";
316
+
317
+ /** The result of one branch sub-run, returned for comparison (not merged). */
318
+ export interface BranchOutcome<T extends AgentJson = AgentJson> {
319
+ label: string;
320
+ /**
321
+ * `<parent run id>-op<branch seq>-branch-<k>` — identifies the branch
322
+ * sub-run, including for out-of-band `chidori branch-resume` /
323
+ * `branch-rerun` against its persisted store.
324
+ */
325
+ branchId: string;
326
+ status: BranchStatus;
327
+ /** The branch's output, when `status` is `"completed"`. */
328
+ output?: T;
329
+ /** What the branch is waiting on, when `status` is `"paused"`. */
330
+ pendingPrompt?: string;
331
+ /** The failure message, when `status` is `"failed"`. */
332
+ error?: string;
333
+ }
334
+
335
+ export interface BranchOptions {
336
+ /**
337
+ * Maximum branches running live at once (cost cap). Defaults to 1 —
338
+ * sequential. Higher values run variants in concurrent waves; outcome
339
+ * order always follows variant order.
340
+ */
341
+ concurrency?: number;
342
+ }
343
+
344
+ export interface RetryOptions {
345
+ attempts?: number;
346
+ delayMs?: number;
347
+ backoff?: "fixed" | "exponential";
348
+ }
349
+
350
+ export interface TryCallResult<T> {
351
+ ok: boolean;
352
+ value?: T;
353
+ error?: string;
354
+ }
355
+
356
+ export interface TemplateOptions {
357
+ source?: "file" | "inline";
358
+ }
359
+
360
+ export type MemoryAction = "get" | "set" | "delete" | "list" | "clear";
361
+
362
+ export type WorkspaceFileStatus = "complete" | "writing" | "failed";
363
+
364
+ export interface WorkspaceEntry {
365
+ path: string;
366
+ status: WorkspaceFileStatus;
367
+ sha256: string;
368
+ bytes: number;
369
+ language?: string | null;
370
+ attempt?: number | null;
371
+ updatedAt?: string | null;
372
+ }
373
+
374
+ export interface WorkspaceListOptions {
375
+ completeOnly?: boolean;
376
+ }
377
+
378
+ export interface WorkspaceWriteOptions {
379
+ language?: string;
380
+ }
381
+
382
+ export interface WorkspaceHost {
383
+ list(options?: WorkspaceListOptions): Promise<WorkspaceEntry[]>;
384
+ read(path: string): Promise<string>;
385
+ write(path: string, content: string, options?: WorkspaceWriteOptions): Promise<WorkspaceEntry>;
386
+ delete(path: string, reason?: string): Promise<void>;
387
+ remove(path: string, reason?: string): Promise<void>;
388
+ manifest(): Promise<AgentJson>;
389
+ }
390
+
391
+ export type TypeScriptImportPolicy = "none" | "relative" | "project";
392
+ export type DatePolicy = "disabled" | "fixed" | "host";
393
+ export type RandomPolicy = "disabled" | "seeded" | "host";
394
+ export type MapSetSnapshotPolicy = "reject" | "serialize";
395
+
396
+ export interface RuntimePolicyConfig {
397
+ typescript?: {
398
+ imports?: TypeScriptImportPolicy;
399
+ };
400
+ runtime?: {
401
+ date?: DatePolicy;
402
+ random?: RandomPolicy;
403
+ };
404
+ snapshot?: {
405
+ mapsSets?: MapSetSnapshotPolicy;
406
+ };
407
+ }
408
+
409
+ export interface Chidori {
410
+ workspace: WorkspaceHost;
411
+ /** Start an immutable multi-turn prompt context (optionally seeded). */
412
+ context(seed?: { system?: string; tools?: string[] }): Context;
413
+ /**
414
+ * Start a multi-turn chat assistant — a stateful wrapper over `context()`
415
+ * that owns the running dialogue. Send turns with `chat.say(message)` or drive
416
+ * an interactive `input()` loop with `chat.loop()`.
417
+ */
418
+ conversation(options?: ConversationOptions): Conversation;
419
+ prompt(text: string, options?: PromptOptions): Promise<string>;
420
+ input(message: string, options?: InputOptions): Promise<string>;
421
+ /**
422
+ * Pause at a named listen point until a matching signal is delivered (or one
423
+ * is already queued in the durable mailbox), then resolve to
424
+ * `{ name, payload, from }`. The inverse of `input()`: the run idles cheaply
425
+ * on disk and an outside party delivers via `POST /sessions/{id}/signal`.
426
+ */
427
+ signal<T = AgentJson>(name: string): Promise<Signal<T>>;
428
+ signal<T = AgentJson>(
429
+ name: string,
430
+ options: SignalOptions,
431
+ ): Promise<Signal<T> | SignalTimeout>;
432
+ /**
433
+ * Non-blocking: consume a queued signal of this name if present, else resolve
434
+ * to `null`. Records the result (value or null) at this seq so replay is
435
+ * deterministic.
436
+ */
437
+ pollSignal<T = AgentJson>(name: string): Promise<Signal<T> | null>;
438
+ /**
439
+ * Fan-in: pause until ANY of the named signals is delivered (or one is
440
+ * already queued in the durable mailbox). Resolves to the bare consumed
441
+ * signal — its `name` says which fired. Pre-arrived candidates are consumed
442
+ * in delivery order (lowest `delivery_seq` across the whole name set).
443
+ */
444
+ signalAny<T = AgentJson>(names: string[]): Promise<Signal<T>>;
445
+ signalAny<T = AgentJson>(
446
+ names: string[],
447
+ options: SignalOptions,
448
+ ): Promise<Signal<T> | SignalTimeout>;
449
+ /**
450
+ * Durable value checkpoint: run `fn` once and journal its JSON-serializable
451
+ * result; on replay/resume the recorded value (or error) is returned without
452
+ * re-running `fn`. Wrap expensive deterministic computation in a step so a
453
+ * resumed run does not re-pay it. The callback must be pure, synchronous
454
+ * compute — host effects (`chidori.*`), captured randomness, filesystem
455
+ * writes, timers, and async callbacks are refused inside a step.
456
+ */
457
+ step<T extends AgentJson = AgentJson>(name: string, fn: () => T): Promise<T>;
458
+ callAgent<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson>(
459
+ path: string,
460
+ input?: TInput,
461
+ ): Promise<TOutput>;
462
+ /**
463
+ * Fork the run into one sub-run per variant from the current anchored state
464
+ * (the VFS plus each variant's explicit `input`), run each variant's own
465
+ * source module, and return every outcome so the agent can compare and pick.
466
+ * The whole fan-out is one recorded durable call: a replay of this run
467
+ * returns the outcomes from cache without re-running the branches.
468
+ */
469
+ branch<T extends AgentJson = AgentJson>(
470
+ variants: BranchVariant[],
471
+ options?: BranchOptions,
472
+ ): Promise<BranchOutcome<T>[]>;
473
+ tool<TArgs extends JsonObject = JsonObject, TResult extends AgentJson = AgentJson>(
474
+ name: string,
475
+ args?: TArgs,
476
+ ): Promise<TResult>;
477
+ parallel<TTasks extends readonly (() => Promise<unknown>)[]>(
478
+ tasks: TTasks,
479
+ options?: ParallelOptions,
480
+ ): Promise<{ [Index in keyof TTasks]: Awaited<ReturnType<TTasks[Index]>> }>;
481
+ retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
482
+ tryCall<T>(fn: () => Promise<T>): Promise<TryCallResult<T>>;
483
+ template(pathOrText: string, vars?: JsonObject, options?: TemplateOptions): Promise<string>;
484
+ log(message: string, fields?: JsonObject): Promise<void>;
485
+ memory<T extends AgentJson = AgentJson>(
486
+ action: MemoryAction,
487
+ key?: string,
488
+ value?: T,
489
+ options?: JsonObject,
490
+ ): Promise<T | AgentJson[] | null>;
491
+ checkpoint(label?: string, data?: AgentJson): Promise<void>;
492
+ }
493
+
494
+ export type AgentFunction<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson> = (
495
+ input: TInput,
496
+ ) => TOutput | Promise<TOutput>;
497
+
498
+ export type ToolFunction<TArgs extends JsonObject = JsonObject, TResult extends AgentJson = AgentJson> = (
499
+ args: TArgs,
500
+ ) => TResult | Promise<TResult>;
501
+
502
+ /**
503
+ * The chidori host object — the durable surface your agents and tools call
504
+ * (`chidori.log`, `chidori.prompt`, `chidori.tool`, `chidori.input`, …).
505
+ *
506
+ * Import it for typed access; the runtime strips this import and supplies the
507
+ * real object at execution time, so there's no actual module dependency (and no
508
+ * need for a `(input, chidori)` second parameter):
509
+ *
510
+ * ```ts
511
+ * import { chidori, run } from "chidori";
512
+ * run(async (input: { topic: string }) => {
513
+ * await chidori.log("starting", { topic: input.topic });
514
+ * return { ok: true };
515
+ * });
516
+ * ```
517
+ *
518
+ * Accessing it from a plain import outside the runtime throws.
519
+ */
520
+ export const chidori: Chidori = new Proxy({} as Chidori, {
521
+ get(_target, prop) {
522
+ throw new Error(
523
+ `chidori.${String(prop)} is only available inside the chidori runtime; ` +
524
+ `this import is replaced when an agent runs under chidori.`,
525
+ );
526
+ },
527
+ });
528
+
529
+ /**
530
+ * Define the agent entrypoint. Call it once at the top level of an agent module
531
+ * with your handler; the runtime invokes the handler with the run input and
532
+ * uses its return value as the output. This replaces the old "export a function
533
+ * named `agent`" convention.
534
+ *
535
+ * ```ts
536
+ * import { run } from "chidori";
537
+ * run(async (input) => ({ greeting: `hello ${input.name}` }));
538
+ * ```
539
+ */
540
+ export function run<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson>(
541
+ handler: AgentFunction<TInput, TOutput>,
542
+ ): void {
543
+ void handler;
544
+ throw new Error(
545
+ "run() is only available inside the chidori runtime; this import is " +
546
+ "replaced when an agent runs under chidori.",
547
+ );
548
+ }