experimental-ash 0.29.0 → 0.30.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 (51) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/dist/src/context/hook-lifecycle.d.ts +23 -67
  3. package/dist/src/context/hook-lifecycle.js +1 -1
  4. package/dist/src/execution/await-authorization-orchestrator.d.ts +18 -29
  5. package/dist/src/execution/await-authorization-orchestrator.js +1 -1
  6. package/dist/src/execution/connection-auth-steps.d.ts +28 -65
  7. package/dist/src/execution/connection-auth-steps.js +1 -1
  8. package/dist/src/execution/create-session-step.d.ts +15 -0
  9. package/dist/src/execution/create-session-step.js +1 -0
  10. package/dist/src/execution/delegated-parent-notification.d.ts +15 -0
  11. package/dist/src/execution/delegated-parent-notification.js +1 -0
  12. package/dist/src/execution/delegated-parent-result.d.ts +14 -0
  13. package/dist/src/execution/delegated-parent-result.js +1 -0
  14. package/dist/src/execution/dispatch-runtime-actions-step.d.ts +20 -0
  15. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -0
  16. package/dist/src/execution/durable-session-migrations/chain.d.ts +31 -0
  17. package/dist/src/execution/durable-session-migrations/chain.js +1 -0
  18. package/dist/src/execution/durable-session-migrations/snapshot.d.ts +22 -0
  19. package/dist/src/execution/durable-session-migrations/snapshot.js +1 -0
  20. package/dist/src/execution/durable-session-store.d.ts +104 -0
  21. package/dist/src/execution/durable-session-store.js +1 -0
  22. package/dist/src/execution/next-driver-action.d.ts +30 -0
  23. package/dist/src/execution/next-driver-action.js +1 -0
  24. package/dist/src/execution/session.d.ts +29 -28
  25. package/dist/src/execution/session.js +1 -1
  26. package/dist/src/execution/subagent-hitl-proxy.d.ts +8 -25
  27. package/dist/src/execution/subagent-hitl-proxy.js +1 -1
  28. package/dist/src/execution/subagent-tool.js +1 -1
  29. package/dist/src/execution/turn-workflow.d.ts +21 -21
  30. package/dist/src/execution/turn-workflow.js +1 -1
  31. package/dist/src/execution/workflow-entry.d.ts +12 -16
  32. package/dist/src/execution/workflow-entry.js +1 -1
  33. package/dist/src/execution/workflow-runtime.js +1 -1
  34. package/dist/src/execution/workflow-steps.d.ts +36 -91
  35. package/dist/src/execution/workflow-steps.js +1 -1
  36. package/dist/src/harness/emission.d.ts +3 -5
  37. package/dist/src/harness/emission.js +1 -1
  38. package/dist/src/harness/input-requests.d.ts +3 -3
  39. package/dist/src/harness/input-requests.js +1 -1
  40. package/dist/src/harness/proxy-input-requests.d.ts +12 -16
  41. package/dist/src/harness/proxy-input-requests.js +1 -1
  42. package/dist/src/harness/runtime-actions.d.ts +17 -24
  43. package/dist/src/harness/runtime-actions.js +1 -1
  44. package/dist/src/harness/tool-loop.js +1 -1
  45. package/dist/src/harness/types.d.ts +3 -1
  46. package/dist/src/internal/application/package.js +1 -1
  47. package/dist/src/internal/nitro/routes/info.js +1 -1
  48. package/dist/src/internal/workflow-bundle/builder.d.ts +2 -0
  49. package/dist/src/internal/workflow-bundle/builder.js +1 -1
  50. package/dist/src/runtime/framework-channels/index.js +1 -1
  51. package/package.json +1 -1
