@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/README.md CHANGED
@@ -1,7 +1,117 @@
1
- # Chidori
1
+ # chidori TypeScript SDK
2
2
 
3
- ## Generating Python Client
4
- - maturin develop --features python
3
+ Zero-dependency TypeScript client for a running `chidori serve` instance.
4
+ Uses the global `fetch` (Node 18+, browsers). Mirrors the Python SDK.
5
5
 
6
- ## Generating Nodejs Client
7
- - npm run build-release
6
+ ## Install
7
+
8
+ The package is published to npm as
9
+ [`@1kbirds/chidori`](https://www.npmjs.com/package/@1kbirds/chidori) (the
10
+ unscoped `chidori` npm name belongs to an unrelated project). Installing it
11
+ under the `chidori` alias keeps the historical import spelling working:
12
+
13
+ ```bash
14
+ npm install chidori@npm:@1kbirds/chidori
15
+ ```
16
+
17
+ ```ts
18
+ import { AgentClient, Checkpoint } from "chidori";
19
+ ```
20
+
21
+ Or install under the scoped name directly — the Chidori runtime accepts both
22
+ `"chidori"` and `"@1kbirds/chidori"` as the SDK module specifier in agent
23
+ files:
24
+
25
+ ```bash
26
+ npm install @1kbirds/chidori
27
+ ```
28
+
29
+ To build from source instead:
30
+
31
+ ```bash
32
+ cd sdk/typescript
33
+ npm install
34
+ npm run build
35
+ ```
36
+
37
+ Agent and tool authoring types are also exported:
38
+
39
+ ```ts
40
+ import type { Chidori, ToolDefinition } from "chidori";
41
+ ```
42
+
43
+ ## Usage
44
+
45
+ ```ts
46
+ import { AgentClient, Checkpoint, isSignalQueued } from "chidori";
47
+
48
+ const client = new AgentClient("http://localhost:8080");
49
+
50
+ // Run an agent
51
+ const session = await client.run({ document: "Rust is a systems language." });
52
+ console.log(session.output);
53
+
54
+ // Save and replay a checkpoint — zero LLM calls on replay
55
+ const checkpoint = await session.checkpoint();
56
+ const replayed = await client.replay(checkpoint);
57
+
58
+ // Durable TypeScript runs may include snapshot metadata in the checkpoint.
59
+ // The manifest is safe to inspect; raw VM snapshot bytes remain server-side.
60
+ if (checkpoint.snapshotManifest) {
61
+ console.log(checkpoint.snapshotManifest.pending?.kind);
62
+ console.log(checkpoint.snapshotManifest.abi.engine_fork);
63
+ }
64
+
65
+ const manifest = await client.getSnapshotManifest(session.id);
66
+ console.log(manifest.policy.typescript_imports);
67
+
68
+ // Live streaming: host calls, prompt stream deltas, then `done`
69
+ for await (const evt of client.stream({ document: "hi" })) {
70
+ if (evt.type === "call") console.log(evt.record.function);
71
+ if (evt.type === "prompt_delta" && evt.prompt_type === "progress") {
72
+ process.stdout.write(evt.delta);
73
+ }
74
+ if (evt.type === "done") console.log(evt.status, evt.output);
75
+ }
76
+
77
+ // Paused sessions (from input())
78
+ if (session.status === "paused") {
79
+ const resumed = await client.resume(session.id, "yes");
80
+ console.log(resumed.output);
81
+ }
82
+
83
+ // Multiplayer signals (from chidori.signal / pollSignal): deliver
84
+ // { name, payload?, from? } to a run.
85
+ const result = await client.signal(session.id, {
86
+ name: "review",
87
+ payload: { decision: "approve", notes: "LGTM" },
88
+ from: { kind: "human", id: "mara" },
89
+ });
90
+ if (isSignalQueued(result)) {
91
+ // run wasn't paused-waiting on this name → enqueued in the durable mailbox (202)
92
+ console.log("queued at delivery_seq", result.delivery_seq);
93
+ } else {
94
+ // run was paused-waiting on this name → resolved + resumed (200)
95
+ console.log(result.status, result.output);
96
+ }
97
+ ```
98
+
99
+ See the top-level `sdk/python/chidori` for the Python equivalent.
100
+
101
+ ## Snapshot-aware checkpoints
102
+
103
+ `Checkpoint` contains the replay call log plus optional `snapshotManifest`
104
+ metadata. The manifest records the runtime ABI, deterministic policy, source
105
+ hashes, pending host operation, and snapshot file name. Clients can use it to
106
+ display durable-resume state or diagnose why resume is blocked without handling
107
+ the raw `runtime.snapshot` VM bytes.
108
+
109
+ `client.replay(checkpoint)` uses the call log for deterministic replay. Durable
110
+ resume is exposed through `client.resume(sessionId, response)` for paused
111
+ sessions, recovering through persisted host-promise metadata and the replay
112
+ journal. Replay **is** the resume mechanism by design — the QuickJS live-VM
113
+ snapshot path was removed in #39, not merely deferred, so the manifest carries
114
+ journal/scaffold metadata rather than serialized VM bytes.
115
+
116
+ Use `client.getSnapshotManifest(sessionId)` when a UI needs only snapshot
117
+ metadata. The endpoint never returns the binary VM snapshot.
@@ -0,0 +1,487 @@
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
+ export type AgentJson = null | boolean | number | string | AgentJson[] | {
8
+ [key: string]: AgentJson;
9
+ };
10
+ export type JsonObject = {
11
+ [key: string]: AgentJson;
12
+ };
13
+ export interface JsonSchema {
14
+ type?: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null";
15
+ description?: string;
16
+ properties?: Record<string, JsonSchema>;
17
+ items?: JsonSchema;
18
+ required?: string[];
19
+ enum?: AgentJson[];
20
+ default?: AgentJson;
21
+ additionalProperties?: boolean | JsonSchema;
22
+ [keyword: string]: unknown;
23
+ }
24
+ export interface ToolDefinition {
25
+ name: string;
26
+ description: string;
27
+ parameters: JsonSchema & {
28
+ type: "object";
29
+ };
30
+ }
31
+ export type PromptStreamType = "progress" | "draft" | "subagent" | "final" | (string & {});
32
+ /** Provider prompt-cache lifetime for a cached prefix. */
33
+ export type CacheTtl = "5m" | "1h";
34
+ export interface PromptOptions {
35
+ type?: PromptStreamType;
36
+ system?: string;
37
+ model?: string;
38
+ maxTokens?: number;
39
+ max_tokens?: number;
40
+ maxTurns?: number;
41
+ max_turns?: number;
42
+ temperature?: number;
43
+ tools?: string[];
44
+ format?: "json" | (string & {});
45
+ stream?: boolean;
46
+ /**
47
+ * Prompt-cache posture. Defaults to on (`"5m"`): the runtime marks the
48
+ * stable request head (system, tools, conversation prefix) so providers
49
+ * bill repeated prefixes at the cached rate. `false` disables marking for
50
+ * this call; `"1h"` (or `{ ttl: "1h" }`) requests the extended TTL.
51
+ * Caching never changes a response — only how it is billed.
52
+ */
53
+ cache?: boolean | CacheTtl | {
54
+ ttl?: CacheTtl;
55
+ };
56
+ }
57
+ /** Structured response from `Context.respond()` — mirrors the provider turn. */
58
+ export interface LlmResponseJson {
59
+ content: string;
60
+ blocks: AgentJson[];
61
+ tool_calls: {
62
+ id: string;
63
+ name: string;
64
+ input: AgentJson;
65
+ }[];
66
+ stop_reason: string;
67
+ input_tokens: number;
68
+ output_tokens: number;
69
+ cache_creation_tokens: number;
70
+ cache_read_tokens: number;
71
+ }
72
+ /** Options for `Context.compact()` — explicit, opt-in window compaction. */
73
+ export interface CompactOptions {
74
+ /** How many of the newest conversation turns to keep verbatim (default 2). */
75
+ keepTurns?: number;
76
+ /**
77
+ * Skip compaction (pure no-op, no host call) while `estimateTokens()` is at
78
+ * or under this budget — lets a loop call `compact()` unconditionally.
79
+ */
80
+ budgetTokens?: number;
81
+ /** Model for the summarization prompt (defaults like `prompt()`). */
82
+ model?: string;
83
+ /** System instructions for the summarizer (a faithful-brief default). */
84
+ instructions?: string;
85
+ /** `maxTokens` for the summarization prompt. */
86
+ maxTokens?: number;
87
+ /** Cache posture for the summarization prompt (see `PromptOptions.cache`). */
88
+ cache?: boolean | CacheTtl | {
89
+ ttl?: CacheTtl;
90
+ };
91
+ /** TTL of the fresh cache breakpoint placed on the summary (default "5m"). */
92
+ ttl?: CacheTtl;
93
+ }
94
+ /**
95
+ * An immutable, content-addressed, turn-structured prompt context.
96
+ *
97
+ * Builder methods return a NEW context that structurally shares this one's
98
+ * segments — `base.user("a")` and `base.user("b")` are independent and share
99
+ * `base`'s prefix — which keeps cache prefixes stable and makes forks cheap.
100
+ * Only `prompt()` / `respond()` perform a durable host call.
101
+ *
102
+ * ```ts
103
+ * const base = chidori.context()
104
+ * .system("You are a policy analyst.")
105
+ * .doc("corpus", corpusText)
106
+ * .cacheBreakpoint("1h");
107
+ * let ctx = base;
108
+ * for (const q of questions) {
109
+ * ctx = ctx.user(q);
110
+ * const { text, context } = await ctx.prompt();
111
+ * ctx = context; // assistant turn appended, prefix still shared
112
+ * }
113
+ * ```
114
+ */
115
+ export interface Context {
116
+ system(text: string): Context;
117
+ /** Expose registered tools (by name, resolved like `prompt({ tools })`). */
118
+ tools(names: string[]): Context;
119
+ /** A large stable reference block, labelled for the trace. */
120
+ doc(label: string, text: string): Context;
121
+ user(text: string): Context;
122
+ assistant(text: string): Context;
123
+ toolResult(id: string, content: string, isError?: boolean): Context;
124
+ /**
125
+ * Freeze everything appended so far as a cacheable prefix (one provider
126
+ * cache breakpoint). Providers cap breakpoints, so marks are coalesced —
127
+ * latest wins. Most authors never need this: stable heads are auto-marked.
128
+ */
129
+ cacheBreakpoint(ttl?: CacheTtl): Context;
130
+ /** Send this context; returns the text and the context extended with the
131
+ * assistant turn (including any internal tool-use exchange). */
132
+ prompt(options?: PromptOptions): Promise<{
133
+ text: string;
134
+ context: Context;
135
+ }>;
136
+ /** Single structured turn for author-driven tool loops. */
137
+ respond(options?: PromptOptions): Promise<{
138
+ response: LlmResponseJson;
139
+ context: Context;
140
+ }>;
141
+ /**
142
+ * Summarize the older conversation turns into one durable summary segment
143
+ * (via a recorded `prompt` host call, so it replays deterministically) and
144
+ * return a new context: stable head + summary + fresh cache breakpoint +
145
+ * the kept newest turns. Never automatic — compaction changes what the
146
+ * model sees, so it is always an explicit author decision. Returns this
147
+ * context unchanged (without a host call) when there is nothing to compact
148
+ * or the context is within `budgetTokens`.
149
+ */
150
+ compact(options?: CompactOptions): Promise<Context>;
151
+ /** Stable content hash of the request this context would assemble. */
152
+ digest(options?: PromptOptions): string;
153
+ /** Rough local token estimate for window budgeting. */
154
+ estimateTokens(): number;
155
+ }
156
+ /** One recorded exchange in a {@link Conversation} transcript. */
157
+ export interface ConversationTurn {
158
+ role: "user" | "assistant";
159
+ text: string;
160
+ }
161
+ /** Options for `chidori.conversation()`. */
162
+ export interface ConversationOptions {
163
+ /** System prompt — frozen once as the conversation's cacheable prefix. */
164
+ system?: string;
165
+ /** Tool names available on every turn (resolved like `prompt({ tools })`). */
166
+ tools?: string[];
167
+ /** Default stream label for each turn's prompt (default `"final"`). */
168
+ type?: PromptStreamType;
169
+ /** Default model for each turn (a per-turn override still wins). */
170
+ model?: string;
171
+ /** Default output token cap for each turn. */
172
+ maxTokens?: number;
173
+ /** Default sampling temperature for each turn. */
174
+ temperature?: number;
175
+ /** Default cache posture for each turn (see {@link PromptOptions.cache}). */
176
+ cache?: boolean | CacheTtl | {
177
+ ttl?: CacheTtl;
178
+ };
179
+ /** TTL of the cache breakpoint frozen over the system/tools head. */
180
+ cacheTtl?: CacheTtl;
181
+ /**
182
+ * Opt-in window management: when set, each turn first runs the same budgeted
183
+ * `Context.compact()` — a pure no-op until the running tail exceeds budget,
184
+ * then the older turns fold into one recorded summary segment.
185
+ */
186
+ compact?: CompactOptions;
187
+ }
188
+ /** Options for `Conversation.loop()` — an interactive `input()`-driven loop. */
189
+ export interface ConversationLoopOptions {
190
+ /** Prompt shown to the human each turn (or a function of the turn index). */
191
+ prompt?: string | ((turn: number) => string);
192
+ /** Extra options forwarded to `chidori.input()` (defaults to `{ type: "message" }`). */
193
+ inputOptions?: InputOptions;
194
+ /** Words that end the loop, case-insensitive (default `["exit", "quit"]`). */
195
+ exit?: string | string[];
196
+ /** Hard cap on the number of exchanges before returning. */
197
+ maxTurns?: number;
198
+ /** Skip blank input lines instead of sending them (default `true`). */
199
+ skipEmpty?: boolean;
200
+ /** Per-turn prompt options applied to every `say()` in the loop. */
201
+ turn?: PromptOptions;
202
+ /** Called with the assistant reply (and the user message) after each turn. */
203
+ onReply?: (reply: string, message: string) => void | Promise<void>;
204
+ /** Return `true` after a turn to end the loop (checked after `onReply`). */
205
+ until?: (message: string, reply: string) => boolean;
206
+ }
207
+ /**
208
+ * A small stateful wrapper over {@link Context} for the most common shape — a
209
+ * multi-turn chat assistant. It owns the running context (system + tools frozen
210
+ * as a cacheable prefix) and threads each turn through it, so you write
211
+ * `chat.say(message)` instead of re-plumbing `ctx = (await
212
+ * ctx.user(message).prompt()).context` by hand. Every turn is still one durable
213
+ * `prompt`/`respond` host call that replays for free.
214
+ *
215
+ * ```ts
216
+ * const chat = chidori.conversation({ system: "You are concise." });
217
+ * const a = await chat.say("Hi, who are you?");
218
+ * const b = await chat.say("What can you help with?");
219
+ * // or drive it interactively:
220
+ * const transcript = await chat.loop({ prompt: "you>" });
221
+ * ```
222
+ */
223
+ export interface Conversation {
224
+ /** The underlying immutable context, for dropping to the lower-level API. */
225
+ readonly context: Context;
226
+ /** Number of completed exchanges (user+assistant pairs) so far. */
227
+ readonly length: number;
228
+ /** The transcript so far as plain `{ role, text }` entries. */
229
+ history(): ConversationTurn[];
230
+ /** Send one user message; resolves to the assistant's reply text. */
231
+ say(message: string, options?: PromptOptions): Promise<string>;
232
+ /**
233
+ * Like `say()`, but resolves to the structured response (`tool_calls`,
234
+ * `blocks`) for author-driven tool loops. Append tool results with
235
+ * `chat.context.toolResult(...)`, then call `say()` again.
236
+ */
237
+ respond(message: string, options?: PromptOptions): Promise<LlmResponseJson>;
238
+ /**
239
+ * Drive an interactive loop: read a human message via `chidori.input()`
240
+ * (terminal stdin under `chidori run`, a paused session resume under `chidori
241
+ * serve`), reply with `say()`, and repeat until the user types an exit word
242
+ * or `until` returns true. Resolves to the full transcript.
243
+ */
244
+ loop(options?: ConversationLoopOptions): Promise<ConversationTurn[]>;
245
+ }
246
+ export interface InputOptions {
247
+ type?: string;
248
+ default?: string;
249
+ choices?: string[];
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
+ * A named message delivered into a run mid-flight (`docs/signals.md` §6.1). The
263
+ * inverse of `input()`: an outside party (human or agent) pushes
264
+ * `{ name, payload, from }` at an agent-declared listen point. Every signal is
265
+ * recorded in the call log, so the multiplayer session replays deterministically.
266
+ */
267
+ export interface Signal<T = AgentJson> {
268
+ name: string;
269
+ payload: T;
270
+ from: SignalSender;
271
+ }
272
+ export interface SignalOptions {
273
+ /**
274
+ * Resolve to a {@link SignalTimeout} sentinel after this many milliseconds
275
+ * instead of waiting forever. The deadline is enforced by the supervising
276
+ * server while the run idles; the recorded result (signal or sentinel)
277
+ * replays deterministically. Discriminate with `"timedOut" in result`.
278
+ */
279
+ timeoutMs?: number;
280
+ }
281
+ /**
282
+ * The sentinel a `timeoutMs` listen point resolves to when the deadline passes
283
+ * with no matching delivery (`docs/signals.md` §16, pinned:
284
+ * resolve-to-sentinel rather than reject). `name` is the single awaited name,
285
+ * or `null` for a multi-name `signalAny`.
286
+ */
287
+ export interface SignalTimeout {
288
+ name: string | null;
289
+ payload: null;
290
+ from: null;
291
+ timedOut: true;
292
+ }
293
+ export interface ParallelOptions {
294
+ concurrency?: number;
295
+ }
296
+ /**
297
+ * One `chidori.branch` variant (`docs/branching-execution.md` §6.1). A branch
298
+ * runs its own continuation source module from the parent's anchored state —
299
+ * not a re-run of the parent agent — so `source` is required.
300
+ */
301
+ export interface BranchVariant {
302
+ /** Branch label, shown in outcomes and the trace. Defaults to `branch-<k>`. */
303
+ label?: string;
304
+ /** Branch source module path, resolved like `callAgent` paths. */
305
+ source: string;
306
+ /** State handed to the branch as its run input. Defaults to `{}`. */
307
+ input?: AgentJson;
308
+ }
309
+ export type BranchStatus = "completed" | "paused" | "failed";
310
+ /** The result of one branch sub-run, returned for comparison (not merged). */
311
+ export interface BranchOutcome<T extends AgentJson = AgentJson> {
312
+ label: string;
313
+ /**
314
+ * `<parent run id>-op<branch seq>-branch-<k>` — identifies the branch
315
+ * sub-run, including for out-of-band `chidori branch-resume` /
316
+ * `branch-rerun` against its persisted store.
317
+ */
318
+ branchId: string;
319
+ status: BranchStatus;
320
+ /** The branch's output, when `status` is `"completed"`. */
321
+ output?: T;
322
+ /** What the branch is waiting on, when `status` is `"paused"`. */
323
+ pendingPrompt?: string;
324
+ /** The failure message, when `status` is `"failed"`. */
325
+ error?: string;
326
+ }
327
+ export interface BranchOptions {
328
+ /**
329
+ * Maximum branches running live at once (cost cap). Defaults to 1 —
330
+ * sequential. Higher values run variants in concurrent waves; outcome
331
+ * order always follows variant order.
332
+ */
333
+ concurrency?: number;
334
+ }
335
+ export interface RetryOptions {
336
+ attempts?: number;
337
+ delayMs?: number;
338
+ backoff?: "fixed" | "exponential";
339
+ }
340
+ export interface TryCallResult<T> {
341
+ ok: boolean;
342
+ value?: T;
343
+ error?: string;
344
+ }
345
+ export interface TemplateOptions {
346
+ source?: "file" | "inline";
347
+ }
348
+ export type MemoryAction = "get" | "set" | "delete" | "list" | "clear";
349
+ export type WorkspaceFileStatus = "complete" | "writing" | "failed";
350
+ export interface WorkspaceEntry {
351
+ path: string;
352
+ status: WorkspaceFileStatus;
353
+ sha256: string;
354
+ bytes: number;
355
+ language?: string | null;
356
+ attempt?: number | null;
357
+ updatedAt?: string | null;
358
+ }
359
+ export interface WorkspaceListOptions {
360
+ completeOnly?: boolean;
361
+ }
362
+ export interface WorkspaceWriteOptions {
363
+ language?: string;
364
+ }
365
+ export interface WorkspaceHost {
366
+ list(options?: WorkspaceListOptions): Promise<WorkspaceEntry[]>;
367
+ read(path: string): Promise<string>;
368
+ write(path: string, content: string, options?: WorkspaceWriteOptions): Promise<WorkspaceEntry>;
369
+ delete(path: string, reason?: string): Promise<void>;
370
+ remove(path: string, reason?: string): Promise<void>;
371
+ manifest(): Promise<AgentJson>;
372
+ }
373
+ export type TypeScriptImportPolicy = "none" | "relative" | "project";
374
+ export type DatePolicy = "disabled" | "fixed" | "host";
375
+ export type RandomPolicy = "disabled" | "seeded" | "host";
376
+ export type MapSetSnapshotPolicy = "reject" | "serialize";
377
+ export interface RuntimePolicyConfig {
378
+ typescript?: {
379
+ imports?: TypeScriptImportPolicy;
380
+ };
381
+ runtime?: {
382
+ date?: DatePolicy;
383
+ random?: RandomPolicy;
384
+ };
385
+ snapshot?: {
386
+ mapsSets?: MapSetSnapshotPolicy;
387
+ };
388
+ }
389
+ export interface Chidori {
390
+ workspace: WorkspaceHost;
391
+ /** Start an immutable multi-turn prompt context (optionally seeded). */
392
+ context(seed?: {
393
+ system?: string;
394
+ tools?: string[];
395
+ }): Context;
396
+ /**
397
+ * Start a multi-turn chat assistant — a stateful wrapper over `context()`
398
+ * that owns the running dialogue. Send turns with `chat.say(message)` or drive
399
+ * an interactive `input()` loop with `chat.loop()`.
400
+ */
401
+ conversation(options?: ConversationOptions): Conversation;
402
+ prompt(text: string, options?: PromptOptions): Promise<string>;
403
+ input(message: string, options?: InputOptions): Promise<string>;
404
+ /**
405
+ * Pause at a named listen point until a matching signal is delivered (or one
406
+ * is already queued in the durable mailbox), then resolve to
407
+ * `{ name, payload, from }`. The inverse of `input()`: the run idles cheaply
408
+ * on disk and an outside party delivers via `POST /sessions/{id}/signal`.
409
+ */
410
+ signal<T = AgentJson>(name: string): Promise<Signal<T>>;
411
+ signal<T = AgentJson>(name: string, options: SignalOptions): Promise<Signal<T> | SignalTimeout>;
412
+ /**
413
+ * Non-blocking: consume a queued signal of this name if present, else resolve
414
+ * to `null`. Records the result (value or null) at this seq so replay is
415
+ * deterministic.
416
+ */
417
+ pollSignal<T = AgentJson>(name: string): Promise<Signal<T> | null>;
418
+ /**
419
+ * Fan-in: pause until ANY of the named signals is delivered (or one is
420
+ * already queued in the durable mailbox). Resolves to the bare consumed
421
+ * signal — its `name` says which fired. Pre-arrived candidates are consumed
422
+ * in delivery order (lowest `delivery_seq` across the whole name set).
423
+ */
424
+ signalAny<T = AgentJson>(names: string[]): Promise<Signal<T>>;
425
+ signalAny<T = AgentJson>(names: string[], options: SignalOptions): Promise<Signal<T> | SignalTimeout>;
426
+ /**
427
+ * Durable value checkpoint: run `fn` once and journal its JSON-serializable
428
+ * result; on replay/resume the recorded value (or error) is returned without
429
+ * re-running `fn`. Wrap expensive deterministic computation in a step so a
430
+ * resumed run does not re-pay it. The callback must be pure, synchronous
431
+ * compute — host effects (`chidori.*`), captured randomness, filesystem
432
+ * writes, timers, and async callbacks are refused inside a step.
433
+ */
434
+ step<T extends AgentJson = AgentJson>(name: string, fn: () => T): Promise<T>;
435
+ callAgent<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson>(path: string, input?: TInput): Promise<TOutput>;
436
+ /**
437
+ * Fork the run into one sub-run per variant from the current anchored state
438
+ * (the VFS plus each variant's explicit `input`), run each variant's own
439
+ * source module, and return every outcome so the agent can compare and pick.
440
+ * The whole fan-out is one recorded durable call: a replay of this run
441
+ * returns the outcomes from cache without re-running the branches.
442
+ */
443
+ branch<T extends AgentJson = AgentJson>(variants: BranchVariant[], options?: BranchOptions): Promise<BranchOutcome<T>[]>;
444
+ tool<TArgs extends JsonObject = JsonObject, TResult extends AgentJson = AgentJson>(name: string, args?: TArgs): Promise<TResult>;
445
+ parallel<TTasks extends readonly (() => Promise<unknown>)[]>(tasks: TTasks, options?: ParallelOptions): Promise<{
446
+ [Index in keyof TTasks]: Awaited<ReturnType<TTasks[Index]>>;
447
+ }>;
448
+ retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
449
+ tryCall<T>(fn: () => Promise<T>): Promise<TryCallResult<T>>;
450
+ template(pathOrText: string, vars?: JsonObject, options?: TemplateOptions): Promise<string>;
451
+ log(message: string, fields?: JsonObject): Promise<void>;
452
+ memory<T extends AgentJson = AgentJson>(action: MemoryAction, key?: string, value?: T, options?: JsonObject): Promise<T | AgentJson[] | null>;
453
+ checkpoint(label?: string, data?: AgentJson): Promise<void>;
454
+ }
455
+ export type AgentFunction<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson> = (input: TInput) => TOutput | Promise<TOutput>;
456
+ export type ToolFunction<TArgs extends JsonObject = JsonObject, TResult extends AgentJson = AgentJson> = (args: TArgs) => TResult | Promise<TResult>;
457
+ /**
458
+ * The chidori host object — the durable surface your agents and tools call
459
+ * (`chidori.log`, `chidori.prompt`, `chidori.tool`, `chidori.input`, …).
460
+ *
461
+ * Import it for typed access; the runtime strips this import and supplies the
462
+ * real object at execution time, so there's no actual module dependency (and no
463
+ * need for a `(input, chidori)` second parameter):
464
+ *
465
+ * ```ts
466
+ * import { chidori, run } from "chidori";
467
+ * run(async (input: { topic: string }) => {
468
+ * await chidori.log("starting", { topic: input.topic });
469
+ * return { ok: true };
470
+ * });
471
+ * ```
472
+ *
473
+ * Accessing it from a plain import outside the runtime throws.
474
+ */
475
+ export declare const chidori: Chidori;
476
+ /**
477
+ * Define the agent entrypoint. Call it once at the top level of an agent module
478
+ * with your handler; the runtime invokes the handler with the run input and
479
+ * uses its return value as the output. This replaces the old "export a function
480
+ * named `agent`" convention.
481
+ *
482
+ * ```ts
483
+ * import { run } from "chidori";
484
+ * run(async (input) => ({ greeting: `hello ${input.name}` }));
485
+ * ```
486
+ */
487
+ export declare function run<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson>(handler: AgentFunction<TInput, TOutput>): void;
package/dist/agent.js ADDED
@@ -0,0 +1,46 @@
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
+ * The chidori host object — the durable surface your agents and tools call
9
+ * (`chidori.log`, `chidori.prompt`, `chidori.tool`, `chidori.input`, …).
10
+ *
11
+ * Import it for typed access; the runtime strips this import and supplies the
12
+ * real object at execution time, so there's no actual module dependency (and no
13
+ * need for a `(input, chidori)` second parameter):
14
+ *
15
+ * ```ts
16
+ * import { chidori, run } from "chidori";
17
+ * run(async (input: { topic: string }) => {
18
+ * await chidori.log("starting", { topic: input.topic });
19
+ * return { ok: true };
20
+ * });
21
+ * ```
22
+ *
23
+ * Accessing it from a plain import outside the runtime throws.
24
+ */
25
+ export const chidori = new Proxy({}, {
26
+ get(_target, prop) {
27
+ throw new Error(`chidori.${String(prop)} is only available inside the chidori runtime; ` +
28
+ `this import is replaced when an agent runs under chidori.`);
29
+ },
30
+ });
31
+ /**
32
+ * Define the agent entrypoint. Call it once at the top level of an agent module
33
+ * with your handler; the runtime invokes the handler with the run input and
34
+ * uses its return value as the output. This replaces the old "export a function
35
+ * named `agent`" convention.
36
+ *
37
+ * ```ts
38
+ * import { run } from "chidori";
39
+ * run(async (input) => ({ greeting: `hello ${input.name}` }));
40
+ * ```
41
+ */
42
+ export function run(handler) {
43
+ void handler;
44
+ throw new Error("run() is only available inside the chidori runtime; this import is " +
45
+ "replaced when an agent runs under chidori.");
46
+ }