@minpeter/pss-runtime 0.1.0-next.1 → 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 +290 -61
- package/dist/agent-host-session-store.js +10 -0
- package/dist/agent-host-session-store.js.map +1 -0
- package/dist/agent-loop.js +57 -28
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent-namespace.js +6 -3
- package/dist/agent-namespace.js.map +1 -1
- package/dist/agent-options.d.ts +29 -0
- package/dist/agent-options.js +16 -0
- package/dist/agent-options.js.map +1 -0
- package/dist/agent-resume.js +63 -0
- package/dist/agent-resume.js.map +1 -0
- package/dist/agent-session-entry.d.ts +13 -0
- package/dist/agent.d.ts +8 -44
- package/dist/agent.js +61 -83
- 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 +62 -0
- package/dist/execution/host.js.map +1 -0
- package/dist/execution/index.d.ts +6 -0
- package/dist/execution/index.js +4 -0
- package/dist/execution/memory-notifications.js +54 -0
- package/dist/execution/memory-notifications.js.map +1 -0
- package/dist/execution/memory-state.js +34 -0
- package/dist/execution/memory-state.js.map +1 -0
- package/dist/execution/memory-store.js +203 -0
- package/dist/execution/memory-store.js.map +1 -0
- package/dist/execution/memory.d.ts +7 -0
- package/dist/execution/memory.js +28 -0
- package/dist/execution/memory.js.map +1 -0
- package/dist/execution/types.d.ts +150 -0
- package/dist/index.d.ts +13 -6
- package/dist/index.js +6 -1
- package/dist/llm-tool-execution.d.ts +35 -0
- package/dist/llm-tool-execution.js +126 -0
- package/dist/llm-tool-execution.js.map +1 -0
- package/dist/llm.d.ts +11 -15
- package/dist/llm.js +5 -3
- package/dist/llm.js.map +1 -1
- package/dist/plugins.d.ts +42 -0
- package/dist/plugins.js +43 -0
- package/dist/plugins.js.map +1 -0
- 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 -22
- 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 +10 -24
- package/dist/session/runtime-input.js.map +1 -1
- package/dist/session/session-errors.js +1 -6
- package/dist/session/session-errors.js.map +1 -1
- package/dist/session/session-events.js +73 -0
- package/dist/session/session-events.js.map +1 -0
- package/dist/session/session-execution.js +88 -0
- package/dist/session/session-execution.js.map +1 -0
- package/dist/session/session-notification.js +59 -0
- package/dist/session/session-notification.js.map +1 -0
- 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 +125 -0
- package/dist/session/session-turn-processor.js.map +1 -0
- package/dist/session/session.js +81 -102
- package/dist/session/session.js.map +1 -1
- package/dist/session/snapshot.js.map +1 -1
- package/package.json +16 -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/hooks.d.ts +0 -32
- package/dist/subagent-job-cancel.js +0 -28
- package/dist/subagent-job-cancel.js.map +0 -1
- package/dist/subagent-job-output.js +0 -63
- package/dist/subagent-job-output.js.map +0 -1
- package/dist/subagent-jobs.js +0 -151
- 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 -92
- package/dist/subagents.js.map +0 -1
- /package/dist/session/{runtime-input.d.ts → session-execution.d.ts} +0 -0
package/README.md
CHANGED
|
@@ -10,12 +10,31 @@ Minimal, platform-agnostic agent runtime with keyed sessions, synchronized
|
|
|
10
10
|
## Core DX
|
|
11
11
|
|
|
12
12
|
```ts
|
|
13
|
+
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
13
14
|
import { Agent } from "@minpeter/pss-runtime";
|
|
14
|
-
import {
|
|
15
|
+
import { createEnv } from "@t3-oss/env-core";
|
|
16
|
+
import { config as loadEnv } from "dotenv";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
loadEnv({ path: ".env", quiet: true, override: true });
|
|
20
|
+
const env = createEnv({
|
|
21
|
+
runtimeEnv: process.env,
|
|
22
|
+
server: {
|
|
23
|
+
AI_API_KEY: z.string().trim().min(1),
|
|
24
|
+
AI_BASE_URL: z.url().trim().default("https://apis.opengateway.ai/v1"),
|
|
25
|
+
AI_MODEL: z.string().trim().min(1).default("minimax/MiniMax-M2.7"),
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
const provider = createOpenAICompatible({
|
|
30
|
+
name: "custom",
|
|
31
|
+
apiKey: env.AI_API_KEY,
|
|
32
|
+
baseURL: env.AI_BASE_URL,
|
|
33
|
+
});
|
|
15
34
|
|
|
16
35
|
const agent = new Agent({
|
|
17
36
|
instructions: "Answer briefly.",
|
|
18
|
-
model:
|
|
37
|
+
model: provider(env.AI_MODEL),
|
|
19
38
|
});
|
|
20
39
|
|
|
21
40
|
const run = await agent.send("Hello");
|
|
@@ -30,6 +49,23 @@ consume the events for the run to progress. This is what lets code react to
|
|
|
30
49
|
`turn-start`, `step-start`, and `step-end` before the next model snapshot is
|
|
31
50
|
created.
|
|
32
51
|
|
|
52
|
+
`model` is the single public constructor key for model execution. Pass an AI SDK
|
|
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
|
+
adapter yourself:
|
|
56
|
+
|
|
57
|
+
```ts
|
|
58
|
+
import { Agent, type RuntimeLlm } from "@minpeter/pss-runtime";
|
|
59
|
+
|
|
60
|
+
const runtimeModel: RuntimeLlm = async ({ history }) => [
|
|
61
|
+
{ role: "assistant", content: `Seen ${history.length} messages.` },
|
|
62
|
+
];
|
|
63
|
+
|
|
64
|
+
const agent = new Agent({
|
|
65
|
+
model: runtimeModel,
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
33
69
|
Per-key conversations use `session(key)`:
|
|
34
70
|
|
|
35
71
|
```ts
|
|
@@ -80,74 +116,180 @@ The public transcript protocol is `AgentEvent`: live runs emit runtime-defined
|
|
|
80
116
|
events through `run.events()`. Provider/model message history is internal
|
|
81
117
|
continuation state, not a public history API.
|
|
82
118
|
|
|
83
|
-
##
|
|
119
|
+
## Delegation
|
|
84
120
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
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.
|
|
89
124
|
|
|
90
125
|
```ts
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
description: "Researches facts and returns concise evidence.",
|
|
126
|
+
const reader = new Agent({
|
|
127
|
+
instructions: "Read knowledge-base files and cite paths.",
|
|
94
128
|
model,
|
|
95
|
-
|
|
129
|
+
namespace: "reader",
|
|
96
130
|
});
|
|
97
131
|
|
|
98
132
|
const coordinator = new Agent({
|
|
133
|
+
instructions: "Coordinate work and delegate knowledge-base reads.",
|
|
99
134
|
model,
|
|
100
|
-
|
|
101
|
-
|
|
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
|
+
},
|
|
102
152
|
});
|
|
103
153
|
```
|
|
104
154
|
|
|
105
|
-
For
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
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:
|
|
112
166
|
|
|
113
167
|
```ts
|
|
114
|
-
|
|
115
|
-
|
|
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],
|
|
116
183
|
});
|
|
117
184
|
```
|
|
118
185
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
the
|
|
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:
|
|
123
226
|
|
|
124
227
|
```ts
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
228
|
+
import type { AgentPlugin, UserText } from "@minpeter/pss-runtime";
|
|
229
|
+
import { Agent } from "@minpeter/pss-runtime";
|
|
230
|
+
|
|
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
|
+
};
|
|
129
250
|
|
|
130
|
-
|
|
131
|
-
|
|
251
|
+
const executionAgent = new Agent({
|
|
252
|
+
namespace: "execution",
|
|
253
|
+
plugins: [pokeTagsPlugin],
|
|
254
|
+
model,
|
|
255
|
+
});
|
|
132
256
|
```
|
|
133
257
|
|
|
134
|
-
The parent
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
after `background_output` returns.
|
|
258
|
+
The parent coordinator stays unchanged; only the nested child agent carries the
|
|
259
|
+
plugin.
|
|
260
|
+
|
|
261
|
+
### Migration
|
|
139
262
|
|
|
140
|
-
|
|
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.
|
|
267
|
+
|
|
268
|
+
## Send, Host Resume, and Steer
|
|
141
269
|
|
|
142
270
|
Use `session.send(input)` for a new user turn. If a run is already active, the
|
|
143
|
-
turn is queued until the active run finishes. Use `session.steer(input)` when
|
|
144
|
-
input should steer the active run; if no run is active, it starts a normal
|
|
271
|
+
turn is queued until the active run finishes. Use `session.steer(input)` when
|
|
272
|
+
the input should steer the active run; if no run is active, it starts a normal
|
|
273
|
+
run.
|
|
274
|
+
|
|
275
|
+
Durable hosts resume completed background work by writing a notification record
|
|
276
|
+
and calling `agent.resume(notificationRunId)`. The resume call claims the
|
|
277
|
+
notification idempotently through its durable run id and returns one `AgentRun`,
|
|
278
|
+
or `null` when a duplicate queue/alarm delivery already claimed it.
|
|
279
|
+
|
|
280
|
+
Runtime-originated input is delivered through the host notification inbox and
|
|
281
|
+
internal plugin paths. App code should use `session.send()`, `session.steer()`,
|
|
282
|
+
or `agent.resume(runId)` for host-scheduled durable work.
|
|
283
|
+
|
|
284
|
+
Each accepted call returns one `AgentRun`. Drain that run's `events()` stream to
|
|
285
|
+
observe the turn; each `AgentRun.events()` stream is single-consumer.
|
|
145
286
|
|
|
146
|
-
|
|
287
|
+
Input APIs accept the same input shapes: strings, arrays of strings,
|
|
147
288
|
`{ type: "user-text", text }`, and multipart `{ type: "user-message", content }`
|
|
148
|
-
values. Active steering
|
|
149
|
-
runtime/API-originated input mapped internally to the model's
|
|
150
|
-
distinct from human-origin `user-text` and `user-message`
|
|
289
|
+
values. Active steering and host resume input emit `runtime-input` events. A
|
|
290
|
+
`runtime-input` is runtime/API-originated input mapped internally to the model's
|
|
291
|
+
user role. It is distinct from human-origin `user-text` and `user-message`
|
|
292
|
+
events.
|
|
151
293
|
|
|
152
294
|
Runtime input windows are tied to synchronized events:
|
|
153
295
|
|
|
@@ -188,6 +330,10 @@ Stored session state is an opaque, versioned runtime snapshot for continuation.
|
|
|
188
330
|
Do not inspect it as a replay log; exact replay should be modeled separately as
|
|
189
331
|
an `AgentEvent` log if that capability is added later.
|
|
190
332
|
|
|
333
|
+
`SessionStore` is snapshot-only. It does not own background task ids, run
|
|
334
|
+
leases, checkpoints, notification inbox state, or scheduling. Those live on the
|
|
335
|
+
optional `host` execution contract.
|
|
336
|
+
|
|
191
337
|
Custom stores own version generation. `load(key)` returns the opaque `state` with
|
|
192
338
|
the store-minted `version`; `commit(key, { state }, { expectedVersion })` receives
|
|
193
339
|
state only and should reject stale versions by returning `{ ok: false, reason:
|
|
@@ -196,37 +342,89 @@ new version to the runtime. `delete(key)` removes the persisted session for that
|
|
|
196
342
|
key.
|
|
197
343
|
|
|
198
344
|
```ts
|
|
199
|
-
import type { SessionStore } from "@minpeter/pss-runtime";
|
|
200
345
|
import { MemorySessionStore } from "@minpeter/pss-runtime/session-store/memory";
|
|
201
346
|
|
|
202
347
|
const agent = new Agent({
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
namespace: "support-agent",
|
|
206
|
-
store: new MemorySessionStore(), // default when omitted
|
|
348
|
+
host: {
|
|
349
|
+
sessionStore: new MemorySessionStore(), // default when omitted
|
|
207
350
|
},
|
|
351
|
+
model,
|
|
352
|
+
namespace: "support-agent",
|
|
208
353
|
});
|
|
209
354
|
```
|
|
210
355
|
|
|
211
|
-
For durable sessions, use the exported file POC. Set a stable `namespace`
|
|
212
|
-
|
|
213
|
-
|
|
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:
|
|
214
359
|
|
|
215
360
|
```ts
|
|
216
361
|
import { FileSessionStore } from "@minpeter/pss-runtime/session-store/file";
|
|
217
362
|
|
|
218
363
|
const agent = new Agent({
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
namespace: "support-agent",
|
|
222
|
-
store: new FileSessionStore(".pss/sessions"),
|
|
364
|
+
host: {
|
|
365
|
+
sessionStore: new FileSessionStore(".pss/sessions"),
|
|
223
366
|
},
|
|
367
|
+
model,
|
|
368
|
+
namespace: "support-agent",
|
|
224
369
|
});
|
|
225
370
|
```
|
|
226
371
|
|
|
227
|
-
|
|
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.
|
|
380
|
+
|
|
381
|
+
```ts
|
|
382
|
+
import { Agent } from "@minpeter/pss-runtime";
|
|
383
|
+
import {
|
|
384
|
+
createInMemoryExecutionHost,
|
|
385
|
+
type DurableBackgroundHost,
|
|
386
|
+
type ExecutionHost,
|
|
387
|
+
} from "@minpeter/pss-runtime/execution";
|
|
388
|
+
|
|
389
|
+
const host = createInMemoryExecutionHost();
|
|
390
|
+
|
|
391
|
+
const agent = new Agent({
|
|
392
|
+
host,
|
|
393
|
+
model,
|
|
394
|
+
namespace: "support-agent",
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
const durableHost: DurableBackgroundHost = {
|
|
398
|
+
capabilities: {},
|
|
399
|
+
backgroundScheduler,
|
|
400
|
+
checkpointStore,
|
|
401
|
+
eventStore,
|
|
402
|
+
notificationInbox,
|
|
403
|
+
runStore,
|
|
404
|
+
sessionStore,
|
|
405
|
+
transaction,
|
|
406
|
+
};
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
## Supported Deployment Shapes
|
|
410
|
+
|
|
411
|
+
The runtime supports both long-running Node.js processes and edge hosts that
|
|
412
|
+
reconstruct runtime objects between turns. The same public DX stays centered on
|
|
413
|
+
`new Agent({ model, tools, host })`; host-specific durability and scheduling live
|
|
414
|
+
behind the `host` boundary.
|
|
415
|
+
|
|
416
|
+
Long-running Node.js can keep an `Agent` and `SessionHandle` alive across turns.
|
|
417
|
+
`FileSessionStore` persists session snapshots only; app-owned background work
|
|
418
|
+
needs its own durable task/output storage if it must survive process restarts.
|
|
419
|
+
|
|
420
|
+
Cloudflare Durable Objects and similar edge hosts should reconstruct `Agent`
|
|
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.
|
|
228
427
|
|
|
229
|
-
Cloudflare Durable Objects are a future adapter target, not a runtime dependency.
|
|
230
428
|
The same core API supports room/user/session routing through stable session keys.
|
|
231
429
|
|
|
232
430
|
Recommended key patterns:
|
|
@@ -235,6 +433,37 @@ Recommended key patterns:
|
|
|
235
433
|
- Per-user memory inside room: `room:<roomId>:user:<userId>`
|
|
236
434
|
- Ticketed workspace flows: `tenant:<tenantId>:ticket:<ticketId>`
|
|
237
435
|
|
|
238
|
-
In a Durable Object, map the
|
|
239
|
-
durable across hibernation/restores, while in-memory state remains
|
|
240
|
-
Do not store canonical agent session state in memory
|
|
436
|
+
In a Durable Object, map the execution store contract to `ctx.storage` so DO
|
|
437
|
+
storage is durable across hibernation/restores, while in-memory state remains
|
|
438
|
+
request-local. Do not store canonical agent session or run state in memory
|
|
439
|
+
attachments.
|
|
440
|
+
|
|
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(...)`.
|
|
445
|
+
|
|
446
|
+
## Checkpoints and Cancellation
|
|
447
|
+
|
|
448
|
+
Resume is safe only at committed boundaries. Durable hosts can checkpoint before
|
|
449
|
+
and after model steps, around notifications, before child run creation, when a
|
|
450
|
+
child link is committed, and when a run suspends. If a process is killed inside a
|
|
451
|
+
provider call or unsafe tool execution, resume rolls back to the last committed
|
|
452
|
+
checkpoint and may re-enter the operation.
|
|
453
|
+
|
|
454
|
+
When `Agent` receives an `ExecutionHost`, high-level model turns create a
|
|
455
|
+
`user-turn` run record and thread tool execution context into managed model
|
|
456
|
+
calls. Tools are checkpointed before and after execution and receive stable
|
|
457
|
+
`attempt`, `idempotencyKey`, `retryPolicy`, `signal`, and public `toolCallId`
|
|
458
|
+
values. The `@minpeter/pss-runtime/execution` entrypoint also exposes the same
|
|
459
|
+
low-level tool execution checkpoint types for custom resume runners built
|
|
460
|
+
directly on `createLlm`.
|
|
461
|
+
|
|
462
|
+
These checkpoints are rollback boundaries, not a complete host adapter by
|
|
463
|
+
themselves. Edge hosts still need durable scheduling, leases, resume workers,
|
|
464
|
+
and notification resume handling; externally visible side-effect tools still need
|
|
465
|
+
idempotent execution or a manual recovery flow.
|
|
466
|
+
|
|
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.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { sessionHost } from "./execution/host.js";
|
|
2
|
+
import { MemorySessionStore } from "./session/store/memory.js";
|
|
3
|
+
//#region src/agent-host-session-store.ts
|
|
4
|
+
function sessionStoreForHost(host) {
|
|
5
|
+
return sessionHost(host).sessionStore ?? new MemorySessionStore();
|
|
6
|
+
}
|
|
7
|
+
//#endregion
|
|
8
|
+
export { sessionStoreForHost };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=agent-host-session-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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
|
@@ -1,39 +1,29 @@
|
|
|
1
1
|
import { modelMessageToAgentEvents } from "./session/mapping.js";
|
|
2
2
|
//#region src/agent-loop.ts
|
|
3
|
-
async function runAgentLoop({ emit, history,
|
|
4
|
-
let stepIndex = 0;
|
|
3
|
+
async function runAgentLoop({ captureObserverEvents = captureNoObserverEvents, emit, history, llm, signal = new AbortController().signal, toolExecution }) {
|
|
5
4
|
while (true) {
|
|
6
|
-
if (signal.aborted) return "aborted";
|
|
7
|
-
await hooks?.beforeStep?.({
|
|
8
|
-
history: history.modelSnapshot(),
|
|
9
|
-
signal,
|
|
10
|
-
stepIndex
|
|
11
|
-
});
|
|
12
5
|
if (signal.aborted) return "aborted";
|
|
13
6
|
if (await emitBoundary({
|
|
14
7
|
emit,
|
|
15
8
|
event: { type: "step-start" },
|
|
16
9
|
signal
|
|
17
10
|
}) === "aborted") return "aborted";
|
|
18
|
-
const
|
|
11
|
+
const capturedOutput = await captureObserverEvents(() => readLlmOutput({
|
|
19
12
|
history,
|
|
20
13
|
llm,
|
|
21
|
-
signal
|
|
22
|
-
|
|
14
|
+
signal,
|
|
15
|
+
toolExecution
|
|
16
|
+
}));
|
|
17
|
+
const output = capturedOutput.value;
|
|
23
18
|
if (output === "aborted") return "aborted";
|
|
24
|
-
const result =
|
|
19
|
+
const result = await appendCapturedStepOutput({
|
|
20
|
+
capturedOutput,
|
|
25
21
|
emit,
|
|
26
22
|
history,
|
|
27
23
|
output,
|
|
28
24
|
signal
|
|
29
25
|
});
|
|
30
26
|
if (result === "aborted") return "aborted";
|
|
31
|
-
await runAfterStepHook(hooks, {
|
|
32
|
-
history: history.modelSnapshot(),
|
|
33
|
-
result,
|
|
34
|
-
signal,
|
|
35
|
-
stepIndex
|
|
36
|
-
});
|
|
37
27
|
const stepEndDecision = await emitBoundary({
|
|
38
28
|
emit,
|
|
39
29
|
event: { type: "step-end" },
|
|
@@ -41,7 +31,6 @@ async function runAgentLoop({ emit, history, hooks, llm, signal = new AbortContr
|
|
|
41
31
|
});
|
|
42
32
|
if (stepEndDecision === "aborted") return "aborted";
|
|
43
33
|
if (result === "completed" && !stepEndDecision?.runtimeInputAdded) return "completed";
|
|
44
|
-
stepIndex += 1;
|
|
45
34
|
}
|
|
46
35
|
}
|
|
47
36
|
async function emitBoundary({ emit, event, signal }) {
|
|
@@ -68,34 +57,74 @@ function createAbortBoundary(signal) {
|
|
|
68
57
|
promise
|
|
69
58
|
};
|
|
70
59
|
}
|
|
71
|
-
async function
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
60
|
+
async function captureNoObserverEvents(callback) {
|
|
61
|
+
return {
|
|
62
|
+
events: [],
|
|
63
|
+
release: releaseNoObserverEvents,
|
|
64
|
+
value: await callback()
|
|
65
|
+
};
|
|
75
66
|
}
|
|
76
|
-
|
|
67
|
+
function releaseNoObserverEvents() {}
|
|
68
|
+
async function readLlmOutput({ history, llm, signal, toolExecution }) {
|
|
77
69
|
try {
|
|
78
70
|
return await llm({
|
|
79
71
|
history: history.modelSnapshot(),
|
|
80
|
-
signal
|
|
72
|
+
signal,
|
|
73
|
+
toolExecution
|
|
81
74
|
});
|
|
82
75
|
} catch (error) {
|
|
83
76
|
if (signal.aborted) return "aborted";
|
|
84
77
|
throw error;
|
|
85
78
|
}
|
|
86
79
|
}
|
|
87
|
-
function
|
|
80
|
+
async function appendCapturedStepOutput({ capturedOutput, emit, history, output, signal }) {
|
|
81
|
+
try {
|
|
82
|
+
return await appendStepOutput({
|
|
83
|
+
emit,
|
|
84
|
+
history,
|
|
85
|
+
observerEvents: capturedOutput.events,
|
|
86
|
+
output,
|
|
87
|
+
signal
|
|
88
|
+
});
|
|
89
|
+
} finally {
|
|
90
|
+
capturedOutput.release();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
async function appendStepOutput({ emit, history, observerEvents, output, signal }) {
|
|
88
94
|
if (signal.aborted) return "aborted";
|
|
89
95
|
let shouldContinue = false;
|
|
96
|
+
const pendingObserverEvents = observerEvents;
|
|
97
|
+
const flushObserverEvents = async (shouldFlush = () => true) => {
|
|
98
|
+
for (let index = 0; index < pendingObserverEvents.length;) {
|
|
99
|
+
const event = pendingObserverEvents[index];
|
|
100
|
+
if (!(event && shouldFlush(event))) {
|
|
101
|
+
index += 1;
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
pendingObserverEvents.splice(index, 1);
|
|
105
|
+
await emit(event);
|
|
106
|
+
}
|
|
107
|
+
};
|
|
90
108
|
for (const message of output) {
|
|
91
109
|
if (signal.aborted) return "aborted";
|
|
92
110
|
history.appendModelMessage(message);
|
|
93
111
|
const events = modelMessageToAgentEvents(message);
|
|
94
|
-
|
|
95
|
-
|
|
112
|
+
const hasToolResult = events.some((event) => event.type === "tool-result");
|
|
113
|
+
for (const event of events) {
|
|
114
|
+
await emit(event);
|
|
115
|
+
if (event.type === "tool-call") {
|
|
116
|
+
shouldContinue = true;
|
|
117
|
+
await flushObserverEvents(isLaunchOrBlockingObserverEvent);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (hasToolResult) await flushObserverEvents();
|
|
96
121
|
}
|
|
122
|
+
await flushObserverEvents();
|
|
97
123
|
return shouldContinue ? "continue" : "completed";
|
|
98
124
|
}
|
|
125
|
+
function isLaunchOrBlockingObserverEvent(_event) {
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
99
128
|
//#endregion
|
|
100
129
|
export { runAgentLoop };
|
|
101
130
|
|
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 {
|
|
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":";;AA4CA,eAAsB,aAAa,EACjC,wBAAwB,yBACxB,MACA,SACA,KACA,SAAS,IAAI,gBAAgB,EAAE,QAC/B,iBACgD;CAChD,OAAO,MAAM;EACX,IAAI,OAAO,SACT,OAAO;EAST,IAAI,MAN4B,aAAa;GAC3C;GACA,OAAO,EAAE,MAAM,aAAa;GAC5B;EACF,CAAC,MAEyB,WACxB,OAAO;EAGT,MAAM,iBAAiB,MAAM,4BAC3B,cAAc;GAAE;GAAS;GAAK;GAAQ;EAAc,CAAC,CACvD;EACA,MAAM,SAAS,eAAe;EAE9B,IAAI,WAAW,WACb,OAAO;EAGT,MAAM,SAAS,MAAM,yBAAyB;GAC5C;GACA;GACA;GACA;GACA;EACF,CAAC;EAED,IAAI,WAAW,WACb,OAAO;EAGT,MAAM,kBAAkB,MAAM,aAAa;GACzC;GACA,OAAO,EAAE,MAAM,WAAW;GAC1B;EACF,CAAC;EAED,IAAI,oBAAoB,WACtB,OAAO;EAMT,IAAI,WAAW,eAAe,CAAC,iBAAiB,mBAC9C,OAAO;CAEX;AACF;AAEA,eAAe,aAAa,EAC1B,MACA,OACA,UAI6D;CAC7D,IAAI,OAAO,SACT,OAAO;CAGT,MAAM,QAAQ,oBAAoB,MAAM;CACxC,IAAI;EACF,OAAO,MAAM,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK,KAAK,CAAC,GAAG,MAAM,OAAO,CAAC;CACzE,SAAS,OAAO;EACd,IAAI,OAAO,SACT,OAAO;EAGT,MAAM;CACR,UAAU;EACR,MAAM,QAAQ;CAChB;AACF;AAEA,SAAS,oBAAoB,QAG3B;CACA,IAAI,gBAA4B,KAAA;CAEhC,MAAM,UAAU,IAAI,SAAoB,YAAY;EAClD,MAAM,gBAAgB,QAAQ,SAAS;EACvC,gBAAgB,OAAO,oBAAoB,SAAS,OAAO;EAC3D,OAAO,iBAAiB,SAAS,SAAS,EAAE,MAAM,KAAK,CAAC;CAC1D,CAAC;CAED,OAAO;EAAE;EAAS;CAAQ;AAC5B;AAEA,eAAe,wBAA2B,UAIvC;CACD,OAAO;EACL,QAAQ,CAAC;EACT,SAAS;EACT,OAAO,MAAM,SAAS;CACxB;AACF;AAEA,SAAS,0BAAgC,CAEzC;AAEA,eAAe,cAAc,EAC3B,SACA,KACA,QACA,iBAIwC;CACxC,IAAI;EACF,OAAO,MAAM,IAAI;GACf,SAAS,QAAQ,cAAc;GAC/B;GACA;EACF,CAAC;CACH,SAAS,OAAO;EACd,IAAI,OAAO,SACT,OAAO;EAGT,MAAM;CACR;AACF;AAEA,eAAe,yBAAyB,EACtC,gBACA,MACA,SACA,QACA,UAK4B;CAC5B,IAAI;EACF,OAAO,MAAM,iBAAiB;GAC5B;GACA;GACA,gBAAgB,eAAe;GAC/B;GACA;EACF,CAAC;CACH,UAAU;EACR,eAAe,QAAQ;CACzB;AACF;AAEA,eAAe,iBAAiB,EAC9B,MACA,SACA,gBACA,QACA,UAK4B;CAC5B,IAAI,OAAO,SACT,OAAO;CAGT,IAAI,iBAAiB;CACrB,MAAM,wBAAwB;CAC9B,MAAM,sBAAsB,OAC1B,oBAAoD,SACjD;EACH,KAAK,IAAI,QAAQ,GAAG,QAAQ,sBAAsB,SAAU;GAC1D,MAAM,QAAQ,sBAAsB;GACpC,IAAI,EAAE,SAAS,YAAY,KAAK,IAAI;IAClC,SAAS;IACT;GACF;GACA,sBAAsB,OAAO,OAAO,CAAC;GACrC,MAAM,KAAK,KAAK;EAClB;CACF;CAEA,KAAK,MAAM,WAAW,QAAQ;EAC5B,IAAI,OAAO,SACT,OAAO;EAGT,QAAQ,mBAAmB,OAAO;EAClC,MAAM,SAAS,0BAA0B,OAAO;EAChD,MAAM,gBAAgB,OAAO,MAAM,UAAU,MAAM,SAAS,aAAa;EAEzE,KAAK,MAAM,SAAS,QAAQ;GAC1B,MAAM,KAAK,KAAK;GAChB,IAAI,MAAM,SAAS,aAAa;IAC9B,iBAAiB;IACjB,MAAM,oBAAoB,+BAA+B;GAC3D;EACF;EAEA,IAAI,eACF,MAAM,oBAAoB;CAE9B;CAEA,MAAM,oBAAoB;CAE1B,OAAO,iBAAiB,aAAa;AACvC;AAEA,SAAS,gCAAgC,QAA6B;CACpE,OAAO;AACT"}
|
package/dist/agent-namespace.js
CHANGED
|
@@ -8,10 +8,13 @@ function agentNamespace(namespace) {
|
|
|
8
8
|
function namespacePart(value) {
|
|
9
9
|
return encodeURIComponent(value);
|
|
10
10
|
}
|
|
11
|
-
function
|
|
12
|
-
return `${sessionNamespace}:session
|
|
11
|
+
function ownsAgentNamespace(ownerNamespace, sessionNamespace) {
|
|
12
|
+
return ownerNamespace === sessionNamespace || ownerNamespace?.startsWith(`${sessionNamespace}:session:`) === true;
|
|
13
|
+
}
|
|
14
|
+
function stableAgentNamespace({ namespace }) {
|
|
15
|
+
return namespace ? agentNamespace(namespace) : randomAgentNamespace();
|
|
13
16
|
}
|
|
14
17
|
//#endregion
|
|
15
|
-
export {
|
|
18
|
+
export { ownsAgentNamespace, stableAgentNamespace };
|
|
16
19
|
|
|
17
20
|
//# sourceMappingURL=agent-namespace.js.map
|