@1kbirds/chidori 3.5.1 → 3.7.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.
- package/README.md +81 -6
- package/dist/agent.d.ts +483 -51
- package/dist/agent.js +28 -0
- package/dist/index.d.ts +131 -7
- package/dist/index.js +207 -24
- package/package.json +2 -1
- package/src/agent.ts +543 -59
- package/src/index.ts +258 -22
package/dist/agent.d.ts
CHANGED
|
@@ -10,6 +10,23 @@ export type AgentJson = null | boolean | number | string | AgentJson[] | {
|
|
|
10
10
|
export type JsonObject = {
|
|
11
11
|
[key: string]: AgentJson;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Structured fields for `chidori.log`. Values are JSON; `undefined` entries are
|
|
15
|
+
* accepted (and simply dropped on serialization) so optional data can be logged
|
|
16
|
+
* without `?? null` dances.
|
|
17
|
+
*/
|
|
18
|
+
export type LogFields = {
|
|
19
|
+
[key: string]: AgentJson | undefined;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* What an agent handler may return: JSON, except object members may be
|
|
23
|
+
* `undefined` (they are dropped when the output is serialized). This is what
|
|
24
|
+
* lets outcome shapes with optional fields — {@link BranchOutcome},
|
|
25
|
+
* {@link ActorOutcome} — be returned from an agent without `?? null` dances.
|
|
26
|
+
*/
|
|
27
|
+
export type AgentOutput = null | boolean | number | string | AgentOutput[] | {
|
|
28
|
+
[key: string]: AgentOutput | undefined;
|
|
29
|
+
};
|
|
13
30
|
export interface JsonSchema {
|
|
14
31
|
type?: "object" | "array" | "string" | "number" | "integer" | "boolean" | "null";
|
|
15
32
|
description?: string;
|
|
@@ -28,6 +45,44 @@ export interface ToolDefinition {
|
|
|
28
45
|
type: "object";
|
|
29
46
|
};
|
|
30
47
|
}
|
|
48
|
+
/**
|
|
49
|
+
* A tool is nothing more than a function with a documented signature: a
|
|
50
|
+
* `name`, a `description`, and a JSON-schema for its `parameters`, wrapped
|
|
51
|
+
* around the `run` function the model actually calls. That's the whole
|
|
52
|
+
* contract — the signature is what the model reads to decide when and how to
|
|
53
|
+
* call it; the function is what runs. {@link defineTool} builds one as a
|
|
54
|
+
* plain object you import (or define inline) like any other code — no
|
|
55
|
+
* `tools/` directory, no registry.
|
|
56
|
+
*
|
|
57
|
+
* Pass handles directly in `prompt({ tools: [...] })`,
|
|
58
|
+
* `conversation({ tools: [...] })`, or `context().tools([...])`, freely
|
|
59
|
+
* mixed with registered tool names.
|
|
60
|
+
*
|
|
61
|
+
* The `run` function executes in the AGENT'S OWN VM, so closures over agent
|
|
62
|
+
* state and ordinary imports all work, and its side effects (fetch,
|
|
63
|
+
* workspace, node:fs, ...) are the captured effects every agent already
|
|
64
|
+
* has — journaled and deterministically replayable for free. Each model
|
|
65
|
+
* turn of the loop is a durable `respond()` call; each invocation is
|
|
66
|
+
* journaled as a `mark("tool:<name>")` record for the trace.
|
|
67
|
+
*/
|
|
68
|
+
export interface ToolHandle<Args extends JsonObject = JsonObject> {
|
|
69
|
+
readonly __chidoriTool: true;
|
|
70
|
+
/** The name the model calls the tool by. */
|
|
71
|
+
readonly name: string;
|
|
72
|
+
/** What the tool does — the model reads this to decide when to call it. */
|
|
73
|
+
readonly description: string;
|
|
74
|
+
/** JSON-schema for the arguments: the documented shape of the call. */
|
|
75
|
+
readonly parameters: JsonSchema & {
|
|
76
|
+
type: "object";
|
|
77
|
+
};
|
|
78
|
+
/**
|
|
79
|
+
* The function that runs when the tool is called. The `chidori` runtime
|
|
80
|
+
* handle is passed in by the tool loop, but tool bodies usually just close
|
|
81
|
+
* over the imported `chidori`, so it is optional when you call `run`
|
|
82
|
+
* directly (`tool.run(args)`).
|
|
83
|
+
*/
|
|
84
|
+
run(args: Args, chidori?: Chidori): AgentOutput | Promise<AgentOutput>;
|
|
85
|
+
}
|
|
31
86
|
export type PromptStreamType = "progress" | "draft" | "subagent" | "final" | (string & {});
|
|
32
87
|
/** Provider prompt-cache lifetime for a cached prefix. */
|
|
33
88
|
export type CacheTtl = "5m" | "1h";
|
|
@@ -36,12 +91,33 @@ export interface PromptOptions {
|
|
|
36
91
|
system?: string;
|
|
37
92
|
model?: string;
|
|
38
93
|
maxTokens?: number;
|
|
39
|
-
max_tokens?: number;
|
|
40
94
|
maxTurns?: number;
|
|
41
|
-
max_turns?: number;
|
|
42
95
|
temperature?: number;
|
|
43
|
-
tools?: string
|
|
96
|
+
tools?: Array<string | ToolHandle>;
|
|
97
|
+
/**
|
|
98
|
+
* `"json"` parses the reply as JSON (a single wrapping markdown fence is
|
|
99
|
+
* tolerated) and, by default, THROWS when the reply is not valid JSON — a
|
|
100
|
+
* truncated reply (e.g. a reasoning model spending the whole `maxTokens`
|
|
101
|
+
* budget on hidden reasoning) can never masquerade as a successful
|
|
102
|
+
* structured result. Set `strict: false` for the lenient raw-string
|
|
103
|
+
* fallback.
|
|
104
|
+
*/
|
|
44
105
|
format?: "json" | (string & {});
|
|
106
|
+
/**
|
|
107
|
+
* Applies to `format: "json"`. `true` (the default): unparseable output
|
|
108
|
+
* throws with the parse error and the reply head. `false`: fall back to
|
|
109
|
+
* returning the raw reply string.
|
|
110
|
+
*/
|
|
111
|
+
strict?: boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Opt-in guard for plain-text prompts: `true` THROWS a catchable error when
|
|
114
|
+
* the reply is empty after trimming whitespace — a response truncated to
|
|
115
|
+
* nothing (e.g. a reasoning model spending the whole `maxTokens` budget on
|
|
116
|
+
* hidden reasoning) can never flow on as a silently empty result. Has no
|
|
117
|
+
* effect with `format: "json"`, where strict parsing already throws on an
|
|
118
|
+
* empty reply. Off by default: an empty reply resolves to `""`.
|
|
119
|
+
*/
|
|
120
|
+
nonEmpty?: boolean;
|
|
45
121
|
stream?: boolean;
|
|
46
122
|
/**
|
|
47
123
|
* Prompt-cache posture. Defaults to on (`"5m"`): the runtime marks the
|
|
@@ -58,16 +134,23 @@ export interface PromptOptions {
|
|
|
58
134
|
export interface LlmResponseJson {
|
|
59
135
|
content: string;
|
|
60
136
|
blocks: AgentJson[];
|
|
61
|
-
|
|
137
|
+
/** Tool-use requests from the model. `input` is always a JSON object, so it
|
|
138
|
+
* can be passed straight to `chidori.tool(call.name, call.input)`. */
|
|
139
|
+
toolCalls: {
|
|
62
140
|
id: string;
|
|
63
141
|
name: string;
|
|
64
|
-
input:
|
|
142
|
+
input: JsonObject;
|
|
65
143
|
}[];
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
144
|
+
stopReason: string;
|
|
145
|
+
inputTokens: number;
|
|
146
|
+
outputTokens: number;
|
|
147
|
+
cacheCreationTokens: number;
|
|
148
|
+
cacheReadTokens: number;
|
|
149
|
+
/** Hidden reasoning text from reasoning models (OpenAI-compatible
|
|
150
|
+
* `reasoning_content`, e.g. DeepSeek). Present only when the provider
|
|
151
|
+
* reported it; never part of the conversation. Useful for inspecting why
|
|
152
|
+
* a model spent output budget before its visible answer. */
|
|
153
|
+
reasoning?: string;
|
|
71
154
|
}
|
|
72
155
|
/** Options for `Context.compact()` — explicit, opt-in window compaction. */
|
|
73
156
|
export interface CompactOptions {
|
|
@@ -115,7 +198,7 @@ export interface CompactOptions {
|
|
|
115
198
|
export interface Context {
|
|
116
199
|
system(text: string): Context;
|
|
117
200
|
/** Expose registered tools (by name, resolved like `prompt({ tools })`). */
|
|
118
|
-
tools(
|
|
201
|
+
tools(list: Array<string | ToolHandle>): Context;
|
|
119
202
|
/** A large stable reference block, labelled for the trace. */
|
|
120
203
|
doc(label: string, text: string): Context;
|
|
121
204
|
user(text: string): Context;
|
|
@@ -153,17 +236,19 @@ export interface Context {
|
|
|
153
236
|
/** Rough local token estimate for window budgeting. */
|
|
154
237
|
estimateTokens(): number;
|
|
155
238
|
}
|
|
156
|
-
/** One recorded exchange in a {@link Conversation} transcript.
|
|
157
|
-
|
|
239
|
+
/** One recorded exchange in a {@link Conversation} transcript. A type alias
|
|
240
|
+
* (not an interface) so transcripts stay assignable to {@link AgentJson} and
|
|
241
|
+
* can be returned as agent output directly. */
|
|
242
|
+
export type ConversationTurn = {
|
|
158
243
|
role: "user" | "assistant";
|
|
159
244
|
text: string;
|
|
160
|
-
}
|
|
245
|
+
};
|
|
161
246
|
/** Options for `chidori.conversation()`. */
|
|
162
247
|
export interface ConversationOptions {
|
|
163
248
|
/** System prompt — frozen once as the conversation's cacheable prefix. */
|
|
164
249
|
system?: string;
|
|
165
250
|
/** Tool names available on every turn (resolved like `prompt({ tools })`). */
|
|
166
|
-
tools?: string
|
|
251
|
+
tools?: Array<string | ToolHandle>;
|
|
167
252
|
/** Default stream label for each turn's prompt (default `"final"`). */
|
|
168
253
|
type?: PromptStreamType;
|
|
169
254
|
/** Default model for each turn (a per-turn override still wins). */
|
|
@@ -247,28 +332,41 @@ export interface InputOptions {
|
|
|
247
332
|
type?: string;
|
|
248
333
|
default?: string;
|
|
249
334
|
choices?: string[];
|
|
335
|
+
/**
|
|
336
|
+
* The artifact under review — a draft, a diff, a report — shown to the
|
|
337
|
+
* human alongside the question so an approval gate is never blind. The CLI
|
|
338
|
+
* renders it above the prompt; over HTTP it is surfaced as the paused
|
|
339
|
+
* session's `pending_details`. Never part of the durable record, so adding
|
|
340
|
+
* or editing it does not diverge an existing checkpoint.
|
|
341
|
+
*/
|
|
342
|
+
details?: string;
|
|
250
343
|
}
|
|
251
344
|
/**
|
|
252
345
|
* Who delivered a signal. `kind` distinguishes a human participant from a peer
|
|
253
346
|
* agent; `id` is the participant identity; `runId` is set when an agent sends
|
|
254
347
|
* (its own run id), so agent-to-agent coordination is attributable in the trace.
|
|
348
|
+
*
|
|
349
|
+
* A type alias (not an interface) so it stays assignable to {@link AgentJson} —
|
|
350
|
+
* senders routinely flow into `chidori.log` fields and agent outputs.
|
|
255
351
|
*/
|
|
256
|
-
export
|
|
352
|
+
export type SignalSender = {
|
|
257
353
|
kind: "human" | "agent";
|
|
258
354
|
id: string;
|
|
259
355
|
runId?: string;
|
|
260
|
-
}
|
|
356
|
+
};
|
|
261
357
|
/**
|
|
262
|
-
* A named message delivered into a run mid-flight (`docs/signals.md`
|
|
358
|
+
* A named message delivered into a run mid-flight (`docs/signals.md`). The
|
|
263
359
|
* inverse of `input()`: an outside party (human or agent) pushes
|
|
264
360
|
* `{ name, payload, from }` at an agent-declared listen point. Every signal is
|
|
265
361
|
* recorded in the call log, so the multiplayer session replays deterministically.
|
|
266
362
|
*/
|
|
267
|
-
export
|
|
363
|
+
export type Signal<T = AgentJson> = {
|
|
268
364
|
name: string;
|
|
269
365
|
payload: T;
|
|
270
366
|
from: SignalSender;
|
|
271
|
-
}
|
|
367
|
+
/** Never set on a delivered signal — the discriminant against {@link SignalTimeout}, so `if (result.timedOut)` narrows. */
|
|
368
|
+
timedOut?: undefined;
|
|
369
|
+
};
|
|
272
370
|
export interface SignalOptions {
|
|
273
371
|
/**
|
|
274
372
|
* Resolve to a {@link SignalTimeout} sentinel after this many milliseconds
|
|
@@ -280,21 +378,21 @@ export interface SignalOptions {
|
|
|
280
378
|
}
|
|
281
379
|
/**
|
|
282
380
|
* The sentinel a `timeoutMs` listen point resolves to when the deadline passes
|
|
283
|
-
* with no matching delivery
|
|
284
|
-
*
|
|
285
|
-
*
|
|
381
|
+
* with no matching delivery — a timeout resolves to this sentinel rather than
|
|
382
|
+
* rejecting (`docs/signals.md`). `name` is the single awaited name, or `null`
|
|
383
|
+
* for a multi-name fan-in listen.
|
|
286
384
|
*/
|
|
287
|
-
export
|
|
385
|
+
export type SignalTimeout = {
|
|
288
386
|
name: string | null;
|
|
289
387
|
payload: null;
|
|
290
388
|
from: null;
|
|
291
389
|
timedOut: true;
|
|
292
|
-
}
|
|
390
|
+
};
|
|
293
391
|
export interface ParallelOptions {
|
|
294
392
|
concurrency?: number;
|
|
295
393
|
}
|
|
296
394
|
/**
|
|
297
|
-
* One `chidori.branch` variant (`docs/branching-execution.md`
|
|
395
|
+
* One `chidori.branch` variant (`docs/branching-execution.md`). A branch
|
|
298
396
|
* runs its own continuation source module from the parent's anchored state —
|
|
299
397
|
* not a re-run of the parent agent — so `source` is required.
|
|
300
398
|
*/
|
|
@@ -307,8 +405,9 @@ export interface BranchVariant {
|
|
|
307
405
|
input?: AgentJson;
|
|
308
406
|
}
|
|
309
407
|
export type BranchStatus = "completed" | "paused" | "failed";
|
|
310
|
-
/** The result of one branch sub-run, returned for comparison (not merged).
|
|
311
|
-
|
|
408
|
+
/** The result of one branch sub-run, returned for comparison (not merged).
|
|
409
|
+
* A type alias so outcomes can flow straight into agent output. */
|
|
410
|
+
export type BranchOutcome<T extends AgentJson = AgentJson> = {
|
|
312
411
|
label: string;
|
|
313
412
|
/**
|
|
314
413
|
* `<parent run id>-op<branch seq>-branch-<k>` — identifies the branch
|
|
@@ -323,7 +422,7 @@ export interface BranchOutcome<T extends AgentJson = AgentJson> {
|
|
|
323
422
|
pendingPrompt?: string;
|
|
324
423
|
/** The failure message, when `status` is `"failed"`. */
|
|
325
424
|
error?: string;
|
|
326
|
-
}
|
|
425
|
+
};
|
|
327
426
|
export interface BranchOptions {
|
|
328
427
|
/**
|
|
329
428
|
* Maximum branches running live at once (cost cap). Defaults to 1 —
|
|
@@ -337,6 +436,249 @@ export interface RetryOptions {
|
|
|
337
436
|
delayMs?: number;
|
|
338
437
|
backoff?: "fixed" | "exponential";
|
|
339
438
|
}
|
|
439
|
+
/**
|
|
440
|
+
* What the runtime does when an actor iteration fails (`docs/actors.md`):
|
|
441
|
+
* - `"never"` (default) — the failure is the actor's final outcome;
|
|
442
|
+
* - `"clean"` — re-run the actor's module from scratch (fresh log, the
|
|
443
|
+
* spawn-time filesystem anchor, the original input);
|
|
444
|
+
* - `"resume"` — replay the actor's accumulated call log with the trailing
|
|
445
|
+
* failed records stripped, so completed work returns from cache and the
|
|
446
|
+
* failing call itself retries live.
|
|
447
|
+
*/
|
|
448
|
+
export type ActorRestartStrategy = "never" | "clean" | "resume";
|
|
449
|
+
export interface SpawnActorOptions {
|
|
450
|
+
/** Register the actor under a name for `actors.lookup`/`actors.send` addressing. */
|
|
451
|
+
name?: string;
|
|
452
|
+
/** Restart strategy applied when an iteration fails. Default `"never"`. */
|
|
453
|
+
restart?: ActorRestartStrategy;
|
|
454
|
+
/** Restart intensity cap (default 3). */
|
|
455
|
+
maxRestarts?: number;
|
|
456
|
+
/** Base delay between restarts, doubling per attempt (default 0). */
|
|
457
|
+
backoffMs?: number;
|
|
458
|
+
/**
|
|
459
|
+
* How long the actor may sit at an empty-mailbox listen point with no
|
|
460
|
+
* explicit `timeoutMs` before the runtime parks it as a `paused` outcome
|
|
461
|
+
* (default 300 000 ms).
|
|
462
|
+
*/
|
|
463
|
+
idleTimeoutMs?: number;
|
|
464
|
+
}
|
|
465
|
+
/** How an actor's supervision loop settled. */
|
|
466
|
+
export type ActorOutcomeStatus = "completed" | "failed" | "paused" | "stopped";
|
|
467
|
+
/** The settlement `actors.join()`/`actors.stop()` resolve to.
|
|
468
|
+
* A type alias so outcomes can flow straight into agent output. */
|
|
469
|
+
export type ActorOutcome<T extends AgentJson = AgentJson> = {
|
|
470
|
+
pid: string;
|
|
471
|
+
status: ActorOutcomeStatus;
|
|
472
|
+
/** The actor's return value, when `status` is `"completed"`. */
|
|
473
|
+
output?: T;
|
|
474
|
+
/** The final failure, when `status` is `"failed"`. */
|
|
475
|
+
error?: string;
|
|
476
|
+
/** What the actor is parked on, when `status` is `"paused"`. */
|
|
477
|
+
pendingPrompt?: string;
|
|
478
|
+
/** How many supervised restarts the actor consumed. */
|
|
479
|
+
restarts: number;
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* What a `join`/`stop` with `timeoutMs` resolves to when the deadline passes
|
|
483
|
+
* before the actor settles: a snapshot, not a settlement — nothing merged,
|
|
484
|
+
* join again later. Discriminate with `outcome.status === "running"`.
|
|
485
|
+
*/
|
|
486
|
+
export type ActorStillRunning = {
|
|
487
|
+
pid: string;
|
|
488
|
+
status: "running";
|
|
489
|
+
restarts: number;
|
|
490
|
+
};
|
|
491
|
+
export type ActorStatus = {
|
|
492
|
+
pid: string;
|
|
493
|
+
status: ActorOutcomeStatus | "running" | "waiting" | "unknown";
|
|
494
|
+
restarts?: number;
|
|
495
|
+
/** Messages queued and not yet consumed. */
|
|
496
|
+
mailbox?: number;
|
|
497
|
+
/** The listen-point names a `"waiting"` actor is parked on. */
|
|
498
|
+
waitingFor?: string[];
|
|
499
|
+
};
|
|
500
|
+
/** A message consumed from a mailbox. */
|
|
501
|
+
export type ActorMessage<T = AgentJson> = {
|
|
502
|
+
name: string;
|
|
503
|
+
payload: T;
|
|
504
|
+
/** Sender identity: `id` is the sending actor's pid, or `"run"`. */
|
|
505
|
+
from: SignalSender;
|
|
506
|
+
/** Never set on a delivered message — the discriminant against {@link SignalTimeout}. */
|
|
507
|
+
timedOut?: undefined;
|
|
508
|
+
};
|
|
509
|
+
export interface ReceiveOptions {
|
|
510
|
+
/** Resolve to the `{ timedOut: true }` sentinel after this many ms. */
|
|
511
|
+
timeoutMs?: number;
|
|
512
|
+
}
|
|
513
|
+
export interface JoinActorOptions {
|
|
514
|
+
/**
|
|
515
|
+
* Give up waiting after this many ms: the join resolves to
|
|
516
|
+
* {@link ActorStillRunning} without settling the actor — join again later.
|
|
517
|
+
*/
|
|
518
|
+
timeoutMs?: number;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* A spawned actor's handle: its address plus its lifecycle methods, so code
|
|
522
|
+
* reads `worker.send(...)` / `worker.join()` instead of threading pid strings.
|
|
523
|
+
* Pure sugar — every method is one recorded durable host call, identical to
|
|
524
|
+
* the string-addressed forms on {@link Actors}.
|
|
525
|
+
*/
|
|
526
|
+
export interface ActorHandle {
|
|
527
|
+
pid: string;
|
|
528
|
+
/** The registered name, when the spawn options provided one. */
|
|
529
|
+
name: string | null;
|
|
530
|
+
send<T extends AgentJson = AgentJson>(name: string, payload?: T): Promise<{
|
|
531
|
+
delivered: boolean;
|
|
532
|
+
}>;
|
|
533
|
+
join<T extends AgentJson = AgentJson>(): Promise<ActorOutcome<T>>;
|
|
534
|
+
join<T extends AgentJson = AgentJson>(options: JoinActorOptions): Promise<ActorOutcome<T> | ActorStillRunning>;
|
|
535
|
+
stop<T extends AgentJson = AgentJson>(): Promise<ActorOutcome<T>>;
|
|
536
|
+
stop<T extends AgentJson = AgentJson>(options: JoinActorOptions): Promise<ActorOutcome<T> | ActorStillRunning>;
|
|
537
|
+
status(): Promise<ActorStatus>;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* `chidori.actors` — supervised, message-passing actor processes
|
|
541
|
+
* (`docs/actors.md`). `spawn` starts another agent module as a concurrent,
|
|
542
|
+
* addressable sub-run with a durable mailbox and a restart policy; actors can
|
|
543
|
+
* spawn their own children, forming a supervision tree (settling is
|
|
544
|
+
* owner-only, `"parent"` addresses the owner, and supervisors reap their
|
|
545
|
+
* children). Every method is a recorded durable call: a replay re-runs
|
|
546
|
+
* nothing.
|
|
547
|
+
*/
|
|
548
|
+
export interface Actors {
|
|
549
|
+
spawn<TInput extends AgentJson = JsonObject>(source: string, input?: TInput, options?: SpawnActorOptions): Promise<ActorHandle>;
|
|
550
|
+
/**
|
|
551
|
+
* Deliver a named message to a mailbox. `to` is a pid, a registered name,
|
|
552
|
+
* or `"parent"` (the sender's spawner: its owning actor, or the run for a
|
|
553
|
+
* top-level actor). Never blocks; `delivered` is false once the target has
|
|
554
|
+
* settled.
|
|
555
|
+
*/
|
|
556
|
+
send<T extends AgentJson = AgentJson>(to: string, name: string, payload?: T): Promise<{
|
|
557
|
+
delivered: boolean;
|
|
558
|
+
}>;
|
|
559
|
+
/** String-addressed `join` — see {@link ActorHandle.join}. Owner-only. */
|
|
560
|
+
join<T extends AgentJson = AgentJson>(target: string): Promise<ActorOutcome<T>>;
|
|
561
|
+
join<T extends AgentJson = AgentJson>(target: string, options: JoinActorOptions): Promise<ActorOutcome<T> | ActorStillRunning>;
|
|
562
|
+
/**
|
|
563
|
+
* Request a cooperative stop (honored between iterations, at mailbox waits,
|
|
564
|
+
* and during restart backoff — a live LLM/tool call finishes first), then
|
|
565
|
+
* settle and merge exactly like `join`. Owner-only.
|
|
566
|
+
*/
|
|
567
|
+
stop<T extends AgentJson = AgentJson>(target: string): Promise<ActorOutcome<T>>;
|
|
568
|
+
stop<T extends AgentJson = AgentJson>(target: string, options: JoinActorOptions): Promise<ActorOutcome<T> | ActorStillRunning>;
|
|
569
|
+
/** A durable snapshot of an actor's lifecycle. */
|
|
570
|
+
status(target: string): Promise<ActorStatus>;
|
|
571
|
+
/** Registry lookup: a handle for the actor registered under `name`, or `null`. */
|
|
572
|
+
lookup(name: string): Promise<ActorHandle | null>;
|
|
573
|
+
}
|
|
574
|
+
export interface SpawnAgentOptions {
|
|
575
|
+
/** Register the agent under a name in the durable registry; generated when omitted. */
|
|
576
|
+
name?: string;
|
|
577
|
+
/** Restart strategy applied when an iteration fails. Default `"resume"`. */
|
|
578
|
+
restart?: ActorRestartStrategy;
|
|
579
|
+
/** Restart intensity cap (default 3). */
|
|
580
|
+
maxRestarts?: number;
|
|
581
|
+
/** Base delay between restarts, doubling per attempt (default 0). */
|
|
582
|
+
backoffMs?: number;
|
|
583
|
+
/**
|
|
584
|
+
* Default model for the agent's prompts. Defaults to the spawner's
|
|
585
|
+
* resolved model and travels with the agent's durable descriptor, so a
|
|
586
|
+
* wake in a differently-configured process (another server, another env)
|
|
587
|
+
* keeps running on the same model.
|
|
588
|
+
*/
|
|
589
|
+
model?: string;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* A detached agent's lifecycle status (`docs/detached-agents.md`).
|
|
593
|
+
* `hibernating` means parked at a listen point holding no thread and no VM,
|
|
594
|
+
* waiting on a mailbox delivery or an alarm deadline.
|
|
595
|
+
*/
|
|
596
|
+
export type DetachedAgentStatus = "running" | "hibernating" | "paused" | "completed" | "failed" | "stopped";
|
|
597
|
+
/** The snapshot `agents.status()`/`agents.join()` resolve to.
|
|
598
|
+
* A type alias so outcomes can flow straight into agent output. */
|
|
599
|
+
export type DetachedAgentOutcome<T extends AgentJson = AgentJson> = {
|
|
600
|
+
name: string;
|
|
601
|
+
runId: string;
|
|
602
|
+
status: DetachedAgentStatus;
|
|
603
|
+
output?: T;
|
|
604
|
+
error?: string;
|
|
605
|
+
restarts: number;
|
|
606
|
+
/** The listen-point names a hibernating agent wakes on. */
|
|
607
|
+
waitingFor?: string[] | null;
|
|
608
|
+
/** The alarm deadline, when the current wait carries one (ISO timestamp). */
|
|
609
|
+
deadline?: string | null;
|
|
610
|
+
};
|
|
611
|
+
/**
|
|
612
|
+
* A detached agent's handle — same sugar as {@link ActorHandle}, addressed by
|
|
613
|
+
* the agent's registered name. Every method is one recorded durable call.
|
|
614
|
+
*/
|
|
615
|
+
export interface DetachedAgentHandle {
|
|
616
|
+
name: string;
|
|
617
|
+
runId: string | null;
|
|
618
|
+
send<T extends AgentJson = AgentJson>(name: string, payload?: T): Promise<{
|
|
619
|
+
delivered: boolean;
|
|
620
|
+
}>;
|
|
621
|
+
join<T extends AgentJson = AgentJson>(options?: JoinActorOptions): Promise<DetachedAgentOutcome<T>>;
|
|
622
|
+
stop<T extends AgentJson = AgentJson>(options?: JoinActorOptions): Promise<DetachedAgentOutcome<T>>;
|
|
623
|
+
status<T extends AgentJson = AgentJson>(): Promise<DetachedAgentOutcome<T>>;
|
|
624
|
+
}
|
|
625
|
+
/**
|
|
626
|
+
* `chidori.agents` — detached, durable, addressable agent processes
|
|
627
|
+
* (`docs/detached-agents.md`). Where an actor lives inside its spawning run,
|
|
628
|
+
* a detached agent is its OWN durable run: it has its own journal, a
|
|
629
|
+
* registered name that outlives the spawner, a durable mailbox, and a
|
|
630
|
+
* hibernate/wake lifecycle that survives process restarts. Requires
|
|
631
|
+
* persistence.
|
|
632
|
+
*/
|
|
633
|
+
export interface DetachedAgents {
|
|
634
|
+
spawn<TInput extends AgentJson = JsonObject>(source: string, input?: TInput, options?: SpawnAgentOptions): Promise<DetachedAgentHandle>;
|
|
635
|
+
/** Durable delivery into the agent's mailbox; wakes a hibernating agent on a matching name. */
|
|
636
|
+
send<T extends AgentJson = AgentJson>(to: string, name: string, payload?: T): Promise<{
|
|
637
|
+
delivered: boolean;
|
|
638
|
+
}>;
|
|
639
|
+
/** Wait for the agent to settle; with `timeoutMs`, resolves to a status snapshot on expiry. */
|
|
640
|
+
join<T extends AgentJson = AgentJson>(target: string, options?: JoinActorOptions): Promise<DetachedAgentOutcome<T>>;
|
|
641
|
+
/** Cooperative stop (a live LLM call finishes first). */
|
|
642
|
+
stop<T extends AgentJson = AgentJson>(target: string, options?: JoinActorOptions): Promise<DetachedAgentOutcome<T>>;
|
|
643
|
+
/** Point-in-time snapshot; never blocks. */
|
|
644
|
+
status<T extends AgentJson = AgentJson>(target: string): Promise<DetachedAgentOutcome<T>>;
|
|
645
|
+
/** Registry lookup: a handle for the agent registered under `name`, or `null`. */
|
|
646
|
+
lookup(name: string): Promise<DetachedAgentHandle | null>;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* `chidori.memory` — the persistent, namespaced key-value store. Values are
|
|
650
|
+
* JSON; `options.namespace` scopes keys (default `"default"`).
|
|
651
|
+
*/
|
|
652
|
+
export interface MemoryStore {
|
|
653
|
+
set<T extends AgentJson = AgentJson>(key: string, value: T, options?: JsonObject): Promise<void>;
|
|
654
|
+
get<T extends AgentJson = AgentJson>(key: string, options?: JsonObject): Promise<T | null>;
|
|
655
|
+
delete(key: string, options?: JsonObject): Promise<void>;
|
|
656
|
+
/** List entries, optionally filtered with `options.prefix`. */
|
|
657
|
+
list(options?: JsonObject): Promise<AgentJson[]>;
|
|
658
|
+
clear(options?: JsonObject): Promise<void>;
|
|
659
|
+
}
|
|
660
|
+
/**
|
|
661
|
+
* `chidori.util` — in-VM control-flow helpers. Unlike everything else on the
|
|
662
|
+
* host object these are pure JavaScript and record NOTHING: only the durable
|
|
663
|
+
* calls made inside your callbacks appear in the journal.
|
|
664
|
+
*/
|
|
665
|
+
export interface ChidoriUtil {
|
|
666
|
+
parallel<TTasks extends readonly (() => Promise<unknown>)[]>(tasks: TTasks, options?: ParallelOptions): Promise<{
|
|
667
|
+
[Index in keyof TTasks]: Awaited<ReturnType<TTasks[Index]>>;
|
|
668
|
+
}>;
|
|
669
|
+
retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
670
|
+
tryCall<T>(fn: () => Promise<T>): Promise<TryCallResult<T>>;
|
|
671
|
+
}
|
|
672
|
+
/**
|
|
673
|
+
* `chidori.appData` — the agent-run application-data store (generative-UI
|
|
674
|
+
* runs). Writes and queries execute through the host boundary (the agent
|
|
675
|
+
* never holds a credential) and are journaled like every other effect;
|
|
676
|
+
* `params` bind server-side (`$1`, `$2`, …), never string-concatenated.
|
|
677
|
+
*/
|
|
678
|
+
export interface AppData {
|
|
679
|
+
write(sql: string, params?: AgentJson[]): Promise<AgentJson>;
|
|
680
|
+
query(sql: string, params?: AgentJson[]): Promise<AgentJson>;
|
|
681
|
+
}
|
|
340
682
|
export interface TryCallResult<T> {
|
|
341
683
|
ok: boolean;
|
|
342
684
|
value?: T;
|
|
@@ -345,7 +687,6 @@ export interface TryCallResult<T> {
|
|
|
345
687
|
export interface TemplateOptions {
|
|
346
688
|
source?: "file" | "inline";
|
|
347
689
|
}
|
|
348
|
-
export type MemoryAction = "get" | "set" | "delete" | "list" | "clear";
|
|
349
690
|
export type WorkspaceFileStatus = "complete" | "writing" | "failed";
|
|
350
691
|
export interface WorkspaceEntry {
|
|
351
692
|
path: string;
|
|
@@ -391,7 +732,7 @@ export interface Chidori {
|
|
|
391
732
|
/** Start an immutable multi-turn prompt context (optionally seeded). */
|
|
392
733
|
context(seed?: {
|
|
393
734
|
system?: string;
|
|
394
|
-
tools?: string
|
|
735
|
+
tools?: Array<string | ToolHandle>;
|
|
395
736
|
}): Context;
|
|
396
737
|
/**
|
|
397
738
|
* Start a multi-turn chat assistant — a stateful wrapper over `context()`
|
|
@@ -399,6 +740,16 @@ export interface Chidori {
|
|
|
399
740
|
* an interactive `input()` loop with `chat.loop()`.
|
|
400
741
|
*/
|
|
401
742
|
conversation(options?: ConversationOptions): Conversation;
|
|
743
|
+
/**
|
|
744
|
+
* `format: "json"` parses the reply as JSON before returning it, so the
|
|
745
|
+
* resolved value is structured data (`AgentJson`), not a string. Narrow it
|
|
746
|
+
* to your shape with a single cast: `await chidori.prompt(p, { format:
|
|
747
|
+
* "json" }) as Triage`. (With `strict: false` an unparseable reply falls
|
|
748
|
+
* back to the raw string — still assignable to `AgentJson`.)
|
|
749
|
+
*/
|
|
750
|
+
prompt(text: string, options: PromptOptions & {
|
|
751
|
+
format: "json";
|
|
752
|
+
}): Promise<AgentJson>;
|
|
402
753
|
prompt(text: string, options?: PromptOptions): Promise<string>;
|
|
403
754
|
input(message: string, options?: InputOptions): Promise<string>;
|
|
404
755
|
/**
|
|
@@ -406,23 +757,19 @@ export interface Chidori {
|
|
|
406
757
|
* is already queued in the durable mailbox), then resolve to
|
|
407
758
|
* `{ name, payload, from }`. The inverse of `input()`: the run idles cheaply
|
|
408
759
|
* on disk and an outside party delivers via `POST /sessions/{id}/signal`.
|
|
760
|
+
* Pass an array for fan-in — the resolved signal's `name` says which fired;
|
|
761
|
+
* pre-arrived candidates are consumed in delivery order. Reach for `signal`
|
|
762
|
+
* when the delivery comes from OUTSIDE the process; use `receive` for actor
|
|
763
|
+
* messages.
|
|
409
764
|
*/
|
|
410
|
-
signal<T = AgentJson>(name: string): Promise<Signal<T>>;
|
|
411
|
-
signal<T = AgentJson>(name: string, options: SignalOptions): Promise<Signal<T> | SignalTimeout>;
|
|
765
|
+
signal<T = AgentJson>(name: string | string[]): Promise<Signal<T>>;
|
|
766
|
+
signal<T = AgentJson>(name: string | string[], options: SignalOptions): Promise<Signal<T> | SignalTimeout>;
|
|
412
767
|
/**
|
|
413
768
|
* Non-blocking: consume a queued signal of this name if present, else resolve
|
|
414
769
|
* to `null`. Records the result (value or null) at this seq so replay is
|
|
415
770
|
* deterministic.
|
|
416
771
|
*/
|
|
417
772
|
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
773
|
/**
|
|
427
774
|
* Durable value checkpoint: run `fn` once and journal its JSON-serializable
|
|
428
775
|
* result; on replay/resume the recorded value (or error) is returned without
|
|
@@ -430,8 +777,19 @@ export interface Chidori {
|
|
|
430
777
|
* resumed run does not re-pay it. The callback must be pure, synchronous
|
|
431
778
|
* compute — host effects (`chidori.*`), captured randomness, filesystem
|
|
432
779
|
* writes, timers, and async callbacks are refused inside a step.
|
|
780
|
+
*
|
|
781
|
+
* Type the result with a `type` alias, not an `interface`: interfaces lack
|
|
782
|
+
* the index signature `AgentJson` requires, so `interface Commit {...}`
|
|
783
|
+
* fails to satisfy `T extends AgentJson` while the structurally identical
|
|
784
|
+
* `type Commit = {...}` works.
|
|
433
785
|
*/
|
|
434
786
|
step<T extends AgentJson = AgentJson>(name: string, fn: () => T): Promise<T>;
|
|
787
|
+
/**
|
|
788
|
+
* Run another agent module inline and return its output — a synchronous
|
|
789
|
+
* child call sharing this run's context and log. Of the three module
|
|
790
|
+
* runners: need the answer inline → `callAgent`; comparing strategies →
|
|
791
|
+
* `branch`; coordinating concurrent processes → `actors.spawn`.
|
|
792
|
+
*/
|
|
435
793
|
callAgent<TInput extends AgentJson = JsonObject, TOutput extends AgentJson = AgentJson>(path: string, input?: TInput): Promise<TOutput>;
|
|
436
794
|
/**
|
|
437
795
|
* Fork the run into one sub-run per variant from the current anchored state
|
|
@@ -441,18 +799,61 @@ export interface Chidori {
|
|
|
441
799
|
* returns the outcomes from cache without re-running the branches.
|
|
442
800
|
*/
|
|
443
801
|
branch<T extends AgentJson = AgentJson>(variants: BranchVariant[], options?: BranchOptions): Promise<BranchOutcome<T>[]>;
|
|
802
|
+
/**
|
|
803
|
+
* Supervised actor processes: spawn agent modules as concurrent,
|
|
804
|
+
* addressable sub-runs with durable mailboxes, supervision trees, and
|
|
805
|
+
* restart policies (`docs/actors.md`).
|
|
806
|
+
*/
|
|
807
|
+
actors: Actors;
|
|
808
|
+
/**
|
|
809
|
+
* Detached durable agent processes: spawn agent modules as long-lived,
|
|
810
|
+
* named runs that outlive the spawner, hibernate at listen points holding
|
|
811
|
+
* no thread and no VM, and wake on mailbox deliveries or alarm deadlines
|
|
812
|
+
* (`docs/detached-agents.md`).
|
|
813
|
+
*/
|
|
814
|
+
agents: DetachedAgents;
|
|
815
|
+
/**
|
|
816
|
+
* A durable timer: hibernate until the deadline, surviving process
|
|
817
|
+
* restarts (the deadline is persisted and re-armed at boot). Resolves to
|
|
818
|
+
* the `{ timedOut: true }` sentinel when the alarm fires.
|
|
819
|
+
*/
|
|
820
|
+
alarm(ms: number): Promise<SignalTimeout>;
|
|
821
|
+
/**
|
|
822
|
+
* Blocking, in-place message consumption: inside an actor, drains the
|
|
823
|
+
* actor's own mailbox; in the spawning run, drains messages actors sent to
|
|
824
|
+
* `"parent"` (and any pre-queued external signals). Unlike `signal()` —
|
|
825
|
+
* which pauses the whole run so an external party can resume it — `receive`
|
|
826
|
+
* waits in place and is woken directly by in-process senders. Reach for
|
|
827
|
+
* `receive` for actor messages; use `signal` for external deliveries.
|
|
828
|
+
*
|
|
829
|
+
* Actor death is observable: an actor that settles `failed` (restart
|
|
830
|
+
* budget spent) or `paused` delivers a monitor message named
|
|
831
|
+
* `"__chidori.down__"` to its owner's mailbox with payload
|
|
832
|
+
* `{ pid, name, status, error?, pendingPrompt?, restarts }` — include it in
|
|
833
|
+
* a fan-in (`receive(["result", "__chidori.down__"])`) so a collection
|
|
834
|
+
* loop reacts to worker death instead of waiting out its timeout. As a
|
|
835
|
+
* backstop, a `receive` (even with `timeoutMs`) fails fast once every
|
|
836
|
+
* spawned actor has settled and nothing matching is queued — nothing
|
|
837
|
+
* in-process can deliver anymore, so blocking would be pure starvation.
|
|
838
|
+
*/
|
|
839
|
+
receive<T = AgentJson>(names: string | string[]): Promise<ActorMessage<T>>;
|
|
840
|
+
receive<T = AgentJson>(names: string | string[], options: ReceiveOptions): Promise<ActorMessage<T> | SignalTimeout>;
|
|
444
841
|
tool<TArgs extends JsonObject = JsonObject, TResult extends AgentJson = AgentJson>(name: string, args?: TArgs): Promise<TResult>;
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
}>;
|
|
448
|
-
retry<T>(fn: () => Promise<T>, options?: RetryOptions): Promise<T>;
|
|
449
|
-
tryCall<T>(fn: () => Promise<T>): Promise<TryCallResult<T>>;
|
|
842
|
+
/** In-VM control-flow helpers (`parallel`, `retry`, `tryCall`) — pure JS, never recorded. */
|
|
843
|
+
util: ChidoriUtil;
|
|
450
844
|
template(pathOrText: string, vars?: JsonObject, options?: TemplateOptions): Promise<string>;
|
|
451
|
-
log(message: string, fields?:
|
|
452
|
-
|
|
453
|
-
|
|
845
|
+
log(message: string, fields?: LogFields): Promise<void>;
|
|
846
|
+
/** The persistent, namespaced key-value store. */
|
|
847
|
+
memory: MemoryStore;
|
|
848
|
+
/** The journaled agent-run application-data store (generative-UI runs). */
|
|
849
|
+
appData: AppData;
|
|
850
|
+
/**
|
|
851
|
+
* Record a labelled trace marker in the call log — an annotation, nothing
|
|
852
|
+
* more. (The durable VALUE checkpoint is `chidori.step`.)
|
|
853
|
+
*/
|
|
854
|
+
mark(label?: string, data?: AgentJson): Promise<void>;
|
|
454
855
|
}
|
|
455
|
-
export type AgentFunction<TInput extends AgentJson = JsonObject, TOutput extends
|
|
856
|
+
export type AgentFunction<TInput extends AgentJson = JsonObject, TOutput extends AgentOutput = AgentOutput> = (input: TInput) => TOutput | Promise<TOutput>;
|
|
456
857
|
export type ToolFunction<TArgs extends JsonObject = JsonObject, TResult extends AgentJson = AgentJson> = (args: TArgs) => TResult | Promise<TResult>;
|
|
457
858
|
/**
|
|
458
859
|
* The chidori host object — the durable surface your agents and tools call
|
|
@@ -484,4 +885,35 @@ export declare const chidori: Chidori;
|
|
|
484
885
|
* run(async (input) => ({ greeting: `hello ${input.name}` }));
|
|
485
886
|
* ```
|
|
486
887
|
*/
|
|
487
|
-
export declare function run<TInput extends AgentJson = JsonObject, TOutput extends
|
|
888
|
+
export declare function run<TInput extends AgentJson = JsonObject, TOutput extends AgentOutput = AgentOutput>(handler: AgentFunction<TInput, TOutput>): void;
|
|
889
|
+
/**
|
|
890
|
+
* Wrap a function into a {@link ToolHandle} by attaching its documented
|
|
891
|
+
* signature — a `name`, a `description`, and a JSON-schema for its
|
|
892
|
+
* `parameters`. That signature is all the model needs to call the function;
|
|
893
|
+
* the function itself is just code. No `tools/` directory, no registry —
|
|
894
|
+
* import (or define inline) the handle like any other value. `parameters`
|
|
895
|
+
* defaults to an empty object schema; `description` to `""`. Inside the
|
|
896
|
+
* runtime this import is replaced by the live implementation, exactly like
|
|
897
|
+
* `run` and `chidori`.
|
|
898
|
+
*
|
|
899
|
+
* ```ts
|
|
900
|
+
* import { chidori, run, defineTool } from "chidori:agent";
|
|
901
|
+
*
|
|
902
|
+
* const search = defineTool({
|
|
903
|
+
* name: "search",
|
|
904
|
+
* description: "Search the corpus.",
|
|
905
|
+
* parameters: { type: "object", properties: { q: { type: "string" } }, required: ["q"] },
|
|
906
|
+
* run: async ({ q }) => (await fetch(BASE + q)).json(),
|
|
907
|
+
* });
|
|
908
|
+
*
|
|
909
|
+
* run(async () => chidori.prompt("find chidori", { tools: [search], maxTurns: 6 }));
|
|
910
|
+
* ```
|
|
911
|
+
*/
|
|
912
|
+
export declare function defineTool<Args extends JsonObject = JsonObject>(def: {
|
|
913
|
+
name: string;
|
|
914
|
+
description?: string;
|
|
915
|
+
parameters?: JsonSchema & {
|
|
916
|
+
type: "object";
|
|
917
|
+
};
|
|
918
|
+
run(args: Args, chidori?: Chidori): AgentOutput | Promise<AgentOutput>;
|
|
919
|
+
}): ToolHandle<Args>;
|