experimental-ash 0.28.1 → 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.
- package/CHANGELOG.md +40 -0
- package/README.md +1 -0
- package/dist/docs/public/cli-build-and-debugging.md +2 -0
- package/dist/docs/public/getting-started.md +1 -0
- package/dist/src/cli/run.d.ts +9 -0
- package/dist/src/cli/run.js +1 -1
- package/dist/src/context/hook-lifecycle.d.ts +23 -67
- package/dist/src/context/hook-lifecycle.js +1 -1
- package/dist/src/execution/await-authorization-orchestrator.d.ts +18 -29
- package/dist/src/execution/await-authorization-orchestrator.js +1 -1
- package/dist/src/execution/connection-auth-steps.d.ts +28 -65
- package/dist/src/execution/connection-auth-steps.js +1 -1
- package/dist/src/execution/create-session-step.d.ts +15 -0
- package/dist/src/execution/create-session-step.js +1 -0
- package/dist/src/execution/delegated-parent-notification.d.ts +15 -0
- package/dist/src/execution/delegated-parent-notification.js +1 -0
- package/dist/src/execution/delegated-parent-result.d.ts +14 -0
- package/dist/src/execution/delegated-parent-result.js +1 -0
- package/dist/src/execution/dispatch-runtime-actions-step.d.ts +20 -0
- package/dist/src/execution/dispatch-runtime-actions-step.js +1 -0
- package/dist/src/execution/durable-session-migrations/chain.d.ts +31 -0
- package/dist/src/execution/durable-session-migrations/chain.js +1 -0
- package/dist/src/execution/durable-session-migrations/snapshot.d.ts +22 -0
- package/dist/src/execution/durable-session-migrations/snapshot.js +1 -0
- package/dist/src/execution/durable-session-store.d.ts +104 -0
- package/dist/src/execution/durable-session-store.js +1 -0
- package/dist/src/execution/next-driver-action.d.ts +30 -0
- package/dist/src/execution/next-driver-action.js +1 -0
- package/dist/src/execution/sandbox/prewarm.d.ts +12 -2
- package/dist/src/execution/sandbox/prewarm.js +1 -1
- package/dist/src/execution/session.d.ts +29 -28
- package/dist/src/execution/session.js +1 -1
- package/dist/src/execution/subagent-hitl-proxy.d.ts +8 -25
- package/dist/src/execution/subagent-hitl-proxy.js +1 -1
- package/dist/src/execution/subagent-tool.js +1 -1
- package/dist/src/execution/turn-workflow.d.ts +21 -21
- package/dist/src/execution/turn-workflow.js +1 -1
- package/dist/src/execution/workflow-entry.d.ts +12 -16
- package/dist/src/execution/workflow-entry.js +1 -1
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/execution/workflow-steps.d.ts +36 -91
- package/dist/src/execution/workflow-steps.js +1 -1
- package/dist/src/harness/emission.d.ts +3 -5
- package/dist/src/harness/emission.js +1 -1
- package/dist/src/harness/input-requests.d.ts +3 -3
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/proxy-input-requests.d.ts +12 -16
- package/dist/src/harness/proxy-input-requests.js +1 -1
- package/dist/src/harness/runtime-actions.d.ts +17 -24
- package/dist/src/harness/runtime-actions.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/types.d.ts +3 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/nitro/host/start-production-server.d.ts +8 -0
- package/dist/src/internal/nitro/host/start-production-server.js +3 -0
- package/dist/src/internal/nitro/host/types.d.ts +8 -0
- package/dist/src/internal/nitro/host.d.ts +2 -1
- package/dist/src/internal/nitro/host.js +1 -1
- package/dist/src/internal/nitro/routes/agent-info/load-agent-info-data.js +1 -1
- package/dist/src/internal/nitro/routes/info.js +1 -1
- package/dist/src/internal/workflow-bundle/builder.d.ts +2 -0
- package/dist/src/internal/workflow-bundle/builder.js +1 -1
- package/dist/src/runtime/cache-key.js +1 -1
- package/dist/src/runtime/framework-channels/index.js +1 -1
- package/dist/src/runtime/loaders/bundled-artifacts.d.ts +12 -0
- package/dist/src/runtime/loaders/bundled-artifacts.js +1 -1
- package/dist/src/runtime/loaders/compile-metadata.js +1 -1
- package/dist/src/runtime/loaders/manifest.js +1 -1
- package/dist/src/runtime/loaders/module-map.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Starts every pending runtime action for the parked parent session.
|
|
3
|
+
*
|
|
4
|
+
* Each child run starts in task mode, emits a parent `subagent.called`
|
|
5
|
+
* control-plane event, and then runs independently on its own child
|
|
6
|
+
* stream. Records each child's continuation token on the parent
|
|
7
|
+
* session and appends the updated snapshot to `ash.session`.
|
|
8
|
+
*/
|
|
9
|
+
import type { RuntimeSubagentResultActionResult } from "#runtime/actions/types.js";
|
|
10
|
+
import { type DurableSessionSnapshot, type DurableSessionState } from "#execution/durable-session-store.js";
|
|
11
|
+
export declare function dispatchRuntimeActionsStep(input: {
|
|
12
|
+
readonly callbackBaseUrl?: string;
|
|
13
|
+
readonly parentWritable: WritableStream<Uint8Array>;
|
|
14
|
+
readonly serializedContext: Record<string, unknown>;
|
|
15
|
+
readonly sessionState: DurableSessionState;
|
|
16
|
+
readonly sessionWritable: WritableStream<DurableSessionSnapshot>;
|
|
17
|
+
}): Promise<{
|
|
18
|
+
readonly results: readonly RuntimeSubagentResultActionResult[];
|
|
19
|
+
readonly sessionState: DurableSessionState;
|
|
20
|
+
}>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{toErrorMessage}from"#shared/errors.js";import{AuthKey,CapabilitiesKey,InitiatorAuthKey}from"#context/keys.js";import{createSubagentCalledEvent,encodeMessageStreamEvent,timestampHandleMessageStreamEvent}from"#protocol/message.js";import{callAdapterEventHandler}from"#channel/adapter.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{deserializeContext}from"#context/serialize.js";import{readDurableSession,writeDurableSession}from"#execution/durable-session-store.js";import{hydrateDurableSession}from"#execution/session.js";import{getPendingRuntimeActionBatch,recordPendingSubagentChildToken}from"#harness/runtime-actions.js";import{resolveRemoteAgentForAction,startRemoteAgentSession}from"#execution/remote-agent-dispatch.js";import{buildSubagentRunInput}from"#execution/subagent-tool.js";import{createWorkflowRuntime,workflowEntryReference}from"#execution/workflow-runtime.js";async function dispatchRuntimeActionsStep(e){"use step";let u=await readDurableSession(e.sessionState),d=getPendingRuntimeActionBatch(u.state);if(d===void 0||d.actions.length===0)return{results:[],sessionState:e.sessionState};let f=await deserializeContext(e.serializedContext),p=f.require(BundleKey),m=hydrateDurableSession({compactionOverrides:{thresholdPercent:p.resolvedAgent.config.compaction?.thresholdPercent},durable:u,turnAgent:p.turnAgent}),h=f.require(ChannelKey),g=f.get(AuthKey)??null,_=f.get(CapabilitiesKey),v=f.get(InitiatorAuthKey)??null,y=e.parentWritable.getWriter(),b=buildAdapterContext(h,f),x=m,S=[];try{for(let t of d.actions){let n,r,s,c;switch(t.kind){case`subagent-call`:{let e=createWorkflowRuntime({compiledArtifactsSource:p.compiledArtifactsSource,nodeId:t.nodeId}),{childContinuationToken:i,runInput:a}=buildSubagentRunInput({action:t,auth:g,batchEvent:d.event,capabilities:_,initiatorAuth:v,session:m}),o=await e.run(a);x=recordPendingSubagentChildToken({callId:t.callId,childContinuationToken:i,session:x}),n=o.sessionId,r=t.name,c=t.subagentName;break}case`remote-agent-call`:{let i;try{i=resolveRemoteAgentForAction({nodeId:t.nodeId,remoteAgentName:t.remoteAgentName,registry:p.subagentRegistry.subagentsByNodeId}),n=await startRemoteAgentSession({action:t,callbackBaseUrl:e.callbackBaseUrl,remote:i,session:m})}catch(e){S.push(createRemoteAgentStartFailureResult({action:t,error:e}));continue}r=t.name,s={url:i.url},c=t.remoteAgentName;break}default:throw Error(`Unsupported runtime action kind "${t.kind}" in workflow runtime.`)}let l=await callAdapterEventHandler(h,createSubagentCalledEvent({callId:t.callId,childSessionId:n,name:r,remote:s,sequence:d.event.sequence,sessionId:m.sessionId,toolName:c,turnId:d.event.turnId,workflowId:workflowEntryReference.workflowId}),b);await y.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(l)))}}finally{y.releaseLock()}return{results:S,sessionState:x===m?e.sessionState:await writeDurableSession({session:x,writable:e.sessionWritable})}}function createRemoteAgentStartFailureResult(t){return{callId:t.action.callId,isError:!0,kind:`subagent-result`,output:{code:`REMOTE_AGENT_START_FAILED`,message:toErrorMessage(t.error)},subagentName:t.action.remoteAgentName}}export{dispatchRuntimeActionsStep};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generic version-walking migration framework for versioned durable
|
|
3
|
+
* wire shapes. Each migration steps a value one version forward; the
|
|
4
|
+
* runner chains them so a value written at any historic version can
|
|
5
|
+
* be read at the current one.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* One migration step in a version chain. `to` MUST equal `from + 1`
|
|
9
|
+
* and `migrate` MUST stamp the returned value's `version` field with
|
|
10
|
+
* `to`; the runner verifies both.
|
|
11
|
+
*/
|
|
12
|
+
export interface VersionMigration {
|
|
13
|
+
readonly from: number;
|
|
14
|
+
readonly to: number;
|
|
15
|
+
migrate: (prior: unknown) => {
|
|
16
|
+
readonly version: number;
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Walks `value` through `migrations` until its `version` matches
|
|
21
|
+
* `targetVersion`. Throws on missing migrations, malformed steps, or
|
|
22
|
+
* a value newer than the runner supports.
|
|
23
|
+
*/
|
|
24
|
+
export declare function runMigrationChain<TOut extends {
|
|
25
|
+
readonly version: number;
|
|
26
|
+
}>(input: {
|
|
27
|
+
readonly value: unknown;
|
|
28
|
+
readonly migrations: readonly VersionMigration[];
|
|
29
|
+
readonly targetVersion: number;
|
|
30
|
+
readonly label: string;
|
|
31
|
+
}): TOut;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function runMigrationChain(e){if(typeof e.value!=`object`||e.value===null||!(`version`in e.value)||typeof e.value.version!=`number`)throw Error(`${e.label}: value has no numeric "version" field.`);let t=e.value;if(!Number.isInteger(t.version)||t.version<1)throw Error(`${e.label}: version ${t.version} is not a positive integer.`);if(t.version>e.targetVersion)throw Error(`${e.label}: encountered version ${t.version}, which is newer than the supported version ${e.targetVersion}. This usually indicates the wire was written by a newer Ash deployment than the one reading it.`);for(;t.version<e.targetVersion;){let n=e.migrations.find(e=>e.from===t.version);if(!n)throw Error(`${e.label}: no migration registered for version ${t.version} → ${t.version+1}.`);if(n.to!==n.from+1)throw Error(`${e.label}: migration ${n.from} → ${n.to} must step exactly one version at a time.`);let r=n.migrate(t);if(r.version!==n.to)throw Error(`${e.label}: migration ${n.from} → ${n.to} produced a value with version ${r.version}.`);t=r}return t}export{runMigrationChain};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable session snapshot migrations.
|
|
3
|
+
*
|
|
4
|
+
* ## Adding a new snapshot version
|
|
5
|
+
*
|
|
6
|
+
* When a shape change cannot be expressed as a purely additive field:
|
|
7
|
+
*
|
|
8
|
+
* 1. Bump `DURABLE_SESSION_VERSION` in `durable-session-store.ts`.
|
|
9
|
+
* 2. Update {@link DurableSessionSnapshot}, {@link DurableSession},
|
|
10
|
+
* `projectToDurableSession`, and `hydrateDurableSession`.
|
|
11
|
+
* 3. Add `snapshot-v{N}-to-v{N+1}.ts` exporting one
|
|
12
|
+
* {@link VersionMigration} (`from: N`, `to: N + 1`, pure
|
|
13
|
+
* function, stamps the new `version`).
|
|
14
|
+
* 4. Append the migration to {@link snapshotMigrations}.
|
|
15
|
+
* 5. Cover it in `snapshot.test.ts`.
|
|
16
|
+
*/
|
|
17
|
+
import type { DurableSessionSnapshot } from "#execution/durable-session-store.js";
|
|
18
|
+
/**
|
|
19
|
+
* Migrates a {@link DurableSessionSnapshot} up to
|
|
20
|
+
* {@link DURABLE_SESSION_VERSION}. Pure; safe to call inline.
|
|
21
|
+
*/
|
|
22
|
+
export declare function migrateDurableSessionSnapshot(value: unknown): DurableSessionSnapshot;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{runMigrationChain}from"./chain.js";import{DURABLE_SESSION_VERSION}from"#execution/durable-session-store.js";const snapshotMigrations=[];function migrateDurableSessionSnapshot(e){return runMigrationChain({label:`durable session snapshot`,migrations:snapshotMigrations,targetVersion:DURABLE_SESSION_VERSION,value:e})}export{migrateDurableSessionSnapshot};
|
|
@@ -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,5 +1,5 @@
|
|
|
1
1
|
import type { SandboxBackend, SandboxBackendPrewarmInput } from "#public/definitions/sandbox-backend.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type RuntimeCompiledArtifactsSource, type RuntimeDiskCompiledArtifactsSource } from "#runtime/compiled-artifacts-source.js";
|
|
3
3
|
import { type ResolvedAgentGraphBundle } from "#runtime/graph.js";
|
|
4
4
|
/**
|
|
5
5
|
* Optional dispatch override that intercepts every `backend.prewarm`
|
|
@@ -13,7 +13,8 @@ export type SandboxBackendPrewarmDispatch = (input: {
|
|
|
13
13
|
readonly input: SandboxBackendPrewarmInput;
|
|
14
14
|
}) => Promise<void>;
|
|
15
15
|
interface PrewarmSandboxesInput {
|
|
16
|
-
readonly
|
|
16
|
+
readonly appRoot: string;
|
|
17
|
+
readonly compiledArtifactsSource: RuntimeCompiledArtifactsSource;
|
|
17
18
|
readonly graph: ResolvedAgentGraphBundle;
|
|
18
19
|
readonly log?: (message: string) => void;
|
|
19
20
|
readonly dispatch?: SandboxBackendPrewarmDispatch;
|
|
@@ -43,4 +44,13 @@ export declare function prewarmAppSandboxes(input: {
|
|
|
43
44
|
readonly log?: (message: string) => void;
|
|
44
45
|
readonly dispatch?: SandboxBackendPrewarmDispatch;
|
|
45
46
|
}): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Loads one built app's bundled compiled artifacts and prewarms the sandbox
|
|
49
|
+
* templates that its production Nitro runtime will request.
|
|
50
|
+
*/
|
|
51
|
+
export declare function prewarmBuiltAppSandboxes(input: {
|
|
52
|
+
readonly appRoot: string;
|
|
53
|
+
readonly log?: (message: string) => void;
|
|
54
|
+
readonly dispatch?: SandboxBackendPrewarmDispatch;
|
|
55
|
+
}): Promise<void>;
|
|
46
56
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{toErrorMessage}from"#shared/errors.js";import{createRuntimeSandboxTemplateKey}from"#runtime/sandbox/keys.js";import{loadCompiledModuleMapFromAuthoredSource}from"#internal/authored-module-map-loader.js";import{createAuthoredSourceRuntimeCompiledArtifactsSource}from"#internal/application/runtime-compiled-artifacts-source.js";import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{loadCompiledManifest}from"#runtime/loaders/manifest.js";import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{resolveRuntimeAgentGraph}from"#runtime/resolve-agent-graph.js";import{materializeWorkspaceDirectory}from"#runtime/workspace/seed-files.js";async function prewarmSandboxes(t){let n=await collectPrewarmTargets(t);if(n.length===0)return;t.log?.(`Ash: initializing ${n.length} sandbox ${pluralize(n.length,`template`)}...`);let r=t.dispatch??(async({backend:e,input:t})=>{await e.prewarm(t)});await Promise.all(n.map(async({backend:n,label:i,input:a})=>{t.log?.(`Ash: initializing sandbox template "${i}"...`);try{await r({backend:n,input:a})}catch(r){throw t.log?.(`Ash: failed to initialize sandbox template "${i}" on backend "${n.name}": ${toErrorMessage(r)}`),r}t.log?.(`Ash: sandbox template "${i}" initialized.`)})),t.log?.(`Ash: initialized ${n.length} sandbox ${pluralize(n.length,`template`)}.`)}async function prewarmAppSandboxes(e){let t=createAuthoredSourceRuntimeCompiledArtifactsSource(e.appRoot),n=await(e.loadAgentGraph??loadGraphFromArtifacts)({compiledArtifactsSource:t});await prewarmSandboxes({compiledArtifactsSource:t,dispatch:e.dispatch,graph:n,log:e.log})}async function
|
|
1
|
+
import{toErrorMessage}from"#shared/errors.js";import{createBundledRuntimeCompiledArtifactsSource}from"#runtime/compiled-artifacts-source.js";import{createRuntimeSandboxTemplateKey}from"#runtime/sandbox/keys.js";import{loadCompiledModuleMapFromAuthoredSource}from"#internal/authored-module-map-loader.js";import{createAuthoredSourceRuntimeCompiledArtifactsSource}from"#internal/application/runtime-compiled-artifacts-source.js";import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{loadCompileMetadata}from"#runtime/loaders/compile-metadata.js";import{withBundledCompiledArtifacts}from"#runtime/loaders/bundled-artifacts.js";import{loadCompiledManifest}from"#runtime/loaders/manifest.js";import{resolveRuntimeCompilerArtifactPaths}from"#runtime/loaders/artifact-paths.js";import{resolveRuntimeAgentGraph}from"#runtime/resolve-agent-graph.js";import{materializeWorkspaceDirectory}from"#runtime/workspace/seed-files.js";async function prewarmSandboxes(t){let n=await collectPrewarmTargets(t);if(n.length===0)return;t.log?.(`Ash: initializing ${n.length} sandbox ${pluralize(n.length,`template`)}...`);let r=t.dispatch??(async({backend:e,input:t})=>{await e.prewarm(t)});await Promise.all(n.map(async({backend:n,label:i,input:a})=>{t.log?.(`Ash: initializing sandbox template "${i}"...`);try{await r({backend:n,input:a})}catch(r){throw t.log?.(`Ash: failed to initialize sandbox template "${i}" on backend "${n.name}": ${toErrorMessage(r)}`),r}t.log?.(`Ash: sandbox template "${i}" initialized.`)})),t.log?.(`Ash: initialized ${n.length} sandbox ${pluralize(n.length,`template`)}.`)}async function prewarmAppSandboxes(e){let t=createAuthoredSourceRuntimeCompiledArtifactsSource(e.appRoot),n=await(e.loadAgentGraph??loadGraphFromArtifacts)({compiledArtifactsSource:t});await prewarmSandboxes({appRoot:e.appRoot,compiledArtifactsSource:t,dispatch:e.dispatch,graph:n,log:e.log})}async function prewarmBuiltAppSandboxes(e){let n=createAuthoredSourceRuntimeCompiledArtifactsSource(e.appRoot),[a,c,l]=await Promise.all([loadCompileMetadata({compiledArtifactsSource:n}),loadCompiledManifest({compiledArtifactsSource:n}),loadCompiledModuleMapFromAuthoredSource({compiledArtifactsSource:n})]);await withBundledCompiledArtifacts({manifest:c,metadata:a??void 0,moduleMap:l,sessionId:`built-app-prewarm`},async()=>{let n=createBundledRuntimeCompiledArtifactsSource(),r=await resolveRuntimeAgentGraph({manifest:c,moduleMap:l});await prewarmSandboxes({appRoot:e.appRoot,compiledArtifactsSource:n,dispatch:e.dispatch,graph:r,log:e.log})})}async function collectPrewarmTargets(e){let t=resolveRuntimeCompilerArtifactPaths(e.appRoot).compileDirectoryPath,r={appRoot:e.appRoot};return[...await Promise.all(collectNodeSandboxes(e.graph).map(async({definition:i,nodeId:a,workspaceResourceRoot:o})=>{let s=await createRuntimeSandboxTemplateKey({backendName:i.backend.name,compiledArtifactsSource:e.compiledArtifactsSource,nodeId:a,sourceId:i.sourceId});return{backend:i.backend,label:formatLabel(a),input:{bootstrap:i.bootstrap,seedFiles:await loadResourceRootSeedFiles({compileDirectoryPath:t,workspaceResourceRoot:o}),runtimeContext:r,templateKey:s}}}))].sort((e,t)=>e.label.localeCompare(t.label))}async function loadResourceRootSeedFiles(e){return e.workspaceResourceRoot.rootEntries.length===0?[]:(await materializeWorkspaceDirectory(`${e.compileDirectoryPath}/${e.workspaceResourceRoot.logicalPath}`)).map(e=>({content:e.content,path:e.path}))}async function loadGraphFromArtifacts(e){let[t,n]=await Promise.all([loadCompiledManifest({compiledArtifactsSource:e.compiledArtifactsSource}),loadCompiledModuleMapFromAuthoredSource({compiledArtifactsSource:e.compiledArtifactsSource})]);return await resolveRuntimeAgentGraph({manifest:t,moduleMap:n})}function collectNodeSandboxes(e){return[...e.nodesByNodeId.entries()].flatMap(([e,t])=>{let n=t.sandboxRegistry.sandbox;return n===null?[]:[{...n,nodeId:e}]})}function pluralize(e,t){return e===1?t:`${t}s`}function formatLabel(e){return e===ROOT_RUNTIME_AGENT_NODE_ID?`root`:e}export{prewarmAppSandboxes,prewarmBuiltAppSandboxes,prewarmSandboxes};
|
|
@@ -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
|
|
41
|
-
*
|
|
42
|
-
*
|
|
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
|
|
51
|
-
*
|
|
52
|
-
*
|
|
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
|
-
*
|
|
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
|
|
7
|
-
* the
|
|
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
|
|
24
|
-
*
|
|
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
|
|
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.
|
|
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{
|
|
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
|
-
|
|
5
|
-
|
|
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
|
|
8
|
-
|
|
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
|
-
|
|
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
|
|
25
|
+
readonly sessionState: DurableSessionState;
|
|
26
|
+
readonly sessionWritable: WritableStream<DurableSessionSnapshot>;
|
|
24
27
|
}
|
|
25
28
|
/**
|
|
26
|
-
* Short-lived workflow that owns one runtime turn for the
|
|
27
|
-
* driver.
|
|
29
|
+
* Short-lived workflow that owns one runtime turn for the driver.
|
|
28
30
|
*
|
|
29
|
-
* `parentWritable`
|
|
30
|
-
*
|
|
31
|
-
*
|
|
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{
|
|
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
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
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{
|
|
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};
|