@@ -0,0 +1,104 @@
1
+ /**
2
+ * Durable session storage.
3
+ *
4
+ * Each driver workflow run owns one stream at namespace `"ash.session"`.
5
+ * Session-mutating steps append one snapshot per mutation; reads pull
6
+ * the tail (`startIndex: -1`). Step inputs, step results, and hook
7
+ * payloads carry a small {@link DurableSessionState} value — never the
8
+ * full {@link HarnessSession}.
9
+ *
10
+ * The driver workflow run is pinned to the deployment that called
11
+ * `start()`; child turn workflows run on latest. Both
12
+ * {@link DurableSessionState} and {@link DurableSessionSnapshot} carry
13
+ * a `version` so a pinned driver can ferry shapes written by newer
14
+ * steps. Adding optional fields is forward-compatible (devalue
15
+ * preserves unknown POJO fields); shape-breaking changes bump
16
+ * `version` and add a migrator.
17
+ */
18
+ import type { ModelMessage } from "ai";
19
+ import { type HarnessEmissionState } from "#harness/emission.js";
20
+ import type { HarnessSession, SessionStateMap } from "#harness/types.js";
21
+ import type { SandboxState } from "#sandbox/state.js";
22
+ /** Workflow stream namespace where every session snapshot lands. */
23
+ export declare const ASH_SESSION_STREAM_NAMESPACE = "ash.session";
24
+ /** Current wire version for {@link DurableSessionState} and {@link DurableSessionSnapshot}. */
25
+ export declare const DURABLE_SESSION_VERSION = 1;
26
+ /**
27
+ * Serializable handle to a durable session.
28
+ *
29
+ * Carries only the small projections the workflow body needs without
30
+ * taking a step boundary: identity, the hook continuation token,
31
+ * `hasProxyInputRequests` (a closed-contract short-circuit that lets
32
+ * the driver skip a per-delivery proxy-routing step when no
33
+ * descendant subagent is active), and `emissionState` (so workflow-body
34
+ * orchestrators — eg. await-authorization — can stamp protocol events
35
+ * with `{ turnId, sequence, stepIndex }` without reading the full
36
+ * durable session). All other control-plane state travels via
37
+ * {@link import("#execution/next-driver-action.js").NextDriverAction}.
38
+ */
39
+ export interface DurableSessionState {
40
+ readonly version: typeof DURABLE_SESSION_VERSION;
41
+ readonly sessionId: string;
42
+ readonly continuationToken: string;
43
+ readonly hasProxyInputRequests: boolean;
44
+ readonly emissionState: HarnessEmissionState;
45
+ }
46
+ /**
47
+ * Durable projection of {@link HarnessSession} written to the
48
+ * `ash.session` stream.
49
+ *
50
+ * Omits `agent.modelReference`, `agent.tools`,
51
+ * `agent.compactionModelReference`, and the `compaction` thresholds —
52
+ * those are rebuilt every turn from `bundle.turnAgent` by
53
+ * {@link import("#execution/session.js").hydrateDurableSession}.
54
+ * `agent.system` is the session-start prompt snapshot, pinned at
55
+ * `createSession`.
56
+ */
57
+ export interface DurableSession {
58
+ readonly sessionId: string;
59
+ readonly continuationToken: string;
60
+ readonly history: ModelMessage[];
61
+ readonly state?: SessionStateMap;
62
+ readonly sandboxState?: SandboxState;
63
+ readonly agent: {
64
+ readonly system: string;
65
+ };
66
+ readonly compaction?: {
67
+ readonly lastKnownInputTokens?: number;
68
+ readonly lastKnownPromptMessageCount?: number;
69
+ };
70
+ }
71
+ /** Versioned wrapper around a {@link DurableSession} on the wire. */
72
+ export interface DurableSessionSnapshot {
73
+ readonly version: typeof DURABLE_SESSION_VERSION;
74
+ readonly session: DurableSession;
75
+ }
76
+ /** Projects a {@link HarnessSession} into the boundary-safe state value. */
77
+ export declare function projectSessionState(input: {
78
+ readonly session: HarnessSession;
79
+ }): DurableSessionState;
80
+ /**
81
+ * Reads the latest snapshot from the `ash.session` stream and returns
82
+ * the {@link DurableSession} inside.
83
+ *
84
+ * Always pulls the tail chunk (`startIndex: -1`); the
85
+ * single-writer-per-session-stream invariant makes that safe. The
86
+ * snapshot is migrated to {@link DURABLE_SESSION_VERSION} before
87
+ * return; unknown versions throw.
88
+ *
89
+ * Devalue handles encode/decode so rich types in the session (URL
90
+ * `FilePart.data`, Buffer, Date, Map, Set) round-trip structurally.
91
+ *
92
+ * MUST be called from inside a `"use step"` body.
93
+ */
94
+ export declare function readDurableSession(state: DurableSessionState): Promise<DurableSession>;
95
+ /**
96
+ * Appends one snapshot to the `ash.session` stream and returns the
97
+ * projected {@link DurableSessionState}.
98
+ *
99
+ * MUST be called from inside a `"use step"` body.
100
+ */
101
+ export declare function writeDurableSession(input: {
102
+ readonly session: HarnessSession;
103
+ readonly writable: WritableStream<DurableSessionSnapshot>;
104
+ }): Promise<DurableSessionState>;
@@ -0,0 +1 @@
1
+ import{getHarnessEmissionState}from"#harness/emission.js";import{projectToDurableSession}from"#execution/session.js";import{hasProxyInputRequests}from"#harness/proxy-input-requests.js";import{migrateDurableSessionSnapshot}from"#execution/durable-session-migrations/snapshot.js";const ASH_SESSION_STREAM_NAMESPACE=`ash.session`,DURABLE_SESSION_VERSION=1;function projectSessionState(t){return{continuationToken:t.session.continuationToken,emissionState:getHarnessEmissionState(t.session.state),hasProxyInputRequests:hasProxyInputRequests(t.session.state),sessionId:t.session.sessionId,version:1}}async function readDurableSession(e){let{getRun:t}=await import(`#compiled/@workflow/core/runtime.js`),{value:n,done:i}=await t(e.sessionId).getReadable({namespace:ASH_SESSION_STREAM_NAMESPACE,startIndex:-1}).getReader().read();if(i||n===void 0)throw Error(`No durable session snapshot found in stream "${ASH_SESSION_STREAM_NAMESPACE}" for run ${e.sessionId}.`);return migrateDurableSessionSnapshot(n).session}async function writeDurableSession(e){let n={session:projectToDurableSession(e.session),version:1},r=e.writable.getWriter();try{await r.write(n)}finally{r.releaseLock()}return projectSessionState({session:e.session})}export{ASH_SESSION_STREAM_NAMESPACE,DURABLE_SESSION_VERSION,projectSessionState,readDurableSession,writeDurableSession};
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Closed-contract dispatch surface between session-mutating step
3
+ * bodies (latest deployment) and the durable driver workflow (pinned
4
+ * to whichever deployment called `start()`).
5
+ *
6
+ * The driver matches on `kind` and follows a fixed playbook per arm.
7
+ * Adding a new arm is breaking (pinned drivers can't dispatch an
8
+ * unknown `kind`); adding optional fields inside an existing arm is
9
+ * forward-compatible because the driver passes the action through by
10
+ * reference and devalue preserves unknown POJO fields. Do not
11
+ * destructure-and-rebuild a `NextDriverAction` — full destructuring
12
+ * strips unknown fields.
13
+ */
14
+ import type { DurableSessionState } from "#execution/durable-session-store.js";
15
+ /** Discriminated union the driver workflow body dispatches on. */
16
+ export type NextDriverAction = {
17
+ readonly kind: "done";
18
+ readonly output: string;
19
+ readonly sessionState: DurableSessionState;
20
+ readonly serializedContext: Record<string, unknown>;
21
+ } | {
22
+ readonly kind: "park";
23
+ readonly sessionState: DurableSessionState;
24
+ readonly serializedContext: Record<string, unknown>;
25
+ } | {
26
+ readonly kind: "dispatch-runtime-actions";
27
+ readonly pendingActionKeys: readonly string[];
28
+ readonly sessionState: DurableSessionState;
29
+ readonly serializedContext: Record<string, unknown>;
30
+ };
@@ -0,0 +1 @@
1
+ export{};
@@ -1,3 +1,4 @@
1
+ import type { DurableSession } from "#execution/durable-session-store.js";
1
2
  import type { HarnessSession } from "#harness/types.js";
2
3
  import type { RuntimeTurnAgent } from "#runtime/agent/bootstrap.js";
