experimental-ash 0.40.1 → 0.42.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/docs/internals/hooks.md +53 -11
  3. package/dist/docs/public/advanced/hooks.md +9 -6
  4. package/dist/docs/public/tools.md +176 -0
  5. package/dist/src/compiler/manifest.d.ts +16 -2
  6. package/dist/src/compiler/manifest.js +1 -1
  7. package/dist/src/compiler/module-map.js +1 -1
  8. package/dist/src/compiler/normalize-agent-config.js +1 -1
  9. package/dist/src/compiler/normalize-manifest.js +1 -1
  10. package/dist/src/compiler/normalize-tool.d.ts +7 -3
  11. package/dist/src/compiler/normalize-tool.js +1 -1
  12. package/dist/src/context/dynamic-tool-lifecycle.d.ts +29 -0
  13. package/dist/src/context/dynamic-tool-lifecycle.js +1 -0
  14. package/dist/src/context/hook-lifecycle.js +1 -1
  15. package/dist/src/context/keys.d.ts +36 -0
  16. package/dist/src/context/keys.js +1 -1
  17. package/dist/src/context/providers/sandbox.js +1 -1
  18. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  19. package/dist/src/execution/node-step.d.ts +2 -2
  20. package/dist/src/execution/node-step.js +1 -1
  21. package/dist/src/execution/workflow-steps.js +1 -1
  22. package/dist/src/harness/attachment-staging.js +1 -1
  23. package/dist/src/harness/code-mode.d.ts +1 -1
  24. package/dist/src/harness/code-mode.js +1 -1
  25. package/dist/src/harness/tool-loop.js +1 -1
  26. package/dist/src/harness/types.d.ts +17 -1
  27. package/dist/src/internal/application/package.js +1 -1
  28. package/dist/src/internal/authored-definition/core.js +1 -1
  29. package/dist/src/internal/authored-definition/schema-backed.d.ts +9 -3
  30. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  31. package/dist/src/internal/authored-module.d.ts +4 -0
  32. package/dist/src/internal/authored-module.js +1 -1
  33. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  34. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.d.ts +39 -0
  35. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +4 -0
  36. package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
  37. package/dist/src/public/definitions/agent.d.ts +1 -1
  38. package/dist/src/public/definitions/defineChannel.js +1 -1
  39. package/dist/src/public/definitions/tool.d.ts +67 -0
  40. package/dist/src/public/definitions/tool.js +1 -1
  41. package/dist/src/public/index.d.ts +1 -1
  42. package/dist/src/public/tools/index.d.ts +2 -1
  43. package/dist/src/public/tools/index.js +1 -1
  44. package/dist/src/runtime/framework-tools/connection-search.js +1 -1
  45. package/dist/src/runtime/framework-tools/connection-tools.js +1 -1
  46. package/dist/src/runtime/resolve-agent-graph.js +1 -1
  47. package/dist/src/runtime/resolve-agent.js +1 -1
  48. package/dist/src/runtime/resolve-dynamic-tool.d.ts +12 -0
  49. package/dist/src/runtime/resolve-dynamic-tool.js +1 -0
  50. package/dist/src/runtime/types.d.ts +12 -0
  51. package/dist/src/shared/agent-definition.d.ts +25 -0
  52. package/dist/src/shared/code-mode.d.ts +14 -1
  53. package/dist/src/shared/code-mode.js +1 -1
  54. package/dist/src/shared/dynamic-tool-definition.d.ts +134 -0
  55. package/dist/src/shared/dynamic-tool-definition.js +1 -0
  56. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # experimental-ash
2
2
 
3
+ ## 0.42.0
4
+
5
+ ### Minor Changes
6
+
7
+ - edce3c9: Unified event dispatch: single `handleEvent` pipeline for all event-based handlers (channels, hooks, dynamic tools). Dynamic tool entries now require the `tool()` wrapper — the bundler transform only matches `execute` inside `tool()` calls.
8
+
9
+ ## 0.41.0
10
+
11
+ ### Minor Changes
12
+
13
+ - d4dd396: Move code mode from the `CODE_MODE` environment variable to a per-agent
14
+ `experimental.codeMode` flag on `defineAgent({ experimental: { codeMode: true } })`.
15
+ Each agent and subagent can now opt in independently. For backwards
16
+ compatibility, agents that omit the flag fall back to the
17
+ `ASH_EXPERIMENTAL_CODE_MODE` environment variable (`"1"` enables it); the
18
+ previous `CODE_MODE` variable is no longer read.
19
+ - 09beab5: Add `defineTools` and `defineTool` dynamic overloads for runtime tool resolution.
20
+
21
+ Tools can now be resolved dynamically at runtime based on session context via `defineTools({ events: { "session.started": handler } })` and `defineTool({ events: { "session.started": handler } })`. Session-scoped resolvers run once and are cached; step-scoped resolvers re-resolve before every model call. Dynamic tools appear in the model's tool list identically to static tools.
22
+
3
23
  ## 0.40.1
4
24
 
5
25
  ### Patch Changes
@@ -124,13 +124,35 @@ itself throws while the dispatcher is emitting the recoverable
124
124
  `session.failed` instead. This is the bounded second-order behavior
125
125
  when both a `lifecycle.turn` and a `turn.failed` event hook fail.
126
126
 
127
- Stream-event dispatch is `dispatchStreamEventHooks`, called from each
128
- runtime's `HarnessEmitFn` composer **after** the channel adapter's
129
- event handler runs. The dispatcher reads the typed bucket
127
+ ### Stream event dispatch (`handleEvent`)
128
+
129
+ Every stream event passes through one `handleEvent` function
130
+ (`execution/workflow-steps.ts`) that coordinates three stages:
131
+
132
+ ```
133
+ handleEvent(event):
134
+ 1. emit(event) — channel adapter handler + durable stream write
135
+ 2. dispatchStreamEventHooks — typed bucket, then wildcard bucket
136
+ 3. dispatchDynamicToolEvent — resolvers subscribed to event.type
137
+ ```
138
+
139
+ `emit` handles the channel adapter's event handler (can mutate
140
+ adapter state, can transform the event) and writes the (possibly
141
+ transformed) event to the durable stream. The durable record is
142
+ consistent with what was written even if a downstream handler throws.
143
+
144
+ `dispatchStreamEventHooks` reads the typed bucket
130
145
  (`registry.streamEventsByType.get(eventType)`) followed by the flat
131
- wildcard bucket (`registry.streamEventsWildcard`); thrown errors
132
- propagate through the emit composer. The existing harness error path
133
- catches them and emits the recoverable `turn.failed` cascade.
146
+ wildcard bucket (`registry.streamEventsWildcard`). Thrown errors
147
+ propagate through the handler; the existing harness error path catches
148
+ them and emits the recoverable `turn.failed` cascade.
149
+
150
+ `dispatchDynamicToolEvent` (`context/dynamic-tool-lifecycle.ts`) runs
151
+ dynamic tool resolvers subscribed to the event type and merges
152
+ resolved tools into `DynamicToolsKey`. The tool-loop reads this key
153
+ right before each model call. See the [event dispatch
154
+ doc](../../research/active/unified-event-dispatch.md) for the full
155
+ design.
134
156
 
135
157
  ## `SessionPreparedKey`
136
158
 
@@ -162,11 +184,31 @@ The `discover/discover-subagent.ts` path walks each local subagent's
162
184
  | `lifecycle.turn` | Caught by dispatcher → recoverable `turn.failed` cascade emitted |
163
185
  | Stream-event hooks | Propagated through the emit composer → existing harness error path emits `turn.failed` |
164
186
 
165
- The contract with `HarnessEmitFn`: the wrapped emit fn calls the
166
- channel adapter's event handler first, writes the (possibly
167
- transformed) event to the durable stream, **then** fans out to authored
168
- stream-event hook subscribers. The durable record is consistent with
169
- what was written even if a downstream hook throws.
187
+ ### Full per-turn execution order
188
+
189
+ ```
190
+ dispatchHookLifecycle():
191
+ lifecycle.session hooks (once per session, produce modelContext)
192
+ lifecycle.turn hooks (once per turn, produce modelContext)
193
+
194
+ emitTurnPreamble() via handleEvent:
195
+ handleEvent(session.started) → emit, hooks, dynamic tool resolvers
196
+ handleEvent(turn.started) → emit, hooks, dynamic tool resolvers
197
+ handleEvent(message.received) → emit, hooks
198
+
199
+ emitStepStarted() via handleEvent:
200
+ handleEvent(step.started) → emit, hooks, dynamic tool resolvers
201
+
202
+ runOneModelCall():
203
+ read DynamicToolsKey (current tools from all prior events)
204
+ build effective toolset (static + dynamic + connections)
205
+ model.stream()
206
+
207
+ emitStepActions() via handleEvent:
208
+ handleEvent(actions.requested) → emit, hooks, dynamic tool resolvers
209
+ handleEvent(action.result) × N → emit, hooks, dynamic tool resolvers
210
+ handleEvent(step.completed) → emit, hooks
211
+ ```
170
212
 
171
213
  ## Testing Strategy
172
214
 
