experimental-ash 0.2.0-alpha.21 → 0.2.0-alpha.22
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/dist/src/channel/slack-channel.d.ts +14 -7
- package/dist/src/channel/slack-channel.d.ts.map +1 -1
- package/dist/src/channel/slack-channel.js +21 -11
- package/dist/src/channel/slack-channel.js.map +1 -1
- package/dist/src/channel/types.d.ts +14 -14
- package/dist/src/channel/types.d.ts.map +1 -1
- package/dist/src/channel/types.js +6 -0
- package/dist/src/channel/types.js.map +1 -1
- package/dist/src/context/accessors.d.ts +24 -10
- package/dist/src/context/accessors.d.ts.map +1 -1
- package/dist/src/context/accessors.js +34 -16
- package/dist/src/context/accessors.js.map +1 -1
- package/dist/src/context/container.d.ts +43 -20
- package/dist/src/context/container.d.ts.map +1 -1
- package/dist/src/context/container.js +54 -22
- package/dist/src/context/container.js.map +1 -1
- package/dist/src/context/key.d.ts +68 -39
- package/dist/src/context/key.d.ts.map +1 -1
- package/dist/src/context/key.js +49 -62
- package/dist/src/context/key.js.map +1 -1
- package/dist/src/context/keys.d.ts +6 -6
- package/dist/src/context/keys.d.ts.map +1 -1
- package/dist/src/context/keys.js +7 -9
- package/dist/src/context/keys.js.map +1 -1
- package/dist/src/context/node.d.ts +2 -2
- package/dist/src/context/node.d.ts.map +1 -1
- package/dist/src/context/node.js +1 -1
- package/dist/src/context/node.js.map +1 -1
- package/dist/src/context/provider.d.ts +24 -11
- package/dist/src/context/provider.d.ts.map +1 -1
- package/dist/src/context/providers/connection.d.ts +2 -2
- package/dist/src/context/providers/connection.d.ts.map +1 -1
- package/dist/src/context/providers/connection.js +1 -1
- package/dist/src/context/providers/connection.js.map +1 -1
- package/dist/src/context/providers/sandbox.d.ts +2 -2
- package/dist/src/context/providers/sandbox.d.ts.map +1 -1
- package/dist/src/context/providers/sandbox.js +2 -2
- package/dist/src/context/providers/sandbox.js.map +1 -1
- package/dist/src/context/providers/session.d.ts +2 -2
- package/dist/src/context/providers/session.d.ts.map +1 -1
- package/dist/src/context/providers/session.js +4 -4
- package/dist/src/context/providers/session.js.map +1 -1
- package/dist/src/context/providers/skill.d.ts +2 -2
- package/dist/src/context/providers/skill.d.ts.map +1 -1
- package/dist/src/context/providers/skill.js +2 -2
- package/dist/src/context/providers/skill.js.map +1 -1
- package/dist/src/context/run-step.d.ts +9 -8
- package/dist/src/context/run-step.d.ts.map +1 -1
- package/dist/src/context/run-step.js +32 -22
- package/dist/src/context/run-step.js.map +1 -1
- package/dist/src/context/seed-keys.d.ts +7 -7
- package/dist/src/context/seed-keys.d.ts.map +1 -1
- package/dist/src/context/seed-keys.js +7 -19
- package/dist/src/context/seed-keys.js.map +1 -1
- package/dist/src/context/serialize.d.ts +10 -9
- package/dist/src/context/serialize.d.ts.map +1 -1
- package/dist/src/context/serialize.js +18 -30
- package/dist/src/context/serialize.js.map +1 -1
- package/dist/src/execution/continuous-entry.d.ts +8 -6
- package/dist/src/execution/continuous-entry.d.ts.map +1 -1
- package/dist/src/execution/continuous-entry.js +27 -25
- package/dist/src/execution/continuous-entry.js.map +1 -1
- package/dist/src/execution/continuous-runtime.d.ts.map +1 -1
- package/dist/src/execution/continuous-runtime.js +1 -4
- package/dist/src/execution/continuous-runtime.js.map +1 -1
- package/dist/src/execution/node-step.js +1 -0
- package/dist/src/execution/node-step.js.map +1 -1
- package/dist/src/execution/runtime-context.d.ts +3 -3
- package/dist/src/execution/runtime-context.d.ts.map +1 -1
- package/dist/src/execution/runtime-context.js +3 -3
- package/dist/src/execution/runtime-context.js.map +1 -1
- package/dist/src/execution/sandboxes/read-file-tool.js +2 -2
- package/dist/src/execution/sandboxes/read-file-tool.js.map +1 -1
- package/dist/src/execution/sandboxes/require-sandbox.js +2 -2
- package/dist/src/execution/sandboxes/require-sandbox.js.map +1 -1
- package/dist/src/execution/sandboxes/write-file-tool.d.ts.map +1 -1
- package/dist/src/execution/sandboxes/write-file-tool.js +3 -3
- package/dist/src/execution/sandboxes/write-file-tool.js.map +1 -1
- package/dist/src/execution/subagent-tool.js +6 -6
- package/dist/src/execution/subagent-tool.js.map +1 -1
- package/dist/src/execution/tool-compaction.d.ts +3 -1
- package/dist/src/execution/tool-compaction.d.ts.map +1 -1
- package/dist/src/execution/tool-compaction.js +19 -8
- package/dist/src/execution/tool-compaction.js.map +1 -1
- package/dist/src/execution/types.d.ts +1 -0
- package/dist/src/execution/types.d.ts.map +1 -1
- package/dist/src/execution/workflow-entry.d.ts +5 -4
- package/dist/src/execution/workflow-entry.d.ts.map +1 -1
- package/dist/src/execution/workflow-entry.js +8 -3
- package/dist/src/execution/workflow-entry.js.map +1 -1
- package/dist/src/execution/workflow-runtime.d.ts.map +1 -1
- package/dist/src/execution/workflow-runtime.js +2 -3
- package/dist/src/execution/workflow-runtime.js.map +1 -1
- package/dist/src/execution/workflow-steps.d.ts +2 -2
- package/dist/src/execution/workflow-steps.d.ts.map +1 -1
- package/dist/src/execution/workflow-steps.js +42 -17
- package/dist/src/execution/workflow-steps.js.map +1 -1
- package/dist/src/harness/emission.d.ts +1 -1
- package/dist/src/harness/emission.js +3 -3
- package/dist/src/harness/emission.js.map +1 -1
- package/dist/src/harness/execute-tool.d.ts +1 -0
- package/dist/src/harness/execute-tool.d.ts.map +1 -1
- package/dist/src/harness/execute-tool.js.map +1 -1
- package/dist/src/harness/input-requests.d.ts +2 -22
- package/dist/src/harness/input-requests.d.ts.map +1 -1
- package/dist/src/harness/input-requests.js +47 -41
- package/dist/src/harness/input-requests.js.map +1 -1
- package/dist/src/harness/tool-loop.d.ts.map +1 -1
- package/dist/src/harness/tool-loop.js +19 -1
- package/dist/src/harness/tool-loop.js.map +1 -1
- package/dist/src/harness/tools.js +5 -1
- package/dist/src/harness/tools.js.map +1 -1
- package/dist/src/harness/types.d.ts +3 -15
- package/dist/src/harness/types.d.ts.map +1 -1
- package/dist/src/harness/types.js +1 -6
- package/dist/src/harness/types.js.map +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/connection.d.ts.map +1 -1
- package/dist/src/internal/authored-definition/connection.js +14 -1
- package/dist/src/internal/authored-definition/connection.js.map +1 -1
- package/dist/src/internal/nitro/routes/runtime-stack.d.ts +3 -3
- package/dist/src/internal/nitro/routes/runtime-stack.js +3 -3
- package/dist/src/public/channels/slack/index.d.ts +0 -5
- package/dist/src/public/channels/slack/index.d.ts.map +1 -1
- package/dist/src/public/channels/slack/index.js.map +1 -1
- package/dist/src/public/definitions/connections/mcp.d.ts +13 -0
- package/dist/src/public/definitions/connections/mcp.d.ts.map +1 -1
- package/dist/src/public/definitions/connections/mcp.js.map +1 -1
- package/dist/src/public/definitions/tool.d.ts +10 -6
- package/dist/src/public/definitions/tool.d.ts.map +1 -1
- package/dist/src/public/definitions/tool.js.map +1 -1
- package/dist/src/public/index.d.ts +2 -1
- package/dist/src/public/index.d.ts.map +1 -1
- package/dist/src/public/index.js +1 -1
- package/dist/src/public/index.js.map +1 -1
- package/dist/src/public/tools/defaults.d.ts +4 -4
- package/dist/src/public/tools/defaults.js +4 -4
- package/dist/src/runtime/connections/registry.d.ts +6 -0
- package/dist/src/runtime/connections/registry.d.ts.map +1 -1
- package/dist/src/runtime/connections/registry.js +8 -0
- package/dist/src/runtime/connections/registry.js.map +1 -1
- package/dist/src/runtime/connections/types.d.ts +2 -0
- package/dist/src/runtime/connections/types.d.ts.map +1 -1
- package/dist/src/runtime/framework-tools/connection-execute.d.ts.map +1 -1
- package/dist/src/runtime/framework-tools/connection-execute.js +17 -6
- package/dist/src/runtime/framework-tools/connection-execute.js.map +1 -1
- package/dist/src/runtime/framework-tools/connection-search.d.ts +2 -2
- package/dist/src/runtime/framework-tools/connection-search.d.ts.map +1 -1
- package/dist/src/runtime/framework-tools/connection-search.js +4 -4
- package/dist/src/runtime/framework-tools/connection-search.js.map +1 -1
- package/dist/src/runtime/framework-tools/file-state.d.ts +5 -7
- package/dist/src/runtime/framework-tools/file-state.d.ts.map +1 -1
- package/dist/src/runtime/framework-tools/file-state.js +4 -6
- package/dist/src/runtime/framework-tools/file-state.js.map +1 -1
- package/dist/src/runtime/framework-tools/skill.js +3 -3
- package/dist/src/runtime/framework-tools/skill.js.map +1 -1
- package/dist/src/runtime/framework-tools/todo.js +3 -3
- package/dist/src/runtime/framework-tools/todo.js.map +1 -1
- package/dist/src/runtime/prompt/connections.d.ts.map +1 -1
- package/dist/src/runtime/prompt/connections.js +3 -2
- package/dist/src/runtime/prompt/connections.js.map +1 -1
- package/dist/src/runtime/resolve-agent-graph.js +3 -2
- package/dist/src/runtime/resolve-agent-graph.js.map +1 -1
- package/dist/src/runtime/resolve-connection.d.ts.map +1 -1
- package/dist/src/runtime/resolve-connection.js +3 -0
- package/dist/src/runtime/resolve-connection.js.map +1 -1
- package/dist/src/runtime/sessions/auth.d.ts +1 -1
- package/dist/src/runtime/types.d.ts +13 -0
- package/dist/src/runtime/types.d.ts.map +1 -1
- package/docs/internals/context.md +257 -81
- package/docs/public/README.md +17 -19
- package/docs/public/channels/README.md +9 -3
- package/docs/public/session-context.md +95 -49
- package/docs/public/tools.md +25 -17
- package/docs/public/typescript-api.md +2 -6
- package/package.json +1 -1
- package/dist/src/context/durable-context.d.ts +0 -18
- package/dist/src/context/durable-context.d.ts.map +0 -1
- package/dist/src/context/durable-context.js +0 -49
- package/dist/src/context/durable-context.js.map +0 -1
- package/dist/src/execution/step-context.d.ts +0 -27
- package/dist/src/execution/step-context.d.ts.map +0 -1
- package/dist/src/execution/step-context.js +0 -54
- package/dist/src/execution/step-context.js.map +0 -1
- package/docs/public/migration-guide.md +0 -71
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
# Session Context
|
|
2
2
|
|
|
3
|
-
Ash exposes
|
|
3
|
+
Ash exposes runtime helpers for authored code:
|
|
4
4
|
|
|
5
5
|
- `getSession()`
|
|
6
|
-
- `getContext(key)`
|
|
7
|
-
- `setContext(key, value)`
|
|
8
|
-
- `ensureContext(key, valueOrFactory)`
|
|
9
6
|
- `getSandbox(name)`
|
|
10
7
|
- `getSkill(identifier)`
|
|
8
|
+
- `getContext(key)` — returns `T | undefined`
|
|
9
|
+
- `requireContext(key)` — returns `T`, throws if unset
|
|
10
|
+
- `hasContext(key)` — returns `boolean`
|
|
11
|
+
- `setContext(key, valueOrUpdater)` — returns `T`
|
|
12
|
+
- `ensureContext(key, factory)` — returns `T`
|
|
11
13
|
|
|
12
14
|
These APIs work only inside active authored runtime execution such as tools and other Ash-invoked
|
|
13
15
|
callbacks. Under the hood, they read from a single `AshContext` container that the framework binds
|
|
@@ -96,32 +98,11 @@ Important behavior:
|
|
|
96
98
|
|
|
97
99
|
See [`skills.md`](./skills.md) for the full authoring model.
|
|
98
100
|
|
|
99
|
-
## Durable Authored Context
|
|
100
|
-
|
|
101
|
-
`ContextKey` values are session-durable by default. Once authored code sets a key, Ash hydrates it
|
|
102
|
-
from `session.context` before later steps and commits it back after each step.
|
|
103
|
-
|
|
104
|
-
```ts
|
|
105
|
-
import { ContextKey, ensureContext, getContext, setContext } from "experimental-ash";
|
|
106
|
-
|
|
107
|
-
const TenantKey = new ContextKey<string>("myapp.tenant");
|
|
108
|
-
const NotesKey = new ContextKey<{ readonly notes: readonly string[] }>("myapp.notes");
|
|
109
|
-
|
|
110
|
-
const tenant = getContext(TenantKey);
|
|
111
|
-
const notes = ensureContext(NotesKey, () => ({ notes: [] }));
|
|
112
|
-
|
|
113
|
-
setContext(NotesKey, {
|
|
114
|
-
notes: [...notes.notes, `Handled tenant ${tenant}`],
|
|
115
|
-
});
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
Use `ensureContext` when a key needs a default value. `ContextKey({ initial })` no longer exists.
|
|
119
|
-
|
|
120
101
|
## Passing Custom Context From a Channel
|
|
121
102
|
|
|
122
|
-
Channels can inject custom typed context into the agent inside `onDeliver`. This is useful
|
|
123
|
-
channel needs to pass platform-specific metadata (tenant ID, feature flags, etc.) that
|
|
124
|
-
tools can read.
|
|
103
|
+
Channels can inject custom typed durable context into the agent inside `onDeliver`. This is useful
|
|
104
|
+
when a channel needs to pass platform-specific metadata (tenant ID, feature flags, etc.) that
|
|
105
|
+
authored tools can read on the same turn and on later turns.
|
|
125
106
|
|
|
126
107
|
### Defining a key
|
|
127
108
|
|
|
@@ -139,9 +120,8 @@ export const TenantKey = new ContextKey<string>("myapp.tenant");
|
|
|
139
120
|
### Setting context from a channel
|
|
140
121
|
|
|
141
122
|
Wrap an existing channel with `onDeliver` to set custom context keys. The hook receives a narrow
|
|
142
|
-
`ContextAccessor` (`get
|
|
143
|
-
|
|
144
|
-
durable context bag for that turn.
|
|
123
|
+
`ContextAccessor` (typed `get`/`set`) as its first argument and a `DeliverPayload` as the second. It
|
|
124
|
+
runs on both `run()` and `deliver()`.
|
|
145
125
|
|
|
146
126
|
`agent/channels/slack.ts`
|
|
147
127
|
|
|
@@ -167,8 +147,8 @@ class TenantSlackChannel extends SlackChannel<TenantSlackState> {
|
|
|
167
147
|
});
|
|
168
148
|
}
|
|
169
149
|
|
|
170
|
-
async onDeliver(ctx, payload) {
|
|
171
|
-
ctx.set(TenantKey, this.state
|
|
150
|
+
override async onDeliver(ctx, payload) {
|
|
151
|
+
ctx.set(TenantKey, this.state.tenantId);
|
|
172
152
|
return await super.onDeliver(ctx, payload);
|
|
173
153
|
}
|
|
174
154
|
}
|
|
@@ -181,30 +161,96 @@ export default slackRoute({
|
|
|
181
161
|
Auth lives on `RunInput.auth` and `DeliverInput.auth`, not on the channel object. There is no
|
|
182
162
|
`withAuth` or `withContext` wrapper.
|
|
183
163
|
|
|
184
|
-
Keep channel constructor state immutable after the run starts. Stable transport identity belongs in
|
|
185
|
-
serialized channel state; mutable per-session data belongs in durable context or `session.internal`.
|
|
186
|
-
|
|
187
164
|
### Reading context from a tool
|
|
188
165
|
|
|
189
166
|
```ts
|
|
190
|
-
import {
|
|
167
|
+
import { requireContext } from "experimental-ash";
|
|
191
168
|
import { defineTool } from "experimental-ash/tools";
|
|
192
169
|
import { TenantKey } from "../channels/keys.js";
|
|
193
170
|
|
|
194
171
|
export default defineTool({
|
|
195
172
|
description: "Return the active tenant.",
|
|
196
173
|
async execute() {
|
|
197
|
-
const tenant =
|
|
174
|
+
const tenant = requireContext(TenantKey);
|
|
198
175
|
return { tenant };
|
|
199
176
|
},
|
|
200
177
|
});
|
|
201
178
|
```
|
|
202
179
|
|
|
180
|
+
### Rebuilding virtual values with `ContextProvider`
|
|
181
|
+
|
|
182
|
+
If a channel needs to vend a live non-serializable object each step, declare a static
|
|
183
|
+
`contextProviders` array on the channel class. This must be a class field such as
|
|
184
|
+
`static readonly contextProviders = [...]`; the runtime reads providers from the channel class, not
|
|
185
|
+
from the channel instance.
|
|
186
|
+
|
|
187
|
+
For Slack subclasses, the intended pattern is:
|
|
188
|
+
|
|
189
|
+
- `onDeliver()` writes durable serializable facts such as tenant IDs, channel IDs, or installation
|
|
190
|
+
IDs.
|
|
191
|
+
- `static readonly contextProviders = [...]` derives live step-local values such as SDK clients
|
|
192
|
+
from those durable keys.
|
|
193
|
+
- tools and other authored step code read the derived value with `requireContext(...)` or
|
|
194
|
+
`getContext(...)`.
|
|
195
|
+
|
|
196
|
+
Providers run after `onDeliver()` and rebuild virtual values for the current step only, so
|
|
197
|
+
`onDeliver()` should not expect provider output to exist yet.
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import {
|
|
201
|
+
ContextKey,
|
|
202
|
+
type ContextProvider,
|
|
203
|
+
} from "experimental-ash";
|
|
204
|
+
import {
|
|
205
|
+
slackRoute,
|
|
206
|
+
SlackChannel,
|
|
207
|
+
type SlackChannelState,
|
|
208
|
+
} from "experimental-ash/channels/slack";
|
|
209
|
+
|
|
210
|
+
const TenantKey = new ContextKey<string>("myapp.tenant");
|
|
211
|
+
const SlackClientKey = new ContextKey<{ readonly tenantId: string }>("myapp.slackClient");
|
|
212
|
+
|
|
213
|
+
const slackClientProvider: ContextProvider<{ readonly tenantId: string }> = {
|
|
214
|
+
key: SlackClientKey,
|
|
215
|
+
create(ctx) {
|
|
216
|
+
return { tenantId: ctx.require(TenantKey) };
|
|
217
|
+
},
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
interface TenantSlackState extends SlackChannelState {
|
|
221
|
+
readonly tenantId: string;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
class TenantSlackChannel extends SlackChannel<TenantSlackState> {
|
|
225
|
+
static override readonly kind = "tenant-slack";
|
|
226
|
+
static readonly contextProviders = [slackClientProvider];
|
|
227
|
+
|
|
228
|
+
constructor(state: SlackChannelState) {
|
|
229
|
+
super({
|
|
230
|
+
...state,
|
|
231
|
+
tenantId: lookupTenant(state),
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
override async onDeliver(ctx, payload) {
|
|
236
|
+
ctx.set(TenantKey, this.state.tenantId);
|
|
237
|
+
return await super.onDeliver(ctx, payload);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export default slackRoute({
|
|
242
|
+
channel: TenantSlackChannel,
|
|
243
|
+
});
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Provider output is readable through `requireContext(SlackClientKey)` or
|
|
247
|
+
`getContext(SlackClientKey)` during that step, but it is not serialized.
|
|
248
|
+
|
|
203
249
|
### Context on deliver
|
|
204
250
|
|
|
205
251
|
`onDeliver` runs on every turn, including `deliver()` follow-ups. The channel is deserialized from
|
|
206
|
-
the session, so its
|
|
207
|
-
|
|
252
|
+
the session, so its state (including any custom fields like `tenantId`) is available on follow-up
|
|
253
|
+
turns.
|
|
208
254
|
|
|
209
255
|
Auth on `deliver()` is also honored — `session.auth.current` reflects the caller of each follow-up
|
|
210
256
|
message, not just the session initiator. Deliver-time auth is passed via `DeliverInput.auth` and the
|
|
@@ -229,18 +275,18 @@ explaining the required scope.
|
|
|
229
275
|
|
|
230
276
|
## How It Works
|
|
231
277
|
|
|
232
|
-
All
|
|
233
|
-
|
|
278
|
+
All three accessors read from the same `AshContext` container bound by a single `AsyncLocalStorage`.
|
|
279
|
+
The framework sets up this context before invoking authored code:
|
|
234
280
|
|
|
235
|
-
1. The runtime entry point creates an `AshContext` and
|
|
236
|
-
|
|
237
|
-
2.
|
|
238
|
-
|
|
239
|
-
|
|
281
|
+
1. The runtime entry point creates an `AshContext` and populates durable seed keys (auth, session
|
|
282
|
+
ID, channel, compiled bundle).
|
|
283
|
+
2. `onDeliver()` can write durable authored context for the turn.
|
|
284
|
+
3. Before each step, providers create virtual step-local values (session metadata, sandbox access,
|
|
285
|
+
skill access, channel-scoped live objects) from the current context.
|
|
240
286
|
4. The step callback runs inside the `AsyncLocalStorage` scope, making the context available to
|
|
241
287
|
all authored code in the call chain.
|
|
242
|
-
5. After the step,
|
|
243
|
-
|
|
288
|
+
5. After the step, framework providers with provider-owned mutable state (for example sandboxes)
|
|
289
|
+
commit those changes back onto the harness session.
|
|
244
290
|
|
|
245
291
|
This lifecycle is fully managed by the framework. Authored code only needs to call the public
|
|
246
292
|
accessors.
|
package/docs/public/tools.md
CHANGED
|
@@ -36,8 +36,8 @@ exposed to the model as `get_weather`; a file at `agent/tools/get-weather.ts` is
|
|
|
36
36
|
`get-weather`. You can override that by setting `name` in the tool definition.
|
|
37
37
|
|
|
38
38
|
`defineTool`, `disableTool`, `defineBashTool`, `defineReadFileTool`, and `defineWriteFileTool` live on the `experimental-ash/tools` subpath.
|
|
39
|
-
Runtime helpers like `getSession`, `getContext`, `
|
|
40
|
-
|
|
39
|
+
Runtime helpers like `getSession`, `getSandbox`, `getSkill`, `getContext`, `requireContext`, `hasContext`, `setContext`, and `ensureContext` stay on the
|
|
40
|
+
main `experimental-ash` barrel.
|
|
41
41
|
|
|
42
42
|
## What A Tool Definition Needs
|
|
43
43
|
|
|
@@ -106,8 +106,8 @@ execution surface by itself; executable behavior still comes from the tools the
|
|
|
106
106
|
|
|
107
107
|
`read_file` reads a text file from the sandbox filesystem with line-numbered output. `write_file`
|
|
108
108
|
writes a complete file, enforcing read-before-write for existing files and detecting stale reads.
|
|
109
|
-
Both target the framework default sandbox. Compaction clears the durable read-file
|
|
110
|
-
|
|
109
|
+
Both target the framework default sandbox. Compaction clears the durable read-file state so the model
|
|
110
|
+
must re-read files before overwriting after compaction.
|
|
111
111
|
|
|
112
112
|
Authors can wrap, replace, or disable these defaults from `agent/tools/`.
|
|
113
113
|
|
|
@@ -225,23 +225,29 @@ export default defineWriteFileTool({
|
|
|
225
225
|
```
|
|
226
226
|
|
|
227
227
|
When replacing the framework `read_file`, the authored version inherits the same compaction
|
|
228
|
-
|
|
228
|
+
state-reset behavior by default. Provide an explicit `onCompact` to override that.
|
|
229
229
|
|
|
230
230
|
### Replace A Default With Custom Context
|
|
231
231
|
|
|
232
|
-
`agent/tools/todo.ts` - replace the framework `todo` tool with a custom durable-
|
|
233
|
-
Declare your own `ContextKey
|
|
232
|
+
`agent/tools/todo.ts` - replace the framework `todo` tool with a custom durable context-backed
|
|
233
|
+
version. Declare your own `ContextKey`, initialize it with `ensureContext`, and read/write it with
|
|
234
|
+
`requireContext` / `setContext`:
|
|
234
235
|
|
|
235
236
|
```ts
|
|
236
|
-
import {
|
|
237
|
+
import {
|
|
238
|
+
ContextKey,
|
|
239
|
+
ensureContext,
|
|
240
|
+
requireContext,
|
|
241
|
+
setContext,
|
|
242
|
+
} from "experimental-ash";
|
|
237
243
|
import { defineTool } from "experimental-ash/tools";
|
|
238
244
|
import { z } from "zod";
|
|
239
245
|
|
|
240
|
-
interface
|
|
246
|
+
interface NoteListState {
|
|
241
247
|
readonly notes: readonly string[];
|
|
242
248
|
}
|
|
243
249
|
|
|
244
|
-
const
|
|
250
|
+
const NoteListStateKey = new ContextKey<NoteListState>("myapp.notes");
|
|
245
251
|
|
|
246
252
|
export default defineTool({
|
|
247
253
|
description: "Append a note or read the running list of notes.",
|
|
@@ -249,13 +255,15 @@ export default defineTool({
|
|
|
249
255
|
note: z.string().optional(),
|
|
250
256
|
}),
|
|
251
257
|
async execute(input) {
|
|
258
|
+
ensureContext(NoteListStateKey, () => ({ notes: [] }));
|
|
259
|
+
|
|
252
260
|
if (typeof input.note === "string" && input.note.length > 0) {
|
|
253
|
-
const
|
|
254
|
-
setContext(
|
|
255
|
-
notes: [...current
|
|
256
|
-
});
|
|
261
|
+
const next = input.note;
|
|
262
|
+
setContext(NoteListStateKey, (current) => ({
|
|
263
|
+
notes: [...(current?.notes ?? []), next],
|
|
264
|
+
}));
|
|
257
265
|
}
|
|
258
|
-
return
|
|
266
|
+
return requireContext(NoteListStateKey);
|
|
259
267
|
},
|
|
260
268
|
});
|
|
261
269
|
```
|
|
@@ -263,8 +271,8 @@ export default defineTool({
|
|
|
263
271
|
### Subtleties Worth Knowing
|
|
264
272
|
|
|
265
273
|
- The filename is the default name. There is also an explicit `name` property when you need it.
|
|
266
|
-
-
|
|
267
|
-
|
|
274
|
+
- Context is owned by the replacement. Replacing `todo` with a fresh `defineTool` does not inherit
|
|
275
|
+
the framework's durable context key.
|
|
268
276
|
- Authored-vs-authored collisions are impossible by construction. Two files cannot share a slug under
|
|
269
277
|
the same `agent/tools/` directory.
|
|
270
278
|
|
|
@@ -41,18 +41,16 @@ Most apps use `defineAgent`, `defineTool`, and `defineSandbox` the most.
|
|
|
41
41
|
## Runtime Helpers
|
|
42
42
|
|
|
43
43
|
- `getSession()` - current session, turn, auth, and optional parent lineage
|
|
44
|
-
- `getContext(key)` - read one durable authored context value
|
|
45
|
-
- `setContext(key, value)` - write one durable authored context value
|
|
46
|
-
- `ensureContext(key, valueOrFactory)` - read-or-create one durable context value
|
|
47
44
|
- `getSandbox(name)` - live named sandbox session
|
|
48
45
|
- `getSkill(identifier)` - handle for a named skill visible to the current agent
|
|
46
|
+
- `getContext(key)` / `requireContext(key)` / `hasContext(key)` / `setContext(key)` / `ensureContext(key, factory)` - unified context helpers
|
|
49
47
|
|
|
50
48
|
Related exported types:
|
|
51
49
|
|
|
52
50
|
- `Session`, `SessionAuth`, `SessionAuthContext`, `SessionParent`, `SessionTurn`
|
|
53
51
|
- `SkillHandle`, `SkillResource`
|
|
54
52
|
- `RunMode`
|
|
55
|
-
- `ContextKey`, `ContextKeyOptions`, `AshContext`
|
|
53
|
+
- `ContextKey`, `ContextKeyOptions`, `ContextProvider`, `ContextReader`, `AshContext`
|
|
56
54
|
- eval types from `experimental-ash/evals`
|
|
57
55
|
|
|
58
56
|
Ash also exports lower-level runtime primitives such as `createToolLoopHarness(...)`,
|
|
@@ -63,8 +61,6 @@ sessions must finish inside the current invocation.
|
|
|
63
61
|
|
|
64
62
|
These helpers only work inside active authored runtime execution.
|
|
65
63
|
|
|
66
|
-
Breaking change details and before/after examples live in [`migration-guide.md`](./migration-guide.md).
|
|
67
|
-
|
|
68
64
|
## Markdown Helpers
|
|
69
65
|
|
|
70
66
|
Ash also exports helpers for turning markdown into the same shapes as module-authored definitions:
|
package/package.json
CHANGED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import type { HarnessSession } from "../harness/types.js";
|
|
2
|
-
import type { AshContext } from "./container.js";
|
|
3
|
-
/**
|
|
4
|
-
* Hydrates all durable context values from `session.context`.
|
|
5
|
-
*
|
|
6
|
-
* Unknown keys are ignored. Keys without a persisted value remain absent until
|
|
7
|
-
* authored code or a channel explicitly sets or ensures them.
|
|
8
|
-
*/
|
|
9
|
-
export declare function hydrateDurableContext(ctx: AshContext, session: HarnessSession): Promise<void>;
|
|
10
|
-
/**
|
|
11
|
-
* Serializes all durable context values currently set on the context.
|
|
12
|
-
*/
|
|
13
|
-
export declare function serializeDurableContext(ctx: AshContext): Record<string, unknown>;
|
|
14
|
-
/**
|
|
15
|
-
* Commits the full durable context bag back to `session.context`.
|
|
16
|
-
*/
|
|
17
|
-
export declare function commitDurableContext(ctx: AshContext, session: HarnessSession): HarnessSession;
|
|
18
|
-
//# sourceMappingURL=durable-context.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"durable-context.d.ts","sourceRoot":"","sources":["../../../src/context/durable-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAC1D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGjD;;;;;GAKG;AACH,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,UAAU,EACf,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAYhF;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,UAAU,EAAE,OAAO,EAAE,cAAc,GAAG,cAAc,CAY7F"}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { isDeepStrictEqual } from "node:util";
|
|
2
|
-
import { isDurableContextKey, resolveContextKey } from "./key.js";
|
|
3
|
-
/**
|
|
4
|
-
* Hydrates all durable context values from `session.context`.
|
|
5
|
-
*
|
|
6
|
-
* Unknown keys are ignored. Keys without a persisted value remain absent until
|
|
7
|
-
* authored code or a channel explicitly sets or ensures them.
|
|
8
|
-
*/
|
|
9
|
-
export async function hydrateDurableContext(ctx, session) {
|
|
10
|
-
const data = session.context ?? {};
|
|
11
|
-
for (const [name, raw] of Object.entries(data)) {
|
|
12
|
-
if (raw === undefined) {
|
|
13
|
-
continue;
|
|
14
|
-
}
|
|
15
|
-
const key = resolveContextKey(name);
|
|
16
|
-
if (key === undefined) {
|
|
17
|
-
continue;
|
|
18
|
-
}
|
|
19
|
-
ctx.set(key, key.codec ? await key.codec.deserialize(raw, ctx) : raw);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Serializes all durable context values currently set on the context.
|
|
24
|
-
*/
|
|
25
|
-
export function serializeDurableContext(ctx) {
|
|
26
|
-
const data = {};
|
|
27
|
-
for (const [key, value] of ctx.entries()) {
|
|
28
|
-
if (!isDurableContextKey(key) || value === undefined) {
|
|
29
|
-
continue;
|
|
30
|
-
}
|
|
31
|
-
data[key.name] = key.codec ? key.codec.serialize(value) : value;
|
|
32
|
-
}
|
|
33
|
-
return data;
|
|
34
|
-
}
|
|
35
|
-
/**
|
|
36
|
-
* Commits the full durable context bag back to `session.context`.
|
|
37
|
-
*/
|
|
38
|
-
export function commitDurableContext(ctx, session) {
|
|
39
|
-
const nextContext = serializeDurableContext(ctx);
|
|
40
|
-
const currentContext = session.context ?? {};
|
|
41
|
-
if (isDeepStrictEqual(nextContext, currentContext)) {
|
|
42
|
-
return session;
|
|
43
|
-
}
|
|
44
|
-
return {
|
|
45
|
-
...session,
|
|
46
|
-
context: Object.keys(nextContext).length > 0 ? nextContext : undefined,
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
//# sourceMappingURL=durable-context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"durable-context.js","sourceRoot":"","sources":["../../../src/context/durable-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAI9C,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAElE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,GAAe,EACf,OAAuB;IAEvB,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAEnC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/C,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;YACtB,SAAS;QACX,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxE,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,uBAAuB,CAAC,GAAe;IACrD,MAAM,IAAI,GAA4B,EAAE,CAAC;IAEzC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;QACzC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACrD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;IAClE,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAe,EAAE,OAAuB;IAC3E,MAAM,WAAW,GAAG,uBAAuB,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,cAAc,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;IAE7C,IAAI,iBAAiB,CAAC,WAAW,EAAE,cAAc,CAAC,EAAE,CAAC;QACnD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,OAAO;QACL,GAAG,OAAO;QACV,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;KACvE,CAAC;AACJ,CAAC"}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import type { Channel, DeliverPayload, SessionAuthContext } from "../channel/types.js";
|
|
2
|
-
import type { AshContext } from "../context/container.js";
|
|
3
|
-
import type { HarnessSession, StepInput, StepResult } from "../harness/types.js";
|
|
4
|
-
export interface StepDeliveryInput {
|
|
5
|
-
readonly auth?: SessionAuthContext | null;
|
|
6
|
-
readonly payload: DeliverPayload;
|
|
7
|
-
}
|
|
8
|
-
export interface PreparedStepContext {
|
|
9
|
-
readonly channel: Channel;
|
|
10
|
-
readonly channelStateSnapshot: Record<string, unknown>;
|
|
11
|
-
readonly ctx: AshContext;
|
|
12
|
-
readonly input: StepInput | undefined;
|
|
13
|
-
}
|
|
14
|
-
export declare function prepareStepContext(input: {
|
|
15
|
-
readonly delivery?: StepDeliveryInput;
|
|
16
|
-
readonly serializedRuntimeContext: Record<string, unknown>;
|
|
17
|
-
readonly session: HarnessSession;
|
|
18
|
-
}): Promise<PreparedStepContext>;
|
|
19
|
-
/**
|
|
20
|
-
* Runs one step inside the provider lifecycle and asserts that the
|
|
21
|
-
* channel's serialized state was not mutated during execution.
|
|
22
|
-
*
|
|
23
|
-
* Combines {@link runStep} with a post-step channel stability check so
|
|
24
|
-
* callers do not need to repeat the three-call sequence themselves.
|
|
25
|
-
*/
|
|
26
|
-
export declare function runStepWithChannelGuard(prepared: PreparedStepContext, session: HarnessSession, callback: (session: HarnessSession) => Promise<StepResult>): Promise<StepResult>;
|
|
27
|
-
//# sourceMappingURL=step-context.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"step-context.d.ts","sourceRoot":"","sources":["../../../src/execution/step-context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAM1D,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEjF,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,IAAI,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CAClC;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvD,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,SAAS,CAAC;CACvC;AAED,wBAAsB,kBAAkB,CAAC,KAAK,EAAE;IAC9C,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IACtC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC3D,QAAQ,CAAC,OAAO,EAAE,cAAc,CAAC;CAClC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CA0B/B;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAC3C,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,cAAc,EACvB,QAAQ,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,OAAO,CAAC,UAAU,CAAC,GACzD,OAAO,CAAC,UAAU,CAAC,CAQrB"}
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { isDeepStrictEqual } from "node:util";
|
|
2
|
-
import { hydrateDurableContext } from "../context/durable-context.js";
|
|
3
|
-
import { AuthKey, ChannelKey } from "../context/keys.js";
|
|
4
|
-
import { runStep } from "../context/run-step.js";
|
|
5
|
-
import { deserializeRuntimeContext } from "../context/serialize.js";
|
|
6
|
-
import { seedPendingInputRequestsContext } from "../harness/input-requests.js";
|
|
7
|
-
export async function prepareStepContext(input) {
|
|
8
|
-
const ctx = await deserializeRuntimeContext(input.serializedRuntimeContext);
|
|
9
|
-
await hydrateDurableContext(ctx, input.session);
|
|
10
|
-
seedPendingInputRequestsContext(ctx, input.session);
|
|
11
|
-
if (input.delivery?.auth !== undefined) {
|
|
12
|
-
ctx.set(AuthKey, input.delivery.auth ?? null);
|
|
13
|
-
}
|
|
14
|
-
const channel = ctx.get(ChannelKey);
|
|
15
|
-
const channelStateSnapshot = channel.serialize();
|
|
16
|
-
const resolved = input.delivery !== undefined ? await channel.onDeliver(ctx, input.delivery.payload) : undefined;
|
|
17
|
-
assertChannelStateIsStable({
|
|
18
|
-
channel,
|
|
19
|
-
phase: "onDeliver",
|
|
20
|
-
serializedState: channelStateSnapshot,
|
|
21
|
-
});
|
|
22
|
-
return {
|
|
23
|
-
channel,
|
|
24
|
-
channelStateSnapshot,
|
|
25
|
-
ctx,
|
|
26
|
-
input: resolved,
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
/**
|
|
30
|
-
* Runs one step inside the provider lifecycle and asserts that the
|
|
31
|
-
* channel's serialized state was not mutated during execution.
|
|
32
|
-
*
|
|
33
|
-
* Combines {@link runStep} with a post-step channel stability check so
|
|
34
|
-
* callers do not need to repeat the three-call sequence themselves.
|
|
35
|
-
*/
|
|
36
|
-
export async function runStepWithChannelGuard(prepared, session, callback) {
|
|
37
|
-
const stepResult = await runStep(prepared.ctx, session, callback);
|
|
38
|
-
assertChannelStateIsStable({
|
|
39
|
-
channel: prepared.channel,
|
|
40
|
-
phase: "step execution",
|
|
41
|
-
serializedState: prepared.channelStateSnapshot,
|
|
42
|
-
});
|
|
43
|
-
return stepResult;
|
|
44
|
-
}
|
|
45
|
-
function assertChannelStateIsStable(input) {
|
|
46
|
-
const currentState = input.channel.serialize();
|
|
47
|
-
if (isDeepStrictEqual(currentState, input.serializedState)) {
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
throw new Error(`Channel "${input.channel.kind}" mutated its serialized state during ${input.phase}. ` +
|
|
51
|
-
"Channel constructor state must stay immutable after the run starts. " +
|
|
52
|
-
"Move per-session mutable data into durable context or session.internal instead.");
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=step-context.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"step-context.js","sourceRoot":"","sources":["../../../src/execution/step-context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAI9C,OAAO,EAAE,qBAAqB,EAAE,MAAM,+BAA+B,CAAC;AACtE,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,+BAA+B,EAAE,MAAM,8BAA8B,CAAC;AAe/E,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,KAIxC;IACC,MAAM,GAAG,GAAG,MAAM,yBAAyB,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;IAC5E,MAAM,qBAAqB,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAChD,+BAA+B,CAAC,GAAG,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC;IAEpD,IAAI,KAAK,CAAC,QAAQ,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;QACvC,GAAG,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACpC,MAAM,oBAAoB,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;IACjD,MAAM,QAAQ,GACZ,KAAK,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,OAAO,CAAC,SAAS,CAAC,GAAG,EAAE,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAElG,0BAA0B,CAAC;QACzB,OAAO;QACP,KAAK,EAAE,WAAW;QAClB,eAAe,EAAE,oBAAoB;KACtC,CAAC,CAAC;IAEH,OAAO;QACL,OAAO;QACP,oBAAoB;QACpB,GAAG;QACH,KAAK,EAAE,QAAQ;KAChB,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAC3C,QAA6B,EAC7B,OAAuB,EACvB,QAA0D;IAE1D,MAAM,UAAU,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC;IAClE,0BAA0B,CAAC;QACzB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,KAAK,EAAE,gBAAgB;QACvB,eAAe,EAAE,QAAQ,CAAC,oBAAoB;KAC/C,CAAC,CAAC;IACH,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,0BAA0B,CAAC,KAInC;IACC,MAAM,YAAY,GAAG,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;IAC/C,IAAI,iBAAiB,CAAC,YAAY,EAAE,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC;QAC3D,OAAO;IACT,CAAC;IAED,MAAM,IAAI,KAAK,CACb,YAAY,KAAK,CAAC,OAAO,CAAC,IAAI,yCAAyC,KAAK,CAAC,KAAK,IAAI;QACpF,sEAAsE;QACtE,iFAAiF,CACpF,CAAC;AACJ,CAAC"}
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
# Migration Guide
|
|
2
|
-
|
|
3
|
-
Ash now has one durable authored-context model.
|
|
4
|
-
|
|
5
|
-
## Breaking Changes
|
|
6
|
-
|
|
7
|
-
- `getState(key)` is now `getContext(key)`.
|
|
8
|
-
- `setState(key, value)` is now `setContext(key, value)`.
|
|
9
|
-
- `ensureContext(key, valueOrFactory)` replaces `ContextKey({ initial })`.
|
|
10
|
-
- `ContextKeyOptions.initial` was removed.
|
|
11
|
-
- Public `ContextKey` values are session-durable by default.
|
|
12
|
-
- `HarnessSession.state` is now split into `session.context` and internal `session.internal`.
|
|
13
|
-
- Tool compaction hooks no longer return `sessionPatch`. Mutate durable context through `ctx` instead.
|
|
14
|
-
|
|
15
|
-
## Before
|
|
16
|
-
|
|
17
|
-
```ts
|
|
18
|
-
import { ContextKey, getState, setState } from "experimental-ash";
|
|
19
|
-
|
|
20
|
-
const NotesKey = new ContextKey("myapp.notes", {
|
|
21
|
-
initial: () => ({ notes: [] }),
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
setState(NotesKey, (current) => ({
|
|
25
|
-
notes: [...current.notes, "hello"],
|
|
26
|
-
}));
|
|
27
|
-
|
|
28
|
-
return getState(NotesKey);
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
## After
|
|
32
|
-
|
|
33
|
-
```ts
|
|
34
|
-
import { ContextKey, ensureContext, getContext, setContext } from "experimental-ash";
|
|
35
|
-
|
|
36
|
-
const NotesKey = new ContextKey("myapp.notes");
|
|
37
|
-
|
|
38
|
-
const current = ensureContext(NotesKey, () => ({ notes: [] }));
|
|
39
|
-
|
|
40
|
-
setContext(NotesKey, {
|
|
41
|
-
notes: [...current.notes, "hello"],
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
return getContext(NotesKey);
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Channel Guidance
|
|
48
|
-
|
|
49
|
-
- Use `channel.onDeliver(ctx, payload)` to seed or extend durable context on every turn.
|
|
50
|
-
- Treat serialized channel state as immutable after the run starts.
|
|
51
|
-
- Move mutable per-session data into durable context or `session.internal`, not onto the channel instance.
|
|
52
|
-
|
|
53
|
-
## Compaction Hooks
|
|
54
|
-
|
|
55
|
-
Before:
|
|
56
|
-
|
|
57
|
-
```ts
|
|
58
|
-
onCompact() {
|
|
59
|
-
return {
|
|
60
|
-
sessionPatch: { state: {} },
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
After:
|
|
66
|
-
|
|
67
|
-
```ts
|
|
68
|
-
onCompact({ ctx }) {
|
|
69
|
-
ctx.set(NotesKey, { notes: [] });
|
|
70
|
-
}
|
|
71
|
-
```
|