@minpeter/pss-runtime 0.1.0-next.2 → 0.1.0-next.3
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 +166 -78
- package/dist/agent-host-session-store.js +2 -4
- package/dist/agent-host-session-store.js.map +1 -1
- package/dist/agent-loop.js +2 -3
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent-namespace.js +3 -7
- package/dist/agent-namespace.js.map +1 -1
- package/dist/agent-options.d.ts +2 -8
- package/dist/agent-options.js +4 -4
- package/dist/agent-options.js.map +1 -1
- package/dist/agent-resume.js +2 -82
- package/dist/agent-resume.js.map +1 -1
- package/dist/agent-session-entry.d.ts +1 -1
- package/dist/agent.d.ts +4 -4
- package/dist/agent.js +16 -70
- package/dist/agent.js.map +1 -1
- package/dist/cloudflare/cloudflare-agent-context.d.ts +40 -0
- package/dist/cloudflare/cloudflare-agent-context.js +37 -0
- package/dist/cloudflare/cloudflare-agent-context.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-budget.d.ts +18 -0
- package/dist/cloudflare/cloudflare-alarm-budget.js +77 -0
- package/dist/cloudflare/cloudflare-alarm-budget.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.d.ts +45 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.js +103 -0
- package/dist/cloudflare/cloudflare-alarm-drainer.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.d.ts +13 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.js +81 -0
- package/dist/cloudflare/cloudflare-alarm-run-drain.js.map +1 -0
- package/dist/cloudflare/cloudflare-alarm-work.js +110 -0
- package/dist/cloudflare/cloudflare-alarm-work.js.map +1 -0
- package/dist/cloudflare/cloudflare-checkpoint-store.js +39 -0
- package/dist/cloudflare/cloudflare-checkpoint-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.d.ts +21 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.js +11 -0
- package/dist/cloudflare/cloudflare-durable-object-fetch.js.map +1 -0
- package/dist/cloudflare/cloudflare-event-store.js +33 -0
- package/dist/cloudflare/cloudflare-event-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-execution-session-store.js +40 -0
- package/dist/cloudflare/cloudflare-execution-session-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-execution-store.js +35 -0
- package/dist/cloudflare/cloudflare-execution-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-host.d.ts +61 -0
- package/dist/cloudflare/cloudflare-host.js +113 -0
- package/dist/cloudflare/cloudflare-host.js.map +1 -0
- package/dist/cloudflare/cloudflare-notification-store.js +59 -0
- package/dist/cloudflare/cloudflare-notification-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-run-store.js +81 -0
- package/dist/cloudflare/cloudflare-run-store.js.map +1 -0
- package/dist/cloudflare/cloudflare-store-utils.js +43 -0
- package/dist/cloudflare/cloudflare-store-utils.js.map +1 -0
- package/dist/cloudflare/durable-object-storage.d.ts +20 -0
- package/dist/cloudflare/durable-object-storage.js +76 -0
- package/dist/cloudflare/durable-object-storage.js.map +1 -0
- package/dist/cloudflare/index.d.ts +7 -0
- package/dist/cloudflare/index.js +6 -0
- package/dist/execution/capabilities.d.ts +40 -0
- package/dist/execution/host.d.ts +9 -0
- package/dist/execution/host.js +49 -1
- package/dist/execution/host.js.map +1 -1
- package/dist/execution/index.d.ts +3 -1
- package/dist/execution/index.js +2 -1
- package/dist/execution/memory.js +1 -1
- package/dist/execution/memory.js.map +1 -1
- package/dist/execution/types.d.ts +5 -10
- package/dist/index.d.ts +8 -4
- package/dist/index.js +6 -1
- package/dist/plugins.d.ts +25 -3
- package/dist/plugins.js +35 -6
- package/dist/plugins.js.map +1 -1
- package/dist/session/delegate-input.d.ts +9 -0
- package/dist/session/delegate-input.js +16 -0
- package/dist/session/delegate-input.js.map +1 -0
- package/dist/session/events.d.ts +43 -25
- package/dist/session/events.js +41 -0
- package/dist/session/events.js.map +1 -0
- package/dist/session/input-meta-types.d.ts +10 -0
- package/dist/session/input-meta.d.ts +13 -0
- package/dist/session/input-meta.js +45 -0
- package/dist/session/input-meta.js.map +1 -0
- package/dist/session/input.d.ts +4 -0
- package/dist/session/mapping.js +4 -2
- package/dist/session/mapping.js.map +1 -1
- package/dist/session/runtime-input-emit.js +41 -0
- package/dist/session/runtime-input-emit.js.map +1 -0
- package/dist/session/runtime-input.js +5 -1
- package/dist/session/runtime-input.js.map +1 -1
- package/dist/session/session-events.js +20 -6
- package/dist/session/session-events.js.map +1 -1
- package/dist/session/session-notification.js +3 -2
- package/dist/session/session-notification.js.map +1 -1
- package/dist/session/session-runtime-drain.js +3 -9
- package/dist/session/session-runtime-drain.js.map +1 -1
- package/dist/session/session-turn-processor.js +7 -17
- package/dist/session/session-turn-processor.js.map +1 -1
- package/dist/session/session.js +11 -4
- package/dist/session/session.js.map +1 -1
- package/package.json +6 -1
- package/dist/agent-child-runs.js +0 -16
- package/dist/agent-child-runs.js.map +0 -1
- package/dist/agent-host-capabilities.js +0 -9
- package/dist/agent-host-capabilities.js.map +0 -1
- package/dist/agent-validation.js +0 -35
- package/dist/agent-validation.js.map +0 -1
- package/dist/child-session-cleanups.js +0 -61
- package/dist/child-session-cleanups.js.map +0 -1
- package/dist/execution/run.js +0 -55
- package/dist/execution/run.js.map +0 -1
- package/dist/subagent-background-child-run-state.js +0 -51
- package/dist/subagent-background-child-run-state.js.map +0 -1
- package/dist/subagent-background-child-run.js +0 -103
- package/dist/subagent-background-child-run.js.map +0 -1
- package/dist/subagent-background-in-process.js +0 -98
- package/dist/subagent-background-in-process.js.map +0 -1
- package/dist/subagent-background-notification-inbox.js +0 -106
- package/dist/subagent-background-notification-inbox.js.map +0 -1
- package/dist/subagent-background-notify.js +0 -136
- package/dist/subagent-background-notify.js.map +0 -1
- package/dist/subagent-background-resume-group.js +0 -99
- package/dist/subagent-background-resume-group.js.map +0 -1
- package/dist/subagent-background-runner.js +0 -115
- package/dist/subagent-background-runner.js.map +0 -1
- package/dist/subagent-background-schedule.js +0 -43
- package/dist/subagent-background-schedule.js.map +0 -1
- package/dist/subagent-child-run.js +0 -68
- package/dist/subagent-child-run.js.map +0 -1
- package/dist/subagent-job-cancel.js +0 -84
- package/dist/subagent-job-cancel.js.map +0 -1
- package/dist/subagent-job-observer.js +0 -19
- package/dist/subagent-job-observer.js.map +0 -1
- package/dist/subagent-job-output.js +0 -87
- package/dist/subagent-job-output.js.map +0 -1
- package/dist/subagent-job-state.js +0 -66
- package/dist/subagent-job-state.js.map +0 -1
- package/dist/subagent-jobs.js +0 -96
- package/dist/subagent-jobs.js.map +0 -1
- package/dist/subagent-prompt-schema.js +0 -114
- package/dist/subagent-prompt-schema.js.map +0 -1
- package/dist/subagent-run.js +0 -111
- package/dist/subagent-run.js.map +0 -1
- package/dist/subagents.js +0 -125
- package/dist/subagents.js.map +0 -1
package/README.md
CHANGED
|
@@ -50,8 +50,8 @@ consume the events for the run to progress. This is what lets code react to
|
|
|
50
50
|
created.
|
|
51
51
|
|
|
52
52
|
`model` is the single public constructor key for model execution. Pass an AI SDK
|
|
53
|
-
`LanguageModel` for the managed runtime path with `instructions
|
|
54
|
-
|
|
53
|
+
`LanguageModel` for the managed runtime path with `instructions` and `tools`, or
|
|
54
|
+
pass a custom `RuntimeLlm` function when you want to own the model
|
|
55
55
|
adapter yourself:
|
|
56
56
|
|
|
57
57
|
```ts
|
|
@@ -116,69 +116,154 @@ The public transcript protocol is `AgentEvent`: live runs emit runtime-defined
|
|
|
116
116
|
events through `run.events()`. Provider/model message history is internal
|
|
117
117
|
continuation state, not a public history API.
|
|
118
118
|
|
|
119
|
-
##
|
|
119
|
+
## Delegation
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
delegate tools.
|
|
121
|
+
Delegation is app-owned. Build ordinary tools that call another `Agent`,
|
|
122
|
+
`session.send(...)`, `session.notify(...)`, or host-owned background work, then
|
|
123
|
+
return the compact result shape your product wants the model to see.
|
|
125
124
|
|
|
126
125
|
```ts
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
description: "Researches facts and returns concise evidence.",
|
|
126
|
+
const reader = new Agent({
|
|
127
|
+
instructions: "Read knowledge-base files and cite paths.",
|
|
130
128
|
model,
|
|
131
|
-
|
|
129
|
+
namespace: "reader",
|
|
132
130
|
});
|
|
133
131
|
|
|
134
132
|
const coordinator = new Agent({
|
|
133
|
+
instructions: "Coordinate work and delegate knowledge-base reads.",
|
|
135
134
|
model,
|
|
136
|
-
|
|
137
|
-
|
|
135
|
+
namespace: "coordinator",
|
|
136
|
+
tools: {
|
|
137
|
+
delegate_to_reader: tool({
|
|
138
|
+
description: "Ask the reader agent to inspect the knowledge base.",
|
|
139
|
+
execute: async ({ prompt }) => {
|
|
140
|
+
const run = await reader.session("kb").send(prompt);
|
|
141
|
+
const text: string[] = [];
|
|
142
|
+
for await (const event of run.events()) {
|
|
143
|
+
if (event.type === "assistant-text") {
|
|
144
|
+
text.push(event.text);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return { result: text.join("\n") };
|
|
148
|
+
},
|
|
149
|
+
inputSchema,
|
|
150
|
+
}),
|
|
151
|
+
},
|
|
138
152
|
});
|
|
139
153
|
```
|
|
140
154
|
|
|
141
|
-
For
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
155
|
+
For background delegation, let your host own task ids, scheduling, output
|
|
156
|
+
storage, and notification resume. The runtime provides generic execution stores,
|
|
157
|
+
notifications, `Agent.resume(...)`, and `run.events()`; it does not generate
|
|
158
|
+
delegation tools or own child-agent lifecycle semantics. See
|
|
159
|
+
the sync and background example packages for app-owned blocking and background
|
|
160
|
+
delegation patterns.
|
|
161
|
+
|
|
162
|
+
## Plugins
|
|
163
|
+
|
|
164
|
+
Pass `plugins: [...]` on `Agent` to observe or intercept runtime events. Each
|
|
165
|
+
plugin exposes one handler:
|
|
148
166
|
|
|
149
167
|
```ts
|
|
150
|
-
|
|
151
|
-
|
|
168
|
+
import type { AgentPlugin } from "@minpeter/pss-runtime";
|
|
169
|
+
import { Agent } from "@minpeter/pss-runtime";
|
|
170
|
+
|
|
171
|
+
const tracePlugin: AgentPlugin = {
|
|
172
|
+
name: "trace",
|
|
173
|
+
on: ({ event }) => {
|
|
174
|
+
if (event.type === "turn-end") {
|
|
175
|
+
console.log("turn finished");
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const agent = new Agent({
|
|
181
|
+
model,
|
|
182
|
+
plugins: [tracePlugin],
|
|
152
183
|
});
|
|
153
184
|
```
|
|
154
185
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
186
|
+
### Observe vs intercept
|
|
187
|
+
|
|
188
|
+
For most events, `on` is observe-only: return nothing (or `{ action: "continue" }`)
|
|
189
|
+
and the runtime emits the event unchanged.
|
|
190
|
+
|
|
191
|
+
Three input event types support intercept returns:
|
|
192
|
+
|
|
193
|
+
- `user-text`
|
|
194
|
+
- `user-message`
|
|
195
|
+
- `runtime-input`
|
|
196
|
+
|
|
197
|
+
Return one of:
|
|
198
|
+
|
|
199
|
+
- `{ action: "continue" }` — emit the current event (default when omitted)
|
|
200
|
+
- `{ action: "transform", event }` — emit a replacement input event
|
|
201
|
+
- `{ action: "handled" }` — skip emit; for `session.send`, close the run without
|
|
202
|
+
starting a turn
|
|
203
|
+
|
|
204
|
+
Plugins run in registration order. Each `transform` updates the event seen by
|
|
205
|
+
later plugins, so transforms chain sequentially.
|
|
206
|
+
|
|
207
|
+
### Input `meta.source`
|
|
208
|
+
|
|
209
|
+
The runtime attaches `meta` on input events at API boundaries. Plugins can route
|
|
210
|
+
on `event.meta?.source`:
|
|
211
|
+
|
|
212
|
+
| `source` | Boundary |
|
|
213
|
+
|----------|----------|
|
|
214
|
+
| `send` | `session.send()` / `agent.send()` |
|
|
215
|
+
| `steer` | `session.steer()` and drained steering queue |
|
|
216
|
+
| `notify` | `session.notify()` runtime input |
|
|
217
|
+
| `delegate` | parent `delegate_to_*` child `session.send()` |
|
|
218
|
+
|
|
219
|
+
`meta` appears on `run.events()` for input events but is stripped before session
|
|
220
|
+
history persistence and model mapping. It never reaches the LLM prompt.
|
|
221
|
+
|
|
222
|
+
### Delegate prompt wrapping
|
|
223
|
+
|
|
224
|
+
Child agents receive delegated prompts with `meta.source === "delegate"`. Wrap or
|
|
225
|
+
rewrite them with a plugin instead of agent-level prompt shims:
|
|
161
226
|
|
|
162
227
|
```ts
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
run_in_background: true,
|
|
166
|
-
});
|
|
228
|
+
import type { AgentPlugin, UserText } from "@minpeter/pss-runtime";
|
|
229
|
+
import { Agent } from "@minpeter/pss-runtime";
|
|
167
230
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
231
|
+
const pokeTagsPlugin: AgentPlugin = {
|
|
232
|
+
name: "poke-tags",
|
|
233
|
+
on: ({ event }) => {
|
|
234
|
+
if (event.type !== "user-text" || event.meta?.source !== "delegate") {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const text =
|
|
239
|
+
typeof event.text === "string" ? event.text : event.text.join("\n");
|
|
240
|
+
|
|
241
|
+
return {
|
|
242
|
+
action: "transform",
|
|
243
|
+
event: {
|
|
244
|
+
...event,
|
|
245
|
+
text: `<poke>\n${text}\n</poke>`,
|
|
246
|
+
} satisfies UserText,
|
|
247
|
+
};
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
const executionAgent = new Agent({
|
|
252
|
+
namespace: "execution",
|
|
253
|
+
plugins: [pokeTagsPlugin],
|
|
254
|
+
model,
|
|
255
|
+
});
|
|
171
256
|
```
|
|
172
257
|
|
|
173
|
-
The parent
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
258
|
+
The parent coordinator stays unchanged; only the nested child agent carries the
|
|
259
|
+
plugin.
|
|
260
|
+
|
|
261
|
+
### Migration
|
|
262
|
+
|
|
263
|
+
- **`plugins[].events.on`** — deprecated. Use top-level `plugins[].on`. The legacy
|
|
264
|
+
handler still receives every event but intercept returns are ignored (observe-only).
|
|
265
|
+
- **`wrapDelegatePrompt`** — removed. Use a child `plugins[].on` handler that checks
|
|
266
|
+
`meta.source === "delegate"` and returns `transform`, as above.
|
|
182
267
|
|
|
183
268
|
## Send, Host Resume, and Steer
|
|
184
269
|
|
|
@@ -268,9 +353,9 @@ const agent = new Agent({
|
|
|
268
353
|
});
|
|
269
354
|
```
|
|
270
355
|
|
|
271
|
-
For durable sessions, use the exported file POC. Set a stable `namespace`
|
|
272
|
-
|
|
273
|
-
|
|
356
|
+
For durable sessions, use the exported file POC. Set a stable `namespace` so
|
|
357
|
+
reconstructed agents map the same app-owned session keys back to the same
|
|
358
|
+
transcripts:
|
|
274
359
|
|
|
275
360
|
```ts
|
|
276
361
|
import { FileSessionStore } from "@minpeter/pss-runtime/session-store/file";
|
|
@@ -284,15 +369,20 @@ const agent = new Agent({
|
|
|
284
369
|
});
|
|
285
370
|
```
|
|
286
371
|
|
|
287
|
-
Hosts that need durable runs pass `host:` into `Agent`.
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
372
|
+
Hosts that need durable runs pass `host:` into `Agent`. The execution subpath
|
|
373
|
+
keeps the durable surface split by responsibility, so hosts can implement only
|
|
374
|
+
the capabilities they need: `SessionHost`, `RunHost`, `CheckpointHost`,
|
|
375
|
+
`EventHost`, `NotificationHost`, `BackgroundSchedulerHost`, and
|
|
376
|
+
`ExecutionTransactionHost`. `ExecutionHost` remains the aggregate contract for
|
|
377
|
+
in-process or full-store hosts, while `DurableBackgroundHost` and
|
|
378
|
+
`DurableNotificationResumeHost` describe the smaller durable surfaces required
|
|
379
|
+
for background scheduling and notification resume.
|
|
291
380
|
|
|
292
381
|
```ts
|
|
293
382
|
import { Agent } from "@minpeter/pss-runtime";
|
|
294
383
|
import {
|
|
295
384
|
createInMemoryExecutionHost,
|
|
385
|
+
type DurableBackgroundHost,
|
|
296
386
|
type ExecutionHost,
|
|
297
387
|
} from "@minpeter/pss-runtime/execution";
|
|
298
388
|
|
|
@@ -304,10 +394,15 @@ const agent = new Agent({
|
|
|
304
394
|
namespace: "support-agent",
|
|
305
395
|
});
|
|
306
396
|
|
|
307
|
-
const durableHost:
|
|
308
|
-
capabilities: {
|
|
309
|
-
|
|
310
|
-
|
|
397
|
+
const durableHost: DurableBackgroundHost = {
|
|
398
|
+
capabilities: {},
|
|
399
|
+
backgroundScheduler,
|
|
400
|
+
checkpointStore,
|
|
401
|
+
eventStore,
|
|
402
|
+
notificationInbox,
|
|
403
|
+
runStore,
|
|
404
|
+
sessionStore,
|
|
405
|
+
transaction,
|
|
311
406
|
};
|
|
312
407
|
```
|
|
313
408
|
|
|
@@ -315,25 +410,20 @@ const durableHost: ExecutionHost = {
|
|
|
315
410
|
|
|
316
411
|
The runtime supports both long-running Node.js processes and edge hosts that
|
|
317
412
|
reconstruct runtime objects between turns. The same public DX stays centered on
|
|
318
|
-
`new Agent({
|
|
413
|
+
`new Agent({ model, tools, host })`; host-specific durability and scheduling live
|
|
319
414
|
behind the `host` boundary.
|
|
320
415
|
|
|
321
416
|
Long-running Node.js can keep an `Agent` and `SessionHandle` alive across turns.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
available while that process owns the work. `FileSessionStore` persists session
|
|
325
|
-
snapshots only; it does not make background work durable by itself.
|
|
417
|
+
`FileSessionStore` persists session snapshots only; app-owned background work
|
|
418
|
+
needs its own durable task/output storage if it must survive process restarts.
|
|
326
419
|
|
|
327
420
|
Cloudflare Durable Objects and similar edge hosts should reconstruct `Agent`
|
|
328
|
-
objects per turn and persist opaque session state through
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
See `examples/cloudflare-edge-subagent` for an edge-hosted turn loop with a
|
|
335
|
-
Worker/Durable Object-shaped host, and `examples/subagent` for a long-running
|
|
336
|
-
local background subagent flow.
|
|
421
|
+
objects per turn and persist opaque session state through a durable
|
|
422
|
+
`sessionStore`.
|
|
423
|
+
Use `@minpeter/pss-runtime/cloudflare` for the packaged Cloudflare Durable
|
|
424
|
+
Object adapter. See the sync example package for blocking app-owned delegation
|
|
425
|
+
and the background example package for durable background delegation in a local
|
|
426
|
+
interactive CLI.
|
|
337
427
|
|
|
338
428
|
The same core API supports room/user/session routing through stable session keys.
|
|
339
429
|
|
|
@@ -348,11 +438,10 @@ storage is durable across hibernation/restores, while in-memory state remains
|
|
|
348
438
|
request-local. Do not store canonical agent session or run state in memory
|
|
349
439
|
attachments.
|
|
350
440
|
|
|
351
|
-
Durable background
|
|
352
|
-
|
|
353
|
-
notifications. The Cloudflare
|
|
354
|
-
|
|
355
|
-
resumes work through `Agent.resume(...)`.
|
|
441
|
+
Durable background workflows require host-owned task ids, attempts, leases,
|
|
442
|
+
checkpoints, cancellation, scheduling, session snapshots, and completion
|
|
443
|
+
notifications. The Cloudflare adapter persists scheduled runs and session
|
|
444
|
+
prompts, sets alarms, and resumes work through `Agent.resume(...)`.
|
|
356
445
|
|
|
357
446
|
## Checkpoints and Cancellation
|
|
358
447
|
|
|
@@ -375,7 +464,6 @@ themselves. Edge hosts still need durable scheduling, leases, resume workers,
|
|
|
375
464
|
and notification resume handling; externally visible side-effect tools still need
|
|
376
465
|
idempotent execution or a manual recovery flow.
|
|
377
466
|
|
|
378
|
-
Cancellation is persisted before aborting active work.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
new parent notifications.
|
|
467
|
+
Cancellation is persisted before aborting active work. `delete()` and `dispose()`
|
|
468
|
+
stop the current session's in-process work; durable hosts remain responsible for
|
|
469
|
+
any app-owned background run cancellation, cleanup, and notification policy.
|
|
@@ -1,10 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { sessionHost } from "./execution/host.js";
|
|
2
2
|
import { MemorySessionStore } from "./session/store/memory.js";
|
|
3
3
|
//#region src/agent-host-session-store.ts
|
|
4
4
|
function sessionStoreForHost(host) {
|
|
5
|
-
|
|
6
|
-
const hostExecution = executionHost(host);
|
|
7
|
-
return hostExecution ? hostExecution.store.sessions : new MemorySessionStore();
|
|
5
|
+
return sessionHost(host).sessionStore ?? new MemorySessionStore();
|
|
8
6
|
}
|
|
9
7
|
//#endregion
|
|
10
8
|
export { sessionStoreForHost };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-host-session-store.js","names":[],"sources":["../src/agent-host-session-store.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"agent-host-session-store.js","names":[],"sources":["../src/agent-host-session-store.ts"],"sourcesContent":["import { sessionHost } from \"./execution/host\";\nimport type { AgentHost } from \"./execution/types\";\nimport { MemorySessionStore } from \"./session/store/memory\";\nimport type { SessionStore } from \"./session/store/types\";\n\nexport function sessionStoreForHost(host: AgentHost): SessionStore {\n return sessionHost(host).sessionStore ?? new MemorySessionStore();\n}\n"],"mappings":";;;AAKA,SAAgB,oBAAoB,MAA+B;CACjE,OAAO,YAAY,IAAI,EAAE,gBAAgB,IAAI,mBAAmB;AAClE"}
|
package/dist/agent-loop.js
CHANGED
|
@@ -122,9 +122,8 @@ async function appendStepOutput({ emit, history, observerEvents, output, signal
|
|
|
122
122
|
await flushObserverEvents();
|
|
123
123
|
return shouldContinue ? "continue" : "completed";
|
|
124
124
|
}
|
|
125
|
-
function isLaunchOrBlockingObserverEvent(
|
|
126
|
-
|
|
127
|
-
return !(event.type === "subagent-job-end" && event.task_id);
|
|
125
|
+
function isLaunchOrBlockingObserverEvent(_event) {
|
|
126
|
+
return true;
|
|
128
127
|
}
|
|
129
128
|
//#endregion
|
|
130
129
|
export { runAgentLoop };
|
package/dist/agent-loop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-loop.js","names":[],"sources":["../src/agent-loop.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { RuntimeLlm, RuntimeLlmOutput } from \"./llm\";\nimport type { RuntimeToolExecutionContext } from \"./llm-tool-execution\";\nimport type { AgentEvent } from \"./session/events\";\nimport { modelMessageToAgentEvents } from \"./session/mapping\";\n\ninterface ModelHistory {\n appendModelMessage(message: ModelMessage): void;\n modelSnapshot(): ModelMessage[];\n}\n\ninterface RunAgentLoopOptions {\n captureObserverEvents?: ObserverEventCapture;\n emit: AgentLoopEventListener;\n history: ModelHistory;\n llm: RuntimeLlm;\n signal?: AbortSignal;\n toolExecution?: RuntimeToolExecutionContext;\n}\n\ntype AgentLoopResult = \"completed\" | \"aborted\";\ntype AgentLoopBoundaryEvent = Extract<\n AgentEvent,\n { type: \"step-end\" } | { type: \"step-start\" }\n>;\ninterface AgentLoopBoundaryDecision {\n readonly runtimeInputAdded?: boolean;\n}\ntype AgentLoopEventListener = (\n event: AgentEvent\n) =>\n | AgentLoopBoundaryDecision\n | Promise<AgentLoopBoundaryDecision | undefined>\n | undefined;\ntype StepOutputResult = \"aborted\" | \"completed\" | \"continue\";\ninterface ObserverEventCaptureResult<T> {\n readonly events: AgentEvent[];\n readonly release: () => void;\n readonly value: T;\n}\ntype ObserverEventCapture = <T>(\n callback: () => Promise<T>\n) => Promise<ObserverEventCaptureResult<T>>;\n\nexport async function runAgentLoop({\n captureObserverEvents = captureNoObserverEvents,\n emit,\n history,\n llm,\n signal = new AbortController().signal,\n toolExecution,\n}: RunAgentLoopOptions): Promise<AgentLoopResult> {\n while (true) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n const stepStartDecision = await emitBoundary({\n emit,\n event: { type: \"step-start\" },\n signal,\n });\n\n if (stepStartDecision === \"aborted\") {\n return \"aborted\";\n }\n\n const capturedOutput = await captureObserverEvents(() =>\n readLlmOutput({ history, llm, signal, toolExecution })\n );\n const output = capturedOutput.value;\n\n if (output === \"aborted\") {\n return \"aborted\";\n }\n\n const result = await appendCapturedStepOutput({\n capturedOutput,\n emit,\n history,\n output,\n signal,\n });\n\n if (result === \"aborted\") {\n return \"aborted\";\n }\n\n const stepEndDecision = await emitBoundary({\n emit,\n event: { type: \"step-end\" },\n signal,\n });\n\n if (stepEndDecision === \"aborted\") {\n return \"aborted\";\n }\n\n // Runtime input after step-end intentionally forces another inference step,\n // even after final-looking assistant text. Unconditional insertion on every\n // step-end can create an unbounded loop.\n if (result === \"completed\" && !stepEndDecision?.runtimeInputAdded) {\n return \"completed\";\n }\n }\n}\n\nasync function emitBoundary({\n emit,\n event,\n signal,\n}: Pick<RunAgentLoopOptions, \"emit\"> & {\n event: AgentLoopBoundaryEvent;\n signal: AbortSignal;\n}): Promise<AgentLoopBoundaryDecision | \"aborted\" | undefined> {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n const abort = createAbortBoundary(signal);\n try {\n return await Promise.race([Promise.resolve(emit(event)), abort.promise]);\n } catch (error) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n throw error;\n } finally {\n abort.dispose();\n }\n}\n\nfunction createAbortBoundary(signal: AbortSignal): {\n dispose: () => void;\n promise: Promise<\"aborted\">;\n} {\n let dispose: () => void = () => undefined;\n\n const promise = new Promise<\"aborted\">((resolve) => {\n const onAbort = () => resolve(\"aborted\");\n dispose = () => signal.removeEventListener(\"abort\", onAbort);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n\n return { dispose, promise };\n}\n\nasync function captureNoObserverEvents<T>(callback: () => Promise<T>): Promise<{\n readonly events: AgentEvent[];\n readonly release: () => void;\n readonly value: T;\n}> {\n return {\n events: [],\n release: releaseNoObserverEvents,\n value: await callback(),\n };\n}\n\nfunction releaseNoObserverEvents(): void {\n return;\n}\n\nasync function readLlmOutput({\n history,\n llm,\n signal,\n toolExecution,\n}: Pick<RunAgentLoopOptions, \"history\" | \"llm\"> & {\n signal: AbortSignal;\n toolExecution?: RuntimeToolExecutionContext;\n}): Promise<RuntimeLlmOutput | \"aborted\"> {\n try {\n return await llm({\n history: history.modelSnapshot(),\n signal,\n toolExecution,\n });\n } catch (error) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n throw error;\n }\n}\n\nasync function appendCapturedStepOutput({\n capturedOutput,\n emit,\n history,\n output,\n signal,\n}: Pick<RunAgentLoopOptions, \"emit\"> & { history: ModelHistory } & {\n capturedOutput: ObserverEventCaptureResult<RuntimeLlmOutput | \"aborted\">;\n output: RuntimeLlmOutput;\n signal: AbortSignal;\n}): Promise<StepOutputResult> {\n try {\n return await appendStepOutput({\n emit,\n history,\n observerEvents: capturedOutput.events,\n output,\n signal,\n });\n } finally {\n capturedOutput.release();\n }\n}\n\nasync function appendStepOutput({\n emit,\n history,\n observerEvents,\n output,\n signal,\n}: Pick<RunAgentLoopOptions, \"emit\"> & { history: ModelHistory } & {\n observerEvents: AgentEvent[];\n output: RuntimeLlmOutput;\n signal: AbortSignal;\n}): Promise<StepOutputResult> {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n let shouldContinue = false;\n const pendingObserverEvents = observerEvents;\n const flushObserverEvents = async (\n shouldFlush: (event: AgentEvent) => boolean = () => true\n ) => {\n for (let index = 0; index < pendingObserverEvents.length; ) {\n const event = pendingObserverEvents[index];\n if (!(event && shouldFlush(event))) {\n index += 1;\n continue;\n }\n pendingObserverEvents.splice(index, 1);\n await emit(event);\n }\n };\n\n for (const message of output) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n history.appendModelMessage(message);\n const events = modelMessageToAgentEvents(message);\n const hasToolResult = events.some((event) => event.type === \"tool-result\");\n\n for (const event of events) {\n await emit(event);\n if (event.type === \"tool-call\") {\n shouldContinue = true;\n await flushObserverEvents(isLaunchOrBlockingObserverEvent);\n }\n }\n\n if (hasToolResult) {\n await flushObserverEvents();\n }\n }\n\n await flushObserverEvents();\n\n return shouldContinue ? \"continue\" : \"completed\";\n}\n\nfunction isLaunchOrBlockingObserverEvent(
|
|
1
|
+
{"version":3,"file":"agent-loop.js","names":[],"sources":["../src/agent-loop.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { RuntimeLlm, RuntimeLlmOutput } from \"./llm\";\nimport type { RuntimeToolExecutionContext } from \"./llm-tool-execution\";\nimport type { AgentEvent } from \"./session/events\";\nimport { modelMessageToAgentEvents } from \"./session/mapping\";\n\ninterface ModelHistory {\n appendModelMessage(message: ModelMessage): void;\n modelSnapshot(): ModelMessage[];\n}\n\ninterface RunAgentLoopOptions {\n captureObserverEvents?: ObserverEventCapture;\n emit: AgentLoopEventListener;\n history: ModelHistory;\n llm: RuntimeLlm;\n signal?: AbortSignal;\n toolExecution?: RuntimeToolExecutionContext;\n}\n\ntype AgentLoopResult = \"completed\" | \"aborted\";\ntype AgentLoopBoundaryEvent = Extract<\n AgentEvent,\n { type: \"step-end\" } | { type: \"step-start\" }\n>;\ninterface AgentLoopBoundaryDecision {\n readonly runtimeInputAdded?: boolean;\n}\ntype AgentLoopEventListener = (\n event: AgentEvent\n) =>\n | AgentLoopBoundaryDecision\n | Promise<AgentLoopBoundaryDecision | undefined>\n | undefined;\ntype StepOutputResult = \"aborted\" | \"completed\" | \"continue\";\ninterface ObserverEventCaptureResult<T> {\n readonly events: AgentEvent[];\n readonly release: () => void;\n readonly value: T;\n}\ntype ObserverEventCapture = <T>(\n callback: () => Promise<T>\n) => Promise<ObserverEventCaptureResult<T>>;\n\nexport async function runAgentLoop({\n captureObserverEvents = captureNoObserverEvents,\n emit,\n history,\n llm,\n signal = new AbortController().signal,\n toolExecution,\n}: RunAgentLoopOptions): Promise<AgentLoopResult> {\n while (true) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n const stepStartDecision = await emitBoundary({\n emit,\n event: { type: \"step-start\" },\n signal,\n });\n\n if (stepStartDecision === \"aborted\") {\n return \"aborted\";\n }\n\n const capturedOutput = await captureObserverEvents(() =>\n readLlmOutput({ history, llm, signal, toolExecution })\n );\n const output = capturedOutput.value;\n\n if (output === \"aborted\") {\n return \"aborted\";\n }\n\n const result = await appendCapturedStepOutput({\n capturedOutput,\n emit,\n history,\n output,\n signal,\n });\n\n if (result === \"aborted\") {\n return \"aborted\";\n }\n\n const stepEndDecision = await emitBoundary({\n emit,\n event: { type: \"step-end\" },\n signal,\n });\n\n if (stepEndDecision === \"aborted\") {\n return \"aborted\";\n }\n\n // Runtime input after step-end intentionally forces another inference step,\n // even after final-looking assistant text. Unconditional insertion on every\n // step-end can create an unbounded loop.\n if (result === \"completed\" && !stepEndDecision?.runtimeInputAdded) {\n return \"completed\";\n }\n }\n}\n\nasync function emitBoundary({\n emit,\n event,\n signal,\n}: Pick<RunAgentLoopOptions, \"emit\"> & {\n event: AgentLoopBoundaryEvent;\n signal: AbortSignal;\n}): Promise<AgentLoopBoundaryDecision | \"aborted\" | undefined> {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n const abort = createAbortBoundary(signal);\n try {\n return await Promise.race([Promise.resolve(emit(event)), abort.promise]);\n } catch (error) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n throw error;\n } finally {\n abort.dispose();\n }\n}\n\nfunction createAbortBoundary(signal: AbortSignal): {\n dispose: () => void;\n promise: Promise<\"aborted\">;\n} {\n let dispose: () => void = () => undefined;\n\n const promise = new Promise<\"aborted\">((resolve) => {\n const onAbort = () => resolve(\"aborted\");\n dispose = () => signal.removeEventListener(\"abort\", onAbort);\n signal.addEventListener(\"abort\", onAbort, { once: true });\n });\n\n return { dispose, promise };\n}\n\nasync function captureNoObserverEvents<T>(callback: () => Promise<T>): Promise<{\n readonly events: AgentEvent[];\n readonly release: () => void;\n readonly value: T;\n}> {\n return {\n events: [],\n release: releaseNoObserverEvents,\n value: await callback(),\n };\n}\n\nfunction releaseNoObserverEvents(): void {\n return;\n}\n\nasync function readLlmOutput({\n history,\n llm,\n signal,\n toolExecution,\n}: Pick<RunAgentLoopOptions, \"history\" | \"llm\"> & {\n signal: AbortSignal;\n toolExecution?: RuntimeToolExecutionContext;\n}): Promise<RuntimeLlmOutput | \"aborted\"> {\n try {\n return await llm({\n history: history.modelSnapshot(),\n signal,\n toolExecution,\n });\n } catch (error) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n throw error;\n }\n}\n\nasync function appendCapturedStepOutput({\n capturedOutput,\n emit,\n history,\n output,\n signal,\n}: Pick<RunAgentLoopOptions, \"emit\"> & { history: ModelHistory } & {\n capturedOutput: ObserverEventCaptureResult<RuntimeLlmOutput | \"aborted\">;\n output: RuntimeLlmOutput;\n signal: AbortSignal;\n}): Promise<StepOutputResult> {\n try {\n return await appendStepOutput({\n emit,\n history,\n observerEvents: capturedOutput.events,\n output,\n signal,\n });\n } finally {\n capturedOutput.release();\n }\n}\n\nasync function appendStepOutput({\n emit,\n history,\n observerEvents,\n output,\n signal,\n}: Pick<RunAgentLoopOptions, \"emit\"> & { history: ModelHistory } & {\n observerEvents: AgentEvent[];\n output: RuntimeLlmOutput;\n signal: AbortSignal;\n}): Promise<StepOutputResult> {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n let shouldContinue = false;\n const pendingObserverEvents = observerEvents;\n const flushObserverEvents = async (\n shouldFlush: (event: AgentEvent) => boolean = () => true\n ) => {\n for (let index = 0; index < pendingObserverEvents.length; ) {\n const event = pendingObserverEvents[index];\n if (!(event && shouldFlush(event))) {\n index += 1;\n continue;\n }\n pendingObserverEvents.splice(index, 1);\n await emit(event);\n }\n };\n\n for (const message of output) {\n if (signal.aborted) {\n return \"aborted\";\n }\n\n history.appendModelMessage(message);\n const events = modelMessageToAgentEvents(message);\n const hasToolResult = events.some((event) => event.type === \"tool-result\");\n\n for (const event of events) {\n await emit(event);\n if (event.type === \"tool-call\") {\n shouldContinue = true;\n await flushObserverEvents(isLaunchOrBlockingObserverEvent);\n }\n }\n\n if (hasToolResult) {\n await flushObserverEvents();\n }\n }\n\n await flushObserverEvents();\n\n return shouldContinue ? \"continue\" : \"completed\";\n}\n\nfunction isLaunchOrBlockingObserverEvent(_event: AgentEvent): boolean {\n return true;\n}\n"],"mappings":"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"}
|
package/dist/agent-namespace.js
CHANGED
|
@@ -8,17 +8,13 @@ function agentNamespace(namespace) {
|
|
|
8
8
|
function namespacePart(value) {
|
|
9
9
|
return encodeURIComponent(value);
|
|
10
10
|
}
|
|
11
|
-
function parentSessionNamespace({ generation, sessionKey, sessionNamespace }) {
|
|
12
|
-
return `${sessionNamespace}:session:${namespacePart(sessionKey)}:generation:${generation}`;
|
|
13
|
-
}
|
|
14
11
|
function ownsAgentNamespace(ownerNamespace, sessionNamespace) {
|
|
15
12
|
return ownerNamespace === sessionNamespace || ownerNamespace?.startsWith(`${sessionNamespace}:session:`) === true;
|
|
16
13
|
}
|
|
17
|
-
function stableAgentNamespace({
|
|
18
|
-
|
|
19
|
-
return stableNamespace ? agentNamespace(stableNamespace) : randomAgentNamespace();
|
|
14
|
+
function stableAgentNamespace({ namespace }) {
|
|
15
|
+
return namespace ? agentNamespace(namespace) : randomAgentNamespace();
|
|
20
16
|
}
|
|
21
17
|
//#endregion
|
|
22
|
-
export { ownsAgentNamespace,
|
|
18
|
+
export { ownsAgentNamespace, stableAgentNamespace };
|
|
23
19
|
|
|
24
20
|
//# sourceMappingURL=agent-namespace.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-namespace.js","names":[],"sources":["../src/agent-namespace.ts"],"sourcesContent":["export function randomAgentNamespace(): string {\n return agentNamespace(crypto.randomUUID());\n}\n\nexport function agentNamespace(namespace: string): string {\n return `agent:${namespacePart(namespace)}`;\n}\n\nexport function namespacePart(value: string): string {\n return encodeURIComponent(value);\n}\n\nexport function parentSessionNamespace({\n generation,\n sessionKey,\n sessionNamespace,\n}: {\n readonly generation: number;\n readonly sessionKey: string;\n readonly sessionNamespace: string;\n}): string {\n return `${sessionNamespace}:session:${namespacePart(\n sessionKey\n )}:generation:${generation}`;\n}\n\nexport function ownsAgentNamespace(\n ownerNamespace: string | undefined,\n sessionNamespace: string\n): boolean {\n return (\n ownerNamespace === sessionNamespace ||\n ownerNamespace?.startsWith(`${sessionNamespace}:session:`) === true\n );\n}\n\nexport function stableAgentNamespace({\n
|
|
1
|
+
{"version":3,"file":"agent-namespace.js","names":[],"sources":["../src/agent-namespace.ts"],"sourcesContent":["export function randomAgentNamespace(): string {\n return agentNamespace(crypto.randomUUID());\n}\n\nexport function agentNamespace(namespace: string): string {\n return `agent:${namespacePart(namespace)}`;\n}\n\nexport function namespacePart(value: string): string {\n return encodeURIComponent(value);\n}\n\nexport function parentSessionNamespace({\n generation,\n sessionKey,\n sessionNamespace,\n}: {\n readonly generation: number;\n readonly sessionKey: string;\n readonly sessionNamespace: string;\n}): string {\n return `${sessionNamespace}:session:${namespacePart(\n sessionKey\n )}:generation:${generation}`;\n}\n\nexport function ownsAgentNamespace(\n ownerNamespace: string | undefined,\n sessionNamespace: string\n): boolean {\n return (\n ownerNamespace === sessionNamespace ||\n ownerNamespace?.startsWith(`${sessionNamespace}:session:`) === true\n );\n}\n\nexport function stableAgentNamespace({\n namespace,\n}: {\n readonly namespace?: string;\n}): string {\n return namespace ? agentNamespace(namespace) : randomAgentNamespace();\n}\n"],"mappings":";AAAA,SAAgB,uBAA+B;CAC7C,OAAO,eAAe,OAAO,WAAW,CAAC;AAC3C;AAEA,SAAgB,eAAe,WAA2B;CACxD,OAAO,SAAS,cAAc,SAAS;AACzC;AAEA,SAAgB,cAAc,OAAuB;CACnD,OAAO,mBAAmB,KAAK;AACjC;AAgBA,SAAgB,mBACd,gBACA,kBACS;CACT,OACE,mBAAmB,oBACnB,gBAAgB,WAAW,GAAG,iBAAiB,UAAU,MAAM;AAEnE;AAEA,SAAgB,qBAAqB,EACnC,aAGS;CACT,OAAO,YAAY,eAAe,SAAS,IAAI,qBAAqB;AACtE"}
|
package/dist/agent-options.d.ts
CHANGED
|
@@ -1,35 +1,29 @@
|
|
|
1
1
|
import { AgentToolChoice, RuntimeLlm } from "./llm.js";
|
|
2
2
|
import { AgentHost } from "./execution/types.js";
|
|
3
3
|
import { AgentPlugin } from "./plugins.js";
|
|
4
|
-
import { Agent } from "./agent.js";
|
|
5
4
|
import { LanguageModel, ToolSet } from "ai";
|
|
6
5
|
|
|
7
6
|
//#region src/agent-options.d.ts
|
|
8
7
|
interface AgentLanguageModelOptions {
|
|
9
|
-
readonly description?: string;
|
|
10
8
|
readonly host?: AgentHost;
|
|
11
9
|
readonly instructions?: string;
|
|
12
10
|
readonly model: LanguageModel;
|
|
13
|
-
readonly name?: string;
|
|
14
11
|
readonly namespace?: string;
|
|
15
12
|
readonly plugins?: readonly AgentPlugin[];
|
|
16
|
-
readonly subagents?: readonly Agent[];
|
|
17
13
|
readonly toolChoice?: AgentToolChoice;
|
|
18
14
|
readonly tools?: ToolSet;
|
|
19
15
|
}
|
|
20
16
|
interface AgentRuntimeModelOptions {
|
|
21
|
-
readonly description?: string;
|
|
22
17
|
readonly host?: AgentHost;
|
|
23
18
|
readonly instructions?: never;
|
|
24
19
|
readonly model: RuntimeLlm;
|
|
25
|
-
readonly name?: string;
|
|
26
20
|
readonly namespace?: string;
|
|
27
21
|
readonly plugins?: readonly AgentPlugin[];
|
|
28
|
-
readonly subagents?: never;
|
|
29
22
|
readonly toolChoice?: never;
|
|
30
23
|
readonly tools?: never;
|
|
31
24
|
}
|
|
32
25
|
type AgentOptions = AgentLanguageModelOptions | AgentRuntimeModelOptions;
|
|
26
|
+
type AgentConstructionOptions = AgentOptions;
|
|
33
27
|
//#endregion
|
|
34
|
-
export { AgentOptions };
|
|
28
|
+
export { AgentConstructionOptions, AgentOptions };
|
|
35
29
|
//# sourceMappingURL=agent-options.d.ts.map
|
package/dist/agent-options.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
//#region src/agent-options.ts
|
|
2
2
|
function assertAgentOptions(options) {
|
|
3
3
|
if (options === null || typeof options !== "object") throw new TypeError("Agent options are required. Provide { model }.");
|
|
4
|
-
if ("sessions" in options) throw new TypeError("Agent: unsupported options.sessions. Use host: { sessionStore } and namespace instead.");
|
|
5
|
-
if ("runtime" in options) throw new TypeError("Agent: unsupported options.runtime. Use host.");
|
|
6
|
-
if ("llm" in options) throw new TypeError("Agent: unsupported options.llm. Use model for both AI SDK models and custom RuntimeLlm functions.");
|
|
7
4
|
if (!("model" in options && options.model != null)) throw new TypeError("Agent: missing options.model.");
|
|
8
5
|
if (typeof options.model !== "function" && (typeof options.model !== "object" || options.model === null)) throw new TypeError("Agent: invalid options.model.");
|
|
9
6
|
}
|
|
10
7
|
function hasRuntimeModel(options) {
|
|
11
8
|
return typeof options.model === "function";
|
|
12
9
|
}
|
|
10
|
+
function hasLanguageModel(options) {
|
|
11
|
+
return typeof options.model !== "function";
|
|
12
|
+
}
|
|
13
13
|
//#endregion
|
|
14
|
-
export { assertAgentOptions, hasRuntimeModel };
|
|
14
|
+
export { assertAgentOptions, hasLanguageModel, hasRuntimeModel };
|
|
15
15
|
|
|
16
16
|
//# sourceMappingURL=agent-options.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-options.js","names":[],"sources":["../src/agent-options.ts"],"sourcesContent":["import type { LanguageModel, ToolSet } from \"ai\";\nimport type {
|
|
1
|
+
{"version":3,"file":"agent-options.js","names":[],"sources":["../src/agent-options.ts"],"sourcesContent":["import type { LanguageModel, ToolSet } from \"ai\";\nimport type { AgentHost } from \"./execution/types\";\nimport type { AgentToolChoice, RuntimeLlm } from \"./llm\";\nimport type { AgentPlugin } from \"./plugins\";\n\ninterface AgentLanguageModelOptions {\n readonly host?: AgentHost;\n readonly instructions?: string;\n readonly model: LanguageModel;\n readonly namespace?: string;\n readonly plugins?: readonly AgentPlugin[];\n readonly toolChoice?: AgentToolChoice;\n readonly tools?: ToolSet;\n}\n\ninterface AgentRuntimeModelOptions {\n readonly host?: AgentHost;\n readonly instructions?: never;\n readonly model: RuntimeLlm;\n readonly namespace?: string;\n readonly plugins?: readonly AgentPlugin[];\n readonly toolChoice?: never;\n readonly tools?: never;\n}\n\nexport type AgentModelOptions = Pick<\n AgentLanguageModelOptions,\n \"instructions\" | \"model\" | \"toolChoice\"\n>;\nexport type AgentOptions = AgentLanguageModelOptions | AgentRuntimeModelOptions;\n\nexport type AgentConstructionOptions = AgentOptions;\n\nexport function assertAgentOptions(\n options: unknown\n): asserts options is AgentConstructionOptions {\n if (options === null || typeof options !== \"object\") {\n throw new TypeError(\"Agent options are required. Provide { model }.\");\n }\n\n const hasModel = \"model\" in options && options.model != null;\n\n if (!hasModel) {\n throw new TypeError(\"Agent: missing options.model.\");\n }\n\n if (\n typeof options.model !== \"function\" &&\n (typeof options.model !== \"object\" || options.model === null)\n ) {\n throw new TypeError(\"Agent: invalid options.model.\");\n }\n}\n\nexport function hasRuntimeModel(\n options: AgentConstructionOptions\n): options is AgentRuntimeModelOptions {\n return typeof options.model === \"function\";\n}\n\nexport function hasLanguageModel(\n options: AgentConstructionOptions\n): options is AgentLanguageModelOptions {\n return typeof options.model !== \"function\";\n}\n"],"mappings":";AAiCA,SAAgB,mBACd,SAC6C;CAC7C,IAAI,YAAY,QAAQ,OAAO,YAAY,UACzC,MAAM,IAAI,UAAU,gDAAgD;CAKtE,IAAI,EAFa,WAAW,WAAW,QAAQ,SAAS,OAGtD,MAAM,IAAI,UAAU,+BAA+B;CAGrD,IACE,OAAO,QAAQ,UAAU,eACxB,OAAO,QAAQ,UAAU,YAAY,QAAQ,UAAU,OAExD,MAAM,IAAI,UAAU,+BAA+B;AAEvD;AAEA,SAAgB,gBACd,SACqC;CACrC,OAAO,OAAO,QAAQ,UAAU;AAClC;AAEA,SAAgB,iBACd,SACsC;CACtC,OAAO,OAAO,QAAQ,UAAU;AAClC"}
|
package/dist/agent-resume.js
CHANGED
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import { readDurableBackgroundChildRunState } from "./subagent-background-child-run-state.js";
|
|
2
1
|
import { ownsAgentNamespace } from "./agent-namespace.js";
|
|
3
|
-
import { StoredAgentRun } from "./execution/run.js";
|
|
4
|
-
import { BufferedAgentRun } from "./session/run.js";
|
|
5
|
-
import { buildDurableResumeGroups } from "./subagent-background-resume-group.js";
|
|
6
|
-
import { runBackgroundJob } from "./subagent-background-runner.js";
|
|
7
2
|
//#region src/agent-resume.ts
|
|
8
|
-
|
|
9
|
-
async function resumeAgentRun({ host, ownerNamespace, resumeNotification, runId, subagents }) {
|
|
3
|
+
async function resumeAgentRun({ host, ownerNamespace, resumeNotification, runId }) {
|
|
10
4
|
const run = await host.store.runs.get(runId);
|
|
11
5
|
if (!run) return null;
|
|
12
6
|
if (!canAccessRun(run, ownerNamespace)) return null;
|
|
13
|
-
if (run.kind === "background-subagent") return await resumeBackgroundSubagentRun({
|
|
14
|
-
host,
|
|
15
|
-
run,
|
|
16
|
-
subagents
|
|
17
|
-
});
|
|
18
7
|
if (run.kind === "notification" && run.dedupeKey) {
|
|
19
8
|
const idempotencyKey = run.dedupeKey;
|
|
20
9
|
const claimed = await claimRun(host, run);
|
|
@@ -59,84 +48,15 @@ async function completeNotificationRun(host, runId) {
|
|
|
59
48
|
status: "completed"
|
|
60
49
|
});
|
|
61
50
|
}
|
|
62
|
-
async function resumeBackgroundSubagentRun({ host, run, subagents }) {
|
|
63
|
-
const claimed = await claimRun(host, run);
|
|
64
|
-
if (!claimed) return null;
|
|
65
|
-
const state = readDurableBackgroundChildRunState(await host.store.checkpoints.latest(run.runId));
|
|
66
|
-
if (!state) throw new AgentResumeError(run.runId, "missing background run state");
|
|
67
|
-
const subagent = subagents.find((candidate) => candidate.name === state.subagent);
|
|
68
|
-
if (!subagent) throw new AgentResumeError(run.runId, `missing subagent ${JSON.stringify(state.subagent)}`);
|
|
69
|
-
const childSession = subagent.session(claimed.sessionKey);
|
|
70
|
-
const job = {
|
|
71
|
-
abort: () => childSession.interrupt(),
|
|
72
|
-
childRunId: claimed.runId,
|
|
73
|
-
childRunLeaseId: claimed.lease?.leaseId,
|
|
74
|
-
cleanup: () => Promise.resolve(),
|
|
75
|
-
dedupeKey: claimed.dedupeKey,
|
|
76
|
-
delegateToolCallId: state.delegateToolCallId,
|
|
77
|
-
description: state.description,
|
|
78
|
-
executionHost: host,
|
|
79
|
-
groupId: state.groupId,
|
|
80
|
-
id: claimed.publicTaskId ?? claimed.runId,
|
|
81
|
-
ownerNamespace: claimed.ownerNamespace,
|
|
82
|
-
parentRunId: claimed.parentRunId,
|
|
83
|
-
parentSessionKey: state.parentSessionKey,
|
|
84
|
-
promise: Promise.resolve(),
|
|
85
|
-
sessionKey: claimed.sessionKey,
|
|
86
|
-
settled: false,
|
|
87
|
-
status: "running",
|
|
88
|
-
subagent: state.subagent
|
|
89
|
-
};
|
|
90
|
-
const jobs = new Map([[job.id, job]]);
|
|
91
|
-
job.promise = runBackgroundJob({
|
|
92
|
-
childSession,
|
|
93
|
-
groups: await buildDurableResumeGroups({
|
|
94
|
-
currentJob: job,
|
|
95
|
-
host,
|
|
96
|
-
run: claimed,
|
|
97
|
-
state,
|
|
98
|
-
jobs
|
|
99
|
-
}),
|
|
100
|
-
jobs,
|
|
101
|
-
job,
|
|
102
|
-
parentSession: durableParentSession(host, run.runId),
|
|
103
|
-
prompt: state.prompt
|
|
104
|
-
}).finally(() => {
|
|
105
|
-
job.settled = true;
|
|
106
|
-
});
|
|
107
|
-
await job.promise;
|
|
108
|
-
return new StoredAgentRun({
|
|
109
|
-
eventStore: host.store.events,
|
|
110
|
-
runId: run.runId
|
|
111
|
-
});
|
|
112
|
-
}
|
|
113
51
|
async function claimRun(host, run) {
|
|
114
52
|
const claim = await host.store.runs.claim(run.runId, {
|
|
115
53
|
attempt: (run.lease?.attempt ?? 0) + 1,
|
|
116
54
|
leaseId: crypto.randomUUID(),
|
|
117
|
-
leaseMs:
|
|
55
|
+
leaseMs: 3e5,
|
|
118
56
|
nowMs: Date.now()
|
|
119
57
|
});
|
|
120
58
|
return claim.ok ? claim.record : null;
|
|
121
59
|
}
|
|
122
|
-
function durableParentSession(host, runId) {
|
|
123
|
-
return {
|
|
124
|
-
emitObserverEvent: (event) => host.store.events.append(runId, event).then(),
|
|
125
|
-
enqueueRuntimeInput: () => void 0,
|
|
126
|
-
notify: () => Promise.resolve(emptyRun())
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
function emptyRun() {
|
|
130
|
-
const run = new BufferedAgentRun();
|
|
131
|
-
run.close();
|
|
132
|
-
return run;
|
|
133
|
-
}
|
|
134
|
-
var AgentResumeError = class extends Error {
|
|
135
|
-
constructor(runId, reason) {
|
|
136
|
-
super(`Cannot resume agent run ${runId}: ${reason}`);
|
|
137
|
-
this.name = "AgentResumeError";
|
|
138
|
-
}
|
|
139
|
-
};
|
|
140
60
|
//#endregion
|
|
141
61
|
export { resumeAgentRun };
|
|
142
62
|
|