@rowan-agent/agent 0.6.0 → 0.6.1
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 +132 -55
- package/dist/index.d.ts +209 -145
- package/dist/index.js +455 -175
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,14 +20,13 @@ or reconstruct an `Agent`, submit input with `send()`, and wait on the returned
|
|
|
20
20
|
import {
|
|
21
21
|
AgentRuntime,
|
|
22
22
|
InMemoryRuntimeStateStore,
|
|
23
|
-
|
|
23
|
+
InMemorySessionStore,
|
|
24
24
|
createCoreTools,
|
|
25
25
|
} from "@rowan-agent/agent";
|
|
26
|
-
import { createModelStream } from "@rowan-agent/models";
|
|
27
26
|
|
|
28
27
|
const runtime = await AgentRuntime.start({
|
|
29
28
|
stateStore: new InMemoryRuntimeStateStore(),
|
|
30
|
-
sessionProvider: new
|
|
29
|
+
sessionProvider: new InMemorySessionStore(),
|
|
31
30
|
});
|
|
32
31
|
|
|
33
32
|
try {
|
|
@@ -42,8 +41,13 @@ try {
|
|
|
42
41
|
entryPhaseId: default,
|
|
43
42
|
},
|
|
44
43
|
},
|
|
45
|
-
model: {
|
|
46
|
-
|
|
44
|
+
model: {
|
|
45
|
+
provider: "openai",
|
|
46
|
+
id: "gpt-4.1-mini",
|
|
47
|
+
protocol: "openai-completions",
|
|
48
|
+
baseUrl: "https://api.openai.com/v1",
|
|
49
|
+
apiKey: process.env.OPENAI_API_KEY!,
|
|
50
|
+
},
|
|
47
51
|
});
|
|
48
52
|
|
|
49
53
|
agent.subscribe((event) => console.log(event.type));
|
|
@@ -67,11 +71,17 @@ Exactly one `AgentRuntime` may be active in a process. It is the sole owner of
|
|
|
67
71
|
Agent creation and reconstruction, durable input, scheduling, leases, Runtime
|
|
68
72
|
Events, and Tool Call control. Always stop it during host shutdown.
|
|
69
73
|
|
|
74
|
+
```ts
|
|
75
|
+
type RuntimeEventConsumer = {
|
|
76
|
+
caughtUp: Promise<void>;
|
|
77
|
+
stop(): void;
|
|
78
|
+
};
|
|
79
|
+
```
|
|
80
|
+
|
|
70
81
|
```ts
|
|
71
82
|
type AgentRuntimeOptions = {
|
|
72
83
|
stateStore: InMemoryRuntimeStateStore | SqliteRuntimeStateStore;
|
|
73
|
-
sessionProvider?:
|
|
74
|
-
factories?: ReadonlyMap<string, AgentFactory> | Readonly<Record<string, AgentFactory>>;
|
|
84
|
+
sessionProvider?: InMemorySessionStore | JsonlSessionStore;
|
|
75
85
|
toolPolicy?: ToolRuntimePolicy;
|
|
76
86
|
maxConcurrentRuns?: number;
|
|
77
87
|
maxInfrastructureAttempts?: number;
|
|
@@ -81,15 +91,20 @@ type AgentRuntimeOptions = {
|
|
|
81
91
|
|
|
82
92
|
class AgentRuntime {
|
|
83
93
|
static start(options: AgentRuntimeOptions): Promise<AgentRuntime>;
|
|
84
|
-
createAgent(options:
|
|
94
|
+
createAgent(options: AgentOptions): Promise<Agent>;
|
|
85
95
|
reconstructAgent(agentId: AgentId, options: AgentOptions): Promise<Agent>;
|
|
86
96
|
pauseAgent(agentId: AgentId): Promise<void>;
|
|
87
97
|
resumeAgent(agentId: AgentId): Promise<void>;
|
|
98
|
+
getMessage(messageId: RuntimeMessageId): Promise<RuntimeMessage | undefined>;
|
|
99
|
+
getToolCall(toolCallId: RuntimeToolCallId): Promise<RuntimeToolCall | undefined>;
|
|
100
|
+
getRun(runId: AgentRunId): Promise<AgentRunRecord | undefined>;
|
|
101
|
+
listRuns(input?: { agentId?: AgentId; states?: AgentRunRecord["state"][] }): Promise<AgentRunRecord[]>;
|
|
102
|
+
listActiveRuns(): Promise<AgentRunRecord[]>;
|
|
88
103
|
abortRun(runId: AgentRunId, reason?: string): Promise<void>;
|
|
89
104
|
consumeEvents(
|
|
90
105
|
consumerId: string,
|
|
91
|
-
listener:
|
|
92
|
-
):
|
|
106
|
+
listener: RuntimeEventListener,
|
|
107
|
+
): RuntimeEventConsumer;
|
|
93
108
|
listEvents(cursor?: RuntimeEventCursor): Promise<RuntimeEvent[]>;
|
|
94
109
|
stop(): Promise<void>;
|
|
95
110
|
}
|
|
@@ -101,7 +116,7 @@ Runtime State and conversation history are deliberately separate:
|
|
|
101
116
|
| Concern | Durable adapter | In-memory adapter |
|
|
102
117
|
|---------|-----------------|-------------------|
|
|
103
118
|
| Agent records, Messages, Runs, Leases, Runtime Events, Tool Calls | `SqliteRuntimeStateStore` | `InMemoryRuntimeStateStore` |
|
|
104
|
-
| Conversation messages, model transcripts, Outcomes | `
|
|
119
|
+
| Conversation messages, model transcripts, Outcomes | `JsonlSessionStore` | `InMemorySessionStore` |
|
|
105
120
|
|
|
106
121
|
The SQLite Runtime schema has no compatibility migration. Replace an older
|
|
107
122
|
Runtime database when adopting a breaking schema; Session JSONL records remain
|
|
@@ -119,35 +134,20 @@ The Runtime renews active leases and retries them up to
|
|
|
119
134
|
`maxInfrastructureAttempts`; exhausted work fails and its triggering Message is
|
|
120
135
|
dead-lettered.
|
|
121
136
|
|
|
122
|
-
###
|
|
137
|
+
### Process Recovery
|
|
123
138
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
Extensions.
|
|
139
|
+
Runtime startup recovers abandoned Leases into durable queued work without
|
|
140
|
+
constructing Agent Bindings. The host supplies its current executable resources
|
|
141
|
+
when it reconstructs an Agent:
|
|
128
142
|
|
|
129
143
|
```ts
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
[factoryId, async () => currentAgentOptions],
|
|
133
|
-
]);
|
|
134
|
-
|
|
135
|
-
const runtime = await AgentRuntime.start({
|
|
136
|
-
stateStore,
|
|
137
|
-
sessionProvider,
|
|
138
|
-
factories,
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
const agent = await runtime.createAgent({
|
|
142
|
-
...currentAgentOptions,
|
|
143
|
-
factoryId,
|
|
144
|
-
});
|
|
144
|
+
const runtime = await AgentRuntime.start({ stateStore, sessionProvider });
|
|
145
|
+
const agent = await runtime.reconstructAgent(agentId, currentAgentOptions);
|
|
145
146
|
```
|
|
146
147
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
Runtime Event.
|
|
148
|
+
Reconstruction preserves the Agent ID and Session ID. Establishing the Binding
|
|
149
|
+
automatically schedules queued Runs. A suspended Agent may remain unbound until
|
|
150
|
+
the host has new input, then reconstruct before calling `send()`.
|
|
151
151
|
|
|
152
152
|
## Agent
|
|
153
153
|
|
|
@@ -174,10 +174,18 @@ class Agent {
|
|
|
174
174
|
### AgentOptions
|
|
175
175
|
|
|
176
176
|
```ts
|
|
177
|
-
type
|
|
177
|
+
type ModelConfig = ModelRef & {
|
|
178
|
+
protocol: Protocol;
|
|
179
|
+
baseUrl: string;
|
|
180
|
+
apiKey: string;
|
|
181
|
+
headers?: Record<string, string>;
|
|
182
|
+
timeoutMs?: number;
|
|
183
|
+
maxRetries?: number;
|
|
184
|
+
retryDelayMs?: number;
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
type AgentCommonOptions = {
|
|
178
188
|
context: AgentContext;
|
|
179
|
-
model: LlmModelRef;
|
|
180
|
-
stream: StreamFn;
|
|
181
189
|
cwd?: string;
|
|
182
190
|
extensions?: LoadedExtension[];
|
|
183
191
|
maxAttempts?: number;
|
|
@@ -185,17 +193,15 @@ type AgentOptions = {
|
|
|
185
193
|
// Lifecycle hooks
|
|
186
194
|
beforeToolCall?: BeforeToolCall;
|
|
187
195
|
afterToolCall?: AfterToolCall;
|
|
188
|
-
onModelTranscript?: (transcript: ModelTranscript, meta: { phase: string; model:
|
|
196
|
+
onModelTranscript?: (transcript: ModelTranscript, meta: { phase: string; model: ModelRef }) => Promise<void>;
|
|
189
197
|
onMessage?: (message: AgentMessage) => Promise<void>;
|
|
190
198
|
onOutcome?: (outcome: Outcome) => Promise<void>;
|
|
191
199
|
};
|
|
192
200
|
|
|
193
|
-
type
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
factoryId?: string;
|
|
198
|
-
};
|
|
201
|
+
type AgentOptions = AgentCommonOptions & (
|
|
202
|
+
| { model: ModelConfig; stream?: never }
|
|
203
|
+
| { model: ModelRef; stream: StreamFn }
|
|
204
|
+
);
|
|
199
205
|
```
|
|
200
206
|
|
|
201
207
|
### Conversation Continuation
|
|
@@ -214,6 +220,11 @@ console.log((await second.result()).message);
|
|
|
214
220
|
If a Run is suspended waiting for input, the next `send()` to that Agent resumes
|
|
215
221
|
the same Run instead of creating a second one.
|
|
216
222
|
|
|
223
|
+
Suspended Runs persist the current input request in `AgentRunRecord.inputRequest`
|
|
224
|
+
so a reconstructed Runtime can show the question without replaying a transient
|
|
225
|
+
Agent Event. The request contains its phase, prompt, and timestamp; it is cleared
|
|
226
|
+
when the Run resumes.
|
|
227
|
+
|
|
217
228
|
### Updating Runtime Resources
|
|
218
229
|
|
|
219
230
|
Resources are fixed for a live Agent Binding. Apply a new model, prompt, Tool
|
|
@@ -228,8 +239,7 @@ await runtime.stop();
|
|
|
228
239
|
const nextRuntime = await AgentRuntime.start({ stateStore, sessionProvider });
|
|
229
240
|
const reconstructed = await nextRuntime.reconstructAgent(agentId, {
|
|
230
241
|
context: currentContext,
|
|
231
|
-
model:
|
|
232
|
-
stream: createModelStream(),
|
|
242
|
+
model: currentModelConfig,
|
|
233
243
|
});
|
|
234
244
|
```
|
|
235
245
|
|
|
@@ -240,18 +250,25 @@ durable. The handle exposes cached state for synchronous inspection and can
|
|
|
240
250
|
refresh from the Runtime Store when needed.
|
|
241
251
|
|
|
242
252
|
```ts
|
|
253
|
+
type AgentInputRequest = {
|
|
254
|
+
phase: string;
|
|
255
|
+
prompt: string;
|
|
256
|
+
requestedAt: string;
|
|
257
|
+
};
|
|
258
|
+
|
|
243
259
|
class AgentRun {
|
|
244
260
|
readonly id: AgentRunId;
|
|
245
261
|
readonly messageId: string;
|
|
246
262
|
readonly status: AgentRunState;
|
|
247
263
|
readonly state: AgentRunState; // alias of status
|
|
264
|
+
readonly inputRequest?: AgentInputRequest;
|
|
248
265
|
|
|
249
266
|
getStatus(): Promise<AgentRunState>;
|
|
250
267
|
subscribe(listener: AgentRunListener): () => void;
|
|
251
268
|
consumeRuntimeEvents(
|
|
252
269
|
consumerId: string,
|
|
253
270
|
listener: (event: RuntimeEvent) => void | Promise<void>,
|
|
254
|
-
):
|
|
271
|
+
): RuntimeEventConsumer;
|
|
255
272
|
result(): Promise<Outcome>;
|
|
256
273
|
abort(reason?: string): Promise<void>;
|
|
257
274
|
}
|
|
@@ -377,7 +394,7 @@ const runtime = await AgentRuntime.start({
|
|
|
377
394
|
stateStore,
|
|
378
395
|
sessionProvider,
|
|
379
396
|
toolPolicy: {
|
|
380
|
-
allowedTools: ["read", "bash"],
|
|
397
|
+
allowedTools: ["read", "bash", "task_manage", "resource_manage"],
|
|
381
398
|
maxConcurrent: 8,
|
|
382
399
|
perToolMaxConcurrent: { bash: 2 },
|
|
383
400
|
},
|
|
@@ -416,9 +433,58 @@ is asynchronous, so a slow or unavailable consumer does not block state
|
|
|
416
433
|
transitions.
|
|
417
434
|
|
|
418
435
|
```ts
|
|
419
|
-
const
|
|
436
|
+
const consumer = runtime.consumeEvents("deployment-observer", async (event) => {
|
|
420
437
|
await deliverRuntimeFact(event);
|
|
421
438
|
});
|
|
439
|
+
await consumer.caughtUp;
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
Runtime Messages and their related Events are committed together. A durable
|
|
443
|
+
consumer can use a `run_enqueued` Event as an outbox signal, read immutable
|
|
444
|
+
business correlation metadata from its Message, and update an external index
|
|
445
|
+
before its Checkpoint advances:
|
|
446
|
+
|
|
447
|
+
```ts
|
|
448
|
+
const indexConsumer = runtime.consumeEvents("everyield-run-index", async (event) => {
|
|
449
|
+
if (event.kind !== "run_enqueued" || !event.messageId || !event.runId) return;
|
|
450
|
+
const message = await runtime.getMessage(event.messageId);
|
|
451
|
+
if (!message) throw new Error(`Runtime Message not found: ${event.messageId}`);
|
|
452
|
+
await upsertRunIndex(event.runId, message.input.metadata);
|
|
453
|
+
});
|
|
454
|
+
await indexConsumer.caughtUp;
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
If the listener fails, Rowan leaves the Checkpoint unchanged and redelivers the
|
|
458
|
+
Event after the consumer restarts. `getMessage()` is read-only; Rowan treats the
|
|
459
|
+
Agent Message metadata as opaque host data.
|
|
460
|
+
|
|
461
|
+
Tool Call Events can likewise be resolved to their durable record. This is
|
|
462
|
+
especially useful when a `tool_call_indeterminate` Event requires host recovery
|
|
463
|
+
or human review:
|
|
464
|
+
|
|
465
|
+
```ts
|
|
466
|
+
if (event.kind === "tool_call_indeterminate" && event.toolCallId) {
|
|
467
|
+
const toolCall = await runtime.getToolCall(event.toolCallId);
|
|
468
|
+
await reviewIndeterminateToolCall(toolCall);
|
|
469
|
+
}
|
|
470
|
+
```
|
|
471
|
+
|
|
472
|
+
A consumer may instead return an `enqueue` disposition to turn the current
|
|
473
|
+
Event into Agent Input. Rowan enqueues the input and advances the Consumer
|
|
474
|
+
Checkpoint in one Runtime State transaction, then schedules the target Agent.
|
|
475
|
+
|
|
476
|
+
```ts
|
|
477
|
+
const routingConsumer = runtime.consumeEvents("delegated-results", (event) => {
|
|
478
|
+
if (event.kind !== "run_completed" || !event.agentId) return;
|
|
479
|
+
return {
|
|
480
|
+
type: "enqueue",
|
|
481
|
+
agentId: targetAgentId,
|
|
482
|
+
input: createMessage("user", JSON.stringify(event.payload), {
|
|
483
|
+
sourceEventId: event.id,
|
|
484
|
+
}),
|
|
485
|
+
};
|
|
486
|
+
});
|
|
487
|
+
await routingConsumer.caughtUp;
|
|
422
488
|
```
|
|
423
489
|
|
|
424
490
|
Only one live subscription may use a Consumer ID. If delivery fails, its
|
|
@@ -427,6 +493,15 @@ started later. `runtime.listEvents()` inspects the durable stream without
|
|
|
427
493
|
advancing a Consumer Checkpoint. Use `run.consumeRuntimeEvents()` for the same
|
|
428
494
|
delivery contract filtered to one Run.
|
|
429
495
|
|
|
496
|
+
`AgentRunMetadata` is optional opaque host data on `AgentMessage.metadata`. It
|
|
497
|
+
is persisted with the Run and echoed on `run_enqueued`, suspension, completion,
|
|
498
|
+
and abort Event payloads. `listActiveRuns()` returns queued, running, and
|
|
499
|
+
suspended Runs for host-side Agent reconstruction with current `AgentOptions`.
|
|
500
|
+
Use the returned `consumer.caughtUp` Promise when startup must wait until all
|
|
501
|
+
Events through the durable Consumer checkpoint have been delivered before
|
|
502
|
+
recovery continues. Call `consumer.stop()` during shutdown. `run.consumeRuntimeEvents()`
|
|
503
|
+
returns the same handle shape.
|
|
504
|
+
|
|
430
505
|
### Parallel Phase Events
|
|
431
506
|
|
|
432
507
|
When multiple phases run concurrently (via multi-target `route`), each branch emits its own `turn_*`, `message_*`, and `tool_execution_*` events into the shared event stream — they are interleaved, not sequenced. Individual parallel phases do **not** emit `phase_start`/`phase_end`; those only fire for serial phases. After all branches complete, their outputs are stashed and surfaced in the next iteration's phase entry message (under `<prev_phase_outputs>`); the `message_start`/`message_end` you observe for that entry message carry the merged results.
|
|
@@ -436,9 +511,9 @@ When multiple phases run concurrently (via multi-target `route`), each branch em
|
|
|
436
511
|
JSONL-based session persistence — lets multi-turn conversations survive across process restarts. Supports create, resume, branch, and history replay.
|
|
437
512
|
|
|
438
513
|
```ts
|
|
439
|
-
import {
|
|
514
|
+
import { JsonlSessionStore } from "@rowan-agent/agent";
|
|
440
515
|
|
|
441
|
-
const sessions = new
|
|
516
|
+
const sessions = new JsonlSessionStore(sessionsDir);
|
|
442
517
|
const session = await sessions.create({
|
|
443
518
|
systemPrompt,
|
|
444
519
|
input: "",
|
|
@@ -665,7 +740,7 @@ export default function myPlugin(rowan: ExtensionAPI) {
|
|
|
665
740
|
|
|
666
741
|
## Model Selection
|
|
667
742
|
|
|
668
|
-
`AgentOptions` accepts a model reference
|
|
743
|
+
`AgentOptions` accepts either one complete `ModelConfig`, which Rowan binds to an Agent-local default stream, or a model reference plus a custom `StreamFn`. A phase model override therefore requires a custom stream that can resolve the override.
|
|
669
744
|
|
|
670
745
|
CLI-specific `.rowan/config.yaml` loading and workspace discovery belong to [`@rowan-agent/cli`](../cli/README.md).
|
|
671
746
|
|
|
@@ -691,6 +766,8 @@ type LoopMetrics = {
|
|
|
691
766
|
| `AgentRun` | Durable Run handle for state, terminal Outcome, observation, and abort |
|
|
692
767
|
| `SqliteRuntimeStateStore` / `InMemoryRuntimeStateStore` | Durable and test Runtime Store adapters |
|
|
693
768
|
| `RuntimeEvent` / consumer ID string | Durable lifecycle facts and checkpointed consumer identity |
|
|
769
|
+
| `RuntimeMessage` / `RuntimeMessageId` | Durable Agent Input and its stable lookup identity |
|
|
770
|
+
| `RuntimeToolCall` / `RuntimeToolCallId` | Durable Tool Call state and its stable lookup identity |
|
|
694
771
|
| `AgentContext` | System prompt, messages, tools, skills, phases |
|
|
695
772
|
| `AgentMessage` | Typed message with role, content, metadata |
|
|
696
773
|
| `AgentEvent` | Discriminated union of 13 event types |
|
|
@@ -702,9 +779,9 @@ type LoopMetrics = {
|
|
|
702
779
|
| `Outcome` | Terminal result with message and tool results |
|
|
703
780
|
| `LoopMetrics` | Loop iteration, timing, and phase transition stats |
|
|
704
781
|
| `SessionManagerProvider` | Session lifecycle seam used by the Runtime |
|
|
705
|
-
| `
|
|
782
|
+
| `JsonlSessionStore` / `InMemorySessionStore` | JSONL and in-memory Session adapters |
|
|
706
783
|
| `ExtensionAPI` / `ExtensionFactory` | Extension developer interface |
|
|
707
|
-
| `StreamFn` / `
|
|
784
|
+
| `StreamFn` / `ModelRef` | Model stream function and model reference |
|
|
708
785
|
|
|
709
786
|
## Documentation
|
|
710
787
|
|