@@ -229,7 +229,7 @@ export default defineHook({
229
229
  The session contribution lands in `modelContext` for the **first** model
230
230
  call only. Subsequent turns proceed without it.
231
231
 
232
- ## Stream events
232
+ ## Stream Events
233
233
 
234
234
  Side-effect-only handlers for accepted runtime events. Subscribe by
235
235
  event type, or use `*` for every event:
@@ -255,12 +255,15 @@ export default defineHook({
255
255
  });
256
256
  ```
257
257
 
258
- Composition:
258
+ ### Execution order
259
259
 
260
- - Stream-event hooks run **after** Ash has accepted the event and
261
- written it to the durable stream.
262
- - Return values are ignored.
263
- - Typed event hooks run **before** `*` for the same event.
260
+ When a stream event fires, three things happen in order:
261
+
262
+ 1. **Emit** the channel adapter handler runs, then the event is written to the durable stream.
263
+ 2. **Hooks** — stream event hooks fire (typed handlers first, then `*` wildcard). Return values are ignored.
264
+ 3. **Dynamic tool resolvers** — resolvers subscribed to the event type run and update the tool set.
265
+
266
+ Hooks always run **after** the event is durably recorded — if a hook throws, the stream is consistent.
264
267
 
265
268
  ## Errors
266
269
 
@@ -368,6 +368,182 @@ full API.
368
368
  Note: `retentionPolicy` and `onCompact` operate on the projected output (what the model sees),
369
369
  not the full `execute` return.
370
370
 
371
+ ## Dynamic Tools
372
+
373
+ Dynamic tools resolve at runtime based on session context — tenant configuration, feature flags, user roles, or external data. Use `defineTools` with an `events` object to produce tools dynamically.
374
+
375
+ ### Single Dynamic Tool
376
+
377
+ `agent/tools/analytics.ts`
378
+
379
+ ```ts
380
+ import { defineTool, tool } from "experimental-ash/tools";
381
+ import { z } from "zod";
382
+
383
+ export default defineTool({
384
+ events: {
385
+ "session.started": async (event, ctx) => {
386
+ const flags = await fetchFeatureFlags(ctx.session.id);
387
+ if (!flags.advancedAnalytics) return null;
388
+
389
+ return tool({
390
+ description: "Run an advanced analytics query.",
391
+ inputSchema: z.object({ query: z.string() }),
392
+ async execute(input) {
393
+ return runAnalytics(input.query);
394
+ },
395
+ });
396
+ },
397
+ },
398
+ });
399
+ ```
400
+
401
+ Return `null` to produce no tool. The tool name is the file slug (`analytics`), identical to a static `defineTool`. Entries must be wrapped with `tool()` — this stamps the entry for the bundler transform so `execute` functions survive workflow step boundaries.
402
+
403
+ ### Multiple Dynamic Tools
404
+
405
+ `agent/tools/tenant.ts`
406
+
407
+ ```ts
408
+ import { defineTools, tool } from "experimental-ash/tools";
409
+ import { z } from "zod";
410
+
411
+ export default defineTools({
412
+ events: {
413
+ "session.started": async (event, ctx) => {
414
+ const tenant = await fetchTenant(ctx.session.id);
415
+ if (!tenant) return null;
416
+
417
+ return {
418
+ export: tool({
419
+ description: `Export ${tenant.name} data`,
420
+ inputSchema: z.object({ format: z.enum(["csv", "json"]) }),
421
+ async execute(input) {
422
+ // input.format is typed as "csv" | "json"
423
+ return callTenantApi(tenant.apiUrl, "export", input.format);
424
+ },
425
+ }),
426
+ query: tool({
427
+ description: `Query ${tenant.name} data`,
428
+ inputSchema: z.object({ sql: z.string() }),
429
+ async execute(input) {
430
+ // input.sql is typed as string
431
+ return callTenantApi(tenant.apiUrl, "query", input.sql);
432
+ },
433
+ }),
434
+ };
435
+ },
436
+ },
437
+ });
438
+ ```
439
+
440
+ Each entry must be wrapped with `tool()` — it captures the schema type so `execute(input)` is inferred from `inputSchema`, matching the AI SDK's `tool()` pattern.
441
+
442
+ ### Tool Naming
443
+
444
+ Dynamic tool names are derived from the file path and the definition function:
445
+
446
+ | Definition | File | Entry keys | Tool name(s) |
447
+ | ------------- | -------------------------- | ----------------- | --------------------------------- |
448
+ | `defineTool` | `agent/tools/analytics.ts` | _(single entry)_ | `analytics` |
449
+ | `defineTools` | `agent/tools/tenant.ts` | `export`, `query` | `tenant__export`, `tenant__query` |
450
+ | `defineTools` | `agent/tools/search.ts` | `run` | `search__run` |
451
+
452
+ `defineTool` always produces one tool named after the file slug — identical to static tools. `defineTools` always uses `slug__key`, even when the resolver returns a single entry. This keeps names stable: adding a second entry to a `defineTools` file does not rename the first.
453
+
454
+ ### Events
455
+
456
+ The `events` object supports three event types:
457
+
458
+ | Event | When the resolver runs | Tools available for |
459
+ | ----------------- | ---------------------- | ------------------------------- |
460
+ | `session.started` | Once per session | Every model call in the session |
461
+ | `turn.started` | Once per turn | Every model call in the turn |
462
+ | `step.started` | Before each model call | That model call |
463
+
464
+ The bundler transform ensures resolvers survive workflow step boundaries — subsequent steps reconstruct execute functions from stored closure variables without re-running the resolver. Resolvers run concurrently — if multiple dynamic tool files declare the same event, their I/O overlaps.
465
+
466
+ ### Execution Order
467
+
468
+ When a stream event fires, three things happen in order:
469
+
470
+ 1. **Emit** — the channel adapter handler runs (can transform the event), then the event is written to the durable stream.
471
+ 2. **Hooks** — stream event hooks fire (typed handlers first, then `*` wildcard).
472
+ 3. **Dynamic tool resolvers** — resolvers subscribed to the event type run and update the tool set.
473
+
474
+ The tool-loop reads the current tool set right before each model call. If an event updated tools since the last read, the model sees the updated set.
475
+
476
+ ### Multiple Events
477
+
478
+ A single file can declare handlers for multiple events. The result of the most recently fired handler owns the tool set for that file:
479
+
480
+ ```ts
481
+ import { defineTools, tool } from "experimental-ash/tools";
482
+
483
+ export default defineTools({
484
+ events: {
485
+ "session.started": async (event, ctx) => {
486
+ return { query: tool({ description: "Query", inputSchema: {}, execute: async () => {} }) };
487
+ },
488
+ "turn.started": async (event, ctx) => {
489
+ // On each turn, re-resolve tools. Replaces this file's
490
+ // session.started tools for subsequent calls.
491
+ return { search: tool({ description: "Search", inputSchema: {}, execute: async () => {} }) };
492
+ },
493
+ },
494
+ });
495
+ ```
496
+
497
+ ### Type Inference
498
+
499
+ `inputSchema` accepts Zod, Standard Schema, or plain JSON Schema — same as static `defineTool`. When using Zod, the `tool()` wrapper infers the `execute` input type automatically:
500
+
501
+ ```ts
502
+ return {
503
+ query: tool({
504
+ inputSchema: z.object({ city: z.string() }),
505
+ async execute(input) {
506
+ // input.city is typed as string
507
+ return fetchWeather(input.city);
508
+ },
509
+ }),
510
+ };
511
+ ```
512
+
513
+ The `execute` signature matches static tools: `execute(input: TInput, ctx: ToolContext)`.
514
+
515
+ ### Helper Functions
516
+
517
+ `execute` can live inside helper functions, `.map()` callbacks, or IIFEs — the bundler transform follows nested scopes and captures all referenced variables:
518
+
519
+ ```ts
520
+ import { defineTools, tool } from "experimental-ash/tools";
521
+ import { z } from "zod";
522
+
523
+ export default defineTools({
524
+ events: {
525
+ "session.started": async (event, ctx) => {
526
+ const tenant = await fetchTenant(ctx.session.id);
527
+
528
+ function buildTool(action: string) {
529
+ const endpoint = `${tenant.apiUrl}/${action}`;
530
+ return tool({
531
+ description: `${action} for ${tenant.name}`,
532
+ inputSchema: z.object({ query: z.string() }),
533
+ async execute(input) {
534
+ return callApi(endpoint, input.query);
535
+ },
536
+ });
537
+ }
538
+
539
+ return { query: buildTool("query"), export: buildTool("export") };
540
+ },
541
+ },
542
+ });
543
+ ```
544
+
545
+ **Limitation:** `execute` must be an inline function — a function expression, arrow function, or method shorthand written directly as the property value. Assigning a variable (`execute: myFn`) or a call result (`execute: makeFn()`) is not detected by the transform; the tool will work on the first workflow step but will not survive replay across step boundaries.
546
+
371
547
  ## What To Read Next
372
548
 
373
549
  - [Session Context](./session-context.md)
@@ -18,7 +18,7 @@ export declare const ROOT_COMPILED_AGENT_NODE_ID = "__root__";
18
18
  /**
19
19
  * Current compiled manifest schema version.
20
20
  */
21
- export declare const COMPILED_AGENT_MANIFEST_VERSION = 24;
21
+ export declare const COMPILED_AGENT_MANIFEST_VERSION = 25;
22
22
  /**
23
23
  * Compiled channel entry preserved in the compiled manifest.
24
24
  */
@@ -100,6 +100,16 @@ export type CompiledConnectionDefinition = z.infer<typeof compiledConnectionDefi
100
100
  * Normalized authored tool metadata preserved in the compiled manifest.
101
101
  */
102
102
  export type CompiledToolDefinition = InternalToolDefinition & ModuleSourceRef;
103
+ /**
104
+ * Compiled dynamic tool resolver entry. The resolver function lives in the
105
+ * compiled module map; the manifest entry carries only the metadata needed
106
+ * to load and invoke it at runtime.
107
+ */
108
+ export interface CompiledDynamicToolDefinition extends ModuleSourceRef {
109
+ readonly slug: string;
110
+ readonly identity: "single" | "multi";
111
+ readonly eventNames: readonly string[];
112
+ }
103
113
  /**
104
114
  * Normalized authored hook entry preserved in the compiled manifest.
105
115
  *
@@ -213,6 +223,7 @@ declare const compiledAgentNodeManifestSchema: z.ZodObject<{
213
223
  warnings: z.ZodNumber;
214
224
  }, z.core.$strict>;
215
225
  disabledFrameworkTools: z.ZodReadonly<z.ZodArray<z.ZodString>>;
226
+ dynamicTools: z.ZodDefault<z.ZodArray<z.ZodType<CompiledDynamicToolDefinition, unknown, z.core.$ZodTypeInternals<CompiledDynamicToolDefinition, unknown>>>>;
216
227
  hooks: z.ZodArray<z.ZodType<CompiledHookDefinition, unknown, z.core.$ZodTypeInternals<CompiledHookDefinition, unknown>>>;
217
228
  sandbox: z.ZodNullable<z.ZodObject<{
218
229
  description: z.ZodOptional<z.ZodString>;
@@ -298,6 +309,7 @@ export declare const compiledAgentManifestSchema: z.ZodObject<{
298
309
  warnings: z.ZodNumber;
299
310
  }, z.core.$strict>;
300
311
  disabledFrameworkTools: z.ZodReadonly<z.ZodArray<z.ZodString>>;
312
+ dynamicTools: z.ZodDefault<z.ZodArray<z.ZodType<CompiledDynamicToolDefinition, unknown, z.core.$ZodTypeInternals<CompiledDynamicToolDefinition, unknown>>>>;
301
313
  hooks: z.ZodArray<z.ZodType<CompiledHookDefinition, unknown, z.core.$ZodTypeInternals<CompiledHookDefinition, unknown>>>;
302
314
  kind: z.ZodLiteral<"ash-agent-compiled-manifest">;
303
315
  remoteAgents: z.ZodArray<z.ZodType<Readonly<ModuleSourceRef & Node & {
@@ -368,7 +380,7 @@ export declare const compiledAgentManifestSchema: z.ZodObject<{
368
380
  sourceId: z.ZodString;
369
381
  sourceKind: z.ZodLiteral<"module">;
370
382
  }, z.core.$strict>>;
371
- version: z.ZodLiteral<24>;
383
+ version: z.ZodLiteral<25>;
372
384
  workspaceResourceRoot: z.ZodObject<{
373
385
  logicalPath: z.ZodString;
374
386
  rootEntries: z.ZodReadonly<z.ZodArray<z.ZodString>>;
@@ -385,6 +397,7 @@ export declare function createCompiledAgentNodeManifest(input: {
385
397
  readonly connections?: readonly CompiledConnectionDefinition[];
386
398
  readonly diagnosticsSummary?: DiscoverDiagnosticsSummary;
387
399
  readonly disabledFrameworkTools?: readonly string[];
400
+ readonly dynamicTools?: readonly CompiledDynamicToolDefinition[];
388
401
  readonly hooks?: readonly CompiledHookDefinition[];
389
402
  readonly remoteAgents?: readonly CompiledRemoteAgentNode[];
390
403
  readonly sandbox?: CompiledSandboxDefinition | null;
@@ -423,6 +436,7 @@ export declare function createCompiledAgentManifest(input: {
423
436
  readonly connections?: readonly CompiledConnectionDefinition[];
424
437
  readonly diagnosticsSummary?: DiscoverDiagnosticsSummary;
425
438
  readonly disabledFrameworkTools?: readonly string[];
439
+ readonly dynamicTools?: readonly CompiledDynamicToolDefinition[];
426
440
  readonly hooks?: readonly CompiledHookDefinition[];
427
441
  readonly remoteAgents?: readonly CompiledRemoteAgentNode[];
428
442
  readonly sandbox?: CompiledSandboxDefinition | null;
@@ -1 +1 @@
1
- import{z}from"#compiled/zod/index.js";import{discoverDiagnosticsSummarySchema}from"#discover/diagnostics.js";import{compiledRemoteAgentNodeSchema}from"#compiler/remote-agent-node.js";import{jsonObjectSchema}from"#shared/json-schemas.js";const COMPILED_AGENT_MANIFEST_KIND=`ash-agent-compiled-manifest`,ROOT_COMPILED_AGENT_NODE_ID=`__root__`,COMPILED_AGENT_MANIFEST_VERSION=24,moduleSourceRefSchema=z.object({exportName:z.string().optional(),sourceKind:z.literal(`module`),logicalPath:z.string(),sourceId:z.string()}).strict(),channelMethodSchema=z.union([z.literal(`GET`),z.literal(`POST`),z.literal(`PUT`),z.literal(`PATCH`),z.literal(`DELETE`)]),compiledChannelDefinitionSchema=z.object({kind:z.literal(`channel`),name:z.string(),logicalPath:z.string(),method:channelMethodSchema,urlPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`),exportName:z.string().optional(),adapterKind:z.string().optional()}).strict(),disabledCompiledChannelEntrySchema=z.object({kind:z.literal(`disabled`),name:z.string(),logicalPath:z.string()}).strict(),compiledChannelEntrySchema=z.union([compiledChannelDefinitionSchema,disabledCompiledChannelEntrySchema]),compiledRuntimeModelReferenceSchema=z.object({contextWindowTokens:z.number().int().positive().optional(),id:z.string(),source:moduleSourceRefSchema.optional(),providerOptions:z.record(z.string(),jsonObjectSchema).optional()}).strict(),compiledAgentBuildDefinitionSchema=z.object({externalDependencies:z.array(z.string()).optional()}).strict(),compiledAgentCompactionDefinitionSchema=z.object({model:compiledRuntimeModelReferenceSchema.optional(),thresholdPercent:z.number().finite().min(0).max(1).optional()}).strict(),compiledAgentConfigSchema=z.object({build:compiledAgentBuildDefinitionSchema.optional(),compaction:compiledAgentCompactionDefinitionSchema.optional(),description:z.string().optional(),model:compiledRuntimeModelReferenceSchema,name:z.string(),source:moduleSourceRefSchema.optional()}).strict(),compiledInstructionsSchema=z.object({name:z.string(),logicalPath:z.string(),markdown:z.string(),sourceId:z.string(),sourceKind:z.union([z.literal(`markdown`),z.literal(`module`)])}).strict(),compiledSkillBaseFields={name:z.string(),description:z.string(),license:z.string().optional(),markdown:z.string(),metadata:z.record(z.string(),z.string()).optional(),sourceId:z.string(),logicalPath:z.string()},compiledSkillSourceSchema=z.discriminatedUnion(`sourceKind`,[z.object({...compiledSkillBaseFields,sourceKind:z.literal(`markdown`)}).strict(),z.object({...compiledSkillBaseFields,sourceKind:z.literal(`module`),exportName:z.string().optional()}).strict(),z.object({...compiledSkillBaseFields,sourceKind:z.literal(`skill-package`),skillId:z.string(),skillFilePath:z.string(),rootPath:z.string(),assetsPath:z.string().optional(),referencesPath:z.string().optional(),scriptsPath:z.string().optional()}).strict()]),compiledScheduleDefinitionSchema=z.object({cron:z.string(),hasRun:z.boolean(),name:z.string(),logicalPath:z.string(),markdown:z.string().optional(),sourceId:z.string(),sourceKind:z.union([z.literal(`markdown`),z.literal(`module`)])}).strict(),compiledSandboxDefinitionSchema=z.object({description:z.string().optional(),exportName:z.string().optional(),logicalPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledSandboxWorkspaceSchema=z.object({logicalPath:z.string(),rootEntries:z.array(z.string()).readonly(),sourceId:z.string(),sourcePath:z.string()}).strict(),compiledWorkspaceResourceRootSchema=z.object({logicalPath:z.string(),rootEntries:z.array(z.string()).readonly()}).strict(),compiledConnectionDefinitionSchema=z.object({connectionName:z.string(),description:z.string(),exportName:z.string().optional(),logicalPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`),url:z.string(),vercelConnect:z.object({connector:z.string()}).strict().optional()}).strict(),compiledToolDefinitionSchema=z.object({description:z.string(),exportName:z.string().optional(),inputSchema:jsonObjectSchema.nullable(),logicalPath:z.string(),name:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledHookDefinitionSchema=z.object({exportName:z.string().optional(),logicalPath:z.string(),slug:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledAgentNodeManifestSchema=z.object({agentRoot:z.string(),appRoot:z.string(),channels:z.array(compiledChannelEntrySchema),config:compiledAgentConfigSchema,connections:z.array(compiledConnectionDefinitionSchema),diagnosticsSummary:discoverDiagnosticsSummarySchema,disabledFrameworkTools:z.array(z.string()).readonly(),hooks:z.array(compiledHookDefinitionSchema),sandbox:compiledSandboxDefinitionSchema.nullable(),sandboxWorkspaces:z.array(compiledSandboxWorkspaceSchema),schedules:z.array(compiledScheduleDefinitionSchema),remoteAgents:z.array(compiledRemoteAgentNodeSchema),skills:z.array(compiledSkillSourceSchema).readonly(),instructions:compiledInstructionsSchema.optional(),tools:z.array(compiledToolDefinitionSchema),workspaceResourceRoot:compiledWorkspaceResourceRootSchema}).strict(),compiledSubagentNodeSchema=z.object({agent:compiledAgentNodeManifestSchema,description:z.string(),entryPath:z.string(),logicalPath:z.string(),name:z.string(),nodeId:z.string(),rootPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`),exportName:z.string().optional()}).strict(),compiledSubagentEdgeSchema=z.object({childNodeId:z.string(),parentNodeId:z.string()}).strict(),compiledAgentManifestSchema=z.object({agentRoot:z.string(),appRoot:z.string(),channels:z.array(compiledChannelEntrySchema),config:compiledAgentConfigSchema,connections:z.array(compiledConnectionDefinitionSchema),diagnosticsSummary:discoverDiagnosticsSummarySchema,disabledFrameworkTools:z.array(z.string()).readonly(),hooks:z.array(compiledHookDefinitionSchema),kind:z.literal(COMPILED_AGENT_MANIFEST_KIND),remoteAgents:z.array(compiledRemoteAgentNodeSchema),sandbox:compiledSandboxDefinitionSchema.nullable(),sandboxWorkspaces:z.array(compiledSandboxWorkspaceSchema),schedules:z.array(compiledScheduleDefinitionSchema),skills:z.array(compiledSkillSourceSchema).readonly(),subagentEdges:z.array(compiledSubagentEdgeSchema),subagents:z.array(compiledSubagentNodeSchema),instructions:compiledInstructionsSchema.optional(),tools:z.array(compiledToolDefinitionSchema),version:z.literal(24),workspaceResourceRoot:compiledWorkspaceResourceRootSchema}).strict();function createCompiledAgentNodeManifest(e){let t={agentRoot:e.agentRoot,appRoot:e.appRoot,channels:[...e.channels??[]],connections:[...e.connections??[]],config:{build:e.config.build===void 0?void 0:{externalDependencies:e.config.build.externalDependencies===void 0?void 0:[...e.config.build.externalDependencies]},compaction:{model:e.config.compaction?.model===void 0?void 0:cloneCompiledRuntimeModelReference(e.config.compaction.model),thresholdPercent:e.config.compaction?.thresholdPercent},description:e.config.description,model:cloneCompiledRuntimeModelReference(e.config.model),name:e.config.name,source:e.config.source===void 0?void 0:{...e.config.source}},diagnosticsSummary:e.diagnosticsSummary??{errors:0,warnings:0},disabledFrameworkTools:[...e.disabledFrameworkTools??[]],hooks:[...e.hooks??[]],remoteAgents:[...e.remoteAgents??[]],sandbox:e.sandbox??null,sandboxWorkspaces:[...e.sandboxWorkspaces??[]],schedules:[...e.schedules??[]],skills:[...e.skills??[]],tools:[...e.tools??[]],workspaceResourceRoot:e.workspaceResourceRoot??{logicalPath:``,rootEntries:deriveResourceRootEntries({sandboxWorkspaces:e.sandboxWorkspaces,skills:e.skills})}};return e.instructions!==void 0&&(t.instructions=e.instructions),t}function deriveResourceRootEntries(e){let t=new Set;(e.skills??[]).length>0&&t.add(`skills/`);for(let n of e.sandboxWorkspaces??[])for(let e of n.rootEntries)t.add(e);return[...t].sort((e,t)=>e.localeCompare(t))}function createCompiledSubagentNodeId(e,t){return e===`__root__`?t:`${e}::${t}`}function createCompiledAgentManifest(e){return{...createCompiledAgentNodeManifest(e),kind:COMPILED_AGENT_MANIFEST_KIND,subagentEdges:[...e.subagentEdges??[]],subagents:[...e.subagents??[]],version:24}}function cloneCompiledRuntimeModelReference(e){return e.contextWindowTokens===void 0&&e.source===void 0&&e.providerOptions===void 0?{id:e.id}:e.source===void 0?e.providerOptions===void 0?{contextWindowTokens:e.contextWindowTokens,id:e.id}:{contextWindowTokens:e.contextWindowTokens,id:e.id,providerOptions:{...e.providerOptions}}:e.contextWindowTokens===void 0&&e.providerOptions===void 0?{id:e.id,source:{...e.source}}:{contextWindowTokens:e.contextWindowTokens,id:e.id,providerOptions:e.providerOptions===void 0?void 0:{...e.providerOptions},source:{...e.source}}}export{COMPILED_AGENT_MANIFEST_KIND,COMPILED_AGENT_MANIFEST_VERSION,ROOT_COMPILED_AGENT_NODE_ID,compiledAgentManifestSchema,createCompiledAgentManifest,createCompiledAgentNodeManifest,createCompiledSubagentNodeId,deriveResourceRootEntries};
1
+ import{z}from"#compiled/zod/index.js";import{discoverDiagnosticsSummarySchema}from"#discover/diagnostics.js";import{compiledRemoteAgentNodeSchema}from"#compiler/remote-agent-node.js";import{jsonObjectSchema}from"#shared/json-schemas.js";const COMPILED_AGENT_MANIFEST_KIND=`ash-agent-compiled-manifest`,ROOT_COMPILED_AGENT_NODE_ID=`__root__`,COMPILED_AGENT_MANIFEST_VERSION=25,moduleSourceRefSchema=z.object({exportName:z.string().optional(),sourceKind:z.literal(`module`),logicalPath:z.string(),sourceId:z.string()}).strict(),channelMethodSchema=z.union([z.literal(`GET`),z.literal(`POST`),z.literal(`PUT`),z.literal(`PATCH`),z.literal(`DELETE`)]),compiledChannelDefinitionSchema=z.object({kind:z.literal(`channel`),name:z.string(),logicalPath:z.string(),method:channelMethodSchema,urlPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`),exportName:z.string().optional(),adapterKind:z.string().optional()}).strict(),disabledCompiledChannelEntrySchema=z.object({kind:z.literal(`disabled`),name:z.string(),logicalPath:z.string()}).strict(),compiledChannelEntrySchema=z.union([compiledChannelDefinitionSchema,disabledCompiledChannelEntrySchema]),compiledRuntimeModelReferenceSchema=z.object({contextWindowTokens:z.number().int().positive().optional(),id:z.string(),source:moduleSourceRefSchema.optional(),providerOptions:z.record(z.string(),jsonObjectSchema).optional()}).strict(),compiledAgentBuildDefinitionSchema=z.object({externalDependencies:z.array(z.string()).optional()}).strict(),compiledAgentCompactionDefinitionSchema=z.object({model:compiledRuntimeModelReferenceSchema.optional(),thresholdPercent:z.number().finite().min(0).max(1).optional()}).strict(),compiledAgentConfigSchema=z.object({build:compiledAgentBuildDefinitionSchema.optional(),compaction:compiledAgentCompactionDefinitionSchema.optional(),description:z.string().optional(),experimental:z.object({codeMode:z.boolean().optional()}).strict().optional(),model:compiledRuntimeModelReferenceSchema,name:z.string(),source:moduleSourceRefSchema.optional()}).strict(),compiledInstructionsSchema=z.object({name:z.string(),logicalPath:z.string(),markdown:z.string(),sourceId:z.string(),sourceKind:z.union([z.literal(`markdown`),z.literal(`module`)])}).strict(),compiledSkillBaseFields={name:z.string(),description:z.string(),license:z.string().optional(),markdown:z.string(),metadata:z.record(z.string(),z.string()).optional(),sourceId:z.string(),logicalPath:z.string()},compiledSkillSourceSchema=z.discriminatedUnion(`sourceKind`,[z.object({...compiledSkillBaseFields,sourceKind:z.literal(`markdown`)}).strict(),z.object({...compiledSkillBaseFields,sourceKind:z.literal(`module`),exportName:z.string().optional()}).strict(),z.object({...compiledSkillBaseFields,sourceKind:z.literal(`skill-package`),skillId:z.string(),skillFilePath:z.string(),rootPath:z.string(),assetsPath:z.string().optional(),referencesPath:z.string().optional(),scriptsPath:z.string().optional()}).strict()]),compiledScheduleDefinitionSchema=z.object({cron:z.string(),hasRun:z.boolean(),name:z.string(),logicalPath:z.string(),markdown:z.string().optional(),sourceId:z.string(),sourceKind:z.union([z.literal(`markdown`),z.literal(`module`)])}).strict(),compiledSandboxDefinitionSchema=z.object({description:z.string().optional(),exportName:z.string().optional(),logicalPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledSandboxWorkspaceSchema=z.object({logicalPath:z.string(),rootEntries:z.array(z.string()).readonly(),sourceId:z.string(),sourcePath:z.string()}).strict(),compiledWorkspaceResourceRootSchema=z.object({logicalPath:z.string(),rootEntries:z.array(z.string()).readonly()}).strict(),compiledConnectionDefinitionSchema=z.object({connectionName:z.string(),description:z.string(),exportName:z.string().optional(),logicalPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`),url:z.string(),vercelConnect:z.object({connector:z.string()}).strict().optional()}).strict(),compiledToolDefinitionSchema=z.object({description:z.string(),exportName:z.string().optional(),inputSchema:jsonObjectSchema.nullable(),logicalPath:z.string(),name:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledDynamicToolDefinitionSchema=z.object({eventNames:z.array(z.string()).readonly(),exportName:z.string().optional(),identity:z.enum([`single`,`multi`]),logicalPath:z.string(),slug:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledHookDefinitionSchema=z.object({exportName:z.string().optional(),logicalPath:z.string(),slug:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`)}).strict(),compiledAgentNodeManifestSchema=z.object({agentRoot:z.string(),appRoot:z.string(),channels:z.array(compiledChannelEntrySchema),config:compiledAgentConfigSchema,connections:z.array(compiledConnectionDefinitionSchema),diagnosticsSummary:discoverDiagnosticsSummarySchema,disabledFrameworkTools:z.array(z.string()).readonly(),dynamicTools:z.array(compiledDynamicToolDefinitionSchema).default([]),hooks:z.array(compiledHookDefinitionSchema),sandbox:compiledSandboxDefinitionSchema.nullable(),sandboxWorkspaces:z.array(compiledSandboxWorkspaceSchema),schedules:z.array(compiledScheduleDefinitionSchema),remoteAgents:z.array(compiledRemoteAgentNodeSchema),skills:z.array(compiledSkillSourceSchema).readonly(),instructions:compiledInstructionsSchema.optional(),tools:z.array(compiledToolDefinitionSchema),workspaceResourceRoot:compiledWorkspaceResourceRootSchema}).strict(),compiledSubagentNodeSchema=z.object({agent:compiledAgentNodeManifestSchema,description:z.string(),entryPath:z.string(),logicalPath:z.string(),name:z.string(),nodeId:z.string(),rootPath:z.string(),sourceId:z.string(),sourceKind:z.literal(`module`),exportName:z.string().optional()}).strict(),compiledSubagentEdgeSchema=z.object({childNodeId:z.string(),parentNodeId:z.string()}).strict(),compiledAgentManifestSchema=z.object({agentRoot:z.string(),appRoot:z.string(),channels:z.array(compiledChannelEntrySchema),config:compiledAgentConfigSchema,connections:z.array(compiledConnectionDefinitionSchema),diagnosticsSummary:discoverDiagnosticsSummarySchema,disabledFrameworkTools:z.array(z.string()).readonly(),dynamicTools:z.array(compiledDynamicToolDefinitionSchema).default([]),hooks:z.array(compiledHookDefinitionSchema),kind:z.literal(COMPILED_AGENT_MANIFEST_KIND),remoteAgents:z.array(compiledRemoteAgentNodeSchema),sandbox:compiledSandboxDefinitionSchema.nullable(),sandboxWorkspaces:z.array(compiledSandboxWorkspaceSchema),schedules:z.array(compiledScheduleDefinitionSchema),skills:z.array(compiledSkillSourceSchema).readonly(),subagentEdges:z.array(compiledSubagentEdgeSchema),subagents:z.array(compiledSubagentNodeSchema),instructions:compiledInstructionsSchema.optional(),tools:z.array(compiledToolDefinitionSchema),version:z.literal(25),workspaceResourceRoot:compiledWorkspaceResourceRootSchema}).strict();function createCompiledAgentNodeManifest(e){let t={agentRoot:e.agentRoot,appRoot:e.appRoot,channels:[...e.channels??[]],connections:[...e.connections??[]],config:{build:e.config.build===void 0?void 0:{externalDependencies:e.config.build.externalDependencies===void 0?void 0:[...e.config.build.externalDependencies]},compaction:{model:e.config.compaction?.model===void 0?void 0:cloneCompiledRuntimeModelReference(e.config.compaction.model),thresholdPercent:e.config.compaction?.thresholdPercent},description:e.config.description,experimental:e.config.experimental===void 0?void 0:{codeMode:e.config.experimental.codeMode},model:cloneCompiledRuntimeModelReference(e.config.model),name:e.config.name,source:e.config.source===void 0?void 0:{...e.config.source}},diagnosticsSummary:e.diagnosticsSummary??{errors:0,warnings:0},disabledFrameworkTools:[...e.disabledFrameworkTools??[]],dynamicTools:[...e.dynamicTools??[]],hooks:[...e.hooks??[]],remoteAgents:[...e.remoteAgents??[]],sandbox:e.sandbox??null,sandboxWorkspaces:[...e.sandboxWorkspaces??[]],schedules:[...e.schedules??[]],skills:[...e.skills??[]],tools:[...e.tools??[]],workspaceResourceRoot:e.workspaceResourceRoot??{logicalPath:``,rootEntries:deriveResourceRootEntries({sandboxWorkspaces:e.sandboxWorkspaces,skills:e.skills})}};return e.instructions!==void 0&&(t.instructions=e.instructions),t}function deriveResourceRootEntries(e){let t=new Set;(e.skills??[]).length>0&&t.add(`skills/`);for(let n of e.sandboxWorkspaces??[])for(let e of n.rootEntries)t.add(e);return[...t].sort((e,t)=>e.localeCompare(t))}function createCompiledSubagentNodeId(e,t){return e===`__root__`?t:`${e}::${t}`}function createCompiledAgentManifest(e){return{...createCompiledAgentNodeManifest(e),kind:COMPILED_AGENT_MANIFEST_KIND,subagentEdges:[...e.subagentEdges??[]],subagents:[...e.subagents??[]],version:25}}function cloneCompiledRuntimeModelReference(e){return e.contextWindowTokens===void 0&&e.source===void 0&&e.providerOptions===void 0?{id:e.id}:e.source===void 0?e.providerOptions===void 0?{contextWindowTokens:e.contextWindowTokens,id:e.id}:{contextWindowTokens:e.contextWindowTokens,id:e.id,providerOptions:{...e.providerOptions}}:e.contextWindowTokens===void 0&&e.providerOptions===void 0?{id:e.id,source:{...e.source}}:{contextWindowTokens:e.contextWindowTokens,id:e.id,providerOptions:e.providerOptions===void 0?void 0:{...e.providerOptions},source:{...e.source}}}export{COMPILED_AGENT_MANIFEST_KIND,COMPILED_AGENT_MANIFEST_VERSION,ROOT_COMPILED_AGENT_NODE_ID,compiledAgentManifestSchema,createCompiledAgentManifest,createCompiledAgentNodeManifest,createCompiledSubagentNodeId,deriveResourceRootEntries};
@@ -1,5 +1,5 @@
1
1
  import{z}from"#compiled/zod/index.js";import{ROOT_COMPILED_AGENT_NODE_ID}from"#compiler/manifest.js";import{normalizeEsmImportSpecifier}from"#internal/application/import-specifier.js";const compiledModuleNodeScopeSchema=z.object({modules:z.record(z.string(),z.object({}).passthrough())}).strict(),compiledModuleMapSchema=z.object({nodes:z.record(z.string(),compiledModuleNodeScopeSchema)}).strict();function createCompiledModuleMapSource(e){let n=dirnameFilesystemPath(e.moduleMapPath),r=e.importSpecifierStyle??`relative`,i=0,a=[collectModuleNodeScope({agentRoot:e.manifest.agentRoot,importSpecifierStyle:r,manifest:e.manifest,moduleMapDirectory:n,nextBindingName(){return`module_${i++}`},nodeId:ROOT_COMPILED_AGENT_NODE_ID}),...[...e.manifest.subagents].sort((e,t)=>e.nodeId.localeCompare(t.nodeId)).map(e=>collectModuleNodeScope({agentRoot:e.agent.agentRoot,importSpecifierStyle:r,manifest:e.agent,moduleMapDirectory:n,nextBindingName(){return`module_${i++}`},nodeId:e.nodeId}))],o=a.flatMap(e=>e.modules.map(e=>`import * as ${e.bindingName} from ${JSON.stringify(e.importSpecifier)};`));return[`// Generated by Ash. Do not edit by hand.`,``,...o,...o.length>0?[``]:[],`export const moduleMap = ${renderModuleMap(a)};`,``,`export default moduleMap;`,``].join(`
2
- `)}function collectModuleNodeScope(e){return{modules:collectModuleRefsForManifest(e.manifest).sort((e,t)=>e.sourceId.localeCompare(t.sourceId)).map(t=>({bindingName:e.nextBindingName(),importSpecifier:createImportSpecifier({fromDirectory:e.moduleMapDirectory,importSpecifierStyle:e.importSpecifierStyle,targetPath:joinFilesystemPath(e.agentRoot,t.logicalPath)}),sourceId:t.sourceId})),nodeId:e.nodeId}}function collectModuleRefsForManifest(e){let t=new Map;e.config.source!==void 0&&t.set(e.config.source.sourceId,e.config.source),e.config.model.source!==void 0&&t.set(e.config.model.source.sourceId,e.config.model.source);for(let n of e.channels)n.kind!==`disabled`&&t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.connections)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.tools)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.remoteAgents)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.hooks)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.schedules)n.sourceKind!==`module`||!n.hasRun||t.set(n.sourceId,{sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});return e.sandbox!==null&&t.set(e.sandbox.sourceId,{exportName:e.sandbox.exportName,sourceKind:`module`,logicalPath:e.sandbox.logicalPath,sourceId:e.sandbox.sourceId}),[...t.values()]}function createImportSpecifier(e){if(e.importSpecifierStyle===`absolute`)return normalizeEsmImportSpecifier(normalizeFilesystemPath(e.targetPath));let t=relativeFilesystemPath(e.fromDirectory,e.targetPath);return t.startsWith(`.`)?t:`./${t}`}function renderModuleMap(e){return renderFrozenObject([{key:`nodes`,value:renderFrozenObject(e.map(e=>({key:e.nodeId,value:renderFrozenObject([{key:`modules`,value:renderFrozenObject(e.modules.map(e=>({key:e.sourceId,value:e.bindingName})))}],3)})))}],0)}function renderFrozenObject(e,t=1){if(e.length===0)return`Object.freeze({})`;let n=` `.repeat(t),r=` `.repeat(t+1);return[`Object.freeze({`,e.map(e=>`${r}${JSON.stringify(e.key)}: ${e.value.replaceAll(`
2
+ `)}function collectModuleNodeScope(e){return{modules:collectModuleRefsForManifest(e.manifest).sort((e,t)=>e.sourceId.localeCompare(t.sourceId)).map(t=>({bindingName:e.nextBindingName(),importSpecifier:createImportSpecifier({fromDirectory:e.moduleMapDirectory,importSpecifierStyle:e.importSpecifierStyle,targetPath:joinFilesystemPath(e.agentRoot,t.logicalPath)}),sourceId:t.sourceId})),nodeId:e.nodeId}}function collectModuleRefsForManifest(e){let t=new Map;e.config.source!==void 0&&t.set(e.config.source.sourceId,e.config.source),e.config.model.source!==void 0&&t.set(e.config.model.source.sourceId,e.config.model.source);for(let n of e.channels)n.kind!==`disabled`&&t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.connections)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.tools)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.dynamicTools)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.remoteAgents)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.hooks)t.set(n.sourceId,{exportName:n.exportName,sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});for(let n of e.schedules)n.sourceKind!==`module`||!n.hasRun||t.set(n.sourceId,{sourceKind:`module`,logicalPath:n.logicalPath,sourceId:n.sourceId});return e.sandbox!==null&&t.set(e.sandbox.sourceId,{exportName:e.sandbox.exportName,sourceKind:`module`,logicalPath:e.sandbox.logicalPath,sourceId:e.sandbox.sourceId}),[...t.values()]}function createImportSpecifier(e){if(e.importSpecifierStyle===`absolute`)return normalizeEsmImportSpecifier(normalizeFilesystemPath(e.targetPath));let t=relativeFilesystemPath(e.fromDirectory,e.targetPath);return t.startsWith(`.`)?t:`./${t}`}function renderModuleMap(e){return renderFrozenObject([{key:`nodes`,value:renderFrozenObject(e.map(e=>({key:e.nodeId,value:renderFrozenObject([{key:`modules`,value:renderFrozenObject(e.modules.map(e=>({key:e.sourceId,value:e.bindingName})))}],3)})))}],0)}function renderFrozenObject(e,t=1){if(e.length===0)return`Object.freeze({})`;let n=` `.repeat(t),r=` `.repeat(t+1);return[`Object.freeze({`,e.map(e=>`${r}${JSON.stringify(e.key)}: ${e.value.replaceAll(`
3
3
  `,`\n${r}`)}`).join(`,
4
4
  `),`${n}})`].join(`
5
5
  `)}function dirnameFilesystemPath(e){let t=splitFilesystemPath(e);return t.segments.length===0?t.root.length===0?`.`:t.root:createFilesystemPath(t.root,t.segments.slice(0,-1))}function joinFilesystemPath(e,t){let n=splitFilesystemPath(e),r=splitFilesystemPath(t);return r.root.length>0?createFilesystemPath(r.root,r.segments):createFilesystemPath(n.root,[...n.segments,...r.segments])}function relativeFilesystemPath(e,t){let n=splitFilesystemPath(e),r=splitFilesystemPath(t);if(n.root!==r.root)return normalizeFilesystemPath(t);let i=0;for(;i<n.segments.length&&i<r.segments.length&&n.segments[i]===r.segments[i];)i+=1;let a=[...Array.from({length:n.segments.length-i},()=>`..`),...r.segments.slice(i)];return a.length===0?`.`:a.join(`/`)}function normalizeFilesystemPath(e){let t=splitFilesystemPath(e);return createFilesystemPath(t.root,t.segments)}function splitFilesystemPath(e){let t=e.replaceAll(`\\`,`/`),n=``,r=t,i=t.match(/^[A-Za-z]:/);i===null?t.startsWith(`/`)&&(n=`/`,r=t.slice(1)):(n=i[0],r=t.slice(n.length),r.startsWith(`/`)&&(n=`${n}/`,r=r.slice(1)));let a=[];for(let e of r.split(`/`))if(!(e.length===0||e===`.`)){if(e===`..`){if(a.length>0&&a[a.length-1]!==`..`){a.pop();continue}n.length===0&&a.push(e);continue}a.push(e)}return{root:n,segments:a}}function createFilesystemPath(e,t){return e===`/`?t.length===0?`/`:`/${t.join(`/`)}`:e.endsWith(`/`)?t.length===0?e:`${e}${t.join(`/`)}`:e.length>0?t.length===0?e:`${e}/${t.join(`/`)}`:t.length===0?`.`:t.join(`/`)}export{collectModuleRefsForManifest,compiledModuleMapSchema,createCompiledModuleMapSource};
@@ -1 +1 @@
1
- import{toErrorMessage}from"#shared/errors.js";import{normalizeAgentDefinition}from"#internal/authored-definition/core.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{parseJsonObject}from"#shared/json.js";import{loadModuleBackedDefinition}from"#compiler/normalize-helpers.js";var MissingAgentConfigModuleError=class extends Error{agentId;constructor(e){super(`Agent "${e}" does not have an agent.ts config module. The "model" field is required.`),this.name=`MissingAgentConfigModuleError`,this.agentId=e}};async function compileAgentConfig(e,n){if(e.configModule===void 0)throw new MissingAgentConfigModuleError(e.agentId);let r=normalizeAgentDefinition(await loadModuleBackedDefinition({agentRoot:e.agentRoot,kind:`agent config`,source:e.configModule}),`Expected the agent config export "${e.configModule.exportName??`default`}" from "${e.configModule.logicalPath}" to match the public Ash shape.`),a=await normalizeAuthoredModelReference({modelCatalog:n.modelCatalog,purpose:`the primary compaction trigger model`,contextWindowTokens:r.modelContextWindowTokens,providerOptions:r.modelOptions?.providerOptions,source:e.configModule,value:r.model}),o={},s={compaction:o,model:a,name:e.agentId};return r.description!==void 0&&(s.description=r.description),r.build!==void 0&&(s.build={externalDependencies:r.build.externalDependencies===void 0?void 0:[...r.build.externalDependencies]}),s.source={exportName:e.configModule.exportName,sourceKind:`module`,logicalPath:e.configModule.logicalPath,sourceId:e.configModule.sourceId},r.compaction?.model!==void 0&&(o.model=await normalizeAuthoredModelReference({modelCatalog:n.modelCatalog,purpose:`the compaction summary model`,contextWindowTokens:r.compaction.modelContextWindowTokens,providerOptions:r.modelOptions?.providerOptions,source:e.configModule,value:r.compaction.model})),r.compaction?.thresholdPercent!==void 0&&(o.thresholdPercent=r.compaction.thresholdPercent),s}async function normalizeAuthoredModelReference(e){if(typeof e.value==`string`)return await withCompiledRuntimeModelLimits({id:formatLanguageModelGatewayId(e.value),providerOptions:parseProviderOptionsRecord(e.providerOptions)},e);let t=e.source;if(t===void 0)throw Error(`Expected ${e.purpose} to provide a valid AI SDK language model reference.`);let r=e.value,i=r.specificationVersion;if(i!==`v2`&&i!==`v3`&&i!==`v4`||typeof r.provider!=`string`||typeof r.modelId!=`string`||typeof r.doGenerate!=`function`||typeof r.doStream!=`function`)throw Error(`Expected the authored agent config export "${t.exportName??`default`}" from "${t.logicalPath}" to provide a valid AI SDK language model.`);let a={id:formatLanguageModelGatewayId(r),source:{exportName:t.exportName,sourceKind:`module`,logicalPath:t.logicalPath,sourceId:t.sourceId},providerOptions:parseProviderOptionsRecord(e.providerOptions)};if(e.contextWindowTokens===void 0){let t=await e.modelCatalog.getByProviderModelId(r.provider,r.modelId);if(t)return{...a,id:t.slug,contextWindowTokens:t.limits.contextWindowTokens}}return await withCompiledRuntimeModelLimits(a,e)}async function withCompiledRuntimeModelLimits(t,n){if(n.contextWindowTokens!==void 0)return{...t,contextWindowTokens:n.contextWindowTokens};let r;try{r=await n.modelCatalog.getModelLimits(t.id)}catch(r){throw Error(`Failed to load AI Gateway model metadata for ${n.purpose} "${t.id}". ${toErrorMessage(r)}`)}if(r===null)throw Error(`Cannot compile agent compaction because ${n.purpose} "${t.id}" does not have known AI Gateway context window metadata.`);return{...t,contextWindowTokens:r.contextWindowTokens}}function parseProviderOptionsRecord(e){if(e===void 0)return;let t={};for(let[n,i]of Object.entries(e))t[n]=parseJsonObject(i);return t}export{MissingAgentConfigModuleError,compileAgentConfig};
1
+ import{toErrorMessage}from"#shared/errors.js";import{normalizeAgentDefinition}from"#internal/authored-definition/core.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{parseJsonObject}from"#shared/json.js";import{loadModuleBackedDefinition}from"#compiler/normalize-helpers.js";var MissingAgentConfigModuleError=class extends Error{agentId;constructor(e){super(`Agent "${e}" does not have an agent.ts config module. The "model" field is required.`),this.name=`MissingAgentConfigModuleError`,this.agentId=e}};async function compileAgentConfig(e,n){if(e.configModule===void 0)throw new MissingAgentConfigModuleError(e.agentId);let r=normalizeAgentDefinition(await loadModuleBackedDefinition({agentRoot:e.agentRoot,kind:`agent config`,source:e.configModule}),`Expected the agent config export "${e.configModule.exportName??`default`}" from "${e.configModule.logicalPath}" to match the public Ash shape.`),a=await normalizeAuthoredModelReference({modelCatalog:n.modelCatalog,purpose:`the primary compaction trigger model`,contextWindowTokens:r.modelContextWindowTokens,providerOptions:r.modelOptions?.providerOptions,source:e.configModule,value:r.model}),o={},s={compaction:o,model:a,name:e.agentId};return r.description!==void 0&&(s.description=r.description),r.experimental?.codeMode!==void 0&&(s.experimental={codeMode:r.experimental.codeMode}),r.build!==void 0&&(s.build={externalDependencies:r.build.externalDependencies===void 0?void 0:[...r.build.externalDependencies]}),s.source={exportName:e.configModule.exportName,sourceKind:`module`,logicalPath:e.configModule.logicalPath,sourceId:e.configModule.sourceId},r.compaction?.model!==void 0&&(o.model=await normalizeAuthoredModelReference({modelCatalog:n.modelCatalog,purpose:`the compaction summary model`,contextWindowTokens:r.compaction.modelContextWindowTokens,providerOptions:r.modelOptions?.providerOptions,source:e.configModule,value:r.compaction.model})),r.compaction?.thresholdPercent!==void 0&&(o.thresholdPercent=r.compaction.thresholdPercent),s}async function normalizeAuthoredModelReference(e){if(typeof e.value==`string`)return await withCompiledRuntimeModelLimits({id:formatLanguageModelGatewayId(e.value),providerOptions:parseProviderOptionsRecord(e.providerOptions)},e);let t=e.source;if(t===void 0)throw Error(`Expected ${e.purpose} to provide a valid AI SDK language model reference.`);let r=e.value,i=r.specificationVersion;if(i!==`v2`&&i!==`v3`&&i!==`v4`||typeof r.provider!=`string`||typeof r.modelId!=`string`||typeof r.doGenerate!=`function`||typeof r.doStream!=`function`)throw Error(`Expected the authored agent config export "${t.exportName??`default`}" from "${t.logicalPath}" to provide a valid AI SDK language model.`);let a={id:formatLanguageModelGatewayId(r),source:{exportName:t.exportName,sourceKind:`module`,logicalPath:t.logicalPath,sourceId:t.sourceId},providerOptions:parseProviderOptionsRecord(e.providerOptions)};if(e.contextWindowTokens===void 0){let t=await e.modelCatalog.getByProviderModelId(r.provider,r.modelId);if(t)return{...a,id:t.slug,contextWindowTokens:t.limits.contextWindowTokens}}return await withCompiledRuntimeModelLimits(a,e)}async function withCompiledRuntimeModelLimits(t,n){if(n.contextWindowTokens!==void 0)return{...t,contextWindowTokens:n.contextWindowTokens};let r;try{r=await n.modelCatalog.getModelLimits(t.id)}catch(r){throw Error(`Failed to load AI Gateway model metadata for ${n.purpose} "${t.id}". ${toErrorMessage(r)}`)}if(r===null)throw Error(`Cannot compile agent compaction because ${n.purpose} "${t.id}" does not have known AI Gateway context window metadata.`);return{...t,contextWindowTokens:r.contextWindowTokens}}function parseProviderOptionsRecord(e){if(e===void 0)return;let t={};for(let[n,i]of Object.entries(e))t[n]=parseJsonObject(i);return t}export{MissingAgentConfigModuleError,compileAgentConfig};
@@ -1 +1 @@
1
- import{compileChannelDefinition}from"#compiler/normalize-channel.js";import{ROOT_COMPILED_AGENT_NODE_ID,createCompiledAgentManifest,createCompiledAgentNodeManifest}from"#compiler/manifest.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{compileAgentConfig}from"#compiler/normalize-agent-config.js";import{compileConnectionDefinition}from"#compiler/normalize-connection.js";import{compileHookEntry}from"#compiler/normalize-hook.js";import{compileSandboxDefinition}from"#compiler/normalize-sandbox.js";import{compileInstructions}from"#compiler/normalize-instructions.js";import{compileScheduleDefinition}from"#compiler/normalize-schedule.js";import{compileSkillSource}from"#compiler/normalize-skill.js";import{compileSubagentGraph}from"#compiler/normalize-subagent.js";import{compileToolEntry}from"#compiler/normalize-tool.js";async function compileAgentManifest(e){let r={modelCatalog:createCompiledRuntimeModelCatalogLoader(e.appRoot)},[a,o]=await Promise.all([compileAgentNodeManifest(e,r),compileSubagentGraph({appRoot:e.appRoot,compileAgentNodeManifest,context:r,parentNodeId:ROOT_COMPILED_AGENT_NODE_ID,subagents:e.subagents})]);return createCompiledAgentManifest({...a,remoteAgents:o.remoteAgents,subagentEdges:o.edges,subagents:o.nodes})}async function compileAgentNodeManifest(t,n){let i=await Promise.all(t.tools.map(e=>compileToolEntry(t.agentRoot,e))),s=[],c=[];for(let e of i)e.kind===`tool`?s.push(e.definition):c.push(e.name);let l=(await Promise.all(t.channels.map(n=>compileChannelDefinition(t.agentRoot,n)))).flat();return createCompiledAgentNodeManifest({agentRoot:t.agentRoot,appRoot:t.appRoot,channels:l,config:await compileAgentConfig(t,n),connections:await Promise.all(t.connections.map(e=>compileConnectionDefinition(t.agentRoot,e))),diagnosticsSummary:t.diagnosticsSummary,disabledFrameworkTools:c,hooks:t.hooks.map(e=>compileHookEntry(e)),sandbox:t.sandbox===null?null:await compileSandboxDefinition(t.agentRoot,t.sandbox),sandboxWorkspaces:t.sandboxWorkspaces.map(e=>({logicalPath:e.logicalPath,rootEntries:[...e.rootEntries],sourceId:e.sourceId,sourcePath:e.sourcePath})),schedules:await Promise.all(t.schedules.map(e=>compileScheduleDefinition(t.agentRoot,e))),skills:await Promise.all(t.skills.map(e=>compileSkillSource(t.agentRoot,e))),instructions:t.instructions===void 0?void 0:await compileInstructions(t.agentRoot,t.instructions),tools:s})}export{compileAgentManifest};
1
+ import{compileChannelDefinition}from"#compiler/normalize-channel.js";import{ROOT_COMPILED_AGENT_NODE_ID,createCompiledAgentManifest,createCompiledAgentNodeManifest}from"#compiler/manifest.js";import{createCompiledRuntimeModelCatalogLoader}from"#compiler/model-catalog.js";import{compileAgentConfig}from"#compiler/normalize-agent-config.js";import{compileConnectionDefinition}from"#compiler/normalize-connection.js";import{compileHookEntry}from"#compiler/normalize-hook.js";import{compileSandboxDefinition}from"#compiler/normalize-sandbox.js";import{compileInstructions}from"#compiler/normalize-instructions.js";import{compileScheduleDefinition}from"#compiler/normalize-schedule.js";import{compileSkillSource}from"#compiler/normalize-skill.js";import{compileSubagentGraph}from"#compiler/normalize-subagent.js";import{compileToolEntry}from"#compiler/normalize-tool.js";async function compileAgentManifest(e){let r={modelCatalog:createCompiledRuntimeModelCatalogLoader(e.appRoot)},[a,o]=await Promise.all([compileAgentNodeManifest(e,r),compileSubagentGraph({appRoot:e.appRoot,compileAgentNodeManifest,context:r,parentNodeId:ROOT_COMPILED_AGENT_NODE_ID,subagents:e.subagents})]);return createCompiledAgentManifest({...a,remoteAgents:o.remoteAgents,subagentEdges:o.edges,subagents:o.nodes})}async function compileAgentNodeManifest(t,n){let i=await Promise.all(t.tools.map(e=>compileToolEntry(t.agentRoot,e))),s=[],c=[],l=[];for(let e of i)e.kind===`tool`?s.push(e.definition):e.kind===`dynamic-tool`?c.push(e.definition):l.push(e.name);let u=(await Promise.all(t.channels.map(n=>compileChannelDefinition(t.agentRoot,n)))).flat();return createCompiledAgentNodeManifest({agentRoot:t.agentRoot,appRoot:t.appRoot,channels:u,config:await compileAgentConfig(t,n),connections:await Promise.all(t.connections.map(e=>compileConnectionDefinition(t.agentRoot,e))),diagnosticsSummary:t.diagnosticsSummary,disabledFrameworkTools:l,dynamicTools:c,hooks:t.hooks.map(e=>compileHookEntry(e)),sandbox:t.sandbox===null?null:await compileSandboxDefinition(t.agentRoot,t.sandbox),sandboxWorkspaces:t.sandboxWorkspaces.map(e=>({logicalPath:e.logicalPath,rootEntries:[...e.rootEntries],sourceId:e.sourceId,sourcePath:e.sourcePath})),schedules:await Promise.all(t.schedules.map(e=>compileScheduleDefinition(t.agentRoot,e))),skills:await Promise.all(t.skills.map(e=>compileSkillSource(t.agentRoot,e))),instructions:t.instructions===void 0?void 0:await compileInstructions(t.agentRoot,t.instructions),tools:s})}export{compileAgentManifest};
@@ -1,10 +1,11 @@
1
1
  import type { ModuleSourceRef } from "#shared/source-ref.js";
2
- import type { CompiledToolDefinition } from "#compiler/manifest.js";
2
+ import type { CompiledToolDefinition, CompiledDynamicToolDefinition } from "#compiler/manifest.js";
3
3
  /**
4
4
  * Compiled tool entry produced from one authored `tools/*.ts` file.
5
5
  *
6
- * Either a real tool definition or a `disabled` marker that removes the
7
- * named framework default during graph resolution.
6
+ * Either a real tool definition, a `disabled` marker that removes the
7
+ * named framework default during graph resolution, or a dynamic tool
8
+ * resolver that produces tools at runtime.
8
9
  */
9
10
  export type CompiledToolEntry = {
10
11
  readonly kind: "tool";
@@ -12,6 +13,9 @@ export type CompiledToolEntry = {
12
13
  } | {
13
14
  readonly kind: "disabled";
14
15
  readonly name: string;
16
+ } | {
17
+ readonly kind: "dynamic-tool";
18
+ readonly definition: CompiledDynamicToolDefinition;
15
19
  };
16
20
  /**
17
21
  * Compiles one authored tool module into the normalized tool entry
@@ -1 +1 @@
1
- import{stripLogicalPathExtension}from"#discover/filesystem.js";import{loadModuleBackedDefinition}from"#compiler/normalize-helpers.js";import{normalizeToolDefinition}from"#internal/authored-definition/schema-backed.js";async function compileToolEntry(e,t){let n=normalizeToolDefinition(await loadModuleBackedDefinition({agentRoot:e,kind:`tool`,source:t}),`Expected the tool export "${t.exportName??`default`}" from "${t.logicalPath}" to match the public Ash shape.`),r=stripLogicalPathExtension(t.logicalPath).replace(/^tools\//,``).replaceAll(`/`,`-`);return n.kind===`disabled`?{kind:`disabled`,name:r}:{kind:`tool`,definition:{description:n.definition.description,exportName:t.exportName,inputSchema:n.definition.inputSchema??null,logicalPath:t.logicalPath,name:r,sourceId:t.sourceId,sourceKind:`module`}}}export{compileToolEntry};
1
+ import{stripLogicalPathExtension}from"#discover/filesystem.js";import{loadModuleBackedDefinition}from"#compiler/normalize-helpers.js";import{normalizeToolDefinition}from"#internal/authored-definition/schema-backed.js";async function compileToolEntry(e,t){let n=normalizeToolDefinition(await loadModuleBackedDefinition({agentRoot:e,kind:`tool`,source:t}),`Expected the tool export "${t.exportName??`default`}" from "${t.logicalPath}" to match the public Ash shape.`),r=stripLogicalPathExtension(t.logicalPath).replace(/^tools\//,``).replaceAll(`/`,`-`);return n.kind===`disabled`?{kind:`disabled`,name:r}:n.kind===`dynamic-tool`?{kind:`dynamic-tool`,definition:{eventNames:[...n.eventNames],exportName:t.exportName,identity:n.identity,logicalPath:t.logicalPath,slug:r,sourceId:t.sourceId,sourceKind:`module`}}:{kind:`tool`,definition:{description:n.definition.description,exportName:t.exportName,inputSchema:n.definition.inputSchema??null,logicalPath:t.logicalPath,name:r,sourceId:t.sourceId,sourceKind:`module`}}}export{compileToolEntry};
@@ -0,0 +1,29 @@
1
+ import type { HarnessToolDefinition } from "#harness/execute-tool.js";
2
+ import type { HandleMessageStreamEvent } from "#protocol/message.js";
3
+ import type { ResolvedDynamicToolResolver } from "#runtime/types.js";
4
+ import type { ContextContainer } from "#context/container.js";
5
+ import type { DurableDynamicToolMetadata } from "#context/keys.js";
6
+ /**
7
+ * Reconstructs tool definitions from durable metadata using
8
+ * registered step functions. No resolver re-invocation — the
9
+ * execute function is looked up by step ID and called with stored
10
+ * closure vars.
11
+ */
12
+ export declare function replayDynamicSessionTools(metadata: readonly DurableDynamicToolMetadata[], _resolvers: readonly ResolvedDynamicToolResolver[]): readonly HarnessToolDefinition[];
13
+ /**
14
+ * Unified dynamic tool event dispatch. Called by `handleEvent` for
15
+ * every stream event. Two phases:
16
+ *
17
+ * 1. **Build phase**: reconstruct tools from durable metadata when
18
+ * the virtual key is empty (workflow step boundary crossed).
19
+ * 2. **Resolve phase**: run resolver handlers for the current event,
20
+ * capture closures as durable metadata, produce live tools.
21
+ *
22
+ * The tool-loop reads {@link DynamicToolsKey} right before each model
23
+ * call. Events update it; the tool-loop picks up whatever is current.
24
+ */
25
+ export declare function dispatchDynamicToolEvent(input: {
26
+ readonly ctx: ContextContainer;
27
+ readonly resolvers: readonly ResolvedDynamicToolResolver[];
28
+ readonly event: HandleMessageStreamEvent;
29
+ }): Promise<void>;
@@ -0,0 +1 @@
1
+ import{createLogger}from"#internal/logging.js";import{AuthKey,ContinuationTokenKey,DynamicSessionToolMetadataKey,DynamicToolResolverCacheKey,DynamicToolsKey,InitiatorAuthKey,SessionIdKey}from"#context/keys.js";import{toErrorMessage}from"#shared/errors.js";import{jsonSchema,zodSchema}from"ai";import{ALLOWED_DYNAMIC_TOOL_EVENTS}from"#shared/dynamic-tool-definition.js";import{normalizeJsonSchemaDefinition}from"#internal/json-schema.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{getAdapterKind}from"#channel/adapter.js";const log=createLogger(`dynamic-tools`);function buildResolveContext(e,r,a){let c=e.get(SessionIdKey)??``,l=e.get(AuthKey)??null,u=e.get(InitiatorAuthKey)??null,d=e.get(ChannelKey),f=e.get(ContinuationTokenKey);return{session:{id:c,auth:{current:l,initiator:u}},channel:{kind:d===void 0?void 0:getAdapterKind(d),continuationToken:f},async __cache(t,n){let o=`${r}:${t}`,s=e.get(DynamicToolResolverCacheKey)??{};if(o in s)return s[o];let c=await n();if(a){let e={...s,[o]:c};a.set(DynamicToolResolverCacheKey,e)}return c}}}function toHarnessToolDefinition(e,t){return{description:t.description,execute:e=>t.execute(e,buildCallbackContext()),inputSchema:convertInputSchema(t.inputSchema),name:e}}function convertInputSchema(e){return typeof e==`object`&&e&&`~standard`in e?zodSchema(e):jsonSchema(e)}function qualifyDynamicToolNames(e,t,n){let r=Object.keys(n),i=[];if(r.length===0)return i;if(t===`single`)return i.push({name:e,entryKey:r[0],entry:n[r[0]]}),i;for(let t of r)i.push({name:`${e}__${t}`,entryKey:t,entry:n[t]});return i}function replayDynamicSessionTools(e,t){let n=[];for(let t of e){if(!t.executeStepFnName||!t.closureVars){log.warn(`Dynamic tool "${t.name}" has no registered step function — skipping on this step. The bundler transform may not have processed this tool file.`);continue}let e=lookupStepFunction(t.executeStepFnName);if(!e){log.warn(`Dynamic tool "${t.name}" references step function "${t.executeStepFnName}" which is not registered — skipping on this step.`);continue}n.push({description:t.description,execute:n=>e(t.closureVars,n,buildCallbackContext()),inputSchema:jsonSchema(t.inputSchema),name:t.name})}return n}function lookupStepFunction(e){try{let t=globalThis[Symbol.for(`@workflow/core//registeredSteps`)];return t===void 0?null:t.get(e)||null}catch{return null}}function safeSerialize(e){try{return JSON.parse(JSON.stringify(e))}catch{return{}}}function matchesAnySlug(e,t){for(let n of t)if(e===n||e.startsWith(`${n}__`))return!0;return!1}async function resolveToolsFromEvent(e,t,n){let i=await Promise.allSettled(t.map(async t=>{let r=t.events[n.type];if(r===void 0)return null;let i=await r(n,buildResolveContext(e,t.slug,e));return i==null?null:{resolver:t,result:i}})),a=[],o=[];for(let e of i){if(e.status===`rejected`){log.error(`Dynamic tool resolver (${n.type}) threw — skipping.`,{error:toErrorMessage(e.reason)});continue}if(e.value===null)continue;let{resolver:t,result:r}=e.value,i=qualifyDynamicToolNames(t.slug,t.identity,r);for(let{name:e,entryKey:n,entry:r}of i){a.push(toHarnessToolDefinition(e,r));let i=`__executeStepFn`in r?r.__executeStepFn:void 0,s=`__closureVars`in r?r.__closureVars:void 0;o.push({name:e,description:r.description,inputSchema:normalizeJsonSchemaDefinition(r.inputSchema),resolverSlug:t.slug,entryKey:n,executeStepFnName:i?.stepId,closureVars:s===void 0?void 0:safeSerialize(s)})}}if(o.length>0){let t=e.get(DynamicSessionToolMetadataKey)??[],n=new Set(o.map(e=>e.resolverSlug)),i=t.filter(e=>!n.has(e.resolverSlug));e.set(DynamicSessionToolMetadataKey,[...i,...o])}return a}async function dispatchDynamicToolEvent(e){let{ctx:t,resolvers:n,event:i}=e;if(t.get(DynamicToolsKey)===void 0){let e=t.get(DynamicSessionToolMetadataKey);if(e!==void 0&&e.length>0){let r=replayDynamicSessionTools(e,n);r.length>0&&t.setVirtualContext(DynamicToolsKey,[...r])}}if(!ALLOWED_DYNAMIC_TOOL_EVENTS.has(i.type))return;let o=n.filter(e=>e.eventNames.includes(i.type));if(o.length===0)return;let s=await resolveToolsFromEvent(t,o,i);if(s.length===0)return;let c=new Set(o.map(e=>e.slug)),l=(t.get(DynamicToolsKey)??[]).filter(e=>!matchesAnySlug(e.name,c));t.setVirtualContext(DynamicToolsKey,[...l,...s])}export{dispatchDynamicToolEvent,replayDynamicSessionTools};
@@ -1 +1 @@
1
- import{ContinuationTokenKey,SandboxKey,SessionPreparedKey}from"./keys.js";import{createLogger}from"#internal/logging.js";import{toErrorMessage}from"#shared/errors.js";import{normalizeSkillPackage,writeSkillPackageToSandbox}from"#shared/skill-package.js";import{getAdapterKind}from"#channel/adapter.js";import{emitRecoverableFailedTurn,emitTurnPreamble,getHarnessEmissionState,setHarnessEmissionState}from"#harness/emission.js";import{formatAvailableSkillsSection}from"#execution/skills/instructions.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";const log=createLogger(`hooks.lifecycle`);async function dispatchHookLifecycle(e){let{ctx:t,registry:r,emit:a}=e,o=getHarnessEmissionState(e.session.state),s=buildHookContext(t),c=[],l=e.session;if(r.session.length>0&&t.get(SessionPreparedKey)!==!0){t.set(SessionPreparedKey,!0);let e=[];for(let n of r.session){let r=await n.handler(s);r?.modelContext!==void 0&&r.modelContext.length>0&&c.push(...r.modelContext),e.push(...normalizeLifecycleSkillResults(t,r))}l=await materializeLifecycleSkills(t,l,e)}let u=!1,d=o;try{let e=[];for(let n of r.turn){let r=await n.handler(s);r?.modelContext!==void 0&&r.modelContext.length>0&&c.push(...r.modelContext),e.push(...normalizeLifecycleSkillResults(t,r))}l=await materializeLifecycleSkills(t,l,e)}catch(t){let n=toErrorMessage(t);try{u||=(d=await emitTurnPreamble(a,{message:e.input.message},o,e.runtimeIdentity),!0);let t=await emitRecoverableFailedTurn(a,d,{code:`HOOK_TURN_FAILED`,message:n});return{kind:`turn-failed`,message:n,nextSession:setHarnessEmissionState(l,t)}}catch(e){throw log.error(`Event hook threw while emitting the turn.failed cascade for a lifecycle.turn failure — escalating to session.failed.`,{error:toErrorMessage(e)}),e}}let f=e.input.modelContext??[],p=f.length===0?c:[...f,...c];return{kind:`proceed`,input:p.length>0?{...e.input,modelContext:p}:e.input,nextSession:l}}function normalizeLifecycleSkillResults(e,t){if(t?.skills===void 0||t.skills.length===0)return[];let n=new Set(e.require(BundleKey).resolvedAgent.skills.map(e=>e.name)),r=new Map;for(let e of t.skills){let t=normalizeSkillPackage(e);if(n.has(t.name))throw Error(`Hook-contributed skill "${t.name}" conflicts with an authored skill.`);r.set(t.name,t)}return[...r.values()]}async function materializeLifecycleSkills(e,n,r){if(r.length===0)return n;let i=new Map(r.map(e=>[e.name,e])),a=await e.require(SandboxKey).get();if(a===null)throw Error(`Dynamic skills require a sandbox for the current agent.`);for(let e of i.values())await writeSkillPackageToSandbox({sandbox:a,skill:e});let s=formatAvailableSkillsSection([...i.values()]);return s===null?n:{...n,history:[...n.history,{role:`system`,content:s}]}}async function dispatchStreamEventHooks(e){let t=e.registry.streamEventsByType.get(e.event.type)??[],n=e.registry.streamEventsWildcard;if(t.length===0&&n.length===0)return;let r=buildHookContext(e.ctx);for(let n of t)await n.handler(e.event,r);for(let t of n)await t.handler(e.event,r)}function buildHookContext(t){let n=t.require(BundleKey),r=t.get(ChannelKey),i=t.get(ContinuationTokenKey),a=r===void 0?void 0:getAdapterKind(r);return{...buildCallbackContext(),agent:{name:n.resolvedAgent.config.name??`agent`,nodeId:n.nodeId},channel:{kind:a,continuationToken:i}}}async function runHookLifecycleStep(e,t){let n=await dispatchHookLifecycle(e);return n.kind===`turn-failed`?{next:e.mode===`conversation`?null:{done:!0,output:n.message},session:n.nextSession}:t(n.nextSession,n.input)}export{dispatchHookLifecycle,dispatchStreamEventHooks,runHookLifecycleStep};
1
+ import{ContinuationTokenKey,SandboxKey,SessionPreparedKey}from"./keys.js";import{createLogger}from"#internal/logging.js";import{toErrorMessage}from"#shared/errors.js";import{normalizeSkillPackage,writeSkillPackageToSandbox}from"#shared/skill-package.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{getAdapterKind}from"#channel/adapter.js";import{emitRecoverableFailedTurn,emitTurnPreamble,getHarnessEmissionState,setHarnessEmissionState}from"#harness/emission.js";import{formatAvailableSkillsSection}from"#execution/skills/instructions.js";const log=createLogger(`hooks.lifecycle`);async function dispatchHookLifecycle(e){let{ctx:t,registry:r,emit:a}=e,o=getHarnessEmissionState(e.session.state),s=buildHookContext(t),c=[],l=e.session;if(r.session.length>0&&t.get(SessionPreparedKey)!==!0){t.set(SessionPreparedKey,!0);let e=[];for(let n of r.session){let r=await n.handler(s);r?.modelContext!==void 0&&r.modelContext.length>0&&c.push(...r.modelContext),e.push(...normalizeLifecycleSkillResults(t,r))}l=await materializeLifecycleSkills(t,l,e)}let u=!1,d=o;try{let e=[];for(let n of r.turn){let r=await n.handler(s);r?.modelContext!==void 0&&r.modelContext.length>0&&c.push(...r.modelContext),e.push(...normalizeLifecycleSkillResults(t,r))}l=await materializeLifecycleSkills(t,l,e)}catch(t){let n=toErrorMessage(t);try{u||=(d=await emitTurnPreamble(a,{message:e.input.message},o,e.runtimeIdentity),!0);let t=await emitRecoverableFailedTurn(a,d,{code:`HOOK_TURN_FAILED`,message:n});return{kind:`turn-failed`,message:n,nextSession:setHarnessEmissionState(l,t)}}catch(e){throw log.error(`Event hook threw while emitting the turn.failed cascade for a lifecycle.turn failure — escalating to session.failed.`,{error:toErrorMessage(e)}),e}}let f=e.input.modelContext??[],p=f.length===0?c:[...f,...c];return{kind:`proceed`,input:p.length>0?{...e.input,modelContext:p}:e.input,nextSession:l}}function normalizeLifecycleSkillResults(e,t){if(t?.skills===void 0||t.skills.length===0)return[];let n=new Set(e.require(BundleKey).resolvedAgent.skills.map(e=>e.name)),r=new Map;for(let e of t.skills){let t=normalizeSkillPackage(e);if(n.has(t.name))throw Error(`Hook-contributed skill "${t.name}" conflicts with an authored skill.`);r.set(t.name,t)}return[...r.values()]}async function materializeLifecycleSkills(e,n,r){if(r.length===0)return n;let i=new Map(r.map(e=>[e.name,e])),a=await e.require(SandboxKey).get();if(a===null)throw Error(`Dynamic skills require a sandbox for the current agent.`);for(let e of i.values())await writeSkillPackageToSandbox({sandbox:a,skill:e});let s=formatAvailableSkillsSection([...i.values()]);return s===null?n:{...n,history:[...n.history,{role:`system`,content:s}]}}async function dispatchStreamEventHooks(e){let t=e.registry.streamEventsByType.get(e.event.type)??[],n=e.registry.streamEventsWildcard;if(t.length===0&&n.length===0)return;let r=buildHookContext(e.ctx);for(let n of t)await n.handler(e.event,r);for(let t of n)await t.handler(e.event,r)}function buildHookContext(t){let n=t.require(BundleKey),r=t.get(ChannelKey),i=t.get(ContinuationTokenKey),a=r===void 0?void 0:getAdapterKind(r);return{...buildCallbackContext(),agent:{name:n.resolvedAgent.config.name??`agent`,nodeId:n.nodeId},channel:{kind:a,continuationToken:i}}}async function runHookLifecycleStep(e,t){let n=await dispatchHookLifecycle(e);return n.kind===`turn-failed`?{next:e.mode===`conversation`?null:{done:!0,output:n.message},session:n.nextSession}:t(n.nextSession,n.input)}export{dispatchHookLifecycle,dispatchStreamEventHooks,runHookLifecycleStep};
@@ -55,3 +55,39 @@ export declare const SessionCallbackKey: ContextKey<SessionCallback>;
55
55
  export declare const SessionPreparedKey: ContextKey<boolean>;
56
56
  export declare const SessionKey: ContextKey<Session>;
57
57
  export declare const SandboxKey: ContextKey<SandboxAccess>;
58
+ /**
59
+ * Virtual (non-serialized) live dynamic tool definitions. Updated by
60
+ * {@link dispatchDynamicToolEvent} whenever a subscribed stream event
61
+ * fires. Read by the tool-loop when building the effective toolset.
62
+ */
63
+ export declare const DynamicToolsKey: ContextKey<import("#harness/execute-tool.js").HarnessToolDefinition[]>;
64
+ /**
65
+ * Durable (serialized) metadata for session-scoped dynamic tools.
66
+ * Set on the first step when resolvers run. Read on subsequent steps
67
+ * to reconstruct tool definitions with lazy execute wrappers.
68
+ */
69
+ export interface DurableDynamicToolMetadata {
70
+ readonly name: string;
71
+ readonly description: string;
72
+ readonly inputSchema: import("#shared/json.js").JsonObject;
73
+ readonly resolverSlug: string;
74
+ readonly entryKey: string;
75
+ /**
76
+ * Name of the hoisted execute step function (e.g.
77
+ * `__ash_dynamic_exec_0`). Used to look up the registered step
78
+ * function via `getStepFunction` on replay.
79
+ */
80
+ readonly executeStepFnName?: string;
81
+ /**
82
+ * Serialized closure variables captured from the resolver scope on
83
+ * the first run. Passed as the `__vars` parameter to the hoisted
84
+ * step function on replay.
85
+ */
86
+ readonly closureVars?: Record<string, unknown>;
87
+ }
88
+ export declare const DynamicSessionToolMetadataKey: ContextKey<readonly DurableDynamicToolMetadata[]>;
89
+ /**
90
+ * Durable cache for resolver I/O results. Keyed by resolver slug +
91
+ * await index. Populated on first resolver run, read on replay.
92
+ */
93
+ export declare const DynamicToolResolverCacheKey: ContextKey<Record<string, unknown>>;
@@ -1 +1 @@
1
- import{ContextKey}from"#context/key.js";const AuthKey=new ContextKey(`ash.auth`),InitiatorAuthKey=new ContextKey(`ash.initiatorAuth`),SessionIdKey=new ContextKey(`ash.sessionId`),ContinuationTokenKey=new ContextKey(`ash.continuationToken`),ModeKey=new ContextKey(`ash.mode`),ParentSessionKey=new ContextKey(`ash.parentSession`),CapabilitiesKey=new ContextKey(`ash.capabilities`),SessionCallbackKey=new ContextKey(`ash.sessionCallback`),SessionPreparedKey=new ContextKey(`ash.sessionPrepared`),SessionKey=new ContextKey(`ash.session`),SandboxKey=new ContextKey(`ash.sandbox`);export{AuthKey,CapabilitiesKey,ContinuationTokenKey,InitiatorAuthKey,ModeKey,ParentSessionKey,SandboxKey,SessionCallbackKey,SessionIdKey,SessionKey,SessionPreparedKey};
1
+ import{ContextKey}from"#context/key.js";const AuthKey=new ContextKey(`ash.auth`),InitiatorAuthKey=new ContextKey(`ash.initiatorAuth`),SessionIdKey=new ContextKey(`ash.sessionId`),ContinuationTokenKey=new ContextKey(`ash.continuationToken`),ModeKey=new ContextKey(`ash.mode`),ParentSessionKey=new ContextKey(`ash.parentSession`),CapabilitiesKey=new ContextKey(`ash.capabilities`),SessionCallbackKey=new ContextKey(`ash.sessionCallback`),SessionPreparedKey=new ContextKey(`ash.sessionPrepared`),SessionKey=new ContextKey(`ash.session`),SandboxKey=new ContextKey(`ash.sandbox`),DynamicToolsKey=new ContextKey(`ash.dynamicTools`),DynamicSessionToolMetadataKey=new ContextKey(`ash.dynamicSessionToolMetadata`),DynamicToolResolverCacheKey=new ContextKey(`ash.dynamicToolResolverCache`);export{AuthKey,CapabilitiesKey,ContinuationTokenKey,DynamicSessionToolMetadataKey,DynamicToolResolverCacheKey,DynamicToolsKey,InitiatorAuthKey,ModeKey,ParentSessionKey,SandboxKey,SessionCallbackKey,SessionIdKey,SessionKey,SessionPreparedKey};