experimental-ash 0.23.0 → 0.24.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.
- package/CHANGELOG.md +22 -0
- package/dist/docs/internals/hooks.md +13 -16
- package/dist/docs/internals/message-runtime.md +1 -1
- package/dist/docs/public/auth-and-route-protection.md +3 -3
- package/dist/docs/public/typescript-api.md +2 -2
- package/dist/src/channel/types.d.ts +10 -12
- package/dist/src/chunks/{dev-authored-source-watcher-d_35Mp8T.js → dev-authored-source-watcher-B4PaZGUr.js} +1 -1
- package/dist/src/chunks/host-DsW72Q-w.js +65 -0
- package/dist/src/chunks/{paths-YoCQlavu.js → paths-OknjaYR8.js} +24 -24
- package/dist/src/chunks/prewarm-B4YblQ5m.js +6 -0
- package/dist/src/cli/commands/info.js +1 -1
- package/dist/src/cli/run.js +1 -1
- package/dist/src/compiled/.vendor-stamp.json +2 -2
- package/dist/src/compiled/@workflow/core/classify-error.d.ts +4 -3
- package/dist/src/compiled/@workflow/core/encryption.d.ts +7 -1
- package/dist/src/compiled/@workflow/core/index.js +2 -2
- package/dist/src/compiled/@workflow/core/package.json +1 -1
- package/dist/src/compiled/@workflow/core/runtime/constants.d.ts +47 -0
- package/dist/src/compiled/@workflow/core/runtime/replay-budget.d.ts +98 -0
- package/dist/src/compiled/@workflow/core/runtime.js +27 -27
- package/dist/src/compiled/@workflow/core/serialization/types.d.ts +14 -0
- package/dist/src/compiled/@workflow/core/serialization.d.ts +8 -0
- package/dist/src/compiled/@workflow/core/symbols.d.ts +16 -0
- package/dist/src/compiled/@workflow/core/version.d.ts +1 -1
- package/dist/src/compiled/@workflow/core/workflow.js +1 -1
- package/dist/src/compiled/@workflow/errors/error-codes.d.ts +5 -1
- package/dist/src/compiled/@workflow/errors/index.d.ts +15 -1
- package/dist/src/compiled/@workflow/errors/index.js +1 -1
- package/dist/src/compiled/@workflow/errors/package.json +1 -1
- package/dist/src/compiled/_chunks/workflow/{context-errors-zbKocOyk.js → context-errors-Bbvvp-li.js} +2 -2
- package/dist/src/compiled/_chunks/workflow/{dist-0iNBqPYp.js → dist-C7wPwOI9.js} +2 -2
- package/dist/src/compiled/_chunks/workflow/{dist-D774SUM4.js → dist-C_oiE-l7.js} +1 -1
- package/dist/src/compiled/_chunks/workflow/resume-hook-C3VWUPii.js +12 -0
- package/dist/src/compiled/_chunks/workflow/sleep-QTkC1VFe.js +1 -0
- package/dist/src/compiled/_chunks/workflow/{symbols-D-4tVV8x.js → symbols-QezhMuLg.js} +1 -1
- package/dist/src/evals/cli/eval.js +1 -1
- package/dist/src/execution/await-authorization-orchestrator.d.ts +2 -1
- package/dist/src/execution/await-authorization-orchestrator.js +4 -0
- package/dist/src/execution/connection-auth-steps.d.ts +4 -0
- package/dist/src/execution/connection-auth-steps.js +9 -11
- package/dist/src/execution/node-step.d.ts +4 -5
- package/dist/src/execution/subagent-adapter.d.ts +0 -27
- package/dist/src/execution/subagent-adapter.js +2 -66
- package/dist/src/execution/subagent-hitl-proxy.d.ts +2 -2
- package/dist/src/execution/subagent-hitl-proxy.js +2 -2
- package/dist/src/execution/task-mode.d.ts +3 -3
- package/dist/src/execution/task-mode.js +3 -3
- package/dist/src/execution/turn-workflow.d.ts +41 -0
- package/dist/src/execution/turn-workflow.js +96 -0
- package/dist/src/execution/workflow-entry.js +77 -87
- package/dist/src/execution/workflow-errors.d.ts +14 -0
- package/dist/src/execution/workflow-errors.js +54 -0
- package/dist/src/execution/workflow-runtime.d.ts +34 -3
- package/dist/src/execution/workflow-runtime.js +52 -10
- package/dist/src/execution/workflow-steps.d.ts +27 -2
- package/dist/src/execution/workflow-steps.js +31 -26
- package/dist/src/harness/instrumentation-config.js +14 -7
- package/dist/src/harness/messages.d.ts +7 -7
- package/dist/src/harness/messages.js +4 -4
- package/dist/src/harness/runtime-actions.d.ts +4 -4
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/workflow-bundle/workflow-builders.d.ts +1 -1
- package/dist/src/internal/workflow-bundle/workflow-builders.js +20 -8
- package/dist/src/internal/workflow-bundle/workflow-transformer.d.ts +13 -0
- package/dist/src/internal/workflow-bundle/workflow-transformer.js +10 -4
- package/package.json +4 -4
- package/dist/src/chunks/host-tji7W0Nn.js +0 -65
- package/dist/src/chunks/prewarm-6duWvvb5.js +0 -6
- package/dist/src/compiled/_chunks/workflow/resume-hook-CL8Ed91K.js +0 -12
- package/dist/src/compiled/_chunks/workflow/sleep-Dn3i9nxI.js +0 -1
- package/dist/src/execution/continuous-entry.d.ts +0 -59
- package/dist/src/execution/continuous-entry.js +0 -487
- package/dist/src/execution/continuous-runtime.d.ts +0 -17
- package/dist/src/execution/continuous-runtime.js +0 -123
|
@@ -2,11 +2,22 @@ import type { DeliverPayload, HookPayload, SessionAuthContext, SubagentInputRequ
|
|
|
2
2
|
import { deserializeContext } from "#context/serialize.js";
|
|
3
3
|
import type { HarnessSession } from "#harness/types.js";
|
|
4
4
|
import type { RuntimeCompiledArtifactsSource } from "#runtime/compiled-artifacts-source.js";
|
|
5
|
+
import { type TurnWorkflowInput } from "#execution/turn-workflow.js";
|
|
5
6
|
import type { DurableStepResult } from "#execution/types.js";
|
|
7
|
+
/**
|
|
8
|
+
* Input for one atomic harness step inside a durable `"use step"`
|
|
9
|
+
* boundary.
|
|
10
|
+
*/
|
|
11
|
+
export interface TurnStepInput {
|
|
12
|
+
readonly input: HookPayload | undefined;
|
|
13
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
14
|
+
readonly serializedContext: Record<string, unknown>;
|
|
15
|
+
readonly session: HarnessSession;
|
|
16
|
+
}
|
|
6
17
|
/**
|
|
7
18
|
* Runs one atomic harness step inside a durable `"use step"` boundary.
|
|
8
19
|
*/
|
|
9
|
-
export declare function
|
|
20
|
+
export declare function turnStep(input: TurnStepInput): Promise<DurableStepResult>;
|
|
10
21
|
/**
|
|
11
22
|
* Reconciles `session.continuationToken` with the live
|
|
12
23
|
* `ContinuationTokenKey` value in context.
|
|
@@ -30,6 +41,7 @@ export declare function reconcileSessionContinuationToken(ctx: Awaited<ReturnTyp
|
|
|
30
41
|
* runs independently on its own public child stream.
|
|
31
42
|
*/
|
|
32
43
|
export declare function dispatchPendingRuntimeActionsStep(input: {
|
|
44
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
33
45
|
readonly serializedContext: Record<string, unknown>;
|
|
34
46
|
readonly session: HarnessSession;
|
|
35
47
|
}): Promise<HarnessSession>;
|
|
@@ -38,8 +50,9 @@ export declare function dispatchPendingRuntimeActionsStep(input: {
|
|
|
38
50
|
* adapter before the workflow run tears down.
|
|
39
51
|
*/
|
|
40
52
|
export declare function emitTerminalSessionFailureStep(input: {
|
|
41
|
-
readonly serializedContext: Record<string, unknown>;
|
|
42
53
|
readonly error: unknown;
|
|
54
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
55
|
+
readonly serializedContext: Record<string, unknown>;
|
|
43
56
|
}): Promise<void>;
|
|
44
57
|
/**
|
|
45
58
|
* Outcome of {@link runProxyInputRequestStep}, including the session
|
|
@@ -55,6 +68,7 @@ export interface RunProxyInputRequestResult {
|
|
|
55
68
|
*/
|
|
56
69
|
export declare function runProxyInputRequestStep(input: {
|
|
57
70
|
readonly hookPayload: SubagentInputRequestHookPayload;
|
|
71
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
58
72
|
readonly serializedContext: Record<string, unknown>;
|
|
59
73
|
readonly session: HarnessSession;
|
|
60
74
|
}): Promise<RunProxyInputRequestResult>;
|
|
@@ -81,9 +95,20 @@ export interface RoutedProxiedDeliverResult {
|
|
|
81
95
|
*/
|
|
82
96
|
export declare function routeProxiedDeliverStep(input: {
|
|
83
97
|
readonly auth?: SessionAuthContext | null;
|
|
98
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
84
99
|
readonly payload: DeliverPayload;
|
|
85
100
|
readonly session: HarnessSession;
|
|
86
101
|
}): Promise<RoutedProxiedDeliverResult>;
|
|
102
|
+
/**
|
|
103
|
+
* Starts a per-turn child workflow for the current driver session.
|
|
104
|
+
*
|
|
105
|
+
* `parentWritable` is forwarded to the child in the workflow input so
|
|
106
|
+
* the child's step writes land directly on the driver run's stream —
|
|
107
|
+
* no copier, no double-store.
|
|
108
|
+
*/
|
|
109
|
+
export declare function dispatchTurnStep(input: TurnWorkflowInput): Promise<{
|
|
110
|
+
readonly runId: string;
|
|
111
|
+
}>;
|
|
87
112
|
/**
|
|
88
113
|
* Creates the durable session state inside a step boundary before the
|
|
89
114
|
* workflow enters its long-lived turn loop.
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { getWritable } from "#compiled/@workflow/core/index.js";
|
|
2
1
|
import { buildAdapterContext } from "#channel/adapter-context.js";
|
|
3
2
|
import { callAdapterEventHandler, defaultDeliverResult } from "#channel/adapter.js";
|
|
4
3
|
import { toContextAccessor } from "#context/container.js";
|
|
@@ -19,20 +18,21 @@ import { createExecutionNodeStep } from "#execution/node-step.js";
|
|
|
19
18
|
import { emitProxiedInputRequest, routeDeliverPayload } from "#execution/subagent-hitl-proxy.js";
|
|
20
19
|
import { createSession, refreshSessionFromTurnAgent } from "#execution/session.js";
|
|
21
20
|
import { buildSubagentRunInput } from "#execution/subagent-tool.js";
|
|
22
|
-
import {
|
|
21
|
+
import { turnWorkflow } from "#execution/turn-workflow.js";
|
|
22
|
+
import { createWorkflowRuntime, startWorkflowPreferLatest, workflowEntryReference, } from "#execution/workflow-runtime.js";
|
|
23
23
|
/**
|
|
24
24
|
* Runs one atomic harness step inside a durable `"use step"` boundary.
|
|
25
25
|
*/
|
|
26
|
-
export async function
|
|
26
|
+
export async function turnStep(input) {
|
|
27
27
|
"use step";
|
|
28
|
-
const ctx = await deserializeContext(serializedContext);
|
|
28
|
+
const ctx = await deserializeContext(input.serializedContext);
|
|
29
29
|
const adapter = ctx.require(ChannelKey);
|
|
30
30
|
// Apply deliver-time auth if present. The auth traveled through
|
|
31
31
|
// resumeHook as JSON on the HookPayload. On the first turn (from
|
|
32
32
|
// run()), input carries no auth because it was already seeded by
|
|
33
33
|
// buildRunContext.
|
|
34
|
-
if (input?.kind === "deliver" && input.auth !== undefined) {
|
|
35
|
-
ctx.set(AuthKey, input.auth ?? null);
|
|
34
|
+
if (input.input?.kind === "deliver" && input.input.auth !== undefined) {
|
|
35
|
+
ctx.set(AuthKey, input.input.auth ?? null);
|
|
36
36
|
}
|
|
37
37
|
// Build the adapter context for deliver and event handlers.
|
|
38
38
|
// Slack adapters override this to inject ctx.thread and ctx.slack.
|
|
@@ -41,9 +41,9 @@ export async function durableRunStep(serializedContext, session, input) {
|
|
|
41
41
|
// custom context keys and optionally transforms the message.
|
|
42
42
|
// Coalesces the resulting StepInput values.
|
|
43
43
|
let resolved;
|
|
44
|
-
if (input?.kind === "deliver") {
|
|
44
|
+
if (input.input?.kind === "deliver") {
|
|
45
45
|
const results = [];
|
|
46
|
-
for (const payload of input.payloads) {
|
|
46
|
+
for (const payload of input.input.payloads) {
|
|
47
47
|
const result = adapter.deliver
|
|
48
48
|
? await adapter.deliver(payload, adapterCtx)
|
|
49
49
|
: defaultDeliverResult(payload);
|
|
@@ -53,31 +53,27 @@ export async function durableRunStep(serializedContext, session, input) {
|
|
|
53
53
|
}
|
|
54
54
|
resolved = results.length === 0 ? undefined : results.reduce(coalesceTurnInputs);
|
|
55
55
|
}
|
|
56
|
-
else if (input?.kind === "runtime-action-result") {
|
|
57
|
-
resolved = { runtimeActionResults: input.results };
|
|
56
|
+
else if (input.input?.kind === "runtime-action-result") {
|
|
57
|
+
resolved = { runtimeActionResults: input.input.results };
|
|
58
58
|
}
|
|
59
59
|
// Update adapter state on context after deliver mutations.
|
|
60
|
-
if (input?.kind === "deliver") {
|
|
60
|
+
if (input.input?.kind === "deliver") {
|
|
61
61
|
const updatedAdapter = { ...adapter, state: { ...adapterCtx.state } };
|
|
62
62
|
ctx.set(ChannelKey, updatedAdapter);
|
|
63
63
|
}
|
|
64
64
|
// Adapter handled the delivery inline (e.g. a Slack interaction that
|
|
65
65
|
// only edits a message). Persist any context mutations and re-park
|
|
66
66
|
// without running a model turn.
|
|
67
|
-
if (input?.kind === "deliver" && resolved === undefined) {
|
|
68
|
-
const rekeyed = reconcileSessionContinuationToken(ctx, session);
|
|
67
|
+
if (input.input?.kind === "deliver" && resolved === undefined) {
|
|
68
|
+
const rekeyed = reconcileSessionContinuationToken(ctx, input.session);
|
|
69
69
|
const nextSerializedContext = serializeContext(ctx);
|
|
70
|
-
const writable = getWritable();
|
|
71
|
-
const writer = writable.getWriter();
|
|
72
|
-
writer.releaseLock();
|
|
73
70
|
return {
|
|
74
71
|
action: "park",
|
|
75
72
|
serializedContext: nextSerializedContext,
|
|
76
73
|
session: rekeyed,
|
|
77
74
|
};
|
|
78
75
|
}
|
|
79
|
-
const
|
|
80
|
-
const writer = writable.getWriter();
|
|
76
|
+
const writer = input.parentWritable.getWriter();
|
|
81
77
|
const hookRegistry = ctx.require(BundleKey).hookRegistry;
|
|
82
78
|
const emit = async (event) => {
|
|
83
79
|
const toEmit = await callAdapterEventHandler(adapter, event, adapterCtx);
|
|
@@ -85,7 +81,7 @@ export async function durableRunStep(serializedContext, session, input) {
|
|
|
85
81
|
await writer.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(toEmit)));
|
|
86
82
|
await dispatchStreamEventHooks({ ctx, registry: hookRegistry, event: toEmit });
|
|
87
83
|
};
|
|
88
|
-
let stepResult = await runStep(ctx, session, async (enrichedSession) => {
|
|
84
|
+
let stepResult = await runStep(ctx, input.session, async (enrichedSession) => {
|
|
89
85
|
const bundle = ctx.require(BundleKey);
|
|
90
86
|
const capabilities = ctx.get(CapabilitiesKey);
|
|
91
87
|
const mode = ctx.require(ModeKey);
|
|
@@ -223,8 +219,7 @@ export async function dispatchPendingRuntimeActionsStep(input) {
|
|
|
223
219
|
const auth = ctx.get(AuthKey) ?? null;
|
|
224
220
|
const capabilities = ctx.get(CapabilitiesKey);
|
|
225
221
|
const initiatorAuth = ctx.get(InitiatorAuthKey) ?? null;
|
|
226
|
-
const
|
|
227
|
-
const writer = writable.getWriter();
|
|
222
|
+
const writer = input.parentWritable.getWriter();
|
|
228
223
|
const adapterCtx = buildAdapterContext(adapter, toContextAccessor(ctx));
|
|
229
224
|
let nextSession = input.session;
|
|
230
225
|
try {
|
|
@@ -308,8 +303,7 @@ export async function emitTerminalSessionFailureStep(input) {
|
|
|
308
303
|
// consumers (client SDK readers, event-stream replays, dashboards)
|
|
309
304
|
// see a canonical terminal event instead of an abrupt stream close.
|
|
310
305
|
try {
|
|
311
|
-
const
|
|
312
|
-
const writer = writable.getWriter();
|
|
306
|
+
const writer = input.parentWritable.getWriter();
|
|
313
307
|
try {
|
|
314
308
|
await writer.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(event)));
|
|
315
309
|
}
|
|
@@ -335,8 +329,7 @@ export async function runProxyInputRequestStep(input) {
|
|
|
335
329
|
const adapter = ctx.require(ChannelKey);
|
|
336
330
|
const adapterCtx = buildAdapterContext(adapter, toContextAccessor(ctx));
|
|
337
331
|
const mode = ctx.require(ModeKey);
|
|
338
|
-
const
|
|
339
|
-
const writer = writable.getWriter();
|
|
332
|
+
const writer = input.parentWritable.getWriter();
|
|
340
333
|
let proxyResult;
|
|
341
334
|
try {
|
|
342
335
|
const emit = async (event) => {
|
|
@@ -355,7 +348,7 @@ export async function runProxyInputRequestStep(input) {
|
|
|
355
348
|
}
|
|
356
349
|
// Persist adapter-state mutations (e.g. Slack's `pendingRequests`
|
|
357
350
|
// cache populated by the `input.requested` handler) so the next
|
|
358
|
-
// `
|
|
351
|
+
// `turnStep` observes them across the serialized context
|
|
359
352
|
// boundary. Without this the workflow runtime rehydrates a stale
|
|
360
353
|
// adapter and later text-reply deliveries miss the cached batch.
|
|
361
354
|
ctx.set(ChannelKey, { ...adapter, state: { ...adapterCtx.state } });
|
|
@@ -396,6 +389,18 @@ export async function routeProxiedDeliverStep(input) {
|
|
|
396
389
|
}
|
|
397
390
|
return { remainder: routed.forSelf };
|
|
398
391
|
}
|
|
392
|
+
/**
|
|
393
|
+
* Starts a per-turn child workflow for the current driver session.
|
|
394
|
+
*
|
|
395
|
+
* `parentWritable` is forwarded to the child in the workflow input so
|
|
396
|
+
* the child's step writes land directly on the driver run's stream —
|
|
397
|
+
* no copier, no double-store.
|
|
398
|
+
*/
|
|
399
|
+
export async function dispatchTurnStep(input) {
|
|
400
|
+
"use step";
|
|
401
|
+
const run = await startWorkflowPreferLatest(turnWorkflow, [input]);
|
|
402
|
+
return { runId: run.runId };
|
|
403
|
+
}
|
|
399
404
|
/**
|
|
400
405
|
* Creates the durable session state inside a step boundary before the
|
|
401
406
|
* workflow enters its long-lived turn loop.
|
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Process-global store for the authored instrumentation config.
|
|
3
3
|
*
|
|
4
4
|
* Populated at server startup by the generated Nitro instrumentation plugin
|
|
5
5
|
* when the user's `agent/instrumentation.ts` has a default export produced
|
|
6
|
-
* by `defineInstrumentation()`.
|
|
6
|
+
* by `defineInstrumentation()`. The harness reads from this at turn time
|
|
7
|
+
* to decide whether telemetry is enabled and which settings to pass to the
|
|
8
|
+
* AI SDK.
|
|
7
9
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
+
* Rooted on `globalThis` so the generated Nitro instrumentation plugin
|
|
11
|
+
* (which Nitro keeps external by `file://` URL) and the bundled harness
|
|
12
|
+
* chunk (which Nitro inlines via the package's `#harness/*` import alias)
|
|
13
|
+
* share one source of truth, even though they resolve to two distinct ESM
|
|
14
|
+
* module instances. See `context/key.ts` and
|
|
15
|
+
* `runtime/sessions/runtime-session.ts` for the established pattern.
|
|
10
16
|
*/
|
|
11
|
-
|
|
17
|
+
const INSTRUMENTATION_CONFIG_GLOBAL_KEY = Symbol.for("experimental-ash.harness-instrumentation-config");
|
|
18
|
+
const globalContainer = globalThis;
|
|
12
19
|
/**
|
|
13
20
|
* Registers the authored instrumentation config and invokes its `setup`
|
|
14
21
|
* callback with the resolved agent name.
|
|
@@ -22,7 +29,7 @@ export function registerInstrumentationConfig(config, context) {
|
|
|
22
29
|
if (config.setup !== undefined) {
|
|
23
30
|
config.setup(context);
|
|
24
31
|
}
|
|
25
|
-
|
|
32
|
+
globalContainer[INSTRUMENTATION_CONFIG_GLOBAL_KEY] = config;
|
|
26
33
|
}
|
|
27
34
|
/**
|
|
28
35
|
* Returns the registered instrumentation config, or `undefined` when no
|
|
@@ -31,5 +38,5 @@ export function registerInstrumentationConfig(config, context) {
|
|
|
31
38
|
* @internal — not part of the public API.
|
|
32
39
|
*/
|
|
33
40
|
export function getInstrumentationConfig() {
|
|
34
|
-
return
|
|
41
|
+
return globalContainer[INSTRUMENTATION_CONFIG_GLOBAL_KEY];
|
|
35
42
|
}
|
|
@@ -19,9 +19,9 @@ export declare function coalesceTurnInputs(a: StepInput, b: StepInput): StepInpu
|
|
|
19
19
|
*/
|
|
20
20
|
export declare function resolveAssistantStepText(messages: readonly ModelMessage[], fallback: string | undefined): string | null;
|
|
21
21
|
/**
|
|
22
|
-
* Structural shape
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* Structural shape of the workflow `DeliverHookPayload`. Using a
|
|
23
|
+
* structural type keeps this helper decoupled from the concrete
|
|
24
|
+
* runtime type.
|
|
25
25
|
*/
|
|
26
26
|
interface DeliverLike {
|
|
27
27
|
readonly auth?: SessionAuthContext | null;
|
|
@@ -32,10 +32,10 @@ interface DeliverLike {
|
|
|
32
32
|
* Coalesces an array of deliver-like items into a single item by
|
|
33
33
|
* collecting all payloads and keeping the most recent auth value.
|
|
34
34
|
*
|
|
35
|
-
* Used by
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
35
|
+
* Used by the workflow runtime to batch follow-up deliveries that
|
|
36
|
+
* arrived while a turn or subagent delegation was in progress. Each
|
|
37
|
+
* payload is later passed to `onDeliver` individually so channel-
|
|
38
|
+
* specific fields are never lost.
|
|
39
39
|
*/
|
|
40
40
|
export declare function coalesceDeliveries<T extends DeliverLike>(items: readonly T[]): T;
|
|
41
41
|
export {};
|
|
@@ -122,10 +122,10 @@ function toUserContentArray(value) {
|
|
|
122
122
|
* Coalesces an array of deliver-like items into a single item by
|
|
123
123
|
* collecting all payloads and keeping the most recent auth value.
|
|
124
124
|
*
|
|
125
|
-
* Used by
|
|
126
|
-
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
125
|
+
* Used by the workflow runtime to batch follow-up deliveries that
|
|
126
|
+
* arrived while a turn or subagent delegation was in progress. Each
|
|
127
|
+
* payload is later passed to `onDeliver` individually so channel-
|
|
128
|
+
* specific fields are never lost.
|
|
129
129
|
*/
|
|
130
130
|
export function coalesceDeliveries(items) {
|
|
131
131
|
const [first, ...rest] = items;
|
|
@@ -67,10 +67,10 @@ export declare function recordPendingSubagentChildToken(input: {
|
|
|
67
67
|
/**
|
|
68
68
|
* Discriminated item consumed by {@link accumulateRuntimeActionResults}.
|
|
69
69
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
70
|
+
* The workflow runtime receives interleaved deliveries and runtime-action
|
|
71
|
+
* results while waiting for pending subagent calls; this union lets the
|
|
72
|
+
* accumulation loop process both kinds without coupling to the concrete
|
|
73
|
+
* `HookPayload` shape.
|
|
74
74
|
*/
|
|
75
75
|
export type RuntimeActionAccumulatorItem<TDeliver> = {
|
|
76
76
|
readonly kind: "deliver";
|
|
@@ -6,7 +6,7 @@ import { ASH_PACKAGE_NAME } from "#package-name.js";
|
|
|
6
6
|
let cachedPackageInfo;
|
|
7
7
|
// The package build stamps the published version into `dist` so bundled
|
|
8
8
|
// deployments can still report package metadata without resolving package.json.
|
|
9
|
-
const BUNDLED_FALLBACK_PACKAGE_VERSION = "0.
|
|
9
|
+
const BUNDLED_FALLBACK_PACKAGE_VERSION = "0.24.0";
|
|
10
10
|
const BUNDLED_FALLBACK_PACKAGE_VERSION_PLACEHOLDER = "__ASH_PACKAGE_VERSION_PLACEHOLDER__";
|
|
11
11
|
const WORKFLOW_MODULE_ALIASES = {
|
|
12
12
|
"workflow/api": "src/compiled/@workflow/core/runtime.js",
|
|
@@ -28,7 +28,7 @@ export declare const WORKFLOW_QUEUE_TRIGGER: {
|
|
|
28
28
|
readonly retryAfterSeconds: 5;
|
|
29
29
|
readonly initialDelaySeconds: 0;
|
|
30
30
|
};
|
|
31
|
-
export declare function applyWorkflowTransform(filename: string, source: string, mode: "workflow" | "step" | "client" | false, absolutePath?: string, projectRoot?: string): Promise<{
|
|
31
|
+
export declare function applyWorkflowTransform(filename: string, source: string, mode: "workflow" | "step" | "client" | false, absolutePath?: string, projectRoot?: string, stableWorkflowNames?: ReadonlySet<string>): Promise<{
|
|
32
32
|
code: string;
|
|
33
33
|
workflowManifest: WorkflowManifest;
|
|
34
34
|
}>;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
4
|
+
import { STABLE_WORKFLOW_NAMES } from "#execution/workflow-runtime.js";
|
|
4
5
|
import { transformWorkflowDirectives } from "./workflow-transformer.js";
|
|
5
6
|
export const WORKFLOW_QUEUE_TRIGGER = {
|
|
6
7
|
type: "queue/v2beta",
|
|
@@ -11,15 +12,22 @@ export const WORKFLOW_QUEUE_TRIGGER = {
|
|
|
11
12
|
};
|
|
12
13
|
const packageJsonCache = new Map();
|
|
13
14
|
const projectDepsCache = new Map();
|
|
14
|
-
export async function applyWorkflowTransform(filename, source, mode, absolutePath, projectRoot) {
|
|
15
|
+
export async function applyWorkflowTransform(filename, source, mode, absolutePath, projectRoot, stableWorkflowNames = STABLE_WORKFLOW_NAMES) {
|
|
15
16
|
const resolvedProjectRoot = projectRoot ?? process.cwd();
|
|
16
17
|
const absoluteFilename = absolutePath === undefined
|
|
17
18
|
? isAbsolute(filename)
|
|
18
19
|
? filename
|
|
19
20
|
: join(resolvedProjectRoot, filename)
|
|
20
21
|
: absolutePath;
|
|
21
|
-
const { moduleSpecifier } = resolveModuleSpecifier(absoluteFilename, resolvedProjectRoot);
|
|
22
|
-
return transformWorkflowDirectives({
|
|
22
|
+
const { moduleSpecifier, stableModuleSpecifier } = resolveModuleSpecifier(absoluteFilename, resolvedProjectRoot);
|
|
23
|
+
return transformWorkflowDirectives({
|
|
24
|
+
filename,
|
|
25
|
+
mode,
|
|
26
|
+
moduleSpecifier,
|
|
27
|
+
source,
|
|
28
|
+
stableModuleSpecifier,
|
|
29
|
+
stableWorkflowNames,
|
|
30
|
+
});
|
|
23
31
|
}
|
|
24
32
|
export function detectWorkflowPatterns(source) {
|
|
25
33
|
return {
|
|
@@ -58,17 +66,21 @@ function resolveModuleSpecifier(filePath, projectRoot) {
|
|
|
58
66
|
const inNodeModules = isInNodeModules(filePath);
|
|
59
67
|
const inWorkspace = !inNodeModules && isWorkspacePackage(filePath, projectRoot);
|
|
60
68
|
if (!inNodeModules && !inWorkspace) {
|
|
61
|
-
return { moduleSpecifier: undefined };
|
|
69
|
+
return { moduleSpecifier: undefined, stableModuleSpecifier: undefined };
|
|
62
70
|
}
|
|
63
71
|
const pkg = findPackageJson(filePath);
|
|
64
72
|
if (pkg === null) {
|
|
65
|
-
return { moduleSpecifier: undefined };
|
|
73
|
+
return { moduleSpecifier: undefined, stableModuleSpecifier: undefined };
|
|
66
74
|
}
|
|
67
75
|
const subpath = resolveExportSubpath(filePath, pkg);
|
|
76
|
+
// The default specifier is version-stamped for normal workflow/step
|
|
77
|
+
// ids; the stable variant drops the `@<pkg.version>` suffix so
|
|
78
|
+
// {@link STABLE_WORKFLOW_NAMES} functions emit cross-deployment
|
|
79
|
+
// routable ids.
|
|
80
|
+
const base = subpath ? `${pkg.name}${subpath}` : pkg.name;
|
|
68
81
|
return {
|
|
69
|
-
moduleSpecifier:
|
|
70
|
-
|
|
71
|
-
: `${pkg.name}@${pkg.version}`,
|
|
82
|
+
moduleSpecifier: `${base}@${pkg.version}`,
|
|
83
|
+
stableModuleSpecifier: base,
|
|
72
84
|
};
|
|
73
85
|
}
|
|
74
86
|
function findPackageJson(filePath) {
|
|
@@ -5,6 +5,19 @@ export declare function transformWorkflowDirectives(input: {
|
|
|
5
5
|
mode: WorkflowDirectiveMode;
|
|
6
6
|
moduleSpecifier: string | undefined;
|
|
7
7
|
source: string;
|
|
8
|
+
/**
|
|
9
|
+
* Package-qualified module specifier without the `@<pkg.version>`
|
|
10
|
+
* stamp. Used to mint workflow ids for functions named in
|
|
11
|
+
* {@link transformWorkflowDirectives.input.stableWorkflowNames} so
|
|
12
|
+
* the bundled id matches the runtime reference on every deployment.
|
|
13
|
+
*/
|
|
14
|
+
stableModuleSpecifier?: string | undefined;
|
|
15
|
+
/**
|
|
16
|
+
* Workflow function names whose bundled id should be emitted without
|
|
17
|
+
* the package version stamp. See `STABLE_WORKFLOW_NAMES` in
|
|
18
|
+
* `workflow-runtime.ts` for the canonical set ash itself uses.
|
|
19
|
+
*/
|
|
20
|
+
stableWorkflowNames?: ReadonlySet<string>;
|
|
8
21
|
}): Promise<{
|
|
9
22
|
code: string;
|
|
10
23
|
workflowManifest: WorkflowManifest;
|
|
@@ -13,14 +13,19 @@ export async function transformWorkflowDirectives(input) {
|
|
|
13
13
|
if (functions.length === 0) {
|
|
14
14
|
return { code: input.source, workflowManifest: {} };
|
|
15
15
|
}
|
|
16
|
-
|
|
16
|
+
// Step ids stay version-stamped — they are per-deployment internal
|
|
17
|
+
// identifiers, not cross-deployment routing keys. Only workflow
|
|
18
|
+
// functions whose name appears in `stableWorkflowNames` opt out of
|
|
19
|
+
// the version stamp.
|
|
20
|
+
const defaultIdBase = input.moduleSpecifier ?? `./${stripJavaScriptExtension(input.filename)}`;
|
|
21
|
+
const stableIdBase = input.stableModuleSpecifier ?? defaultIdBase;
|
|
17
22
|
const manifest = {};
|
|
18
23
|
const replacements = [];
|
|
19
24
|
const suffixes = [];
|
|
20
25
|
let hasStepRegistration = false;
|
|
21
26
|
for (const fn of functions) {
|
|
22
27
|
if (fn.directive === "use step") {
|
|
23
|
-
const stepId = createStepId(
|
|
28
|
+
const stepId = createStepId(defaultIdBase, fn.name);
|
|
24
29
|
manifest.steps ??= {};
|
|
25
30
|
const stepsForFile = (manifest.steps[input.filename] ??= {});
|
|
26
31
|
stepsForFile[fn.name] = { stepId };
|
|
@@ -44,7 +49,8 @@ export async function transformWorkflowDirectives(input) {
|
|
|
44
49
|
}
|
|
45
50
|
continue;
|
|
46
51
|
}
|
|
47
|
-
const
|
|
52
|
+
const isStable = input.stableWorkflowNames?.has(fn.name) === true;
|
|
53
|
+
const workflowId = `workflow//${isStable ? stableIdBase : defaultIdBase}//${fn.name}`;
|
|
48
54
|
manifest.workflows ??= {};
|
|
49
55
|
const workflowsForFile = (manifest.workflows[input.filename] ??= {});
|
|
50
56
|
workflowsForFile[fn.name] = { workflowId };
|
|
@@ -66,7 +72,7 @@ export async function transformWorkflowDirectives(input) {
|
|
|
66
72
|
const hasWorkflowDirective = functions.some((fn) => fn.directive === "use workflow");
|
|
67
73
|
if (input.mode === "workflow" && !hasWorkflowDirective) {
|
|
68
74
|
return {
|
|
69
|
-
code: `${manifestComment}\n${createWorkflowStepProxySource(input.source, ast, functions,
|
|
75
|
+
code: `${manifestComment}\n${createWorkflowStepProxySource(input.source, ast, functions, defaultIdBase)}`,
|
|
70
76
|
workflowManifest: manifest,
|
|
71
77
|
};
|
|
72
78
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "experimental-ash",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"bin": {
|
|
5
5
|
"ash": "./bin/ash.js",
|
|
6
6
|
"experimental-ash": "./bin/ash.js"
|
|
@@ -174,9 +174,9 @@
|
|
|
174
174
|
"@types/react-test-renderer": "19.1.0",
|
|
175
175
|
"@vercel/oidc": "3.4.0",
|
|
176
176
|
"@vercel/sandbox": "2.0.0-beta.14",
|
|
177
|
-
"@workflow/core": "5.0.0-beta.
|
|
178
|
-
"@workflow/errors": "5.0.0-beta.
|
|
179
|
-
"@workflow/world-local": "5.0.0-beta.
|
|
177
|
+
"@workflow/core": "5.0.0-beta.7",
|
|
178
|
+
"@workflow/errors": "5.0.0-beta.4",
|
|
179
|
+
"@workflow/world-local": "5.0.0-beta.6",
|
|
180
180
|
"ai": "7.0.0-canary.144",
|
|
181
181
|
"autoevals": "0.0.132",
|
|
182
182
|
"chat": "4.28.1",
|