3
4
  /**
@@ -17,17 +18,6 @@ export declare function createCompactionConfig(input?: {
17
18
  lastKnownInputTokens: number;
18
19
  lastKnownPromptMessageCount: number | undefined;
19
20
  };
20
- /**
21
- * Input for {@link createSession}.
22
- *
23
- * `turnAgent` is the already-resolved agent definition that will drive the
24
- * session — either the root turn agent from a compiled bundle, or a child
25
- * subagent's turn agent from a resolved graph node.
26
- *
27
- * `compactionOverrides` lets the caller override compaction defaults (e.g. a
28
- * root caller forwarding an authored `thresholdPercent` from the resolved
29
- * agent config). Subagent callers typically omit this.
30
- */
31
21
  export interface CreateSessionInput {
32
22
  readonly continuationToken: string;
33
23
  readonly compactionOverrides?: {
@@ -37,22 +27,15 @@ export interface CreateSessionInput {
37
27
  readonly turnAgent: RuntimeTurnAgent;
38
28
  }
39
29
  /**
40
- * Creates a fresh serializable {@link HarnessSession} for a harness run.
41
- *
42
- * This is the only place that derives `session.agent.system` from a
43
- * `turnAgent`. The system prompt is a session-start snapshot: once
44
- * created here it is preserved unchanged for every subsequent turn.
45
- * Use {@link refreshSessionFromTurnAgent} to update model/tool metadata
46
- * on an existing session without touching the system prompt.
30
+ * Creates a fresh {@link HarnessSession}. The only site that derives
31
+ * `session.agent.system` from a `turnAgent` — every subsequent turn
32
+ * preserves the prompt via {@link refreshSessionFromTurnAgent}.
47
33
  */
48
34
  export declare function createSession(input: CreateSessionInput): HarnessSession;
49
35
  /**
50
- * Refreshes one existing session with the latest resolved turn-agent shape.
51
- *
52
- * Preserves durable history, state, and the system prompt while replacing
53
- * model/tool metadata and recalculating compaction thresholds from current
54
- * authored config. The system prompt is a session-start snapshot set by
55
- * {@link createSession} and is never rebuilt during refresh.
36
+ * Refreshes a session with the latest `turnAgent` replaces model/tool
37
+ * metadata and recalculates compaction thresholds; preserves history,
38
+ * state, and the session-start `agent.system` prompt.
56
39
  */
57
40
  export declare function refreshSessionFromTurnAgent(input: {
58
41
  readonly session: HarnessSession;
@@ -63,9 +46,27 @@ export declare function refreshSessionFromTurnAgent(input: {
63
46
  }): HarnessSession;
64
47
  /**
65
48
  * Mints a continuation token for a delegated subagent session.
66
- *
67
- * The `subagent:` prefix identifies the token as a child run handle. The
68
- * token is deterministic per parent call when `suffix` is provided so runtime
69
- * retries can address the same delegated child hook token.
49
+ * Deterministic when `suffix` is provided so retries address the same
50
+ * child hook.
70
51
  */
71
52
  export declare function mintSubagentContinuationToken(suffix?: string): string;
53
+ /**
54
+ * Projects a {@link HarnessSession} to {@link DurableSession}.
55
+ *
56
+ * Drops fields rebuilt every turn from `bundle.turnAgent`; keeps
57
+ * `agent.system` and `compaction.lastKnown*` so compaction stays
58
+ * informed after rehydration.
59
+ */
60
+ export declare function projectToDurableSession(session: HarnessSession): DurableSession;
61
+ /**
62
+ * Rehydrates a {@link HarnessSession} from a {@link DurableSession}
63
+ * plus the current `turnAgent`, rebuilding the runtime-only agent and
64
+ * compaction fields the durable shape omits.
65
+ */
66
+ export declare function hydrateDurableSession(input: {
67
+ readonly durable: DurableSession;
68
+ readonly turnAgent: RuntimeTurnAgent;
69
+ readonly compactionOverrides?: {
70
+ readonly thresholdPercent?: number;
71
+ };
72
+ }): HarnessSession;
@@ -1,3 +1,3 @@
1
1
  function createCompactionConfig(e={}){let t=e.thresholdPercent??.9,n={recentWindowSize:10,threshold:e.contextWindowTokens===void 0?1e5:Math.max(1,Math.floor(e.contextWindowTokens*t))};return e.lastKnownInputTokens===void 0?n:{...n,lastKnownInputTokens:e.lastKnownInputTokens,lastKnownPromptMessageCount:e.lastKnownPromptMessageCount}}function createSession(e){let{turnAgent:t}=e,n=createSessionToolDefinitions(t);return{agent:{compactionModelReference:t.compactionModel,modelReference:t.model,system:t.instructions.join(`
2
2
 
3
- `),tools:n},compaction:createCompactionConfig({contextWindowTokens:t.model.contextWindowTokens,thresholdPercent:e.compactionOverrides?.thresholdPercent}),continuationToken:e.continuationToken,history:[],sessionId:e.sessionId}}function refreshSessionFromTurnAgent(e){return{...e.session,agent:{compactionModelReference:e.turnAgent.compactionModel,modelReference:e.turnAgent.model,system:e.session.agent.system,tools:createSessionToolDefinitions(e.turnAgent)},compaction:createCompactionConfig({contextWindowTokens:e.turnAgent.model.contextWindowTokens,lastKnownInputTokens:e.session.compaction.lastKnownInputTokens,lastKnownPromptMessageCount:e.session.compaction.lastKnownPromptMessageCount,thresholdPercent:e.compactionOverrides?.thresholdPercent})}}function mintSubagentContinuationToken(e){return`subagent:${e??crypto.randomUUID()}`}function createSessionToolDefinitions(e){return e.tools.map(e=>({description:e.description??``,inputSchema:e.inputSchema,name:e.name}))}export{createCompactionConfig,createSession,mintSubagentContinuationToken,refreshSessionFromTurnAgent};
3
+ `),tools:n},compaction:createCompactionConfig({contextWindowTokens:t.model.contextWindowTokens,thresholdPercent:e.compactionOverrides?.thresholdPercent}),continuationToken:e.continuationToken,history:[],sessionId:e.sessionId}}function refreshSessionFromTurnAgent(e){return{...e.session,agent:{compactionModelReference:e.turnAgent.compactionModel,modelReference:e.turnAgent.model,system:e.session.agent.system,tools:createSessionToolDefinitions(e.turnAgent)},compaction:createCompactionConfig({contextWindowTokens:e.turnAgent.model.contextWindowTokens,lastKnownInputTokens:e.session.compaction.lastKnownInputTokens,lastKnownPromptMessageCount:e.session.compaction.lastKnownPromptMessageCount,thresholdPercent:e.compactionOverrides?.thresholdPercent})}}function mintSubagentContinuationToken(e){return`subagent:${e??crypto.randomUUID()}`}function projectToDurableSession(e){let t={agent:{system:e.agent.system},continuationToken:e.continuationToken,history:e.history,sessionId:e.sessionId};return(e.compaction.lastKnownInputTokens!==void 0||e.compaction.lastKnownPromptMessageCount!==void 0)&&(t.compaction={lastKnownInputTokens:e.compaction.lastKnownInputTokens,lastKnownPromptMessageCount:e.compaction.lastKnownPromptMessageCount}),e.sandboxState!==void 0&&(t.sandboxState=e.sandboxState),e.state!==void 0&&(t.state=e.state),t}function hydrateDurableSession(e){let{durable:t,turnAgent:n}=e,r=createSessionToolDefinitions(n),i={agent:{compactionModelReference:n.compactionModel,modelReference:n.model,system:t.agent.system,tools:r},compaction:createCompactionConfig({contextWindowTokens:n.model.contextWindowTokens,lastKnownInputTokens:t.compaction?.lastKnownInputTokens,lastKnownPromptMessageCount:t.compaction?.lastKnownPromptMessageCount,thresholdPercent:e.compactionOverrides?.thresholdPercent}),continuationToken:t.continuationToken,history:t.history,sessionId:t.sessionId};return t.sandboxState!==void 0&&(i.sandboxState=t.sandboxState),t.state!==void 0&&(i.state=t.state),i}function createSessionToolDefinitions(e){return e.tools.map(e=>({description:e.description??``,inputSchema:e.inputSchema,name:e.name}))}export{createCompactionConfig,createSession,hydrateDurableSession,mintSubagentContinuationToken,projectToDurableSession,refreshSessionFromTurnAgent};
@@ -1,13 +1,10 @@
1
1
  import type { DeliverPayload, SubagentInputRequestHookPayload } from "#channel/types.js";
2
- import type { HarnessEmitFn, HarnessSession } from "#harness/types.js";
2
+ import type { HarnessEmitFn, HarnessSession, SessionStateMap } from "#harness/types.js";
3
3
  import type { RunMode } from "#shared/run-mode.js";
4
4
  import type { InputResponse } from "#runtime/input/types.js";
5
5
  /**
6
- * Runs the parent-side work when a `subagent-input-request` arrives at
7
- * the workflow runtime.
8
- *
9
- * Conversation mode emits a waiting boundary on the parent stream while
10
- * the parent harness remains parked on the child call; the returned proxy
6
+ * Runs the parent-side work for a `subagent-input-request`. Conversation
7
+ * mode emits a waiting boundary on the parent stream; the returned proxy
11
8
  * entries route the eventual response back down to the child.
12
9
  */
13
10
  export declare function emitProxiedInputRequest(input: {
@@ -20,16 +17,9 @@ export declare function emitProxiedInputRequest(input: {
20
17
  readonly session: HarnessSession;
21
18
  }>;
22
19
  /**
23
- * Outcome of splitting one deliver payload into parent-local and
24
- * proxied-child buckets.
25
- *
26
- * `forSelf` carries the payload the parent's own harness should see —
27
- * every non-`inputResponses` field is preserved verbatim, and any
28
- * response whose `requestId` does not match a proxy entry stays here.
29
- *
30
- * `forChildren` carries one payload per distinct descendant
31
- * continuation token. Each payload contains only the responses that
32
- * target that child.
20
+ * Outcome of splitting one deliver payload by the session's proxy map.
21
+ * `forSelf` is the parent-local remainder (or `undefined` when fully
22
+ * routed); `forChildren` carries one entry per descendant token.
33
23
  */
34
24
  export interface RoutedDeliverPayload {
35
25
  readonly forChildren: readonly {
@@ -40,15 +30,8 @@ export interface RoutedDeliverPayload {
40
30
  }[];
41
31
  readonly forSelf: DeliverPayload | undefined;
42
32
  }
43
- /**
44
- * Splits an inbound {@link DeliverPayload} into parent-local and
45
- * proxied-child buckets based on the session's proxy map.
46
- *
47
- * When a payload carries neither a parent-local response nor any
48
- * adapter-specific field, `forSelf` is `undefined` and the parent
49
- * should re-park without running a model turn.
50
- */
33
+ /** Splits a deliver payload into parent-local and proxied-child buckets. */
51
34
  export declare function routeDeliverPayload(input: {
52
35
  readonly payload: DeliverPayload;
53
- readonly session: HarnessSession;
36
+ readonly state: SessionStateMap | undefined;
54
37
  }): RoutedDeliverPayload;
@@ -1 +1 @@
1
- import{createInputRequestedEvent}from"#protocol/message.js";import{emitTurnEpilogue,getHarnessEmissionState,setHarnessEmissionState}from"#harness/emission.js";import{getProxyInputRequests,toProxyInputRequestEntries}from"#harness/proxy-input-requests.js";async function emitProxiedInputRequest(i){await i.emit(createInputRequestedEvent({requests:i.hookPayload.event.requests,sequence:i.hookPayload.event.sequence,stepIndex:i.hookPayload.event.stepIndex,turnId:i.hookPayload.event.turnId}));let o=i.session;if(i.mode===`conversation`){let e=getHarnessEmissionState(i.session),a=await emitTurnEpilogue(i.emit,e,i.mode);o=setHarnessEmissionState(i.session,a)}return{entries:toProxyInputRequestEntries(i.hookPayload),session:o}}function routeDeliverPayload(e){let t=getProxyInputRequests(e.session),n=e.payload.inputResponses??[],r=new Map,a=[];for(let e of n){let n=t.get(e.requestId);if(n===void 0){a.push(e);continue}let i=r.get(n);i===void 0?r.set(n,[e]):i.push(e)}let o=[...r.entries()].map(([e,t])=>({childContinuationToken:e,payload:{inputResponses:t}})),s={};for(let[t,n]of Object.entries(e.payload))t===`inputResponses`||n===void 0||(s[t]=n);return a.length>0&&(s.inputResponses=a),{forChildren:o,forSelf:Object.keys(s).length>0?s:void 0}}export{emitProxiedInputRequest,routeDeliverPayload};
1
+ import{createInputRequestedEvent}from"#protocol/message.js";import{emitTurnEpilogue,getHarnessEmissionState,setHarnessEmissionState}from"#harness/emission.js";import{getProxyInputRequests,toProxyInputRequestEntries}from"#harness/proxy-input-requests.js";async function emitProxiedInputRequest(i){await i.emit(createInputRequestedEvent({requests:i.hookPayload.event.requests,sequence:i.hookPayload.event.sequence,stepIndex:i.hookPayload.event.stepIndex,turnId:i.hookPayload.event.turnId}));let o=i.session;if(i.mode===`conversation`){let e=getHarnessEmissionState(i.session.state),a=await emitTurnEpilogue(i.emit,e,i.mode);o=setHarnessEmissionState(i.session,a)}return{entries:toProxyInputRequestEntries(i.hookPayload),session:o}}function routeDeliverPayload(e){let t=getProxyInputRequests(e.state),n=e.payload.inputResponses??[],r=new Map,a=[];for(let e of n){let n=t.get(e.requestId);if(n===void 0){a.push(e);continue}let i=r.get(n);i===void 0?r.set(n,[e]):i.push(e)}let o=[...r.entries()].map(([e,t])=>({childContinuationToken:e,payload:{inputResponses:t}})),s={};for(let[t,n]of Object.entries(e.payload))t===`inputResponses`||n===void 0||(s[t]=n);return a.length>0&&(s.inputResponses=a),{forChildren:o,forSelf:Object.keys(s).length>0?s:void 0}}export{emitProxiedInputRequest,routeDeliverPayload};
@@ -1 +1 @@
1
- import{formatSubagentInvocation}from"#execution/subagent-invocation.js";import{SUBAGENT_ADAPTER_KIND}from"#execution/subagent-adapter.js";import{mintSubagentContinuationToken}from"#execution/session.js";function buildSubagentRunInput(e){let{action:r,auth:i,batchEvent:a,capabilities:o,initiatorAuth:s,session:c}=e,l=mintSubagentContinuationToken(`${c.sessionId}:${r.callId}`);return{childContinuationToken:l,runInput:{adapter:{kind:SUBAGENT_ADAPTER_KIND,state:{callId:r.callId,parentContinuationToken:c.continuationToken,parentSessionId:c.sessionId,subagentName:r.subagentName}},auth:i,capabilities:o,continuationToken:l,initiatorAuth:s,input:{message:formatSubagentCallInputMessage(r)},mode:`task`,parent:{sessionId:c.sessionId,turn:{id:a.turnId,sequence:a.sequence}}}}}function formatSubagentCallInputMessage(t){let{message:n}=t.input;return formatSubagentInvocation({description:t.description,message:n,name:t.subagentName}).message}export{buildSubagentRunInput};
1
+ import{mintSubagentContinuationToken}from"#execution/session.js";import{SUBAGENT_ADAPTER_KIND}from"#execution/subagent-adapter.js";import{formatSubagentInvocation}from"#execution/subagent-invocation.js";function buildSubagentRunInput(n){let{action:r,auth:i,batchEvent:a,capabilities:o,initiatorAuth:s,session:c}=n,l=mintSubagentContinuationToken(`${c.sessionId}:${r.callId}`);return{childContinuationToken:l,runInput:{adapter:{kind:SUBAGENT_ADAPTER_KIND,state:{callId:r.callId,parentContinuationToken:c.continuationToken,parentSessionId:c.sessionId,subagentName:r.subagentName}},auth:i,capabilities:o,continuationToken:l,initiatorAuth:s,input:{message:formatSubagentCallInputMessage(r)},mode:`task`,parent:{sessionId:c.sessionId,turn:{id:a.turnId,sequence:a.sequence}}}}}function formatSubagentCallInputMessage(e){let{message:t}=e.input;return formatSubagentInvocation({description:e.description,message:t,name:e.subagentName}).message}export{buildSubagentRunInput};
@@ -1,18 +1,20 @@
1
1
  import type { HookPayload, SessionCapabilities } from "#channel/types.js";
2
- import type { HarnessSession } from "#harness/types.js";
3
2
  import type { RunMode } from "#shared/run-mode.js";
4
- export interface TurnResultPayload {
5
- readonly action: "done" | "park";
3
+ import type { DurableSessionSnapshot, DurableSessionState } from "#execution/durable-session-store.js";
4
+ import type { NextDriverAction } from "#execution/next-driver-action.js";
5
+ /**
6
+ * Hook payload the turn child workflow delivers to the parent driver
7
+ * on completion. `turn-result` wraps a {@link NextDriverAction} the
8
+ * driver dispatches on; `turn-error` carries a normalized error the
9
+ * driver rethrows.
10
+ */
11
+ export type TurnCompletionPayload = {
6
12
  readonly kind: "turn-result";
7
- readonly output?: string;
8
- readonly serializedContext: Record<string, unknown>;
9
- readonly session: HarnessSession;
10
- }
11
- export interface TurnErrorPayload {
12
- readonly error: unknown;
13
+ readonly action: NextDriverAction;
14
+ } | {
13
15
  readonly kind: "turn-error";
14
- }
15
- export type TurnCompletionPayload = TurnResultPayload | TurnErrorPayload;
16
+ readonly error: unknown;
17
+ };
16
18
  export interface TurnWorkflowInput {
17
19
  readonly capabilities: SessionCapabilities | undefined;
18
20
  readonly completionToken: string;
@@ -20,21 +22,19 @@ export interface TurnWorkflowInput {
20
22
  readonly mode: RunMode;
21
23
  readonly parentWritable: WritableStream<Uint8Array>;
22
24
  readonly serializedContext: Record<string, unknown>;
23
- readonly session: HarnessSession;
25
+ readonly sessionState: DurableSessionState;
26
+ readonly sessionWritable: WritableStream<DurableSessionSnapshot>;
24
27
  }
25
28
  /**
26
- * Short-lived workflow that owns one runtime turn for the durable
27
- * driver.
29
+ * Short-lived workflow that owns one runtime turn for the driver.
28
30
  *
29
- * `parentWritable` is received from the driver input object and
30
- * threaded into every step so the child's writes land directly on the
31
- * driver run's stream.
31
+ * `parentWritable` and `sessionWritable` are threaded in from the
32
+ * driver run so step writes land on the driver's streams. Resolves the
33
+ * turn into a {@link NextDriverAction} and reports it back through
34
+ * {@link notifyDriverStep}.
32
35
  */
33
36
  export declare function turnWorkflow(input: TurnWorkflowInput): Promise<void>;
34
- /**
35
- * Completes a driver-owned one-shot hook with the result of the child
36
- * turn workflow.
37
- */
37
+ /** Resumes the driver's one-shot completion hook with the turn result. */
38
38
  export declare function notifyDriverStep(input: {
39
39
  readonly completionToken: string;
40
40
  readonly payload: TurnCompletionPayload;
@@ -1 +1 @@
1
- import{hasPendingInputBatch}from"#harness/input-requests.js";import{hasPendingRuntimeActionBatch}from"#harness/runtime-actions.js";import{awaitAuthorizationAndResolve}from"#execution/await-authorization-orchestrator.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{turnStep}from"#execution/workflow-steps.js";async function turnWorkflow(r){"use workflow";let i=r.session,a=r.serializedContext,o=r.delivery,s=r.parentWritable;try{for(;;){let n=await turnStep({input:o,parentWritable:s,serializedContext:a,session:i});if(i=n.session,a=n.serializedContext,n.action===`done`){await notifyDriverStep({completionToken:r.completionToken,payload:{action:`done`,kind:`turn-result`,output:n.output??``,serializedContext:a,session:i}});return}if(n.action===`park`){if(hasPendingRuntimeActionBatch(i)||hasPendingInputBatch(i)&&r.capabilities?.requestInput===!0||r.mode===`conversation`){await notifyDriverStep({completionToken:r.completionToken,payload:{action:`park`,kind:`turn-result`,serializedContext:a,session:i}});return}throw Error("Task mode cannot wait for follow-up input (`next: null`).")}if(n.action===`await-authorization`){let e=await awaitAuthorizationAndResolve({parentWritable:s,pendingToolCalls:n.pendingToolCalls,serializedContext:a,session:i});i=e.session,a=e.serializedContext,o=void 0;continue}o=void 0}}catch(e){throw await notifyDriverStep({completionToken:r.completionToken,payload:{error:normalizeSerializableError(e),kind:`turn-error`}}),e}}async function notifyDriverStep(e){"use step";let{resumeHook:t}=await import(`#compiled/@workflow/core/runtime.js`);await t(e.completionToken,e.payload)}export{notifyDriverStep,turnWorkflow};
1
+ import{awaitAuthorizationAndResolve}from"#execution/await-authorization-orchestrator.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{turnStep}from"#execution/workflow-steps.js";async function turnWorkflow(r){"use workflow";let i=r.sessionState,a=r.serializedContext,o=r.delivery,s=r.parentWritable,c=r.sessionWritable;try{for(;;){let t=await turnStep({input:o,parentWritable:s,serializedContext:a,sessionState:i,sessionWritable:c});if(i=t.sessionState,a=t.serializedContext,t.action===`done`){await notifyDriverStep({completionToken:r.completionToken,payload:{action:{kind:`done`,output:t.output??``,serializedContext:a,sessionState:i},kind:`turn-result`}});return}if(t.action===`park`){let e=t.pendingRuntimeActionKeys;if(!(e!==void 0||t.hasPendingInputBatch&&r.capabilities?.requestInput===!0||r.mode===`conversation`))throw Error("Task mode cannot wait for follow-up input (`next: null`).");let n=e===void 0?{kind:`park`,serializedContext:a,sessionState:i}:{kind:`dispatch-runtime-actions`,pendingActionKeys:e,serializedContext:a,sessionState:i};await notifyDriverStep({completionToken:r.completionToken,payload:{action:n,kind:`turn-result`}});return}if(t.action===`await-authorization`){let n=await awaitAuthorizationAndResolve({parentWritable:s,pendingToolCalls:t.pendingToolCalls,serializedContext:a,sessionState:i,sessionWritable:c});i=n.sessionState,a=n.serializedContext,o=void 0;continue}o=void 0}}catch(e){throw await notifyDriverStep({completionToken:r.completionToken,payload:{error:normalizeSerializableError(e),kind:`turn-error`}}),e}}async function notifyDriverStep(e){"use step";let{resumeHook:t}=await import(`#compiled/@workflow/core/runtime.js`);await t(e.completionToken,e.payload)}export{notifyDriverStep,turnWorkflow};
@@ -1,30 +1,26 @@
1
1
  import type { RunInput } from "#channel/types.js";
2
2
  /**
3
- * Serializable input for the workflow entrypoint.
4
- *
5
- * All runtime state is carried inside `serializedContext`, which is produced
6
- * by `serializeContext(ctx)` in the workflow runtime and deserialized at
7
- * each `"use step"` boundary. The workflow body extracts values it needs
8
- * for plumbing (continuation token, mode, bundle source) directly from
9
- * the serialized record.
3
+ * Serializable workflow-entry input. All runtime state travels via
4
+ * `serializedContext`, which is produced by `serializeContext(ctx)`
5
+ * and deserialized at each `"use step"` boundary.
10
6
  */
11
7
  export interface WorkflowEntryInput {
12
8
  readonly input: RunInput["input"];
13
9
  readonly serializedContext: Record<string, unknown>;
14
10
  }
15
- /**
16
- * Value returned when the workflow terminates (harness signals done).
17
- */
18
11
  export interface WorkflowEntryResult {
19
12
  readonly output: string;
20
13
  }
21
14
  /**
22
- * Long-lived workflow entrypoint for the durable runtime.
15
+ * Long-lived workflow entrypoint. Handles both root sessions and
16
+ * delegated child sessions: root sessions expose only parent
17
+ * control-plane events; delegated children publish their full progress
18
+ * on a child stream and resume the parked parent with a
19
+ * `subagent-result` on completion.
23
20
  *
24
- * Root sessions and delegated child sessions both run through this entrypoint.
25
- * Root sessions expose only the parent control-plane events for subagent
26
- * delegation. Delegated children publish their full progress on their own
27
- * child stream and resume the parked parent with a `subagent-result` when the
28
- * child completes.
21
+ * Dispatches on the closed-contract {@link NextDriverAction} returned
22
+ * by each step. The only session-shape flag the driver reads (besides
23
+ * identity) is `hasProxyInputRequests`, the documented short-circuit
24
+ * for hook-payload routing.
29
25
  */
30
26
  export declare function workflowEntry(input: WorkflowEntryInput): Promise<WorkflowEntryResult>;
@@ -1 +1 @@
1
- import{toErrorMessage}from"#shared/errors.js";import{ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{createHook,getWorkflowMetadata,getWritable}from"#compiled/@workflow/core/index.js";import{deserializeContext}from"#context/serialize.js";import{hasProxyInputRequests}from"#harness/proxy-input-requests.js";import{SUBAGENT_ADAPTER_KIND}from"#execution/subagent-adapter.js";import{accumulateRuntimeActionResults,hasPendingRuntimeActionBatch}from"#harness/runtime-actions.js";import{normalizeSerializableError,rebuildSerializableError}from"#execution/workflow-errors.js";import{createSessionStep,dispatchPendingRuntimeActionsStep,dispatchTurnStep,emitTerminalSessionFailureStep,routeProxiedDeliverStep,runProxyInputRequestStep}from"#execution/workflow-steps.js";import{coalesceDeliveries}from"#harness/messages.js";import{fireSessionCallbackStep}from"#execution/session-callback-step.js";async function workflowEntry(e){"use workflow";let{workflowRunId:t}=getWorkflowMetadata(),n=e.serializedContext[`ash.continuationToken`]||``,a=e.serializedContext[`ash.mode`],o=e.serializedContext[`ash.capabilities`],s=e.serializedContext[`ash.bundle`];e.serializedContext[`ash.sessionId`]=t;let c=getWritable();try{let r=await createSessionStep({compiledArtifactsSource:s.source,continuationToken:n,nodeId:s.nodeId,sessionId:t});return await runDriverLoop({capabilities:o,driverWritable:c,initialInput:{kind:`deliver`,payloads:[{message:e.input.message,modelContext:e.input.modelContext}]},mode:a,serializedContext:e.serializedContext,session:r})}catch(t){throw await emitTerminalSessionFailureStep({error:normalizeSerializableError(t),parentWritable:c,serializedContext:e.serializedContext}),await fireSessionCallbackStep({error:normalizeSerializableError(t),serializedContext:e.serializedContext,status:`failed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentErrorResult(e.serializedContext,t),serializedContext:e.serializedContext}),t}}async function runDriverLoop(e){let t=e.session,i=e.serializedContext,a=0,o=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:e.initialInput,mode:e.mode,parentWritable:e.driverWritable,serializedContext:i,session:t,turnGeneration:++a}),s=[];if(t=o.session,i=o.serializedContext,o.action===`done`)return await fireSessionCallbackStep({output:o.output??``,serializedContext:i,status:`completed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentSuccessResult(i,o.output??``),serializedContext:i}),{output:o.output??``};if(!t.continuationToken)throw Error("Cannot park: no continuation token available. The channel must post the first message during the initial turn (anchoring the session) or `send()` must be called with an explicit continuationToken.");let c=t.continuationToken,l=createHook({token:c}),u=l[Symbol.asyncIterator](),d=null,getNextPromise=()=>(d??=u.next(),d),consumeNext=()=>{d=null},rekeyHook=async e=>{e===c||!e||(await closeHookIterator(u),await disposeHook(l),c=e,l=createHook({token:c}),u=l[Symbol.asyncIterator](),d=null)};try{for(;;){if(hasPendingRuntimeActionBatch(t)){let n=await dispatchPendingRuntimeActionsStep({callbackBaseUrl:getWorkflowMetadata().url.replace(/\/$/,``),parentWritable:e.driverWritable,serializedContext:i,session:t});t=n.session;let c=await waitForPendingRuntimeActionResults({bufferedDeliveries:s,getNextPromise,consumeNext,initialResults:n.results,rekeyHook,parentWritable:e.driverWritable,serializedContext:i,session:t});if(c===null)break;t=c.session,i=c.serializedContext,o=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{kind:`runtime-action-result`,results:c.results},mode:e.mode,parentWritable:e.driverWritable,serializedContext:i,session:t,turnGeneration:++a})}else{let n=await waitForNextDeliver({bufferedDeliveries:s,consumeNext,getNextPromise});if(n===null)break;let r=await routeDeliverForChildren({auth:n.auth,parentWritable:e.driverWritable,payloads:n.payloads,session:t});if(r===void 0)continue;o=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{auth:n.auth,kind:`deliver`,payloads:[r]},mode:e.mode,parentWritable:e.driverWritable,serializedContext:i,session:t,turnGeneration:++a})}if(t=o.session,i=o.serializedContext,o.action===`done`)return await fireSessionCallbackStep({output:o.output??``,serializedContext:i,status:`completed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentSuccessResult(i,o.output??``),serializedContext:i}),{output:o.output??``};await rekeyHook(t.continuationToken)}}finally{await closeHookIterator(u),await disposeHook(l)}return{output:``}}async function dispatchAndAwaitTurn(e){let t=`ash://turn/${e.session.sessionId}/${e.turnGeneration}`,r=createHook({token:t});try{await dispatchTurnStep({capabilities:e.capabilities,completionToken:t,delivery:e.delivery,mode:e.mode,parentWritable:e.parentWritable,serializedContext:e.serializedContext,session:e.session});let n=await awaitHookPayload(r);if(n.kind===`turn-error`)throw rebuildSerializableError(n.error);return n}finally{await disposeHook(r)}}async function awaitHookPayload(e){for await(let t of e)return t;throw Error(`Turn completion hook closed before delivering a result.`)}async function waitForPendingRuntimeActionResults(e){let t=e.session,n=e.serializedContext,r=await accumulateRuntimeActionResults({bufferedDeliveries:e.bufferedDeliveries,async getNext(){for(;;){let r=await e.getNextPromise();if(e.consumeNext(),r.done)return null;let i=r.value;if(i.kind===`deliver`){let n=await routeDeliverForChildren({auth:i.auth,parentWritable:e.parentWritable,payloads:i.payloads,session:t});if(n===void 0)continue;return{kind:`deliver`,value:{...i,payloads:[n]}}}if(i.kind===`runtime-action-result`)return{kind:`runtime-action-result`,results:i.results};let a=await runProxyInputRequestStep({hookPayload:i,parentWritable:e.parentWritable,serializedContext:n,session:t});t=a.session,n=a.serializedContext,await e.rekeyHook(t.continuationToken)}},initialResults:e.initialResults,session:t});return r===null?null:{results:r,serializedContext:n,session:t}}async function routeDeliverForChildren(e){let t=coalescePayloads(e.payloads);return hasProxyInputRequests(e.session)?(await routeProxiedDeliverStep({auth:e.auth,parentWritable:e.parentWritable,payload:t,session:e.session})).remainder:t}async function waitForNextDeliver(e){if(e.bufferedDeliveries.length>0)return coalesceDeliveries(e.bufferedDeliveries.splice(0));for(;;){let t=await e.getNextPromise();if(e.consumeNext(),t.done)return null;if(t.value.kind!==`deliver`)continue;let n=t.value;for(;;){let t=await takeReadyPayload(e.getNextPromise());if(t===NO_READY_MESSAGE||(e.consumeNext(),t.done))break;t.value.kind===`deliver`&&(n=coalesceDeliveries([n,t.value]))}return n}}async function notifyDelegatedParentStep(e){"use step";if(e.result===void 0)return;let n=(await deserializeContext(e.serializedContext)).get(ChannelKey);if(n?.kind!==SUBAGENT_ADAPTER_KIND)return;let r=String(n.state?.parentContinuationToken??``);if(r===``)return;let{resumeHook:i}=await import(`#compiled/@workflow/core/runtime.js`);await i(r,{kind:`runtime-action-result`,results:[e.result]})}function createDelegatedSubagentSuccessResult(e,t){let n=e[`ash.channel`];if(n?.kind===SUBAGENT_ADAPTER_KIND)return{callId:String(n.state?.callId??``),kind:`subagent-result`,output:t,subagentName:String(n.state?.subagentName??``)}}function createDelegatedSubagentErrorResult(t,n){let r=createDelegatedSubagentSuccessResult(t,``);if(r!==void 0)return{...r,isError:!0,output:{code:`SUBAGENT_EXECUTION_FAILED`,message:toErrorMessage(n)}}}function coalescePayloads(e){if(e.length===0)return{};if(e.length===1)return e[0]??{};let t={},n=[];for(let r of e){for(let[e,n]of Object.entries(r))e!==`inputResponses`&&n!==void 0&&(t[e]=n);r.inputResponses!==void 0&&n.push(...r.inputResponses)}return n.length>0&&(t.inputResponses=n),t}const NO_READY_MESSAGE=Symbol(`no-ready-message`);async function takeReadyPayload(e){return await Promise.resolve(),await Promise.race([e,Promise.resolve(NO_READY_MESSAGE)])}async function closeHookIterator(e){typeof e.return==`function`&&await e.return(void 0)}async function disposeHook(e){let t=e.dispose;if(typeof t==`function`){await t.call(e);return}let n=e[Symbol.dispose];typeof n==`function`&&await n.call(e)}export{workflowEntry};
1
+ import{createHook,getWorkflowMetadata,getWritable}from"#compiled/@workflow/core/index.js";import{ASH_SESSION_STREAM_NAMESPACE}from"#execution/durable-session-store.js";import{accumulateRuntimeActionResults}from"#harness/runtime-actions.js";import{normalizeSerializableError,rebuildSerializableError}from"#execution/workflow-errors.js";import{dispatchTurnStep,emitTerminalSessionFailureStep,routeProxiedDeliverStep,runProxyInputRequestStep}from"#execution/workflow-steps.js";import{coalesceDeliveries}from"#harness/messages.js";import{notifyDelegatedParentStep}from"#execution/delegated-parent-notification.js";import{createDelegatedSubagentErrorResult,createDelegatedSubagentSuccessResult}from"#execution/delegated-parent-result.js";import{createSessionStep}from"#execution/create-session-step.js";import{dispatchRuntimeActionsStep}from"#execution/dispatch-runtime-actions-step.js";import{fireSessionCallbackStep}from"#execution/session-callback-step.js";async function workflowEntry(e){"use workflow";let{workflowRunId:i}=getWorkflowMetadata(),o=e.serializedContext[`ash.continuationToken`]||``,s=e.serializedContext[`ash.mode`],l=e.serializedContext[`ash.capabilities`],u=e.serializedContext[`ash.bundle`];e.serializedContext[`ash.sessionId`]=i;let d=getWritable(),f=getWritable({namespace:ASH_SESSION_STREAM_NAMESPACE});try{let t=await createSessionStep({compiledArtifactsSource:u.source,continuationToken:o,nodeId:u.nodeId,sessionId:i,sessionWritable:f});return await runDriverLoop({capabilities:l,driverWritable:d,initialInput:{kind:`deliver`,payloads:[{message:e.input.message,modelContext:e.input.modelContext}]},mode:s,serializedContext:e.serializedContext,sessionState:t,sessionWritable:f})}catch(t){throw await emitTerminalSessionFailureStep({error:normalizeSerializableError(t),parentWritable:d,serializedContext:e.serializedContext}),await fireSessionCallbackStep({error:normalizeSerializableError(t),serializedContext:e.serializedContext,status:`failed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentErrorResult(e.serializedContext,t),serializedContext:e.serializedContext}),t}}async function runDriverLoop(n){let r=0,i=await dispatchAndAwaitTurn({capabilities:n.capabilities,delivery:n.initialInput,mode:n.mode,parentWritable:n.driverWritable,serializedContext:n.serializedContext,sessionState:n.sessionState,sessionWritable:n.sessionWritable,turnGeneration:++r});if(i.kind===`done`)return await finalizeDone({action:i,driverWritable:n.driverWritable});if(!i.sessionState.continuationToken)throw Error("Cannot park: no continuation token available. The channel must post the first message during the initial turn (anchoring the session) or `send()` must be called with an explicit continuationToken.");let a=i.sessionState.continuationToken,o=createHook({token:a}),s=o[Symbol.asyncIterator](),c=null,l=[],getNextPromise=()=>(c??=s.next(),c),consumeNext=()=>{c=null},rekeyHook=async t=>{t===a||!t||(await closeHookIterator(s),await disposeHook(o),a=t,o=createHook({token:a}),s=o[Symbol.asyncIterator](),c=null)};try{for(;;)switch(i.kind){case`done`:return await finalizeDone({action:i,driverWritable:n.driverWritable});case`dispatch-runtime-actions`:{let e=await dispatchRuntimeActionsStep({callbackBaseUrl:getWorkflowMetadata().url.replace(/\/$/,``),parentWritable:n.driverWritable,serializedContext:i.serializedContext,sessionState:i.sessionState,sessionWritable:n.sessionWritable}),a=await waitForPendingRuntimeActionResults({bufferedDeliveries:l,consumeNext,getNextPromise,initialResults:e.results,parentWritable:n.driverWritable,pendingActionKeys:i.pendingActionKeys,rekeyHook,serializedContext:i.serializedContext,sessionState:e.sessionState,sessionWritable:n.sessionWritable});if(a===null)return{output:``};i=await dispatchAndAwaitTurn({capabilities:n.capabilities,delivery:{kind:`runtime-action-result`,results:a.results},mode:n.mode,parentWritable:n.driverWritable,serializedContext:a.serializedContext,sessionState:a.sessionState,sessionWritable:n.sessionWritable,turnGeneration:++r}),await rekeyHook(i.sessionState.continuationToken);break}case`park`:{let e=await waitForNextDeliver({bufferedDeliveries:l,consumeNext,getNextPromise});if(e===null)return{output:``};let t=await routeDeliverForChildren({auth:e.auth,parentWritable:n.driverWritable,payloads:e.payloads,sessionState:i.sessionState});if(t===void 0)continue;i=await dispatchAndAwaitTurn({capabilities:n.capabilities,delivery:{auth:e.auth,kind:`deliver`,payloads:[t]},mode:n.mode,parentWritable:n.driverWritable,serializedContext:i.serializedContext,sessionState:i.sessionState,sessionWritable:n.sessionWritable,turnGeneration:++r}),await rekeyHook(i.sessionState.continuationToken);break}}}finally{await closeHookIterator(s),await disposeHook(o)}}async function finalizeDone(e){return await fireSessionCallbackStep({output:e.action.output,serializedContext:e.action.serializedContext,status:`completed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentSuccessResult(e.action.serializedContext,e.action.output),serializedContext:e.action.serializedContext}),{output:e.action.output}}async function dispatchAndAwaitTurn(t){let n=`ash://turn/${t.sessionState.sessionId}/${t.turnGeneration}`,r=createHook({token:n});try{await dispatchTurnStep({capabilities:t.capabilities,completionToken:n,delivery:t.delivery,mode:t.mode,parentWritable:t.parentWritable,serializedContext:t.serializedContext,sessionState:t.sessionState,sessionWritable:t.sessionWritable});let e=await awaitHookPayload(r);if(e.kind===`turn-error`)throw rebuildSerializableError(e.error);return e.action}finally{await disposeHook(r)}}async function awaitHookPayload(e){for await(let t of e)return t;throw Error(`Turn completion hook closed before delivering a result.`)}async function waitForPendingRuntimeActionResults(e){let t=e.sessionState,n=e.serializedContext,r=await accumulateRuntimeActionResults({bufferedDeliveries:e.bufferedDeliveries,async getNext(){for(;;){let r=await e.getNextPromise();if(e.consumeNext(),r.done)return null;let i=r.value;if(i.kind===`deliver`){let n=await routeDeliverForChildren({auth:i.auth,parentWritable:e.parentWritable,payloads:i.payloads,sessionState:t});if(n===void 0)continue;return{kind:`deliver`,value:{...i,payloads:[n]}}}if(i.kind===`runtime-action-result`)return{kind:`runtime-action-result`,results:i.results};let a=await runProxyInputRequestStep({hookPayload:i,parentWritable:e.parentWritable,serializedContext:n,sessionState:t,sessionWritable:e.sessionWritable});t=a.sessionState,n=a.serializedContext,await e.rekeyHook(t.continuationToken)}},initialResults:e.initialResults,pendingActionKeys:e.pendingActionKeys});return r===null?null:{results:r,serializedContext:n,sessionState:t}}async function routeDeliverForChildren(e){let t=coalescePayloads(e.payloads);return e.sessionState.hasProxyInputRequests?(await routeProxiedDeliverStep({auth:e.auth,parentWritable:e.parentWritable,payload:t,sessionState:e.sessionState})).remainder:t}async function waitForNextDeliver(e){if(e.bufferedDeliveries.length>0)return coalesceDeliveries(e.bufferedDeliveries.splice(0));for(;;){let t=await e.getNextPromise();if(e.consumeNext(),t.done)return null;if(t.value.kind!==`deliver`)continue;let n=t.value;for(;;){let t=await takeReadyPayload(e.getNextPromise());if(t===NO_READY_MESSAGE||(e.consumeNext(),t.done))break;t.value.kind===`deliver`&&(n=coalesceDeliveries([n,t.value]))}return n}}function coalescePayloads(e){if(e.length===0)return{};if(e.length===1)return e[0]??{};let t={},n=[];for(let r of e){for(let[e,n]of Object.entries(r))e!==`inputResponses`&&n!==void 0&&(t[e]=n);r.inputResponses!==void 0&&n.push(...r.inputResponses)}return n.length>0&&(t.inputResponses=n),t}const NO_READY_MESSAGE=Symbol(`no-ready-message`);async function takeReadyPayload(e){return await Promise.resolve(),await Promise.race([e,Promise.resolve(NO_READY_MESSAGE)])}async function closeHookIterator(e){typeof e.return==`function`&&await e.return(void 0)}async function disposeHook(e){let t=e.dispose;if(typeof t==`function`){await t.call(e);return}let n=e[Symbol.dispose];typeof n==`function`&&await n.call(e)}export{workflowEntry};
@@ -1,3 +1,3 @@
1
- import{RuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{serializeContext}from"#context/serialize.js";import{getHookByToken,getRun,resumeHook,start}from"#compiled/@workflow/core/runtime.js";import{HookNotFoundError}from"#compiled/@workflow/errors/index.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{buildRunContext}from"#execution/runtime-context.js";const WORKFLOW_ENTRY_NAME=`workflowEntry`,TURN_WORKFLOW_NAME=`turnWorkflow`,ASH_PACKAGE_INFO=resolveInstalledPackageInfo(),LATEST_DEPLOYMENT_UNSUPPORTED_MESSAGE=`deploymentId 'latest' requires a World that implements resolveLatestDeploymentId()`,STABLE_WORKFLOW_NAMES=new Set([WORKFLOW_ENTRY_NAME,TURN_WORKFLOW_NAME]),STABLE_ID_BASE=ASH_PACKAGE_INFO.name,workflowEntryReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_ENTRY_NAME}`},turnWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${TURN_WORKFLOW_NAME}`};function createWorkflowRuntime(t){return{async run(e){let r=serializeContext(buildRunContext({bundle:await getCompiledRuntimeAgentBundle({compiledArtifactsSource:t.compiledArtifactsSource,nodeId:t.nodeId}),run:e})),a=await startWorkflowPreferLatest(workflowEntryReference,[{input:e.input,serializedContext:r}]);return{continuationToken:e.continuationToken??a.runId,events:parseNdjsonStream(getRun(a.runId).getReadable()),sessionId:a.runId}},async deliver(t){let n={auth:t.auth,kind:`deliver`,payloads:[t.payload]};try{let e=normalizeWorkflowHook(await getHookByToken(t.continuationToken));return await resumeHook(t.continuationToken,n),{sessionId:e.runId}}catch(n){throw HookNotFoundError.is(n)?new RuntimeNoActiveSessionError(t.continuationToken):n}},async getEventStream(e,t){return parseNdjsonStream(getRun(e).getReadable({startIndex:t?.startIndex}))}}}async function startWorkflowPreferLatest(e,t){try{return await start(e,t,{deploymentId:`latest`})}catch(n){if(!isLatestDeploymentUnsupportedError(n))throw n;return await start(e,t)}}function isLatestDeploymentUnsupportedError(e){return e instanceof Error&&e.message.includes(`deploymentId 'latest' requires a World that implements resolveLatestDeploymentId()`)}function normalizeWorkflowHook(e){if(typeof e!=`object`||!e||!(`runId`in e))throw Error(`Workflow hook did not include a run id.`);let t=e.runId;if(typeof t!=`string`||t.length===0)throw Error(`Workflow hook did not include a run id.`);return{runId:t}}function parseNdjsonStream(e){let t=new TextDecoder,n=``;return new ReadableStream({async start(r){let i=e.getReader();try{for(;;){let{value:e,done:a}=await i.read();if(a){let e=n.trim();e.length>0&&r.enqueue(JSON.parse(e)),r.close();return}n+=t.decode(e,{stream:!0});for(let e=n.indexOf(`
1
+ import{RuntimeNoActiveSessionError}from"#execution/runtime-errors.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{serializeContext}from"#context/serialize.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{getHookByToken,getRun,resumeHook,start}from"#compiled/@workflow/core/runtime.js";import{HookNotFoundError}from"#compiled/@workflow/errors/index.js";import{buildRunContext}from"#execution/runtime-context.js";const WORKFLOW_ENTRY_NAME=`workflowEntry`,TURN_WORKFLOW_NAME=`turnWorkflow`,ASH_PACKAGE_INFO=resolveInstalledPackageInfo(),LATEST_DEPLOYMENT_UNSUPPORTED_MESSAGE=`deploymentId 'latest' requires a World that implements resolveLatestDeploymentId()`,STABLE_WORKFLOW_NAMES=new Set([WORKFLOW_ENTRY_NAME,TURN_WORKFLOW_NAME]),STABLE_ID_BASE=ASH_PACKAGE_INFO.name,workflowEntryReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_ENTRY_NAME}`},turnWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${TURN_WORKFLOW_NAME}`};function createWorkflowRuntime(t){return{async run(e){let i=serializeContext(buildRunContext({bundle:await getCompiledRuntimeAgentBundle({compiledArtifactsSource:t.compiledArtifactsSource,nodeId:t.nodeId}),run:e})),o=await startWorkflowPreferLatest(workflowEntryReference,[{input:e.input,serializedContext:i}]);return{continuationToken:e.continuationToken??o.runId,events:parseNdjsonStream(getRun(o.runId).getReadable()),sessionId:o.runId}},async deliver(t){let n={auth:t.auth,kind:`deliver`,payloads:[t.payload]};try{let e=normalizeWorkflowHook(await getHookByToken(t.continuationToken));return await resumeHook(t.continuationToken,n),{sessionId:e.runId}}catch(n){throw HookNotFoundError.is(n)?new RuntimeNoActiveSessionError(t.continuationToken):n}},async getEventStream(e,t){return parseNdjsonStream(getRun(e).getReadable({startIndex:t?.startIndex}))}}}async function startWorkflowPreferLatest(e,t){try{return await start(e,t,{deploymentId:`latest`})}catch(n){if(!isLatestDeploymentUnsupportedError(n))throw n;return await start(e,t)}}function isLatestDeploymentUnsupportedError(e){return e instanceof Error&&e.message.includes(`deploymentId 'latest' requires a World that implements resolveLatestDeploymentId()`)}function normalizeWorkflowHook(e){if(typeof e!=`object`||!e||!(`runId`in e))throw Error(`Workflow hook did not include a run id.`);let t=e.runId;if(typeof t!=`string`||t.length===0)throw Error(`Workflow hook did not include a run id.`);return{runId:t}}function parseNdjsonStream(e){let t=new TextDecoder,n=``;return new ReadableStream({async start(r){let i=e.getReader();try{for(;;){let{value:e,done:a}=await i.read();if(a){let e=n.trim();e.length>0&&r.enqueue(JSON.parse(e)),r.close();return}n+=t.decode(e,{stream:!0});for(let e=n.indexOf(`
2
2
  `);e!==-1;e=n.indexOf(`
3
3
  `)){let t=n.slice(0,e).trim();n=n.slice(e+1),t.length>0&&r.enqueue(JSON.parse(t))}}}catch(e){r.error(e)}finally{i.releaseLock()}}})}export{LATEST_DEPLOYMENT_UNSUPPORTED_MESSAGE,STABLE_WORKFLOW_NAMES,createWorkflowRuntime,startWorkflowPreferLatest,turnWorkflowReference,workflowEntryReference};