experimental-ash 0.48.0 → 0.50.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 (60) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/docs/internals/context.md +6 -12
  3. package/dist/docs/internals/hooks.md +15 -74
  4. package/dist/docs/internals/mechanical-invariants.md +3 -4
  5. package/dist/docs/internals/message-runtime.md +2 -3
  6. package/dist/docs/public/advanced/hooks.mdx +39 -76
  7. package/dist/docs/public/advanced/project-layout.md +1 -2
  8. package/dist/src/compiler/manifest.d.ts +1 -1
  9. package/dist/src/compiler/normalize-hook.d.ts +4 -4
  10. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  11. package/dist/src/context/hook-lifecycle.d.ts +1 -46
  12. package/dist/src/context/hook-lifecycle.js +1 -1
  13. package/dist/src/context/keys.d.ts +0 -9
  14. package/dist/src/context/keys.js +1 -1
  15. package/dist/src/execution/create-session-step.d.ts +3 -4
  16. package/dist/src/execution/create-session-step.js +1 -1
  17. package/dist/src/execution/dispatch-runtime-actions-step.d.ts +2 -3
  18. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  19. package/dist/src/execution/durable-session-store.d.ts +24 -24
  20. package/dist/src/execution/durable-session-store.js +1 -1
  21. package/dist/src/execution/turn-workflow.d.ts +4 -5
  22. package/dist/src/execution/turn-workflow.js +1 -1
  23. package/dist/src/execution/workflow-entry.js +1 -1
  24. package/dist/src/execution/workflow-runtime.d.ts +1 -1
  25. package/dist/src/execution/workflow-steps.d.ts +1 -3
  26. package/dist/src/execution/workflow-steps.js +1 -1
  27. package/dist/src/harness/step-hooks.js +1 -1
  28. package/dist/src/harness/tool-loop.js +1 -1
  29. package/dist/src/internal/application/package.js +1 -1
  30. package/dist/src/packages/ash-scaffold/src/channels.js +1 -1
  31. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  32. package/dist/src/public/channels/discord/inbound.d.ts +0 -3
  33. package/dist/src/public/channels/discord/inbound.js +1 -1
  34. package/dist/src/public/channels/discord/index.d.ts +1 -1
  35. package/dist/src/public/channels/discord/index.js +1 -1
  36. package/dist/src/public/channels/slack/inbound.d.ts +4 -13
  37. package/dist/src/public/channels/slack/inbound.js +1 -1
  38. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  39. package/dist/src/public/channels/teams/inbound.d.ts +0 -3
  40. package/dist/src/public/channels/teams/inbound.js +2 -2
  41. package/dist/src/public/channels/teams/index.d.ts +1 -1
  42. package/dist/src/public/channels/teams/index.js +1 -1
  43. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  44. package/dist/src/public/channels/telegram/inbound.d.ts +0 -3
  45. package/dist/src/public/channels/telegram/inbound.js +1 -1
  46. package/dist/src/public/channels/telegram/index.d.ts +1 -1
  47. package/dist/src/public/channels/telegram/index.js +1 -1
  48. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  49. package/dist/src/public/channels/twilio/inbound.d.ts +0 -3
  50. package/dist/src/public/channels/twilio/inbound.js +1 -1
  51. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  52. package/dist/src/public/definitions/hook.d.ts +6 -22
  53. package/dist/src/public/hooks/index.d.ts +4 -5
  54. package/dist/src/runtime/graph.d.ts +2 -3
  55. package/dist/src/runtime/hooks/registry.d.ts +5 -20
  56. package/dist/src/runtime/hooks/registry.js +1 -1
  57. package/dist/src/runtime/resolve-hook.d.ts +2 -2
  58. package/dist/src/runtime/resolve-hook.js +1 -1
  59. package/dist/src/runtime/types.d.ts +3 -9
  60. package/package.json +1 -1
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{callAdapterEventHandler}from"#channel/adapter.js";import{AuthKey,CapabilitiesKey,InitiatorAuthKey}from"#context/keys.js";import{createSubagentCalledEvent,encodeMessageStreamEvent,timestampHandleMessageStreamEvent}from"#protocol/message.js";import{toErrorMessage}from"#shared/errors.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{readDurableSession,writeDurableSession}from"#execution/durable-session-store.js";import{hydrateDurableSession}from"#execution/session.js";import{deserializeContext}from"#context/serialize.js";import{buildAdapterContext}from"#channel/adapter-context.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";const log=createLogger(`execution.dispatch-runtime-actions`);async function dispatchRuntimeActionsStep(e){"use step";let s=await readDurableSession(e.sessionState),u=getPendingRuntimeActionBatch(s.state);if(u===void 0||u.actions.length===0)return{results:[],sessionState:e.sessionState};let d=await deserializeContext(e.serializedContext),f=d.require(BundleKey),p=hydrateDurableSession({compactionOverrides:{thresholdPercent:f.resolvedAgent.config.compaction?.thresholdPercent},durable:s,turnAgent:f.turnAgent}),m=d.require(ChannelKey),h=d.get(AuthKey)??null,g=d.get(CapabilitiesKey),_=d.get(InitiatorAuthKey)??null,v=e.parentWritable.getWriter(),y=buildAdapterContext(m,d),b=p,x=[];try{for(let r of u.actions){let i,a,s,c;switch(r.kind){case`subagent-call`:{let e=createWorkflowRuntime({compiledArtifactsSource:f.compiledArtifactsSource,nodeId:r.nodeId}),{childContinuationToken:t,runInput:n}=buildSubagentRunInput({action:r,auth:h,batchEvent:u.event,capabilities:g,initiatorAuth:_,session:p}),o=await e.run(n);b=recordPendingSubagentChildToken({callId:r.callId,childContinuationToken:t,session:b}),i=o.sessionId,a=r.name,c=r.subagentName;break}case`remote-agent-call`:{let n;try{n=resolveRemoteAgentForAction({nodeId:r.nodeId,remoteAgentName:r.remoteAgentName,registry:f.subagentRegistry.subagentsByNodeId}),i=await startRemoteAgentSession({action:r,callbackBaseUrl:e.callbackBaseUrl,remote:n,session:p})}catch(e){logError(log,`remote agent start failed`,e,{remoteAgentName:r.remoteAgentName,nodeId:r.nodeId,callId:r.callId}),x.push(createRemoteAgentStartFailureResult({action:r,error:e}));continue}a=r.name,s={url:n.url},c=r.remoteAgentName;break}default:throw Error(`Unsupported runtime action kind "${r.kind}" in workflow runtime.`)}let l=await callAdapterEventHandler(m,createSubagentCalledEvent({callId:r.callId,childSessionId:i,name:a,remote:s,sequence:u.event.sequence,sessionId:p.sessionId,toolName:c,turnId:u.event.turnId,workflowId:workflowEntryReference.workflowId}),y);await v.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(l)))}}finally{v.releaseLock()}return{results:x,sessionState:b===p?e.sessionState:await writeDurableSession({session:b,writable:e.sessionWritable})}}function createRemoteAgentStartFailureResult(e){return{callId:e.action.callId,isError:!0,kind:`subagent-result`,output:{code:`REMOTE_AGENT_START_FAILED`,message:toErrorMessage(e.error)},subagentName:e.action.remoteAgentName}}export{dispatchRuntimeActionsStep};
1
+ import{createLogger,logError}from"#internal/logging.js";import{callAdapterEventHandler}from"#channel/adapter.js";import{AuthKey,CapabilitiesKey,InitiatorAuthKey}from"#context/keys.js";import{createSubagentCalledEvent,encodeMessageStreamEvent,timestampHandleMessageStreamEvent}from"#protocol/message.js";import{toErrorMessage}from"#shared/errors.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{createDurableSessionState,readDurableSession}from"#execution/durable-session-store.js";import{hydrateDurableSession}from"#execution/session.js";import{deserializeContext}from"#context/serialize.js";import{buildAdapterContext}from"#channel/adapter-context.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";const log=createLogger(`execution.dispatch-runtime-actions`);async function dispatchRuntimeActionsStep(e){"use step";let s=await readDurableSession(e.sessionState),u=getPendingRuntimeActionBatch(s.state);if(u===void 0||u.actions.length===0)return{results:[],sessionState:e.sessionState};let d=await deserializeContext(e.serializedContext),f=d.require(BundleKey),p=hydrateDurableSession({compactionOverrides:{thresholdPercent:f.resolvedAgent.config.compaction?.thresholdPercent},durable:s,turnAgent:f.turnAgent}),m=d.require(ChannelKey),h=d.get(AuthKey)??null,g=d.get(CapabilitiesKey),_=d.get(InitiatorAuthKey)??null,v=e.parentWritable.getWriter(),y=buildAdapterContext(m,d),b=p,x=[];try{for(let r of u.actions){let i,a,s,c;switch(r.kind){case`subagent-call`:{let e=createWorkflowRuntime({compiledArtifactsSource:f.compiledArtifactsSource,nodeId:r.nodeId}),{childContinuationToken:t,runInput:n}=buildSubagentRunInput({action:r,auth:h,batchEvent:u.event,capabilities:g,initiatorAuth:_,session:p}),o=await e.run(n);b=recordPendingSubagentChildToken({callId:r.callId,childContinuationToken:t,session:b}),i=o.sessionId,a=r.name,c=r.subagentName;break}case`remote-agent-call`:{let n;try{n=resolveRemoteAgentForAction({nodeId:r.nodeId,remoteAgentName:r.remoteAgentName,registry:f.subagentRegistry.subagentsByNodeId}),i=await startRemoteAgentSession({action:r,callbackBaseUrl:e.callbackBaseUrl,remote:n,session:p})}catch(e){logError(log,`remote agent start failed`,e,{remoteAgentName:r.remoteAgentName,nodeId:r.nodeId,callId:r.callId}),x.push(createRemoteAgentStartFailureResult({action:r,error:e}));continue}a=r.name,s={url:n.url},c=r.remoteAgentName;break}default:throw Error(`Unsupported runtime action kind "${r.kind}" in workflow runtime.`)}let l=await callAdapterEventHandler(m,createSubagentCalledEvent({callId:r.callId,childSessionId:i,name:a,remote:s,sequence:u.event.sequence,sessionId:p.sessionId,toolName:c,turnId:u.event.turnId,workflowId:workflowEntryReference.workflowId}),y);await v.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(l)))}}finally{v.releaseLock()}return{results:x,sessionState:b===p?e.sessionState:createDurableSessionState({session:b})}}function createRemoteAgentStartFailureResult(e){return{callId:e.action.callId,isError:!0,kind:`subagent-result`,output:{code:`REMOTE_AGENT_START_FAILED`,message:toErrorMessage(e.error)},subagentName:e.action.remoteAgentName}}export{dispatchRuntimeActionsStep};
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * Durable session storage.
3
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}.
4
+ * Session-mutating steps return the current snapshot inside
5
+ * {@link DurableSessionState}; Workflow step results are the atomic
6
+ * persistence boundary for session program memory. The legacy
7
+ * `"ash.session"` stream remains as a fallback for old in-flight
8
+ * sessions that only carry a small state handle.
9
9
  *
10
10
  * The driver workflow run is pinned to the deployment that called
11
11
  * `start()`; child turn workflows run on latest. Both
@@ -20,15 +20,14 @@ import { type HarnessEmissionState } from "#harness/emission.js";
20
20
  import type { HarnessSession, SessionStateMap } from "#harness/types.js";
21
21
  import type { SandboxState } from "#sandbox/state.js";
22
22
  import type { JsonObject } from "#shared/json.js";
23
- /** Workflow stream namespace where every session snapshot lands. */
24
- export declare const ASH_SESSION_STREAM_NAMESPACE = "ash.session";
25
23
  /** Current wire version for {@link DurableSessionState} and {@link DurableSessionSnapshot}. */
26
24
  export declare const DURABLE_SESSION_VERSION = 1;
27
25
  /**
28
26
  * Serializable handle to a durable session.
29
27
  *
30
- * Carries only the small projections the workflow body needs without
31
- * taking a step boundary: identity, the hook continuation token,
28
+ * Carries the current session snapshot plus the small projections the
29
+ * workflow body needs without taking a step boundary: identity, the
30
+ * hook continuation token,
32
31
  * `hasProxyInputRequests` (a closed-contract short-circuit that lets
33
32
  * the driver skip a per-delivery proxy-routing step when no
34
33
  * descendant subagent is active), and `emissionState` (so workflow-body
@@ -36,6 +35,8 @@ export declare const DURABLE_SESSION_VERSION = 1;
36
35
  * with `{ turnId, sequence, stepIndex }` without reading the full
37
36
  * durable session). All other control-plane state travels via
38
37
  * {@link import("#execution/next-driver-action.js").NextDriverAction}.
38
+ * `snapshot` is optional so old stream-backed states can still read
39
+ * from the legacy `ash.session` fallback.
39
40
  */
40
41
  export interface DurableSessionState {
41
42
  readonly version: typeof DURABLE_SESSION_VERSION;
@@ -43,10 +44,11 @@ export interface DurableSessionState {
43
44
  readonly continuationToken: string;
44
45
  readonly hasProxyInputRequests: boolean;
45
46
  readonly emissionState: HarnessEmissionState;
47
+ readonly snapshot?: DurableSessionSnapshot;
46
48
  }
47
49
  /**
48
- * Durable projection of {@link HarnessSession} written to the
49
- * `ash.session` stream.
50
+ * Durable projection of {@link HarnessSession} embedded in state
51
+ * snapshots or legacy `ash.session` stream chunks.
50
52
  *
51
53
  * Omits `agent.modelReference`, `agent.tools`,
52
54
  * `agent.compactionModelReference`, and the `compaction` thresholds —
@@ -87,13 +89,14 @@ export declare function projectSessionState(input: {
87
89
  readonly session: HarnessSession;
88
90
  }): DurableSessionState;
89
91
  /**
90
- * Reads the latest snapshot from the `ash.session` stream and returns
91
- * the {@link DurableSession} inside.
92
+ * Reads the latest durable session snapshot and returns the
93
+ * {@link DurableSession} inside.
92
94
  *
93
- * Always pulls the tail chunk (`startIndex: -1`); the
94
- * single-writer-per-session-stream invariant makes that safe. The
95
- * snapshot is migrated to {@link DURABLE_SESSION_VERSION} before
96
- * return; unknown versions throw.
95
+ * New states carry the snapshot directly through Workflow step
96
+ * results. States without `snapshot` fall back to the legacy
97
+ * `ash.session` stream tail (`startIndex: -1`). The snapshot is
98
+ * migrated to {@link DURABLE_SESSION_VERSION} before return; unknown
99
+ * versions throw.
97
100
  *
98
101
  * Devalue handles encode/decode so rich types in the session (URL
99
102
  * `FilePart.data`, Buffer, Date, Map, Set) round-trip structurally.
@@ -102,12 +105,9 @@ export declare function projectSessionState(input: {
102
105
  */
103
106
  export declare function readDurableSession(state: DurableSessionState): Promise<DurableSession>;
104
107
  /**
105
- * Appends one snapshot to the `ash.session` stream and returns the
106
- * projected {@link DurableSessionState}.
107
- *
108
- * MUST be called from inside a `"use step"` body.
108
+ * Creates the projected {@link DurableSessionState} with the current
109
+ * snapshot embedded in the Workflow step result.
109
110
  */
110
- export declare function writeDurableSession(input: {
111
+ export declare function createDurableSessionState(input: {
111
112
  readonly session: HarnessSession;
112
- readonly writable: WritableStream<DurableSessionSnapshot>;
113
- }): Promise<DurableSessionState>;
113
+ }): DurableSessionState;
@@ -1 +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,DURABLE_SESSION_READ_TIMEOUT_MS=1e4;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`),n=t(e.sessionId).getReadable({namespace:ASH_SESSION_STREAM_NAMESPACE,startIndex:-1}).getReader(),i=`ash durable session tail read failed`,a;try{let t=await Promise.race([n.read().then(e=>({kind:`read`,read:e})),new Promise(e=>{a=setTimeout(()=>e({kind:`timeout`}),DURABLE_SESSION_READ_TIMEOUT_MS)})]);if(t.kind===`timeout`)throw i=`ash durable session tail read timed out after ${DURABLE_SESSION_READ_TIMEOUT_MS}ms`,new DurableSessionReadTimeoutError(e);if(t.read.done||t.read.value===void 0)throw i=`ash durable session tail read returned no snapshot`,Error(`No durable session snapshot found in stream "${ASH_SESSION_STREAM_NAMESPACE}" for run ${e.sessionId}.`);return i=`ash durable session tail read complete`,migrateDurableSessionSnapshot(t.read.value).session}finally{a!==void 0&&clearTimeout(a),await n.cancel(i).catch(()=>{}),n.releaseLock()}}var DurableSessionReadTimeoutError=class extends Error{constructor(e){super(`Timed out reading durable session snapshot from stream "${ASH_SESSION_STREAM_NAMESPACE}" for run ${e.sessionId} after ${DURABLE_SESSION_READ_TIMEOUT_MS}ms.`),this.name=`DurableSessionReadTimeoutError`}};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};
1
+ import{projectToDurableSession}from"#execution/session.js";import{getHarnessEmissionState}from"#harness/emission.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,DURABLE_SESSION_READ_TIMEOUT_MS=1e4;function projectSessionState(e){return{continuationToken:e.session.continuationToken,emissionState:getHarnessEmissionState(e.session.state),hasProxyInputRequests:hasProxyInputRequests(e.session.state),sessionId:e.session.sessionId,version:1}}async function readDurableSession(e){if(e.snapshot!==void 0)return migrateDurableSessionSnapshot(e.snapshot).session;let{getRun:t}=await import(`#compiled/@workflow/core/runtime.js`),n=t(e.sessionId).getReadable({namespace:ASH_SESSION_STREAM_NAMESPACE,startIndex:-1}).getReader(),r=`ash durable session tail read failed`,i;try{let t=await Promise.race([n.read().then(e=>({kind:`read`,read:e})),new Promise(e=>{i=setTimeout(()=>e({kind:`timeout`}),DURABLE_SESSION_READ_TIMEOUT_MS)})]);if(t.kind===`timeout`)throw r=`ash durable session tail read timed out after ${DURABLE_SESSION_READ_TIMEOUT_MS}ms`,new DurableSessionReadTimeoutError(e);if(t.read.done||t.read.value===void 0)throw r=`ash durable session tail read returned no snapshot`,Error(`No durable session snapshot found in stream "${ASH_SESSION_STREAM_NAMESPACE}" for run ${e.sessionId}.`);return r=`ash durable session tail read complete`,migrateDurableSessionSnapshot(t.read.value).session}finally{i!==void 0&&clearTimeout(i),await n.cancel(r).catch(()=>{}),n.releaseLock()}}var DurableSessionReadTimeoutError=class extends Error{constructor(e){super(`Timed out reading durable session snapshot from stream "${ASH_SESSION_STREAM_NAMESPACE}" for run ${e.sessionId} after ${DURABLE_SESSION_READ_TIMEOUT_MS}ms.`),this.name=`DurableSessionReadTimeoutError`}};function createDurableSessionState(t){let n={session:projectToDurableSession(t.session),version:1};return{...projectSessionState({session:t.session}),snapshot:n}}export{DURABLE_SESSION_VERSION,createDurableSessionState,projectSessionState,readDurableSession};
@@ -1,6 +1,6 @@
1
1
  import type { HookPayload, SessionCapabilities } from "#channel/types.js";
2
2
  import type { RunMode } from "#shared/run-mode.js";
3
- import type { DurableSessionSnapshot, DurableSessionState } from "#execution/durable-session-store.js";
3
+ import type { DurableSessionState } from "#execution/durable-session-store.js";
4
4
  import type { NextDriverAction } from "#execution/next-driver-action.js";
5
5
  /**
6
6
  * Hook payload the turn child workflow delivers to the parent driver
@@ -23,14 +23,13 @@ export interface TurnWorkflowInput {
23
23
  readonly parentWritable: WritableStream<Uint8Array>;
24
24
  readonly serializedContext: Record<string, unknown>;
25
25
  readonly sessionState: DurableSessionState;
26
- readonly sessionWritable: WritableStream<DurableSessionSnapshot>;
27
26
  }
28
27
  /**
29
28
  * Short-lived workflow that owns one runtime turn for the driver.
30
29
  *
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
30
+ * `parentWritable` is threaded in from the driver run so event writes
31
+ * land on the driver's stream. Resolves the turn into a
32
+ * {@link NextDriverAction} and reports it back through
34
33
  * {@link notifyDriverStep}.
35
34
  */
36
35
  export declare function turnWorkflow(input: TurnWorkflowInput): Promise<void>;
@@ -1 +1 @@
1
- import{normalizeSerializableError}from"#execution/workflow-errors.js";import{turnStep}from"#execution/workflow-steps.js";async function turnWorkflow(n){"use workflow";let r=n.sessionState,i=n.serializedContext,a=n.delivery,o=n.parentWritable,s=n.sessionWritable;try{for(;;){let e=await turnStep({input:a,parentWritable:o,serializedContext:i,sessionState:r,sessionWritable:s});if(r=e.sessionState,i=e.serializedContext,e.action===`done`){await notifyDriverStep({completionToken:n.completionToken,payload:{action:{kind:`done`,output:e.output??``,isError:e.isError,serializedContext:i,sessionState:r},kind:`turn-result`}});return}if(e.action===`park`){let t=e.pendingRuntimeActionKeys;if(!(t!==void 0||e.hasPendingAuthorization||e.hasPendingInputBatch&&n.capabilities?.requestInput===!0||n.mode===`conversation`))throw Error("Task mode cannot wait for follow-up input (`next: null`).");let a=t===void 0?{kind:`park`,serializedContext:i,sessionState:r,authorizationNames:e.authorizationNames}:{kind:`dispatch-runtime-actions`,pendingActionKeys:t,serializedContext:i,sessionState:r};await notifyDriverStep({completionToken:n.completionToken,payload:{action:a,kind:`turn-result`}});return}a=void 0}}catch(t){throw await notifyDriverStep({completionToken:n.completionToken,payload:{error:normalizeSerializableError(t),kind:`turn-error`}}),t}}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{normalizeSerializableError}from"#execution/workflow-errors.js";import{turnStep}from"#execution/workflow-steps.js";async function turnWorkflow(n){"use workflow";let r=n.sessionState,i=n.serializedContext,a=n.delivery,o=n.parentWritable;try{for(;;){let e=await turnStep({input:a,parentWritable:o,serializedContext:i,sessionState:r});if(r=e.sessionState,i=e.serializedContext,e.action===`done`){await notifyDriverStep({completionToken:n.completionToken,payload:{action:{kind:`done`,output:e.output??``,isError:e.isError,serializedContext:i,sessionState:r},kind:`turn-result`}});return}if(e.action===`park`){let t=e.pendingRuntimeActionKeys;if(!(t!==void 0||e.hasPendingAuthorization||e.hasPendingInputBatch&&n.capabilities?.requestInput===!0||n.mode===`conversation`))throw Error("Task mode cannot wait for follow-up input (`next: null`).");let a=t===void 0?{kind:`park`,serializedContext:i,sessionState:r,authorizationNames:e.authorizationNames}:{kind:`dispatch-runtime-actions`,pendingActionKeys:t,serializedContext:i,sessionState:r};await notifyDriverStep({completionToken:n.completionToken,payload:{action:a,kind:`turn-result`}});return}a=void 0}}catch(t){throw await notifyDriverStep({completionToken:n.completionToken,payload:{error:normalizeSerializableError(t),kind:`turn-error`}}),t}}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 +1 @@
1
- import{ASH_SESSION_STREAM_NAMESPACE}from"#execution/durable-session-store.js";import{readRootSessionId}from"#execution/ash-workflow-attributes.js";import{accumulateRuntimeActionResults}from"#harness/runtime-actions.js";import{resolveVercelProductionCallbackBaseUrl}from"#execution/workflow-callback-url.js";import{normalizeSerializableError,rebuildSerializableError}from"#execution/workflow-errors.js";import{dispatchTurnStep,emitTerminalSessionFailureStep,routeProxiedDeliverStep,runProxyInputRequestStep}from"#execution/workflow-steps.js";import{createHook,getWorkflowMetadata,getWritable}from"#compiled/@workflow/core/index.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(n){"use workflow";let{workflowRunId:r}=getWorkflowMetadata(),a=n.serializedContext[`ash.continuationToken`]||``,o=n.serializedContext[`ash.mode`],c=n.serializedContext[`ash.capabilities`],l=n.serializedContext[`ash.bundle`];n.serializedContext[`ash.sessionId`]=r;let u=getWritable(),d=getWritable({namespace:ASH_SESSION_STREAM_NAMESPACE});try{let e=readRootSessionId(n.serializedContext),{state:i}=await createSessionStep({compiledArtifactsSource:l.source,continuationToken:a,inputMessage:n.input.message,nodeId:l.nodeId,outputSchema:n.input.outputSchema,rootSessionId:e,serializedContext:n.serializedContext,sessionId:r,sessionWritable:d});return await runDriverLoop({capabilities:c,driverWritable:u,initialInput:{kind:`deliver`,payloads:[{message:n.input.message,context:n.input.context,outputSchema:n.input.outputSchema}]},mode:o,serializedContext:n.serializedContext,sessionState:i,sessionWritable:d})}catch(e){throw await emitTerminalSessionFailureStep({error:normalizeSerializableError(e),parentWritable:u,serializedContext:n.serializedContext}),await fireSessionCallbackStep({error:normalizeSerializableError(e),serializedContext:n.serializedContext,status:`failed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentErrorResult(n.serializedContext,e),serializedContext:n.serializedContext}),e}}async function runDriverLoop(e){let t=createHook({token:`${e.sessionState.sessionId}:auth`}),n=t[Symbol.asyncIterator](),i=e.sessionState.continuationToken,a=createHook({token:i}),o=a[Symbol.asyncIterator](),s=null,c=[],getNextPromise=()=>(s??=o.next(),s),consumeNext=()=>{s=null},rekeyHook=async e=>{e===i||!e||(await closeHookIterator(o),await disposeHook(a),i=e,a=createHook({token:i}),o=a[Symbol.asyncIterator](),s=null)},l=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:e.initialInput,mode:e.mode,parentWritable:e.driverWritable,serializedContext:e.serializedContext,sessionState:e.sessionState,sessionWritable:e.sessionWritable});if(l.kind===`done`)return await closeHookIterator(n),await disposeHook(t),await closeHookIterator(o),await disposeHook(a),await finalizeDone({action:l,driverWritable:e.driverWritable});if(!l.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.");await rekeyHook(l.sessionState.continuationToken);try{for(;;)switch(l.kind){case`done`:return await finalizeDone({action:l,driverWritable:e.driverWritable});case`dispatch-runtime-actions`:{let t=await dispatchRuntimeActionsStep({callbackBaseUrl:resolveVercelProductionCallbackBaseUrl()??getWorkflowMetadata().url,parentWritable:e.driverWritable,serializedContext:l.serializedContext,sessionState:l.sessionState,sessionWritable:e.sessionWritable}),n=await waitForPendingRuntimeActionResults({bufferedDeliveries:c,consumeNext,getNextPromise,initialResults:t.results,parentWritable:e.driverWritable,pendingActionKeys:l.pendingActionKeys,rekeyHook,serializedContext:l.serializedContext,sessionState:t.sessionState,sessionWritable:e.sessionWritable});if(n===null)return{output:``};l=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{kind:`runtime-action-result`,results:n.results},mode:e.mode,parentWritable:e.driverWritable,serializedContext:n.serializedContext,sessionState:n.sessionState,sessionWritable:e.sessionWritable}),await rekeyHook(l.sessionState.continuationToken);break}case`park`:{if(l.authorizationNames&&l.authorizationNames.length>0){let t=l.authorizationNames.length,r=[];for(;r.length<t;){let e=await n.next();if(e.done)break;e.value.kind===`deliver`&&r.push(...e.value.payloads)}l=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{kind:`deliver`,payloads:r},mode:e.mode,parentWritable:e.driverWritable,serializedContext:l.serializedContext,sessionState:l.sessionState,sessionWritable:e.sessionWritable}),await rekeyHook(l.sessionState.continuationToken);break}let t=await waitForNextDeliver({bufferedDeliveries:c,consumeNext,getNextPromise});if(t===null)return{output:``};let r=await routeDeliverForChildren({auth:t.auth,parentWritable:e.driverWritable,payloads:t.payloads,sessionState:l.sessionState});if(r===void 0)continue;l=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{auth:t.auth,kind:`deliver`,payloads:[r]},mode:e.mode,parentWritable:e.driverWritable,serializedContext:l.serializedContext,sessionState:l.sessionState,sessionWritable:e.sessionWritable}),await rekeyHook(l.sessionState.continuationToken);break}}}finally{await closeHookIterator(o),await disposeHook(a),await closeHookIterator(n),await disposeHook(t)}}async function finalizeDone(e){let{output:t,serializedContext:n}=e.action,r=e.action.isError===!0;return await fireSessionCallbackStep({error:r?t:void 0,output:r?void 0:t,serializedContext:n,status:r?`failed`:`completed`}),await notifyDelegatedParentStep({result:r?createDelegatedSubagentErrorResult(n,t):createDelegatedSubagentSuccessResult(n,t),serializedContext:n}),{output:t}}async function dispatchAndAwaitTurn(e){let t=createHook(),n=t.token;try{await dispatchTurnStep({capabilities:e.capabilities,completionToken:n,delivery:e.delivery,mode:e.mode,parentWritable:e.parentWritable,serializedContext:e.serializedContext,sessionState:e.sessionState,sessionWritable:e.sessionWritable});let r=await awaitHookPayload(t);if(r.kind===`turn-error`)throw rebuildSerializableError(r.error);return r.action}finally{await disposeHook(t)}}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,r=e.serializedContext,i=await accumulateRuntimeActionResults({bufferedDeliveries:e.bufferedDeliveries,async getNext(){for(;;){let n=await e.getNextPromise();if(e.consumeNext(),n.done)return null;let i=n.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:r,sessionState:t,sessionWritable:e.sessionWritable});t=a.sessionState,r=a.serializedContext,await e.rekeyHook(t.continuationToken)}},initialResults:e.initialResults,pendingActionKeys:e.pendingActionKeys});return i===null?null:{results:i,serializedContext:r,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
+ import{readRootSessionId}from"#execution/ash-workflow-attributes.js";import{accumulateRuntimeActionResults}from"#harness/runtime-actions.js";import{resolveVercelProductionCallbackBaseUrl}from"#execution/workflow-callback-url.js";import{normalizeSerializableError,rebuildSerializableError}from"#execution/workflow-errors.js";import{dispatchTurnStep,emitTerminalSessionFailureStep,routeProxiedDeliverStep,runProxyInputRequestStep}from"#execution/workflow-steps.js";import{createHook,getWorkflowMetadata,getWritable}from"#compiled/@workflow/core/index.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(t){"use workflow";let{workflowRunId:n}=getWorkflowMetadata(),i=t.serializedContext[`ash.continuationToken`]||``,a=t.serializedContext[`ash.mode`],s=t.serializedContext[`ash.capabilities`],c=t.serializedContext[`ash.bundle`];t.serializedContext[`ash.sessionId`]=n;let l=getWritable();try{let r=readRootSessionId(t.serializedContext),{state:o}=await createSessionStep({compiledArtifactsSource:c.source,continuationToken:i,inputMessage:t.input.message,nodeId:c.nodeId,outputSchema:t.input.outputSchema,rootSessionId:r,serializedContext:t.serializedContext,sessionId:n});return await runDriverLoop({capabilities:s,driverWritable:l,initialInput:{kind:`deliver`,payloads:[{message:t.input.message,context:t.input.context,outputSchema:t.input.outputSchema}]},mode:a,serializedContext:t.serializedContext,sessionState:o})}catch(e){throw await emitTerminalSessionFailureStep({error:normalizeSerializableError(e),parentWritable:l,serializedContext:t.serializedContext}),await fireSessionCallbackStep({error:normalizeSerializableError(e),serializedContext:t.serializedContext,status:`failed`}),await notifyDelegatedParentStep({result:createDelegatedSubagentErrorResult(t.serializedContext,e),serializedContext:t.serializedContext}),e}}async function runDriverLoop(e){let t=createHook({token:`${e.sessionState.sessionId}:auth`}),r=t[Symbol.asyncIterator](),i=e.sessionState.continuationToken,a=createHook({token:i}),o=a[Symbol.asyncIterator](),s=null,c=[],getNextPromise=()=>(s??=o.next(),s),consumeNext=()=>{s=null},rekeyHook=async e=>{e===i||!e||(await closeHookIterator(o),await disposeHook(a),i=e,a=createHook({token:i}),o=a[Symbol.asyncIterator](),s=null)},u=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:e.initialInput,mode:e.mode,parentWritable:e.driverWritable,serializedContext:e.serializedContext,sessionState:e.sessionState});if(u.kind===`done`)return await closeHookIterator(r),await disposeHook(t),await closeHookIterator(o),await disposeHook(a),await finalizeDone({action:u,driverWritable:e.driverWritable});if(!u.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.");await rekeyHook(u.sessionState.continuationToken);try{for(;;)switch(u.kind){case`done`:return await finalizeDone({action:u,driverWritable:e.driverWritable});case`dispatch-runtime-actions`:{let t=await dispatchRuntimeActionsStep({callbackBaseUrl:resolveVercelProductionCallbackBaseUrl()??getWorkflowMetadata().url,parentWritable:e.driverWritable,serializedContext:u.serializedContext,sessionState:u.sessionState}),r=await waitForPendingRuntimeActionResults({bufferedDeliveries:c,consumeNext,getNextPromise,initialResults:t.results,parentWritable:e.driverWritable,pendingActionKeys:u.pendingActionKeys,rekeyHook,serializedContext:u.serializedContext,sessionState:t.sessionState});if(r===null)return{output:``};u=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{kind:`runtime-action-result`,results:r.results},mode:e.mode,parentWritable:e.driverWritable,serializedContext:r.serializedContext,sessionState:r.sessionState}),await rekeyHook(u.sessionState.continuationToken);break}case`park`:{if(u.authorizationNames&&u.authorizationNames.length>0){let t=u.authorizationNames.length,n=[];for(;n.length<t;){let e=await r.next();if(e.done)break;e.value.kind===`deliver`&&n.push(...e.value.payloads)}u=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{kind:`deliver`,payloads:n},mode:e.mode,parentWritable:e.driverWritable,serializedContext:u.serializedContext,sessionState:u.sessionState}),await rekeyHook(u.sessionState.continuationToken);break}let t=await waitForNextDeliver({bufferedDeliveries:c,consumeNext,getNextPromise});if(t===null)return{output:``};let n=await routeDeliverForChildren({auth:t.auth,parentWritable:e.driverWritable,payloads:t.payloads,sessionState:u.sessionState});if(n===void 0)continue;u=await dispatchAndAwaitTurn({capabilities:e.capabilities,delivery:{auth:t.auth,kind:`deliver`,payloads:[n]},mode:e.mode,parentWritable:e.driverWritable,serializedContext:u.serializedContext,sessionState:u.sessionState}),await rekeyHook(u.sessionState.continuationToken);break}}}finally{await closeHookIterator(o),await disposeHook(a),await closeHookIterator(r),await disposeHook(t)}}async function finalizeDone(e){let{output:t,serializedContext:n}=e.action,r=e.action.isError===!0;return await fireSessionCallbackStep({error:r?t:void 0,output:r?void 0:t,serializedContext:n,status:r?`failed`:`completed`}),await notifyDelegatedParentStep({result:r?createDelegatedSubagentErrorResult(n,t):createDelegatedSubagentSuccessResult(n,t),serializedContext:n}),{output:t}}async function dispatchAndAwaitTurn(e){let t=createHook(),n=t.token;try{await dispatchTurnStep({capabilities:e.capabilities,completionToken:n,delivery:e.delivery,mode:e.mode,parentWritable:e.parentWritable,serializedContext:e.serializedContext,sessionState:e.sessionState});let r=await awaitHookPayload(t);if(r.kind===`turn-error`)throw rebuildSerializableError(r.error);return r.action}finally{await disposeHook(t)}}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 n=e.sessionState,r=e.serializedContext,i=await accumulateRuntimeActionResults({bufferedDeliveries:e.bufferedDeliveries,async getNext(){for(;;){let t=await e.getNextPromise();if(e.consumeNext(),t.done)return null;let i=t.value;if(i.kind===`deliver`){let t=await routeDeliverForChildren({auth:i.auth,parentWritable:e.parentWritable,payloads:i.payloads,sessionState:n});if(t===void 0)continue;return{kind:`deliver`,value:{...i,payloads:[t]}}}if(i.kind===`runtime-action-result`)return{kind:`runtime-action-result`,results:i.results};let a=await runProxyInputRequestStep({hookPayload:i,parentWritable:e.parentWritable,serializedContext:r,sessionState:n});n=a.sessionState,r=a.serializedContext,await e.rekeyHook(n.continuationToken)}},initialResults:e.initialResults,pendingActionKeys:e.pendingActionKeys});return i===null?null:{results:i,serializedContext:r,sessionState:n}}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};
@@ -35,7 +35,7 @@ export declare const turnWorkflowReference: {
35
35
  };
36
36
  /**
37
37
  * Creates a workflow-backed runtime whose long-lived driver owns the
38
- * session stream and dispatches each turn as a child workflow run.
38
+ * event stream and dispatches each turn as a child workflow run.
39
39
  */
40
40
  export declare function createWorkflowRuntime(config: {
41
41
  readonly compiledArtifactsSource: RuntimeCompiledArtifactsSource;
@@ -3,7 +3,7 @@ import { deserializeContext } from "#context/serialize.js";
3
3
  import type { HarnessSession, StepInput } from "#harness/types.js";
4
4
  import type { JsonObject } from "#shared/json.js";
5
5
  import type { RunMode } from "#shared/run-mode.js";
6
- import { type DurableSessionSnapshot, type DurableSessionState } from "#execution/durable-session-store.js";
6
+ import { type DurableSessionState } from "#execution/durable-session-store.js";
7
7
  import { type TurnWorkflowInput } from "#execution/turn-workflow.js";
8
8
  /**
9
9
  * Result of one durable harness step, consumed by the turn workflow.
@@ -34,7 +34,6 @@ export interface TurnStepInput {
34
34
  readonly parentWritable: WritableStream<Uint8Array>;
35
35
  readonly serializedContext: Record<string, unknown>;
36
36
  readonly sessionState: DurableSessionState;
37
- readonly sessionWritable: WritableStream<DurableSessionSnapshot>;
38
37
  }
39
38
  /**
40
39
  * Runs one atomic harness step inside a durable `"use step"` boundary.
@@ -83,7 +82,6 @@ export declare function runProxyInputRequestStep(input: {
83
82
  readonly parentWritable: WritableStream<Uint8Array>;
84
83
  readonly serializedContext: Record<string, unknown>;
85
84
  readonly sessionState: DurableSessionState;
86
- readonly sessionWritable: WritableStream<DurableSessionSnapshot>;
87
85
  }): Promise<ProxyInputRequestResult>;
88
86
  export interface RoutedDeliverResult {
89
87
  /** `undefined` when the entire payload was routed to descendants. */
@@ -1 +1 @@
1
- import{createLogger,formatError}from"#internal/logging.js";import{callAdapterEventHandler,defaultDeliverResult}from"#channel/adapter.js";import{AuthKey,CapabilitiesKey,ContinuationTokenKey,ModeKey}from"#context/keys.js";import{createAuthorizationCompletedEvent,createSessionFailedEvent,encodeMessageStreamEvent,timestampHandleMessageStreamEvent}from"#protocol/message.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{getHarnessEmissionState,isHarnessBetweenTurns}from"#harness/emission.js";import{readDurableSession,writeDurableSession}from"#execution/durable-session-store.js";import{hydrateDurableSession,refreshSessionFromTurnAgent}from"#execution/session.js";import{buildTurnAttributes,readRootSessionId}from"#execution/ash-workflow-attributes.js";import{setAshAttributes}from"#runtime/attributes/emit.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{getPendingRuntimeActionBatch}from"#harness/runtime-actions.js";import{createWorkflowRuntime,startWorkflowPreferLatest}from"#execution/workflow-runtime.js";import{upsertProxyInputRequests}from"#harness/proxy-input-requests.js";import{setChannelContext}from"#execution/channel-context.js";import{coalesceTurnInputs}from"#harness/messages.js";import{dispatchStreamEventHooks,runHookLifecycleStep}from"#context/hook-lifecycle.js";import{dispatchDynamicInstructionEvent}from"#context/dynamic-instruction-lifecycle.js";import{dispatchDynamicSkillEvent}from"#context/dynamic-skill-lifecycle.js";import{dispatchDynamicToolEvent}from"#context/dynamic-tool-lifecycle.js";import{runStep,withContextScope}from"#context/run-step.js";import{hasPendingInputBatch}from"#harness/input-requests.js";import{getRuntimeActionRequestKey}from"#runtime/actions/keys.js";import{CallbackBaseUrlKey,PendingAuthorizationResultKey,getPendingAuthorization}from"#harness/authorization.js";import{createExecutionNodeStep}from"#execution/node-step.js";import{emitProxiedInputRequest,routeDeliverPayload}from"#execution/subagent-hitl-proxy.js";import{turnWorkflow}from"#execution/turn-workflow.js";async function turnStep(e){"use step";await setAshAttributes(buildTurnAttributes({parentSessionId:e.sessionState.sessionId,rootSessionId:readRootSessionId(e.serializedContext)??e.sessionState.sessionId}));let t=await readDurableSession(e.sessionState),o=await deserializeContext(e.serializedContext),l=o.require(ChannelKey),f=o.require(BundleKey),p=hydrateDurableSession({compactionOverrides:{thresholdPercent:f.resolvedAgent.config.compaction?.thresholdPercent},durable:t,turnAgent:f.turnAgent});try{let{getWorkflowMetadata:e}=await import(`#compiled/@workflow/core/index.js`),t=e();typeof t.url==`string`&&o.set(CallbackBaseUrlKey,t.url.replace(/\/$/,``))}catch{}let m=getPendingAuthorization(t.state),h;if(m&&e.input?.kind===`deliver`){let t=[],n=[];for(let r of e.input.payloads){let e=r.authorizationCallback;if(e){let n=m.challenges.find(t=>t.name===e.connectionName);n&&t.push({name:n.name,state:n.state,callback:e.request,hookUrl:n.hookUrl})}else n.push(r)}t.length>0&&(o.set(PendingAuthorizationResultKey,t),h=t.map(e=>e.name),e=n.length>0?{...e,input:{...e.input,payloads:n}}:{...e,input:void 0})}e.input?.kind===`deliver`&&e.input.auth!==void 0&&o.set(AuthKey,e.input.auth??null);let g=buildAdapterContext(l,o),_;if(e.input?.kind===`deliver`){let t=[];for(let n of e.input.payloads){let e=l.deliver?await l.deliver(n,g):defaultDeliverResult(n);e!=null&&t.push(e)}_=t.length===0?void 0:t.reduce(coalesceTurnInputs)}else e.input?.kind===`runtime-action-result`&&(_={runtimeActionResults:e.input.results});if(e.input?.kind===`deliver`&&setChannelContext(o,{...l,state:{...g.state}}),e.input?.kind===`deliver`&&_===void 0){let t=reconcileSessionContinuationToken(o,p),n=serializeContext(o),r=t===p?e.sessionState:await writeDurableSession({session:t,writable:e.sessionWritable});return{action:`park`,...derivePendingState(t),serializedContext:n,sessionState:r}}let v=e.parentWritable.getWriter(),y=f.hookRegistry,b=f.resolvedAgent.dynamicInstructionsResolvers??[],x=f.resolvedAgent.dynamicSkillResolvers??[],S=f.resolvedAgent.dynamicToolResolvers??[],emit=async e=>{let t=await callAdapterEventHandler(l,e,g);return setChannelContext(o,{...l,state:{...g.state}}),await v.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(t))),t},handleEvent=async(e,t)=>{let n=await emit(e);await dispatchStreamEventHooks({ctx:o,registry:y,event:n}),await dispatchDynamicToolEvent({ctx:o,resolvers:S,event:n,messages:t??[]}),await dispatchDynamicSkillEvent({ctx:o,resolvers:x,event:n,messages:t??[]}),await dispatchDynamicInstructionEvent({ctx:o,resolvers:b,event:n,messages:t??[]})},C=o.require(ModeKey),w=await runStep(o,p,async e=>{let t=resolveEffectiveOutputSchema({agentOutputSchema:f.turnAgent.outputSchema,input:_,mode:C,session:e});if(h){let e=getHarnessEmissionState(t.state);for(let t of h)await handleEvent(createAuthorizationCompletedEvent({name:t,outcome:`authorized`,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId}))}let n=o.get(CapabilitiesKey),runHarnessStep=async(e,t)=>{let r=refreshSessionFromTurnAgent({compactionOverrides:{thresholdPercent:f.resolvedAgent.config.compaction?.thresholdPercent},session:e,turnAgent:f.turnAgent});return createExecutionNodeStep({capabilities:n,compiledArtifactsSource:f.compiledArtifactsSource,createRuntime:createWorkflowRuntime,handleEvent,mode:C,node:f.graph.root})(r,t)};return _!==void 0&&isHarnessBetweenTurns(t)?runHookLifecycleStep({ctx:o,emit:handleEvent,input:_,mode:C,registry:f.hookRegistry,session:t},runHarnessStep):runHarnessStep(t,_)}),T=reconcileSessionContinuationToken(o,w.session),E=serializeContext(o);w={...w,session:T};let D=await writeDurableSession({session:w.session,writable:e.sessionWritable});return w.next!==null&&typeof w.next==`object`&&`done`in w.next?(await v.close(),{action:`done`,output:w.next.output,isError:w.next.isError,serializedContext:E,sessionState:D}):w.next===null?(v.releaseLock(),{action:`park`,...derivePendingState(w.session),serializedContext:E,sessionState:D}):(v.releaseLock(),{action:`continue`,serializedContext:E,sessionState:D})}function derivePendingState(e){let t=getPendingRuntimeActionBatch(e.state),n=getPendingAuthorization(e.state),r={authorizationNames:n?.challenges.map(e=>e.name),hasPendingAuthorization:n!==void 0,hasPendingInputBatch:hasPendingInputBatch(e.state)};return t===void 0?r:{...r,pendingRuntimeActionKeys:t.actions.map(e=>getRuntimeActionRequestKey(e))}}function reconcileSessionContinuationToken(e,t){let n=e.get(ContinuationTokenKey);return n===void 0||n===t.continuationToken?t:{...t,continuationToken:n}}function resolveEffectiveOutputSchema(e){let{agentOutputSchema:t,input:n,mode:r,session:i}=e;return n?.outputSchema===void 0?r===`task`&&i.outputSchema===void 0&&t!==void 0?{...i,outputSchema:t}:i:{...i,outputSchema:n.outputSchema}}const log=createLogger(`execution.workflow-entry`);async function emitTerminalSessionFailureStep(e){"use step";let r=formatError(e.error),i=typeof r.name==`string`?r.name:`WORKFLOW_EXECUTION_FAILED`,a=typeof r.message==`string`?r.message:String(e.error),o=e.serializedContext[`ash.sessionId`]??``;log.error(`workflow loop threw — emitting terminal session.failed`,{sessionId:o,errorId:typeof r.errorId==`string`?r.errorId:void 0,code:i,message:a,detail:typeof r.detail==`string`?r.detail:void 0});let s=createSessionFailedEvent({code:i,details:r,message:a,sessionId:o});try{let t=await deserializeContext(e.serializedContext),r=t.get(ChannelKey);r!==void 0&&await callAdapterEventHandler(r,s,buildAdapterContext(r,t))}catch(e){log.error(`adapter failed to handle terminal session.failed event`,{errorId:typeof r.errorId==`string`?r.errorId:void 0,sessionId:o,error:e})}try{let t=e.parentWritable.getWriter();try{await t.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(s)))}finally{t.releaseLock()}}catch(e){log.error(`failed to write terminal session.failed event to durable stream`,{errorId:typeof r.errorId==`string`?r.errorId:void 0,sessionId:o,error:e})}}async function runProxyInputRequestStep(e){"use step";let t=await readDurableSession(e.sessionState),r=await deserializeContext(e.serializedContext),i=r.require(ChannelKey),a=buildAdapterContext(i,r),o=r.require(ModeKey),c=r.require(BundleKey),l=hydrateDurableSession({compactionOverrides:{thresholdPercent:c.resolvedAgent.config.compaction?.thresholdPercent},durable:t,turnAgent:c.turnAgent}),u=e.parentWritable.getWriter(),d;try{let emit=async e=>{let t=await callAdapterEventHandler(i,e,a);await u.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(t)))};d=await withContextScope(r,l,async t=>{let n=await emitProxiedInputRequest({emit,hookPayload:e.hookPayload,mode:o,session:t});return{result:n.entries,session:n.session}})}finally{u.releaseLock()}return setChannelContext(r,{...i,state:{...a.state}}),{serializedContext:serializeContext(r),sessionState:await writeDurableSession({session:reconcileSessionContinuationToken(r,upsertProxyInputRequests({entries:d.result,forChildContinuationToken:e.hookPayload.childContinuationToken,session:d.session})),writable:e.sessionWritable})}}async function routeProxiedDeliverStep(e){"use step";let t=await readDurableSession(e.sessionState),n=routeDeliverPayload({payload:e.payload,state:t.state}),{resumeHook:r}=await import(`#compiled/@workflow/core/runtime.js`);for(let t of n.forChildren)await r(t.childContinuationToken,{auth:e.auth,kind:`deliver`,payloads:[t.payload]});return{remainder:n.forSelf}}async function dispatchTurnStep(e){"use step";return{runId:(await startWorkflowPreferLatest(turnWorkflow,[e])).runId}}export{dispatchTurnStep,emitTerminalSessionFailureStep,reconcileSessionContinuationToken,resolveEffectiveOutputSchema,routeProxiedDeliverStep,runProxyInputRequestStep,turnStep};
1
+ import{createLogger,formatError}from"#internal/logging.js";import{callAdapterEventHandler,defaultDeliverResult}from"#channel/adapter.js";import{AuthKey,CapabilitiesKey,ContinuationTokenKey,ModeKey}from"#context/keys.js";import{createAuthorizationCompletedEvent,createSessionFailedEvent,encodeMessageStreamEvent,timestampHandleMessageStreamEvent}from"#protocol/message.js";import{BundleKey,ChannelKey}from"#runtime/sessions/runtime-context-keys.js";import{createDurableSessionState,readDurableSession}from"#execution/durable-session-store.js";import{hydrateDurableSession,refreshSessionFromTurnAgent}from"#execution/session.js";import{buildTurnAttributes,readRootSessionId}from"#execution/ash-workflow-attributes.js";import{setAshAttributes}from"#runtime/attributes/emit.js";import{deserializeContext,serializeContext}from"#context/serialize.js";import{buildAdapterContext}from"#channel/adapter-context.js";import{getPendingRuntimeActionBatch}from"#harness/runtime-actions.js";import{createWorkflowRuntime,startWorkflowPreferLatest}from"#execution/workflow-runtime.js";import{getHarnessEmissionState}from"#harness/emission.js";import{upsertProxyInputRequests}from"#harness/proxy-input-requests.js";import{setChannelContext}from"#execution/channel-context.js";import{coalesceTurnInputs}from"#harness/messages.js";import{dispatchStreamEventHooks}from"#context/hook-lifecycle.js";import{dispatchDynamicInstructionEvent}from"#context/dynamic-instruction-lifecycle.js";import{dispatchDynamicSkillEvent}from"#context/dynamic-skill-lifecycle.js";import{dispatchDynamicToolEvent}from"#context/dynamic-tool-lifecycle.js";import{runStep,withContextScope}from"#context/run-step.js";import{hasPendingInputBatch}from"#harness/input-requests.js";import{getRuntimeActionRequestKey}from"#runtime/actions/keys.js";import{CallbackBaseUrlKey,PendingAuthorizationResultKey,getPendingAuthorization}from"#harness/authorization.js";import{createExecutionNodeStep}from"#execution/node-step.js";import{emitProxiedInputRequest,routeDeliverPayload}from"#execution/subagent-hitl-proxy.js";import{turnWorkflow}from"#execution/turn-workflow.js";async function turnStep(e){"use step";await setAshAttributes(buildTurnAttributes({parentSessionId:e.sessionState.sessionId,rootSessionId:readRootSessionId(e.serializedContext)??e.sessionState.sessionId}));let t=await readDurableSession(e.sessionState),o=await deserializeContext(e.serializedContext),l=o.require(ChannelKey),f=o.require(BundleKey),p=hydrateDurableSession({compactionOverrides:{thresholdPercent:f.resolvedAgent.config.compaction?.thresholdPercent},durable:t,turnAgent:f.turnAgent});try{let{getWorkflowMetadata:e}=await import(`#compiled/@workflow/core/index.js`),t=e();typeof t.url==`string`&&o.set(CallbackBaseUrlKey,t.url.replace(/\/$/,``))}catch{}let m=getPendingAuthorization(t.state),h;if(m&&e.input?.kind===`deliver`){let t=[],n=[];for(let r of e.input.payloads){let e=r.authorizationCallback;if(e){let n=m.challenges.find(t=>t.name===e.connectionName);n&&t.push({name:n.name,state:n.state,callback:e.request,hookUrl:n.hookUrl})}else n.push(r)}t.length>0&&(o.set(PendingAuthorizationResultKey,t),h=t.map(e=>e.name),e=n.length>0?{...e,input:{...e.input,payloads:n}}:{...e,input:void 0})}e.input?.kind===`deliver`&&e.input.auth!==void 0&&o.set(AuthKey,e.input.auth??null);let g=buildAdapterContext(l,o),_;if(e.input?.kind===`deliver`){let t=[];for(let n of e.input.payloads){let e=l.deliver?await l.deliver(n,g):defaultDeliverResult(n);e!=null&&t.push(e)}_=t.length===0?void 0:t.reduce(coalesceTurnInputs)}else e.input?.kind===`runtime-action-result`&&(_={runtimeActionResults:e.input.results});if(e.input?.kind===`deliver`&&setChannelContext(o,{...l,state:{...g.state}}),e.input?.kind===`deliver`&&_===void 0){let t=reconcileSessionContinuationToken(o,p),n=serializeContext(o),r=t===p?e.sessionState:createDurableSessionState({session:t});return{action:`park`,...derivePendingState(t),serializedContext:n,sessionState:r}}let v=e.parentWritable.getWriter(),y=f.hookRegistry,b=f.resolvedAgent.dynamicInstructionsResolvers??[],x=f.resolvedAgent.dynamicSkillResolvers??[],S=f.resolvedAgent.dynamicToolResolvers??[],emit=async e=>{let t=await callAdapterEventHandler(l,e,g);return setChannelContext(o,{...l,state:{...g.state}}),await v.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(t))),t},handleEvent=async(e,t)=>{let n=await emit(e);await dispatchStreamEventHooks({ctx:o,registry:y,event:n}),await dispatchDynamicToolEvent({ctx:o,resolvers:S,event:n,messages:t??[]}),await dispatchDynamicSkillEvent({ctx:o,resolvers:x,event:n,messages:t??[]}),await dispatchDynamicInstructionEvent({ctx:o,resolvers:b,event:n,messages:t??[]})},C=o.require(ModeKey),w=await runStep(o,p,async e=>{let t=resolveEffectiveOutputSchema({agentOutputSchema:f.turnAgent.outputSchema,input:_,mode:C,session:e});if(h){let e=getHarnessEmissionState(t.state);for(let t of h)await handleEvent(createAuthorizationCompletedEvent({name:t,outcome:`authorized`,sequence:e.sequence,stepIndex:e.stepIndex,turnId:e.turnId}))}let n=o.get(CapabilitiesKey);return(async(e,t)=>{let r=refreshSessionFromTurnAgent({compactionOverrides:{thresholdPercent:f.resolvedAgent.config.compaction?.thresholdPercent},session:e,turnAgent:f.turnAgent});return createExecutionNodeStep({capabilities:n,compiledArtifactsSource:f.compiledArtifactsSource,createRuntime:createWorkflowRuntime,handleEvent,mode:C,node:f.graph.root})(r,t)})(t,_)}),T=reconcileSessionContinuationToken(o,w.session),E=serializeContext(o);w={...w,session:T};let D=createDurableSessionState({session:w.session});return w.next!==null&&typeof w.next==`object`&&`done`in w.next?(await v.close(),{action:`done`,output:w.next.output,isError:w.next.isError,serializedContext:E,sessionState:D}):w.next===null?(v.releaseLock(),{action:`park`,...derivePendingState(w.session),serializedContext:E,sessionState:D}):(v.releaseLock(),{action:`continue`,serializedContext:E,sessionState:D})}function derivePendingState(e){let t=getPendingRuntimeActionBatch(e.state),n=getPendingAuthorization(e.state),r={authorizationNames:n?.challenges.map(e=>e.name),hasPendingAuthorization:n!==void 0,hasPendingInputBatch:hasPendingInputBatch(e.state)};return t===void 0?r:{...r,pendingRuntimeActionKeys:t.actions.map(e=>getRuntimeActionRequestKey(e))}}function reconcileSessionContinuationToken(e,t){let n=e.get(ContinuationTokenKey);return n===void 0||n===t.continuationToken?t:{...t,continuationToken:n}}function resolveEffectiveOutputSchema(e){let{agentOutputSchema:t,input:n,mode:r,session:i}=e;return n?.outputSchema===void 0?r===`task`&&i.outputSchema===void 0&&t!==void 0?{...i,outputSchema:t}:i:{...i,outputSchema:n.outputSchema}}const log=createLogger(`execution.workflow-entry`);async function emitTerminalSessionFailureStep(e){"use step";let r=formatError(e.error),i=typeof r.name==`string`?r.name:`WORKFLOW_EXECUTION_FAILED`,a=typeof r.message==`string`?r.message:String(e.error),o=e.serializedContext[`ash.sessionId`]??``;log.error(`workflow loop threw — emitting terminal session.failed`,{sessionId:o,errorId:typeof r.errorId==`string`?r.errorId:void 0,code:i,message:a,detail:typeof r.detail==`string`?r.detail:void 0});let s=createSessionFailedEvent({code:i,details:r,message:a,sessionId:o});try{let t=await deserializeContext(e.serializedContext),r=t.get(ChannelKey);r!==void 0&&await callAdapterEventHandler(r,s,buildAdapterContext(r,t))}catch(e){log.error(`adapter failed to handle terminal session.failed event`,{errorId:typeof r.errorId==`string`?r.errorId:void 0,sessionId:o,error:e})}try{let t=e.parentWritable.getWriter();try{await t.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(s)))}finally{t.releaseLock()}}catch(e){log.error(`failed to write terminal session.failed event to durable stream`,{errorId:typeof r.errorId==`string`?r.errorId:void 0,sessionId:o,error:e})}}async function runProxyInputRequestStep(e){"use step";let t=await readDurableSession(e.sessionState),r=await deserializeContext(e.serializedContext),i=r.require(ChannelKey),a=buildAdapterContext(i,r),o=r.require(ModeKey),c=r.require(BundleKey),l=hydrateDurableSession({compactionOverrides:{thresholdPercent:c.resolvedAgent.config.compaction?.thresholdPercent},durable:t,turnAgent:c.turnAgent}),u=e.parentWritable.getWriter(),d;try{let emit=async e=>{let t=await callAdapterEventHandler(i,e,a);await u.write(encodeMessageStreamEvent(timestampHandleMessageStreamEvent(t)))};d=await withContextScope(r,l,async t=>{let n=await emitProxiedInputRequest({emit,hookPayload:e.hookPayload,mode:o,session:t});return{result:n.entries,session:n.session}})}finally{u.releaseLock()}return setChannelContext(r,{...i,state:{...a.state}}),{serializedContext:serializeContext(r),sessionState:createDurableSessionState({session:reconcileSessionContinuationToken(r,upsertProxyInputRequests({entries:d.result,forChildContinuationToken:e.hookPayload.childContinuationToken,session:d.session}))})}}async function routeProxiedDeliverStep(e){"use step";let t=await readDurableSession(e.sessionState),n=routeDeliverPayload({payload:e.payload,state:t.state}),{resumeHook:r}=await import(`#compiled/@workflow/core/runtime.js`);for(let t of n.forChildren)await r(t.childContinuationToken,{auth:e.auth,kind:`deliver`,payloads:[t.payload]});return{remainder:n.forSelf}}async function dispatchTurnStep(e){"use step";return{runId:(await startWorkflowPreferLatest(turnWorkflow,[e])).runId}}export{dispatchTurnStep,emitTerminalSessionFailureStep,reconcileSessionContinuationToken,resolveEffectiveOutputSchema,routeProxiedDeliverStep,runProxyInputRequestStep,turnStep};
@@ -1 +1 @@
1
- import{createActionResultEvent,createActionsRequestedEvent,createStepCompletedEvent}from"#protocol/message.js";import{emitStepStarted,normalizeAssistantStepFinishReason}from"#harness/emission.js";import{createRuntimeActionRequestFromToolCall}from"#harness/runtime-actions.js";import{createRuntimeToolResultFromMessagePart,createRuntimeToolResultFromStepResult}from"#harness/action-result-helpers.js";import{extractToolApprovalInputRequests}from"#harness/input-extraction.js";import{applyConversationCacheControl,mergeGatewayAutoCaching}from"#harness/prompt-cache.js";import{mergeGatewayProviderPin}from"#harness/provider-tools.js";function buildStepHooks(e){let t=e.session,n=e.emit,i;return{onStepFinish:async e=>{i(e)},prepareStep:async({messages:i})=>{let a=i;n&&e.emitStepStarted!==!1&&await emitStepStarted(n,e.emissionState,i),e.cachePath.kind===`anthropic-direct`&&e.marker&&(a=applyConversationCacheControl([...i],e.marker));let o={messages:a};if(e.cachePath.kind===`gateway-auto`){let n=mergeGatewayAutoCaching(t.agent.modelReference.providerOptions);e.gatewayPinProvider!==void 0&&(n=mergeGatewayProviderPin(n,e.gatewayPinProvider)),o.providerOptions=n}return o},stepResult:new Promise(e=>{i=e})}}async function emitStepActions(r,o,s,c){let l=new Set([...extractToolApprovalInputRequests({content:s.content??[]}).map(e=>e.action.callId),...s.toolCalls.filter(isInvalidToolCall).map(e=>e.toolCallId)]),isExcluded=(e,t)=>l.has(e)||c.excludedActionToolNames.has(t),u=s.toolCalls.filter(e=>!isExcluded(e.toolCallId,e.toolName)).map(e=>createRuntimeActionRequestFromToolCall({toolCall:e,tools:c.tools}));u.length>0&&await r(createActionsRequestedEvent({actions:u,sequence:o.sequence,stepIndex:o.stepIndex,turnId:o.turnId}));let d=c.inlineActionResultCallIds;for(let t of reconcileToolResults(s))isExcluded(t.callId,t.toolName)||d?.has(t.callId)||await r(createActionResultEvent({result:t,sequence:o.sequence,stepIndex:o.stepIndex,turnId:o.turnId}));await r(createStepCompletedEvent({finishReason:normalizeAssistantStepFinishReason(s.finishReason),sequence:o.sequence,stepIndex:o.stepIndex,turnId:o.turnId,usage:extractStepUsage(s.usage)}))}function isInvalidToolCall(e){return e.invalid===!0}function reconcileToolResults(e){let t=new Map;for(let n of e.toolResults)t.set(n.toolCallId,createRuntimeToolResultFromStepResult(n));for(let n of extractToolResultParts(e.response.messages))t.has(n.toolCallId)||t.set(n.toolCallId,createRuntimeToolResultFromMessagePart(n));return[...t.values()]}function extractToolResultParts(e){let t=[];for(let n of e)if(!(n.role!==`tool`||!Array.isArray(n.content)))for(let e of n.content)e.type===`tool-result`&&t.push(e);return t}function extractStepUsage(e){if(e===void 0)return;let t={};return e.inputTokens!==void 0&&(t.inputTokens=e.inputTokens),e.outputTokens!==void 0&&(t.outputTokens=e.outputTokens),e.inputTokenDetails?.cacheReadTokens!==void 0&&(t.cacheReadTokens=e.inputTokenDetails.cacheReadTokens),e.inputTokenDetails?.cacheWriteTokens!==void 0&&(t.cacheWriteTokens=e.inputTokenDetails.cacheWriteTokens),Object.keys(t).length>0?t:void 0}export{buildStepHooks,emitStepActions,isInvalidToolCall};
1
+ import{createActionResultEvent,createActionsRequestedEvent,createStepCompletedEvent}from"#protocol/message.js";import{createRuntimeActionRequestFromToolCall}from"#harness/runtime-actions.js";import{emitStepStarted,normalizeAssistantStepFinishReason}from"#harness/emission.js";import{createRuntimeToolResultFromMessagePart,createRuntimeToolResultFromStepResult}from"#harness/action-result-helpers.js";import{extractToolApprovalInputRequests}from"#harness/input-extraction.js";import{applyConversationCacheControl,mergeGatewayAutoCaching}from"#harness/prompt-cache.js";import{mergeGatewayProviderPin}from"#harness/provider-tools.js";function buildStepHooks(e){let t=e.session,n=e.emit,r;return{onStepFinish:async e=>{r(e)},prepareStep:async({messages:r})=>{let a=r;n&&e.emitStepStarted!==!1&&await emitStepStarted(n,e.emissionState,r),e.cachePath.kind===`anthropic-direct`&&e.marker&&(a=applyConversationCacheControl([...r],e.marker));let o={messages:a};if(e.cachePath.kind===`gateway-auto`){let n=mergeGatewayAutoCaching(t.agent.modelReference.providerOptions);e.gatewayPinProvider!==void 0&&(n=mergeGatewayProviderPin(n,e.gatewayPinProvider)),o.providerOptions=n}return o},stepResult:new Promise(e=>{r=e})}}async function emitStepActions(i,o,s,c){let l=new Set([...extractToolApprovalInputRequests({content:s.content??[]}).map(e=>e.action.callId),...s.toolCalls.filter(isInvalidToolCall).map(e=>e.toolCallId)]),isExcluded=(e,t)=>l.has(e)||c.excludedActionToolNames.has(t),u=s.toolCalls.filter(e=>!isExcluded(e.toolCallId,e.toolName)).map(e=>createRuntimeActionRequestFromToolCall({toolCall:e,tools:c.tools}));u.length>0&&await i(createActionsRequestedEvent({actions:u,sequence:o.sequence,stepIndex:o.stepIndex,turnId:o.turnId}));let d=c.inlineActionResultCallIds;for(let t of reconcileToolResults(s))isExcluded(t.callId,t.toolName)||d?.has(t.callId)||await i(createActionResultEvent({result:t,sequence:o.sequence,stepIndex:o.stepIndex,turnId:o.turnId}));await i(createStepCompletedEvent({finishReason:normalizeAssistantStepFinishReason(s.finishReason),sequence:o.sequence,stepIndex:o.stepIndex,turnId:o.turnId,usage:extractStepUsage(s.usage)}))}function isInvalidToolCall(e){return e.invalid===!0}function reconcileToolResults(e){let t=new Map;for(let n of e.toolResults)t.set(n.toolCallId,createRuntimeToolResultFromStepResult(n));for(let n of extractToolResultParts(e.response.messages))t.has(n.toolCallId)||t.set(n.toolCallId,createRuntimeToolResultFromMessagePart(n));return[...t.values()]}function extractToolResultParts(e){let t=[];for(let n of e)if(!(n.role!==`tool`||!Array.isArray(n.content)))for(let e of n.content)e.type===`tool-result`&&t.push(e);return t}function extractStepUsage(e){if(e===void 0)return;let t={};return e.inputTokens!==void 0&&(t.inputTokens=e.inputTokens),e.outputTokens!==void 0&&(t.outputTokens=e.outputTokens),e.inputTokenDetails?.cacheReadTokens!==void 0&&(t.cacheReadTokens=e.inputTokenDetails.cacheReadTokens),e.inputTokenDetails?.cacheWriteTokens!==void 0&&(t.cacheWriteTokens=e.inputTokenDetails.cacheWriteTokens),Object.keys(t).length>0?t:void 0}export{buildStepHooks,emitStepActions,isInvalidToolCall};
@@ -1 +1 @@
1
- import{createErrorId,createLogger,formatError,logError,recordErrorOnSpan}from"#internal/logging.js";import{createAuthorizationRequiredEvent,createCompactionCompletedEvent,createCompactionRequestedEvent,createInputRequestedEvent,createResultCompletedEvent}from"#protocol/message.js";import{toErrorMessage}from"#shared/errors.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{contextStorage}from"#context/container.js";import{ToolLoopAgent,isStepCount}from"ai";import{advanceStep,emitFailedStep,emitRecoverableFailedTurn,emitStepStarted,emitStreamContent,emitTurnEpilogue,emitTurnPreamble,getHarnessEmissionState,setHarnessEmissionState}from"#harness/emission.js";import{setAshAttributes}from"#runtime/attributes/emit.js";import{createRuntimeActionRequestFromToolCall,resolvePendingRuntimeActions,setPendingRuntimeActionBatch}from"#harness/runtime-actions.js";import{CODE_MODE_TOOL_NAME,loadCodeModeModule}from"#shared/code-mode.js";import{resolveAssistantStepText}from"#harness/messages.js";import{buildDynamicInstructionMessages}from"#context/dynamic-instruction-lifecycle.js";import{PendingSkillAnnouncementKey}from"#context/dynamic-skill-lifecycle.js";import{consumeDeferredStepInput,getApprovedTools,hasDeferredStepInput,hasStepInput,resolvePendingInput,setPendingInputBatch}from"#harness/input-requests.js";import{isAuthorizationSignal,setPendingAuthorization}from"#harness/authorization.js";import{isCodeModeConnectionAuthInterrupt}from"#runtime/framework-tools/code-mode-connection-auth.js";import{buildDynamicTools}from"#context/build-dynamic-tools.js";import{buildToolSetWithProviderTools}from"#harness/tools.js";import{ASK_QUESTION_TOOL_NAME}from"#runtime/framework-tools/ask-question.js";import{WEB_SEARCH_TOOL_DEFINITION}from"#runtime/framework-tools/web-search.js";import{extractQuestionInputRequests,extractToolApprovalInputRequests}from"#harness/input-extraction.js";import{applyLastToolCacheBreakpoint,applySystemCacheBreakpoint,detectPromptCachePath,getAnthropicCacheMarker}from"#harness/prompt-cache.js";import{resolveFrameworkToolFromUpstreamType,resolveGatewayPinForWebSearchBackend,resolveWebSearchBackend}from"#harness/provider-tools.js";import{context,trace}from"#compiled/@opentelemetry/api/index.js";import{hydrateSandboxAttachments,stageAttachmentsToSandbox}from"#harness/attachment-staging.js";import{applyCodeModeToToolSet,buildCodeModeHostTools,createAshCodeModeOptions}from"#harness/code-mode.js";import{createCodeModeLifecycle}from"#harness/code-mode-lifecycle.js";import{clearPendingCodeModeApproval,getPendingCodeModeApproval,replaceCodeModeApprovalInterruptResult,setPendingCodeModeApproval}from"#harness/code-mode-approval.js";import{compactMessages,getInputTokenCount,resolveCompactionModel,shouldCompact}from"#harness/compaction.js";import{accumulateTurnUsage,getTurnUsageState,setTurnUsageState}from"#harness/turn-tag-state.js";import{buildTelemetryRuntimeContext}from"#harness/instrumentation-metadata.js";import{getInstrumentationConfig}from"#harness/instrumentation-config.js";import{clearPendingCodeModeConnectionAuth,getPendingCodeModeConnectionAuth,setPendingCodeModeConnectionAuth}from"#harness/code-mode-connection-auth-state.js";import{classifyModelCallError,extractModelCallErrorDetails,extractUnsupportedProviderToolTypes,summarizeKnownModelCallConfigError,summarizeKnownModelCallRequestError}from"#harness/model-call-error.js";import{ensureOtelIntegration}from"#harness/otel-integration.js";import{buildStepHooks,emitStepActions,isInvalidToolCall}from"#harness/step-hooks.js";import{pruneToolResults}from"#harness/tool-result-pruning.js";import{FINAL_OUTPUT_TOOL_NAME,buildFinalOutputTool}from"#runtime/framework-tools/final-output.js";const environment=process.env.NODE_ENV??`unknown`,ashVersion=resolveInstalledPackageInfo().version,log=createLogger(`harness.tool-loop`);function logToolExecutionError(e){e.toolOutput.type===`tool-error`&&logError(log,`tool execution failed`,e.toolOutput.error,{toolName:e.toolCall.toolName,toolCallId:e.toolCall.toolCallId})}function enrichTelemetry(e,t,n){if(e===void 0)return;let r={};for(let e of Object.keys(n??{}))r[e]=!0;return{functionId:e.functionId??t,includeRuntimeContext:r,isEnabled:!0,recordInputs:e.recordInputs??!0,recordOutputs:e.recordOutputs??!0}}function resolveGatewayPinForStep(e){if(e.cachePath.kind!==`gateway-auto`||e.tools[WEB_SEARCH_TOOL_DEFINITION.name]===void 0)return;let t=resolveWebSearchBackend(e.modelReference);return t===null?void 0:resolveGatewayPinForWebSearchBackend(t)??void 0}function buildGatewayAttributionHeaders(e,t){if(typeof e!=`string`)return;let n=t?.agentName??t?.agentId,r=process.env.VERCEL_PROJECT_PRODUCTION_URL||process.env.VERCEL_URL,i=r?`https://${r}`:void 0;if(!n&&!i)return;let a={};return n&&(a[`x-title`]=n),i&&(a[`http-referer`]=i),a}const TURN_TRACE_STATE_KEY=`ash.harness.turnTrace`;function getTurnTraceState(e){return e.state?.[TURN_TRACE_STATE_KEY]}function setTurnTraceState(e,t){let n={traceId:t.traceId,spanId:t.spanId,traceFlags:t.traceFlags};return{...e,state:{...e.state,[TURN_TRACE_STATE_KEY]:n}}}function resolveStepOtelContext(e,t,n){if(t)return trace.setSpan(context.active(),t);if(e){let e=getTurnTraceState(n);if(e){let t=trace.wrapSpanContext({traceId:e.traceId,spanId:e.spanId,traceFlags:e.traceFlags});return trace.setSpan(context.active(),t)}}}function createToolLoopHarness(t){let n=t.handleEvent,a=getInstrumentationConfig();a!==void 0&&ensureOtelIntegration();let o=a===void 0?void 0:trace.getTracer(`ash`),s=t.runtimeIdentity?.agentName;async function runStep(e,t){let n;if(o&&hasStepInput(t)){let t=a?.functionId??s,r={"ash.version":ashVersion,"ash.environment":environment,"ash.session.id":e.sessionId};t&&(r[`ai.telemetry.functionId`]=t),n=o.startSpan(`ai.ash.turn`,{attributes:r})}let r=resolveStepOtelContext(o,n,e),executeStep=()=>executeStepBody(e,t,n);try{return r?await context.with(r,executeStep):await executeStep()}finally{n?.end()}}async function executeStepBody(o,c,l){let d=o;l&&(d=setTurnTraceState(d,l.spanContext()));let g=getHarnessEmissionState(d.state),x=consumeDeferredStepInput({input:c,session:d});d=x.session;let T=await resolvePendingRuntimeActions({emit:n,session:d,stepInput:x.input});if(T.outcome===`unresolved`)return{next:null,session:T.session};d=T.session;let D=resolvePendingInput({history:T.messages,resolveApprovalKey:resolveApprovalKeyFromTools(t.tools),session:d,stepInput:x.input});if(D.outcome===`unresolved`)return{next:null,session:D.session};n&&hasStepInput(c)&&(g=await emitTurnPreamble(n,c??{},g,t.runtimeIdentity),d=setHarnessEmissionState(d,g),l&&l.setAttribute(`ash.turn.id`,g.turnId)),d=D.session;let O=D.messages;if(x.input?.context!==void 0)for(let e of x.input.context)O.push({content:e,role:`user`});if(x.input?.message!==void 0&&!D.deferredMessage){let e=await stageAttachmentsToSandbox(x.input.message);O.push({content:e,role:`user`})}let k=await t.resolveModel(d.agent.modelReference),A=detectPromptCachePath(k),j=A.kind===`anthropic-direct`?getAnthropicCacheMarker():void 0,M=buildGatewayAttributionHeaders(k,t.runtimeIdentity);({messages:O,session:d}=await maybeCompact({emit:n,emissionState:g,headers:M,messages:O,model:k,onCompaction:t.onCompaction,resolveModel:t.resolveModel,session:d,telemetry:enrichTelemetry(a,s)??void 0}));let N=getApprovedTools(d),P=contextStorage.getStore(),F=await hydrateSandboxAttachments(O),I=[],L=[];for(let e of F)e.role===`system`?I.push(e):L.push(e);if(P!==void 0){I.push(...buildDynamicInstructionMessages(P));let e=P.get(PendingSkillAnnouncementKey);e!==void 0&&e.length>0&&I.push({role:`system`,content:e})}let R=L,prepareModelCallInput=e=>{let t=e?[{role:`system`,content:e}]:[],n=d.agent.system?[{role:`system`,content:d.agent.system}]:[],r=I.length>0||t.length>0?[...t,...n,...I]:void 0,i=r!==void 0&&j?applySystemCacheBreakpoint(r,j):r??d.agent.system??void 0;return{instructions:i,telemetryRuntimeContext:buildTelemetryRuntimeContext({ashVersion,authored:a,emissionState:g,environment,modelInput:{instructions:i,messages:R},session:d})}},runOneModelCall=async e=>{let{instructions:i,telemetryRuntimeContext:o}=e.preparedInput??prepareModelCallInput(e.extraSystemNote),c=t.codeMode===!0,l=await buildToolSetWithProviderTools({approvedTools:N,capabilities:t.capabilities,disabledProviderTools:e.disabledProviderTools,modelReference:d.agent.modelReference,tools:t.tools});if(P!==void 0){let e=buildDynamicTools(P);for(let t of e)l[t.name]??={description:t.description,inputSchema:t.inputSchema,execute:t.execute}}d.outputSchema!==void 0&&(l[FINAL_OUTPUT_TOOL_NAME]=buildFinalOutputTool(d.outputSchema));let u=c?(await applyCodeModeToToolSet({harnessTools:t.tools,lifecycle:n===void 0?void 0:createCodeModeLifecycle({emit:n,emissionState:g,tools:t.tools}),tools:l})).modelTools:l,f=j?applyLastToolCacheBreakpoint(u,j):u,p=resolveGatewayPinForStep({cachePath:A,modelReference:d.agent.modelReference,tools:f}),_=buildStepHooks({cachePath:A,emit:n,emissionState:g,emitStepStarted:e.suppressStepStartedEmission!==!0,gatewayPinProvider:p,marker:j,session:d}),v=new ToolLoopAgent({headers:M,instructions:i,model:k,onToolExecutionEnd:logToolExecutionError,onError(e){logError(log,`tool-loop stream error`,e.error)},onStepFinish:_.onStepFinish,prepareStep:_.prepareStep,runtimeContext:o,stopWhen:isStepCount(1),telemetry:enrichTelemetry(a,s,o),tools:f});return runModelCallWithRetries(async()=>{if(n){let e=await v.stream({messages:R}),{inlineActionResultCallIds:r,inlineToolResultParts:i}=await emitStreamContent(n,g,e.fullStream),a=await _.stepResult;return await emitStepActions(n,g,a,{excludedActionToolNames:new Set([ASK_QUESTION_TOOL_NAME,CODE_MODE_TOOL_NAME,FINAL_OUTPUT_TOOL_NAME]),inlineActionResultCallIds:r,tools:t.tools}),i.length>0?{content:a.content,finishReason:a.finishReason,response:{...a.response,messages:[{role:`tool`,content:[...i]},...a.response.messages]},text:a.text,toolCalls:a.toolCalls,toolResults:a.toolResults,usage:a.usage}:a}return await v.generate({messages:R}),await _.stepResult},{sessionId:d.sessionId,turnId:g.turnId})},z=prepareModelCallInput();n&&await emitStepStarted(n,g,O);let B=await continuePendingCodeModeConnectionAuth({capabilities:t.capabilities,config:t,emit:n,emissionState:g,messages:O,runStep,session:d});if(B!==null)return B;let V=await continuePendingCodeModeApproval({capabilities:t.capabilities,config:t,emit:n,emissionState:g,messages:O,runStep,session:d});if(V!==null)return V;let H;try{H=await runOneModelCall({preparedInput:z,suppressStepStartedEmission:!0})}catch(t){let r=await attemptUnsupportedProviderToolRecovery({error:t,runOneModelCall,sessionId:d.sessionId,turnId:g.turnId});if(r.outcome===`recovered`)H=r.result;else{let t=r.error;if(l&&recordErrorOnSpan(l,t),!n)throw t;let a=classifyModelCallError(t),o=createErrorId(),s=a===`terminal`?summarizeKnownModelCallConfigError(t):null,c=s===null?summarizeKnownModelCallRequestError(t):null,f=s?.message??c?.message??toErrorMessage(t),p=extractModelCallErrorDetails(t),m=buildModelCallFailureDetails({configSummary:s,error:t,errorId:o,modelCallDetails:p,requestSummary:c}),h=buildModelCallFailureLogFields({error:t,errorId:o,modelCallDetails:p,requestSummary:c,sessionId:d.sessionId,turnId:g.turnId});return a===`terminal`?(s===null?log.error(c?.message??`model call failed terminally`,h):log.error(`${s.name}: ${s.message}`,{errorId:o,sessionId:d.sessionId,turnId:g.turnId}),await emitFailedStep(n,g,{code:`MODEL_CALL_FAILED`,details:m,message:f,sessionId:d.sessionId}),{next:{done:!0,output:``},session:d}):(log.error(c?.message??`model call failed — parking session for retry by the user`,h),g=await emitRecoverableFailedTurn(n,g,{code:`MODEL_CALL_FAILED`,details:m,message:f}),{next:null,session:setHarnessEmissionState(d,g)})}}let U=accumulateTurnUsage({previous:getTurnUsageState(d.state),turnId:g.turnId,usage:H.usage??{}});d=setTurnUsageState(d,U);let W;try{W=formatLanguageModelGatewayId(k)}catch{W=void 0}return await setAshAttributes({"$ash.model":W,"$ash.input_tokens":U.inputTokens,"$ash.output_tokens":U.outputTokens,"$ash.cache_read_tokens":U.cacheReadTokens,"$ash.tool_count":t.tools.size}),handleStepResult({config:t,emit:n,emissionState:g,promptMessages:O,result:H,runStep,session:d})}return runStep}function buildModelCallFailureDetails(e){let{configSummary:t,error:r,errorId:i,modelCallDetails:a,requestSummary:o}=e;return t===null?o===null?{...formatError(r,i),...a}:{errorId:i,message:toErrorMessage(r),name:o.name,...a}:{errorId:i,message:t.message,name:t.name,...a}}function buildModelCallFailureLogFields(e){let t={errorId:e.errorId,sessionId:e.sessionId,turnId:e.turnId};return e.requestSummary===null?{...t,error:e.error}:{...t,details:e.modelCallDetails}}async function attemptUnsupportedProviderToolRecovery(e){let t=extractUnsupportedProviderToolTypes(e.error);if(t.length===0)return{outcome:`failed`,error:e.error};let n=[];for(let e of t){let t=resolveFrameworkToolFromUpstreamType(e);t!==null&&!n.includes(t)&&n.push(t)}if(n.length===0)return{outcome:`failed`,error:e.error};log.warn(`disabling unsupported provider tool(s); retrying step once`,{disabled:n,sessionId:e.sessionId,turnId:e.turnId,upstreamTypes:t});try{return{outcome:`recovered`,result:await e.runOneModelCall({disabledProviderTools:new Set(n),extraSystemNote:buildDisabledToolNote(n),suppressStepStartedEmission:!0})}}catch(e){return{outcome:`failed`,error:e}}}function buildDisabledToolNote(e){let t=e.join(`, `);return`The following ${e.length===1?`tool is`:`tools are`} not available with the current model and has been removed: ${t}. Proceed using the remaining tools or your training knowledge.`}async function handleStepResult(e){let{config:t,emit:n,promptMessages:r,result:i,runStep:o}=e,{emissionState:s,session:l}=e,u=i.response.messages,d=resolveAssistantStepText(u,i.text),f={...l,compaction:createNextCompactionConfig(l.compaction,r,i)};if(t.codeMode===!0){let{getCodeModeInterrupt:e,isCodeModeApprovalInterrupt:a}=await loadCodeModeModule(),o=e(i);if(o!==void 0){if(isCodeModeConnectionAuthInterrupt(o))return parkOnCodeModeConnectionAuth({baseSession:f,config:t,emit:n,emissionState:s,interrupt:o,promptMessages:r,responseMessages:u});if(a(o))return parkOnCodeModeApproval({baseSession:f,config:t,emit:n,emissionState:s,interrupt:o,promptMessages:r,responseMessages:u})}}let p=extractToolApprovalInputRequests({content:i.content??[]}),m=new Set(p.map(e=>e.action.callId)),h=extractQuestionInputRequests({toolCalls:i.toolCalls,excludedCallIds:m}),_=[...p,...h],v=(i.toolCalls??[]).filter(e=>!isInvalidToolCall(e)).filter(e=>t.tools.get(e.toolName)?.runtimeAction!==void 0).map(e=>createRuntimeActionRequestFromToolCall({toolCall:e,tools:t.tools}));if(v.length>0)return{next:null,session:setHarnessEmissionState(setPendingRuntimeActionBatch({actions:v,event:{sequence:s.sequence,stepIndex:s.stepIndex,turnId:s.turnId},responseMessages:u,session:{...f,history:[...r]}}),s)};if(_.length>0){let e=setPendingInputBatch({requests:_,responseMessages:u,session:{...f,history:[...r]}});return n&&(await n(createInputRequestedEvent({requests:_,sequence:s.sequence,stepIndex:s.stepIndex,turnId:s.turnId})),t.mode===`conversation`&&(s=await emitTurnEpilogue(n,s,t.mode),e=setHarnessEmissionState(e,s))),{next:null,session:e}}let y=(i.toolResults??[]).find(e=>isAuthorizationSignal(e.output));if(y&&isAuthorizationSignal(y.output)){let{challenges:e}=y.output;if(n)for(let t of e)await n(createAuthorizationRequiredEvent({authorization:t.challenge,name:t.name,description:t.challenge.instructions??`Authorization required for ${t.name}`,webhookUrl:t.hookUrl,sequence:s.sequence,stepIndex:s.stepIndex,turnId:s.turnId}));return{next:null,session:setHarnessEmissionState({...f,history:[...r],state:setPendingAuthorization(f.state,{challenges:e})},s)}}let b=pruneToolResults(r,t.retentionPolicies),S=b!==r,C=f.compaction;S&&C.lastKnownInputTokens!==void 0&&(C={recentWindowSize:C.recentWindowSize,threshold:C.threshold});let w=[...b,...u],E={...f,compaction:C,history:w};return!(E.outputSchema!==void 0&&extractFinalOutput(i)!==void 0)&&(u.at(-1)?.role===`tool`||hasDeferredStepInput(E))?(n&&(s=advanceStep(s),E=setHarnessEmissionState(E,s)),{next:o,session:E}):t.mode===`task`?finishTaskTurn({emissionState:s,emit:n,prunedHistory:b,result:i,schema:E.outputSchema,session:E,stepOutput:d}):finishConversationTurn({emissionState:s,emit:n,prunedHistory:b,result:i,schema:E.outputSchema,session:E})}const OUTPUT_SCHEMA_NOT_FULFILLED={code:`OUTPUT_SCHEMA_NOT_FULFILLED`,message:`The agent could not produce a result matching the requested schema.`};function extractFinalOutput(e){return(e.toolCalls??[]).find(e=>e.toolName===FINAL_OUTPUT_TOOL_NAME)?.input}function persistStructuredAssistantTurn(e,t,n){return{...e,history:[...t,{content:JSON.stringify(n),role:`assistant`}],outputSchema:void 0}}async function emitStructuredResult(e,t,n,r){return await e(createResultCompletedEvent({result:n,sequence:t.sequence,stepIndex:t.stepIndex,turnId:t.turnId})),emitTurnEpilogue(e,t,r)}async function finishTaskTurn(e){let{emit:t,prunedHistory:n,result:r,schema:i,stepOutput:a}=e,{emissionState:o,session:s}=e;if(i===void 0)return t&&(o=await emitTurnEpilogue(t,o,`task`),s=setHarnessEmissionState(s,o)),{next:{done:!0,output:a??``},session:s};let c=extractFinalOutput(r);return c===void 0?(t&&await emitFailedStep(t,o,{...OUTPUT_SCHEMA_NOT_FULFILLED,sessionId:s.sessionId}),{next:{done:!0,isError:!0,output:OUTPUT_SCHEMA_NOT_FULFILLED.message},session:s}):(s=persistStructuredAssistantTurn(s,n,c),t&&(o=await emitStructuredResult(t,o,c,`task`),s=setHarnessEmissionState(s,o)),{next:{done:!0,output:JSON.stringify(c)},session:s})}async function finishConversationTurn(e){let{emit:t,prunedHistory:n,result:r,schema:i}=e,{emissionState:a,session:o}=e;if(i===void 0)return t&&(a=await emitTurnEpilogue(t,a,`conversation`),o=setHarnessEmissionState(o,a)),{next:null,session:o};let s=extractFinalOutput(r);return s===void 0?(t&&(a=await emitRecoverableFailedTurn(t,a,OUTPUT_SCHEMA_NOT_FULFILLED),o=setHarnessEmissionState(o,a)),{next:null,session:o}):(o=persistStructuredAssistantTurn(o,n,s),t&&(a=await emitStructuredResult(t,a,s,`conversation`),o=setHarnessEmissionState(o,a)),{next:null,session:o})}async function continuePendingCodeModeApproval(e){let t=getPendingCodeModeApproval(e.session.state);if(t===void 0)return null;let{continueCodeModeApproval:n,getCodeModeApprovalResponse:i,isCodeModeApprovalInterrupt:a,unwrapCodeModeResult:o}=await loadCodeModeModule(),s=i([...e.messages],t.interrupt);if(s===void 0)return{next:null,session:e.session};let c=await buildCodeModeHostTools({approvedTools:getApprovedTools(e.session),capabilities:e.capabilities,tools:e.config.tools}),l;try{l=await n({approvalResponse:s,interrupt:t.interrupt,options:createAshCodeModeOptions({lifecycle:e.emit===void 0?void 0:createCodeModeLifecycle({emit:e.emit,emissionState:e.emissionState,skipReplayed:!0,tools:e.config.tools})}),tools:c})}catch(e){logError(log,`code-mode approval continuation failed`,e),l={error:`code_mode_continuation_failed`,message:toErrorMessage(e),retryable:!1}}let d=o(l),f=d.status===`interrupted`?d.interrupt:d.output,p=replaceCodeModeApprovalInterruptResult([...e.session.history,...t.responseMessages],t.interrupt,f),m=clearPendingCodeModeApproval({...e.session,history:p});if(d.status===`interrupted`){if(isCodeModeConnectionAuthInterrupt(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeConnectionAuth({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}if(a(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeApproval({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}}return{next:e.runStep,session:m}}async function parkOnCodeModeConnectionAuth(e){let t=[...e.interrupt.payload.challenges??[]];if(e.emit)for(let n of t)await e.emit(createAuthorizationRequiredEvent({authorization:n.challenge,name:n.name,description:n.challenge.instructions??`Authorization required for ${n.name}`,webhookUrl:n.hookUrl,sequence:e.emissionState.sequence,stepIndex:e.emissionState.stepIndex,turnId:e.emissionState.turnId}));return{next:null,session:setPendingCodeModeConnectionAuth({interrupt:e.interrupt,responseMessages:e.responseMessages,session:{...e.baseSession,history:[...e.promptMessages],state:setPendingAuthorization(e.baseSession.state,{challenges:t})}})}}async function continuePendingCodeModeConnectionAuth(e){let t=getPendingCodeModeConnectionAuth(e.session.state);if(t===void 0)return null;let{continueCodeModeInterrupt:n,isCodeModeApprovalInterrupt:i,replaceCodeModeInterruptResult:a,unwrapCodeModeResult:o}=await loadCodeModeModule(),s=await buildCodeModeHostTools({approvedTools:getApprovedTools(e.session),capabilities:e.capabilities,tools:e.config.tools}),c=e.emit===void 0?void 0:createCodeModeLifecycle({emit:e.emit,emissionState:e.emissionState,skipReplayed:!0,tools:e.config.tools}),l;try{l=await n({interrupt:t.interrupt,resolution:{status:`authorized`},tools:s,options:createAshCodeModeOptions({lifecycle:c})})}catch(e){logError(log,`code-mode interrupt continuation failed`,e),l={error:`code_mode_continuation_failed`,message:toErrorMessage(e),retryable:!1}}let d=o(l),f=d.status===`interrupted`?d.interrupt:d.output,p=a([...e.session.history,...t.responseMessages],t.interrupt.pendingContinuation,f),m=clearPendingCodeModeConnectionAuth({...e.session,history:p});if(d.status===`interrupted`){if(isCodeModeConnectionAuthInterrupt(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeConnectionAuth({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}if(i(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeApproval({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}}return{next:e.runStep,session:m}}async function parkOnCodeModeApproval(e){let{toCodeModeApprovalMessages:t}=await loadCodeModeModule(),n=t(e.interrupt),r=extractToolApprovalInputRequests({content:extractAssistantContent(n)}),i=setPendingInputBatch({requests:r,responseMessages:n,session:setPendingCodeModeApproval({interrupt:e.interrupt,responseMessages:e.responseMessages,session:{...e.baseSession,history:[...e.promptMessages]}})});if(e.emit&&(await e.emit(createInputRequestedEvent({requests:r,sequence:e.emissionState.sequence,stepIndex:e.emissionState.stepIndex,turnId:e.emissionState.turnId})),e.config.mode===`conversation`)){let t=await emitTurnEpilogue(e.emit,e.emissionState,e.config.mode);i=setHarnessEmissionState(i,t)}return{next:null,session:i}}function extractAssistantContent(e){let t=[];for(let n of e)n.role===`assistant`&&Array.isArray(n.content)&&t.push(...n.content);return t}function createNextCompactionConfig(e,t,n){let r={recentWindowSize:e.recentWindowSize,threshold:e.threshold};return n.usage?.inputTokens!==void 0&&(r.lastKnownInputTokens=n.usage.inputTokens,r.lastKnownPromptMessageCount=t.length),r}async function maybeCompact(e){let{emit:t,emissionState:n}=e,r=e.messages,i=e.session;if(!shouldCompact(r,i.compaction))return{messages:r,session:i};let a=await resolveCompactionModel({compactionModelReference:i.agent.compactionModelReference,model:e.model,modelReference:i.agent.modelReference,resolveModel:e.resolveModel});if(t&&await t(createCompactionRequestedEvent({modelId:formatLanguageModelGatewayId(a.model),sequence:n.sequence,sessionId:i.sessionId,turnId:n.turnId,usageInputTokens:getInputTokenCount(r,i.compaction)})),r=await compactMessages(r,a.model,i.compaction,a.providerOptions,e.telemetry,e.headers),e.onCompaction){let t=await e.onCompaction(i);i=t.session;for(let e of t.messages)r.push(e)}return t&&await t(createCompactionCompletedEvent({modelId:formatLanguageModelGatewayId(a.model),sequence:n.sequence,sessionId:i.sessionId,turnId:n.turnId})),{messages:r,session:i}}function resolveApprovalKeyFromTools(e){return t=>{let n=e.get(t.action.toolName);if(n?.approvalKey!==void 0)return n.approvalKey(t.action.input)}}async function runModelCallWithRetries(e,t){for(let n=1;;n++)try{return await e()}catch(e){if(n===3||classifyModelCallError(e)!==`retry`)throw e;let r=500*2**(n-1)+Math.floor(Math.random()*250);log.warn(`model call failed transiently — retrying`,{attempt:n,delayMs:r,sessionId:t.sessionId,turnId:t.turnId,error:e}),await new Promise(e=>setTimeout(e,r))}}export{createToolLoopHarness};
1
+ import{createErrorId,createLogger,formatError,logError,recordErrorOnSpan}from"#internal/logging.js";import{createAuthorizationRequiredEvent,createCompactionCompletedEvent,createCompactionRequestedEvent,createInputRequestedEvent,createResultCompletedEvent}from"#protocol/message.js";import{toErrorMessage}from"#shared/errors.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{formatLanguageModelGatewayId}from"#internal/runtime-model.js";import{contextStorage}from"#context/container.js";import{ToolLoopAgent,isStepCount}from"ai";import{setAshAttributes}from"#runtime/attributes/emit.js";import{createRuntimeActionRequestFromToolCall,resolvePendingRuntimeActions,setPendingRuntimeActionBatch}from"#harness/runtime-actions.js";import{advanceStep,emitFailedStep,emitRecoverableFailedTurn,emitStepStarted,emitStreamContent,emitTurnEpilogue,emitTurnPreamble,getHarnessEmissionState,setHarnessEmissionState}from"#harness/emission.js";import{CODE_MODE_TOOL_NAME,loadCodeModeModule}from"#shared/code-mode.js";import{resolveAssistantStepText}from"#harness/messages.js";import{buildDynamicInstructionMessages}from"#context/dynamic-instruction-lifecycle.js";import{PendingSkillAnnouncementKey}from"#context/dynamic-skill-lifecycle.js";import{consumeDeferredStepInput,getApprovedTools,hasDeferredStepInput,hasStepInput,resolvePendingInput,setPendingInputBatch}from"#harness/input-requests.js";import{isAuthorizationSignal,setPendingAuthorization}from"#harness/authorization.js";import{isCodeModeConnectionAuthInterrupt}from"#runtime/framework-tools/code-mode-connection-auth.js";import{buildDynamicTools}from"#context/build-dynamic-tools.js";import{buildToolSetWithProviderTools}from"#harness/tools.js";import{ASK_QUESTION_TOOL_NAME}from"#runtime/framework-tools/ask-question.js";import{WEB_SEARCH_TOOL_DEFINITION}from"#runtime/framework-tools/web-search.js";import{extractQuestionInputRequests,extractToolApprovalInputRequests}from"#harness/input-extraction.js";import{applyLastToolCacheBreakpoint,applySystemCacheBreakpoint,detectPromptCachePath,getAnthropicCacheMarker}from"#harness/prompt-cache.js";import{resolveFrameworkToolFromUpstreamType,resolveGatewayPinForWebSearchBackend,resolveWebSearchBackend}from"#harness/provider-tools.js";import{context,trace}from"#compiled/@opentelemetry/api/index.js";import{hydrateSandboxAttachments,stageAttachmentsToSandbox}from"#harness/attachment-staging.js";import{applyCodeModeToToolSet,buildCodeModeHostTools,createAshCodeModeOptions}from"#harness/code-mode.js";import{createCodeModeLifecycle}from"#harness/code-mode-lifecycle.js";import{clearPendingCodeModeApproval,getPendingCodeModeApproval,replaceCodeModeApprovalInterruptResult,setPendingCodeModeApproval}from"#harness/code-mode-approval.js";import{compactMessages,getInputTokenCount,resolveCompactionModel,shouldCompact}from"#harness/compaction.js";import{accumulateTurnUsage,getTurnUsageState,setTurnUsageState}from"#harness/turn-tag-state.js";import{buildTelemetryRuntimeContext}from"#harness/instrumentation-metadata.js";import{getInstrumentationConfig}from"#harness/instrumentation-config.js";import{clearPendingCodeModeConnectionAuth,getPendingCodeModeConnectionAuth,setPendingCodeModeConnectionAuth}from"#harness/code-mode-connection-auth-state.js";import{classifyModelCallError,extractModelCallErrorDetails,extractUnsupportedProviderToolTypes,summarizeKnownModelCallConfigError,summarizeKnownModelCallRequestError}from"#harness/model-call-error.js";import{ensureOtelIntegration}from"#harness/otel-integration.js";import{buildStepHooks,emitStepActions,isInvalidToolCall}from"#harness/step-hooks.js";import{pruneToolResults}from"#harness/tool-result-pruning.js";import{FINAL_OUTPUT_TOOL_NAME,buildFinalOutputTool}from"#runtime/framework-tools/final-output.js";const environment=process.env.NODE_ENV??`unknown`,ashVersion=resolveInstalledPackageInfo().version,log=createLogger(`harness.tool-loop`);function logToolExecutionError(e){e.toolOutput.type===`tool-error`&&logError(log,`tool execution failed`,e.toolOutput.error,{toolName:e.toolCall.toolName,toolCallId:e.toolCall.toolCallId})}function enrichTelemetry(e,t,n){if(e===void 0)return;let r={};for(let e of Object.keys(n??{}))r[e]=!0;return{functionId:e.functionId??t,includeRuntimeContext:r,isEnabled:!0,recordInputs:e.recordInputs??!0,recordOutputs:e.recordOutputs??!0}}function resolveGatewayPinForStep(e){if(e.cachePath.kind!==`gateway-auto`||e.tools[WEB_SEARCH_TOOL_DEFINITION.name]===void 0)return;let t=resolveWebSearchBackend(e.modelReference);return t===null?void 0:resolveGatewayPinForWebSearchBackend(t)??void 0}function buildGatewayAttributionHeaders(e,t){if(typeof e!=`string`)return;let n=t?.agentName??t?.agentId,r=process.env.VERCEL_PROJECT_PRODUCTION_URL||process.env.VERCEL_URL,i=r?`https://${r}`:void 0;if(!n&&!i)return;let a={};return n&&(a[`x-title`]=n),i&&(a[`http-referer`]=i),a}const TURN_TRACE_STATE_KEY=`ash.harness.turnTrace`;function getTurnTraceState(e){return e.state?.[TURN_TRACE_STATE_KEY]}function setTurnTraceState(e,t){let n={traceId:t.traceId,spanId:t.spanId,traceFlags:t.traceFlags};return{...e,state:{...e.state,[TURN_TRACE_STATE_KEY]:n}}}function resolveStepOtelContext(e,t,n){if(t)return trace.setSpan(context.active(),t);if(e){let e=getTurnTraceState(n);if(e){let t=trace.wrapSpanContext({traceId:e.traceId,spanId:e.spanId,traceFlags:e.traceFlags});return trace.setSpan(context.active(),t)}}}function createToolLoopHarness(t){let n=t.handleEvent,a=getInstrumentationConfig();a!==void 0&&ensureOtelIntegration();let o=a===void 0?void 0:trace.getTracer(`ash`),s=t.runtimeIdentity?.agentName;async function runStep(e,t){let n;if(o&&hasStepInput(t)){let t=a?.functionId??s,r={"ash.version":ashVersion,"ash.environment":environment,"ash.session.id":e.sessionId};t&&(r[`ai.telemetry.functionId`]=t),n=o.startSpan(`ai.ash.turn`,{attributes:r})}let r=resolveStepOtelContext(o,n,e),executeStep=()=>executeStepBody(e,t,n);try{return r?await context.with(r,executeStep):await executeStep()}finally{n?.end()}}async function executeStepBody(o,c,l){let d=o;l&&(d=setTurnTraceState(d,l.spanContext()));let _=getHarnessEmissionState(d.state),y=consumeDeferredStepInput({input:c,session:d});d=y.session;let b=await resolvePendingRuntimeActions({emit:n,session:d,stepInput:y.input});if(b.outcome===`unresolved`)return{next:null,session:b.session};d=b.session;let T=resolvePendingInput({history:b.messages,resolveApprovalKey:resolveApprovalKeyFromTools(t.tools),session:d,stepInput:y.input});if(T.outcome===`unresolved`)return{next:null,session:T.session};n&&hasStepInput(c)&&(_=await emitTurnPreamble(n,c??{},_,t.runtimeIdentity),d=setHarnessEmissionState(d,_),l&&l.setAttribute(`ash.turn.id`,_.turnId)),d=T.session;let O=T.messages;if(y.input?.context!==void 0)for(let e of y.input.context)O.push({content:e,role:`user`});if(y.input?.message!==void 0&&!T.deferredMessage){let e=await stageAttachmentsToSandbox(y.input.message);O.push({content:e,role:`user`})}let k=await t.resolveModel(d.agent.modelReference),A=detectPromptCachePath(k),j=A.kind===`anthropic-direct`?getAnthropicCacheMarker():void 0,M=buildGatewayAttributionHeaders(k,t.runtimeIdentity);({messages:O,session:d}=await maybeCompact({emit:n,emissionState:_,headers:M,messages:O,model:k,onCompaction:t.onCompaction,resolveModel:t.resolveModel,session:d,telemetry:enrichTelemetry(a,s)??void 0}));let N=getApprovedTools(d),P=contextStorage.getStore(),F=await hydrateSandboxAttachments(O),I=[],L=[];for(let e of F)e.role===`system`?I.push(e):L.push(e);if(P!==void 0){I.push(...buildDynamicInstructionMessages(P));let e=P.get(PendingSkillAnnouncementKey);e!==void 0&&e.length>0&&I.push({role:`system`,content:e})}let R=L,prepareModelCallInput=e=>{let t=e?[{role:`system`,content:e}]:[],n=d.agent.system?[{role:`system`,content:d.agent.system}]:[],r=I.length>0||t.length>0?[...t,...n,...I]:void 0,i=r!==void 0&&j?applySystemCacheBreakpoint(r,j):r??d.agent.system??void 0;return{instructions:i,telemetryRuntimeContext:buildTelemetryRuntimeContext({ashVersion,authored:a,emissionState:_,environment,modelInput:{instructions:i,messages:R},session:d})}},runOneModelCall=async e=>{let{instructions:i,telemetryRuntimeContext:o}=e.preparedInput??prepareModelCallInput(e.extraSystemNote),c=t.codeMode===!0,l=await buildToolSetWithProviderTools({approvedTools:N,capabilities:t.capabilities,disabledProviderTools:e.disabledProviderTools,modelReference:d.agent.modelReference,tools:t.tools});if(P!==void 0){let e=buildDynamicTools(P);for(let t of e)l[t.name]??={description:t.description,inputSchema:t.inputSchema,execute:t.execute}}d.outputSchema!==void 0&&(l[FINAL_OUTPUT_TOOL_NAME]=buildFinalOutputTool(d.outputSchema));let u=c?(await applyCodeModeToToolSet({harnessTools:t.tools,lifecycle:n===void 0?void 0:createCodeModeLifecycle({emit:n,emissionState:_,tools:t.tools}),tools:l})).modelTools:l,f=j?applyLastToolCacheBreakpoint(u,j):u,p=resolveGatewayPinForStep({cachePath:A,modelReference:d.agent.modelReference,tools:f}),g=buildStepHooks({cachePath:A,emit:n,emissionState:_,emitStepStarted:e.suppressStepStartedEmission!==!0,gatewayPinProvider:p,marker:j,session:d}),v=new ToolLoopAgent({headers:M,instructions:i,model:k,onToolExecutionEnd:logToolExecutionError,onError(e){logError(log,`tool-loop stream error`,e.error)},onStepFinish:g.onStepFinish,prepareStep:g.prepareStep,runtimeContext:o,stopWhen:isStepCount(1),telemetry:enrichTelemetry(a,s,o),tools:f});return runModelCallWithRetries(async()=>{if(n){let e=await v.stream({messages:R}),{inlineActionResultCallIds:r,inlineToolResultParts:i}=await emitStreamContent(n,_,e.fullStream),a=await g.stepResult;return await emitStepActions(n,_,a,{excludedActionToolNames:new Set([ASK_QUESTION_TOOL_NAME,CODE_MODE_TOOL_NAME,FINAL_OUTPUT_TOOL_NAME]),inlineActionResultCallIds:r,tools:t.tools}),i.length>0?{content:a.content,finishReason:a.finishReason,response:{...a.response,messages:[{role:`tool`,content:[...i]},...a.response.messages]},text:a.text,toolCalls:a.toolCalls,toolResults:a.toolResults,usage:a.usage}:a}return await v.generate({messages:R}),await g.stepResult},{sessionId:d.sessionId,turnId:_.turnId})},z=prepareModelCallInput();n&&await emitStepStarted(n,_,O);let B=await continuePendingCodeModeConnectionAuth({capabilities:t.capabilities,config:t,emit:n,emissionState:_,messages:O,runStep,session:d});if(B!==null)return B;let V=await continuePendingCodeModeApproval({capabilities:t.capabilities,config:t,emit:n,emissionState:_,messages:O,runStep,session:d});if(V!==null)return V;let H;try{H=await runOneModelCall({preparedInput:z,suppressStepStartedEmission:!0})}catch(t){let r=await attemptUnsupportedProviderToolRecovery({error:t,runOneModelCall,sessionId:d.sessionId,turnId:_.turnId});if(r.outcome===`recovered`)H=r.result;else{let t=r.error;if(l&&recordErrorOnSpan(l,t),!n)throw t;let a=classifyModelCallError(t),o=createErrorId(),s=a===`terminal`?summarizeKnownModelCallConfigError(t):null,c=s===null?summarizeKnownModelCallRequestError(t):null,f=s?.message??c?.message??toErrorMessage(t),p=extractModelCallErrorDetails(t),m=buildModelCallFailureDetails({configSummary:s,error:t,errorId:o,modelCallDetails:p,requestSummary:c}),h=buildModelCallFailureLogFields({error:t,errorId:o,modelCallDetails:p,requestSummary:c,sessionId:d.sessionId,turnId:_.turnId});return a===`terminal`?(s===null?log.error(c?.message??`model call failed terminally`,h):log.error(`${s.name}: ${s.message}`,{errorId:o,sessionId:d.sessionId,turnId:_.turnId}),await emitFailedStep(n,_,{code:`MODEL_CALL_FAILED`,details:m,message:f,sessionId:d.sessionId}),{next:{done:!0,output:``},session:d}):(log.error(c?.message??`model call failed — parking session for retry by the user`,h),_=await emitRecoverableFailedTurn(n,_,{code:`MODEL_CALL_FAILED`,details:m,message:f}),{next:null,session:setHarnessEmissionState(d,_)})}}let U=accumulateTurnUsage({previous:getTurnUsageState(d.state),turnId:_.turnId,usage:H.usage??{}});d=setTurnUsageState(d,U);let W;try{W=formatLanguageModelGatewayId(k)}catch{W=void 0}return await setAshAttributes({"$ash.model":W,"$ash.input_tokens":U.inputTokens,"$ash.output_tokens":U.outputTokens,"$ash.cache_read_tokens":U.cacheReadTokens,"$ash.tool_count":t.tools.size}),handleStepResult({config:t,emit:n,emissionState:_,promptMessages:O,result:H,runStep,session:d})}return runStep}function buildModelCallFailureDetails(e){let{configSummary:t,error:r,errorId:i,modelCallDetails:a,requestSummary:o}=e;return t===null?o===null?{...formatError(r,i),...a}:{errorId:i,message:toErrorMessage(r),name:o.name,...a}:{errorId:i,message:t.message,name:t.name,...a}}function buildModelCallFailureLogFields(e){let t={errorId:e.errorId,sessionId:e.sessionId,turnId:e.turnId};return e.requestSummary===null?{...t,error:e.error}:{...t,details:e.modelCallDetails}}async function attemptUnsupportedProviderToolRecovery(e){let t=extractUnsupportedProviderToolTypes(e.error);if(t.length===0)return{outcome:`failed`,error:e.error};let n=[];for(let e of t){let t=resolveFrameworkToolFromUpstreamType(e);t!==null&&!n.includes(t)&&n.push(t)}if(n.length===0)return{outcome:`failed`,error:e.error};log.warn(`disabling unsupported provider tool(s); retrying step once`,{disabled:n,sessionId:e.sessionId,turnId:e.turnId,upstreamTypes:t});try{return{outcome:`recovered`,result:await e.runOneModelCall({disabledProviderTools:new Set(n),extraSystemNote:buildDisabledToolNote(n),suppressStepStartedEmission:!0})}}catch(e){return{outcome:`failed`,error:e}}}function buildDisabledToolNote(e){let t=e.join(`, `);return`The following ${e.length===1?`tool is`:`tools are`} not available with the current model and has been removed: ${t}. Proceed using the remaining tools or your training knowledge.`}async function handleStepResult(e){let{config:t,emit:n,promptMessages:r,result:i,runStep:o}=e,{emissionState:s,session:l}=e,u=i.response.messages,d=resolveAssistantStepText(u,i.text),f={...l,compaction:createNextCompactionConfig(l.compaction,r,i)};if(t.codeMode===!0){let{getCodeModeInterrupt:e,isCodeModeApprovalInterrupt:a}=await loadCodeModeModule(),o=e(i);if(o!==void 0){if(isCodeModeConnectionAuthInterrupt(o))return parkOnCodeModeConnectionAuth({baseSession:f,config:t,emit:n,emissionState:s,interrupt:o,promptMessages:r,responseMessages:u});if(a(o))return parkOnCodeModeApproval({baseSession:f,config:t,emit:n,emissionState:s,interrupt:o,promptMessages:r,responseMessages:u})}}let p=extractToolApprovalInputRequests({content:i.content??[]}),m=new Set(p.map(e=>e.action.callId)),h=extractQuestionInputRequests({toolCalls:i.toolCalls,excludedCallIds:m}),g=[...p,...h],v=(i.toolCalls??[]).filter(e=>!isInvalidToolCall(e)).filter(e=>t.tools.get(e.toolName)?.runtimeAction!==void 0).map(e=>createRuntimeActionRequestFromToolCall({toolCall:e,tools:t.tools}));if(v.length>0)return{next:null,session:setHarnessEmissionState(setPendingRuntimeActionBatch({actions:v,event:{sequence:s.sequence,stepIndex:s.stepIndex,turnId:s.turnId},responseMessages:u,session:{...f,history:[...r]}}),s)};if(g.length>0){let e=setPendingInputBatch({requests:g,responseMessages:u,session:{...f,history:[...r]}});return n&&(await n(createInputRequestedEvent({requests:g,sequence:s.sequence,stepIndex:s.stepIndex,turnId:s.turnId})),t.mode===`conversation`&&(s=await emitTurnEpilogue(n,s,t.mode),e=setHarnessEmissionState(e,s))),{next:null,session:e}}let x=(i.toolResults??[]).find(e=>isAuthorizationSignal(e.output));if(x&&isAuthorizationSignal(x.output)){let{challenges:e}=x.output;if(n)for(let t of e)await n(createAuthorizationRequiredEvent({authorization:t.challenge,name:t.name,description:t.challenge.instructions??`Authorization required for ${t.name}`,webhookUrl:t.hookUrl,sequence:s.sequence,stepIndex:s.stepIndex,turnId:s.turnId}));return{next:null,session:setHarnessEmissionState({...f,history:[...r],state:setPendingAuthorization(f.state,{challenges:e})},s)}}let S=pruneToolResults(r,t.retentionPolicies),C=S!==r,w=f.compaction;C&&w.lastKnownInputTokens!==void 0&&(w={recentWindowSize:w.recentWindowSize,threshold:w.threshold});let E=[...S,...u],D={...f,compaction:w,history:E};return!(D.outputSchema!==void 0&&extractFinalOutput(i)!==void 0)&&(u.at(-1)?.role===`tool`||hasDeferredStepInput(D))?(n&&(s=advanceStep(s),D=setHarnessEmissionState(D,s)),{next:o,session:D}):t.mode===`task`?finishTaskTurn({emissionState:s,emit:n,prunedHistory:S,result:i,schema:D.outputSchema,session:D,stepOutput:d}):finishConversationTurn({emissionState:s,emit:n,prunedHistory:S,result:i,schema:D.outputSchema,session:D})}const OUTPUT_SCHEMA_NOT_FULFILLED={code:`OUTPUT_SCHEMA_NOT_FULFILLED`,message:`The agent could not produce a result matching the requested schema.`};function extractFinalOutput(e){return(e.toolCalls??[]).find(e=>e.toolName===FINAL_OUTPUT_TOOL_NAME)?.input}function persistStructuredAssistantTurn(e,t,n){return{...e,history:[...t,{content:JSON.stringify(n),role:`assistant`}],outputSchema:void 0}}async function emitStructuredResult(e,t,n,r){return await e(createResultCompletedEvent({result:n,sequence:t.sequence,stepIndex:t.stepIndex,turnId:t.turnId})),emitTurnEpilogue(e,t,r)}async function finishTaskTurn(e){let{emit:t,prunedHistory:n,result:r,schema:i,stepOutput:a}=e,{emissionState:o,session:s}=e;if(i===void 0)return t&&(o=await emitTurnEpilogue(t,o,`task`),s=setHarnessEmissionState(s,o)),{next:{done:!0,output:a??``},session:s};let c=extractFinalOutput(r);return c===void 0?(t&&await emitFailedStep(t,o,{...OUTPUT_SCHEMA_NOT_FULFILLED,sessionId:s.sessionId}),{next:{done:!0,isError:!0,output:OUTPUT_SCHEMA_NOT_FULFILLED.message},session:s}):(s=persistStructuredAssistantTurn(s,n,c),t&&(o=await emitStructuredResult(t,o,c,`task`),s=setHarnessEmissionState(s,o)),{next:{done:!0,output:JSON.stringify(c)},session:s})}async function finishConversationTurn(e){let{emit:t,prunedHistory:n,result:r,schema:i}=e,{emissionState:a,session:o}=e;if(i===void 0)return t&&(a=await emitTurnEpilogue(t,a,`conversation`),o=setHarnessEmissionState(o,a)),{next:null,session:o};let s=extractFinalOutput(r);return s===void 0?(t&&(a=await emitRecoverableFailedTurn(t,a,OUTPUT_SCHEMA_NOT_FULFILLED),o=setHarnessEmissionState(o,a)),{next:null,session:o}):(o=persistStructuredAssistantTurn(o,n,s),t&&(a=await emitStructuredResult(t,a,s,`conversation`),o=setHarnessEmissionState(o,a)),{next:null,session:o})}async function continuePendingCodeModeApproval(e){let t=getPendingCodeModeApproval(e.session.state);if(t===void 0)return null;let{continueCodeModeApproval:n,getCodeModeApprovalResponse:i,isCodeModeApprovalInterrupt:a,unwrapCodeModeResult:o}=await loadCodeModeModule(),s=i([...e.messages],t.interrupt);if(s===void 0)return{next:null,session:e.session};let c=await buildCodeModeHostTools({approvedTools:getApprovedTools(e.session),capabilities:e.capabilities,tools:e.config.tools}),l;try{l=await n({approvalResponse:s,interrupt:t.interrupt,options:createAshCodeModeOptions({lifecycle:e.emit===void 0?void 0:createCodeModeLifecycle({emit:e.emit,emissionState:e.emissionState,skipReplayed:!0,tools:e.config.tools})}),tools:c})}catch(e){logError(log,`code-mode approval continuation failed`,e),l={error:`code_mode_continuation_failed`,message:toErrorMessage(e),retryable:!1}}let d=o(l),f=d.status===`interrupted`?d.interrupt:d.output,p=replaceCodeModeApprovalInterruptResult([...e.session.history,...t.responseMessages],t.interrupt,f),m=clearPendingCodeModeApproval({...e.session,history:p});if(d.status===`interrupted`){if(isCodeModeConnectionAuthInterrupt(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeConnectionAuth({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}if(a(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeApproval({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}}return{next:e.runStep,session:m}}async function parkOnCodeModeConnectionAuth(e){let t=[...e.interrupt.payload.challenges??[]];if(e.emit)for(let n of t)await e.emit(createAuthorizationRequiredEvent({authorization:n.challenge,name:n.name,description:n.challenge.instructions??`Authorization required for ${n.name}`,webhookUrl:n.hookUrl,sequence:e.emissionState.sequence,stepIndex:e.emissionState.stepIndex,turnId:e.emissionState.turnId}));return{next:null,session:setPendingCodeModeConnectionAuth({interrupt:e.interrupt,responseMessages:e.responseMessages,session:{...e.baseSession,history:[...e.promptMessages],state:setPendingAuthorization(e.baseSession.state,{challenges:t})}})}}async function continuePendingCodeModeConnectionAuth(e){let t=getPendingCodeModeConnectionAuth(e.session.state);if(t===void 0)return null;let{continueCodeModeInterrupt:n,isCodeModeApprovalInterrupt:i,replaceCodeModeInterruptResult:a,unwrapCodeModeResult:o}=await loadCodeModeModule(),s=await buildCodeModeHostTools({approvedTools:getApprovedTools(e.session),capabilities:e.capabilities,tools:e.config.tools}),c=e.emit===void 0?void 0:createCodeModeLifecycle({emit:e.emit,emissionState:e.emissionState,skipReplayed:!0,tools:e.config.tools}),l;try{l=await n({interrupt:t.interrupt,resolution:{status:`authorized`},tools:s,options:createAshCodeModeOptions({lifecycle:c})})}catch(e){logError(log,`code-mode interrupt continuation failed`,e),l={error:`code_mode_continuation_failed`,message:toErrorMessage(e),retryable:!1}}let d=o(l),f=d.status===`interrupted`?d.interrupt:d.output,p=a([...e.session.history,...t.responseMessages],t.interrupt.pendingContinuation,f),m=clearPendingCodeModeConnectionAuth({...e.session,history:p});if(d.status===`interrupted`){if(isCodeModeConnectionAuthInterrupt(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeConnectionAuth({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}if(i(d.interrupt)){let t=e.session.history.length,n=p.slice(0,t),r=p.slice(t);return m={...m,history:n},parkOnCodeModeApproval({baseSession:m,config:e.config,emit:e.emit,emissionState:e.emissionState,interrupt:d.interrupt,promptMessages:n,responseMessages:r})}}return{next:e.runStep,session:m}}async function parkOnCodeModeApproval(e){let{toCodeModeApprovalMessages:t}=await loadCodeModeModule(),n=t(e.interrupt),r=extractToolApprovalInputRequests({content:extractAssistantContent(n)}),i=setPendingInputBatch({requests:r,responseMessages:n,session:setPendingCodeModeApproval({interrupt:e.interrupt,responseMessages:e.responseMessages,session:{...e.baseSession,history:[...e.promptMessages]}})});if(e.emit&&(await e.emit(createInputRequestedEvent({requests:r,sequence:e.emissionState.sequence,stepIndex:e.emissionState.stepIndex,turnId:e.emissionState.turnId})),e.config.mode===`conversation`)){let t=await emitTurnEpilogue(e.emit,e.emissionState,e.config.mode);i=setHarnessEmissionState(i,t)}return{next:null,session:i}}function extractAssistantContent(e){let t=[];for(let n of e)n.role===`assistant`&&Array.isArray(n.content)&&t.push(...n.content);return t}function createNextCompactionConfig(e,t,n){let r={recentWindowSize:e.recentWindowSize,threshold:e.threshold};return n.usage?.inputTokens!==void 0&&(r.lastKnownInputTokens=n.usage.inputTokens,r.lastKnownPromptMessageCount=t.length),r}async function maybeCompact(e){let{emit:t,emissionState:n}=e,r=e.messages,i=e.session;if(!shouldCompact(r,i.compaction))return{messages:r,session:i};let a=await resolveCompactionModel({compactionModelReference:i.agent.compactionModelReference,model:e.model,modelReference:i.agent.modelReference,resolveModel:e.resolveModel});if(t&&await t(createCompactionRequestedEvent({modelId:formatLanguageModelGatewayId(a.model),sequence:n.sequence,sessionId:i.sessionId,turnId:n.turnId,usageInputTokens:getInputTokenCount(r,i.compaction)})),r=await compactMessages(r,a.model,i.compaction,a.providerOptions,e.telemetry,e.headers),e.onCompaction){let t=await e.onCompaction(i);i=t.session;for(let e of t.messages)r.push(e)}return t&&await t(createCompactionCompletedEvent({modelId:formatLanguageModelGatewayId(a.model),sequence:n.sequence,sessionId:i.sessionId,turnId:n.turnId})),{messages:r,session:i}}function resolveApprovalKeyFromTools(e){return t=>{let n=e.get(t.action.toolName);if(n?.approvalKey!==void 0)return n.approvalKey(t.action.input)}}async function runModelCallWithRetries(e,t){for(let n=1;;n++)try{return await e()}catch(e){if(n===3||classifyModelCallError(e)!==`retry`)throw e;let r=500*2**(n-1)+Math.floor(Math.random()*250);log.warn(`model call failed transiently — retrying`,{attempt:n,delayMs:r,sessionId:t.sessionId,turnId:t.turnId,error:e}),await new Promise(e=>setTimeout(e,r))}}export{createToolLoopHarness};
@@ -1 +1 @@
1
- import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return`0.48.0`}const FALLBACK_PACKAGE_INFO={name:ASH_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),ASH_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${ASH_PACKAGE_NAME}/package.json`),ASH_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
1
+ import{createRequire}from"node:module";import{basename,dirname,join}from"node:path";import{existsSync,readFileSync,realpathSync}from"node:fs";import{ASH_PACKAGE_NAME}from"#internal/package-name.js";import{fileURLToPath}from"node:url";let cachedPackageInfo;const WORKFLOW_MODULE_ALIASES={"workflow/api":`src/compiled/@workflow/core/runtime.js`,"workflow/errors":`src/compiled/@workflow/errors/index.js`,"workflow/internal/private":`src/compiled/@workflow/core/private.js`,"workflow/runtime":`src/compiled/@workflow/core/runtime.js`};function resolveFallbackPackageVersion(){return`0.50.0`}const FALLBACK_PACKAGE_INFO={name:ASH_PACKAGE_NAME,version:resolveFallbackPackageVersion()};function resolveCurrentModulePath(){return typeof __filename==`string`?__filename:resolveCurrentModulePathFromStack()}function resolveCurrentModulePathFromStack(){let e=Error.prepareStackTrace;try{Error.prepareStackTrace=(e,t)=>t;let e=Error().stack?.[0]?.getFileName();if(typeof e!=`string`||e.length===0)throw Error(`Failed to resolve the current module path from the stack trace.`);return e.startsWith(`file:`)?fileURLToPath(e):e}finally{Error.prepareStackTrace=e}}const require=createRequire(resolveCurrentModulePath());function isBuildOutputPackageRoot(e){return basename(e)===`dist`&&existsSync(join(dirname(e),`package.json`))}function resolvePackageBuildRoot(){let e=dirname(realpathSync(resolveCurrentModulePath()));for(;;){if(isBuildOutputPackageRoot(e))return e;let t=dirname(e);if(t===e)return null;e=t}}function findNearestPackageRoot(e){let t=e;for(;;){if(existsSync(join(t,`package.json`))&&!isBuildOutputPackageRoot(t))return t;let r=dirname(t);if(r===t)throw Error(`Failed to resolve package root from "${e}".`);t=r}}function resolvePackageRoot(){return findNearestPackageRoot(dirname(realpathSync(resolveCurrentModulePath())))}function tryResolvePackageRoot(){try{return resolvePackageRoot()}catch{return}}function rewriteSourceFilePathForBuild(e){return e.replace(/\.[cm]?tsx?$/,`.js`)}function resolvePackageSourceFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),e):join(t,rewriteSourceFilePathForBuild(e))}function resolvePackageSourceDirectoryPath(e){let t=resolvePackageBuildRoot();return join(t===null?resolvePackageRoot():t,e)}function resolvePackageCompiledFilePath(e){let t=resolvePackageBuildRoot();return t===null?join(resolvePackageRoot(),`.generated`,`compiled`,e.replace(/^src\/compiled\//,``)):join(t,e)}function normalizeInstalledPackageInfo(e){let t=e;if(!(typeof t.name!=`string`||typeof t.version!=`string`))return{name:t.name,version:t.version}}function tryReadInstalledPackageInfo(e,t){let n=normalizeInstalledPackageInfo(JSON.parse(readFileSync(e,`utf8`)));if(n?.name===t)return n}function resolveInstalledPackageInfo(){if(cachedPackageInfo)return cachedPackageInfo;let e=tryResolvePackageRoot(),t=e===void 0?void 0:tryReadInstalledPackageInfo(join(e,`package.json`),ASH_PACKAGE_NAME);if(t)return cachedPackageInfo=t,cachedPackageInfo;try{let e=tryReadInstalledPackageInfo(require.resolve(`${ASH_PACKAGE_NAME}/package.json`),ASH_PACKAGE_NAME);if(e)return cachedPackageInfo=e,cachedPackageInfo}catch{}return cachedPackageInfo={...FALLBACK_PACKAGE_INFO},cachedPackageInfo}function resolveWorkflowModulePath(e){if(e===`workflow`)return resolvePackageSourceFilePath(`src/internal/workflow/index.ts`);if(e===`workflow/internal/builtins`)return resolvePackageSourceFilePath(`src/internal/workflow/builtins.ts`);let t=WORKFLOW_MODULE_ALIASES[e];return t===void 0?require.resolve(e):resolvePackageCompiledFilePath(t)}export{resolveInstalledPackageInfo,resolvePackageRoot,resolvePackageSourceDirectoryPath,resolvePackageSourceFilePath,resolveWorkflowModulePath};
@@ -1,4 +1,4 @@
1
- import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.48.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.159`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
1
+ import{getSupportedModuleBaseName,matchesSupportedModuleBaseName}from"./module-files.js";import{pathExists,writeTextFile}from"./files.js";import{PNPM_WORKSPACE_PATH,ensurePnpmWorkspacePolicy}from"./pnpm-workspace.js";import{WEB_APP_TEMPLATE_FILES,WEB_APP_TEMPLATE_PACKAGE_JSON}from"./web-template.js";import"./project.js";import{patchPackageJson}from"./package-json.js";import{basename,join,resolve}from"node:path";import{readFile,readdir,writeFile}from"node:fs/promises";const SLACK_CHANNEL_DEFAULT_ROUTE=`/ash/v1/slack`,DEFAULT_SLACK_CONNECTOR_SLUG=`my-agent`,PACKAGE_DEPENDENCY_FIELDS=[`dependencies`,`devDependencies`,`peerDependencies`,`optionalDependencies`],WEB_VERCEL_JSON_PATH=`vercel.json`,WEB_VERCEL_JSON_SCHEMA=`https://openapi.vercel.sh/vercel.json`,WEB_DEFAULT_VERCEL_SERVICES={web:{entrypoint:`.`,framework:`nextjs`,routePrefix:`/`},ash:{buildCommand:`ash build`,entrypoint:`.`,framework:`ash`,routePrefix:`/_ash_internal/ash`}};function toSlackConnectorSlug(e){return e}function isJsonObject(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}async function readDependencyVersion(e,t){let n=JSON.parse(await readFile(e,`utf8`));if(!isJsonObject(n)||!isJsonObject(n.dependencies))return;let r=n.dependencies[t];return typeof r==`string`?r:void 0}function packageJsonHasDependency(e,t){for(let n of PACKAGE_DEPENDENCY_FIELDS){let r=e[n];if(isJsonObject(r)&&typeof r[t]==`string`)return!0}return!1}async function hasPackageDependency(e,t){if(!await pathExists(e))return!1;let r=JSON.parse(await readFile(e,`utf8`));return isJsonObject(r)&&packageJsonHasDependency(r,t)}async function ensurePackageDependency(e,t,r){return!await pathExists(e)||await readDependencyVersion(e,t)===r?[]:(await patchPackageJson(e,{dependencies:{[t]:r}}),[{path:e,dependencies:[t],devDependencies:[],scripts:[]}])}function resolveWebPackageVersions(e){return{ashPackageVersion:e?.ashPackageVersion??`0.50.0`,aiPackageVersion:e?.aiPackageVersion??`7.0.0-canary.159`,nextPackageVersion:e?.nextPackageVersion??`16.2.6`,reactPackageVersion:e?.reactPackageVersion??`19.2.6`,reactDomPackageVersion:e?.reactDomPackageVersion??`19.2.6`,streamdownPackageVersion:e?.streamdownPackageVersion??`2.5.0`,zodPackageVersion:e?.zodPackageVersion??`4.4.3`,tsgoPackageVersion:e?.tsgoPackageVersion??`7.0.0-dev.20260523.1`,typesNodePackageVersion:e?.typesNodePackageVersion??`25.9.1`,typesReactPackageVersion:e?.typesReactPackageVersion??`19.2.15`,typesReactDomPackageVersion:e?.typesReactDomPackageVersion??`19.2.3`}}function formatAshDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}async function patchWebPackageJson(e,t){if(!await pathExists(e))return[];assertStampedVersion(`ashPackageVersion`,t.ashPackageVersion),assertStampedVersion(`aiPackageVersion`,t.aiPackageVersion),assertStampedVersion(`nextPackageVersion`,t.nextPackageVersion),assertStampedVersion(`reactPackageVersion`,t.reactPackageVersion),assertStampedVersion(`reactDomPackageVersion`,t.reactDomPackageVersion),assertStampedVersion(`streamdownPackageVersion`,t.streamdownPackageVersion),assertStampedVersion(`zodPackageVersion`,t.zodPackageVersion),assertStampedVersion(`tsgoPackageVersion`,t.tsgoPackageVersion),assertStampedVersion(`typesNodePackageVersion`,t.typesNodePackageVersion),assertStampedVersion(`typesReactPackageVersion`,t.typesReactPackageVersion),assertStampedVersion(`typesReactDomPackageVersion`,t.typesReactDomPackageVersion);let r={...WEB_APP_TEMPLATE_PACKAGE_JSON.dependencies,ai:t.aiPackageVersion,"experimental-ash":formatAshDependencySpecifier(t.ashPackageVersion),next:t.nextPackageVersion,react:t.reactPackageVersion,"react-dom":t.reactDomPackageVersion,streamdown:t.streamdownPackageVersion,zod:t.zodPackageVersion},i={...WEB_APP_TEMPLATE_PACKAGE_JSON.devDependencies,"@types/node":t.typesNodePackageVersion,"@types/react":t.typesReactPackageVersion,"@types/react-dom":t.typesReactDomPackageVersion,"@typescript/native-preview":t.tsgoPackageVersion},a=WEB_APP_TEMPLATE_PACKAGE_JSON.scripts;return await patchPackageJson(e,{dependencies:r,devDependencies:i,scripts:a}),[{path:e,dependencies:Object.keys(r),devDependencies:Object.keys(i),scripts:Object.keys(a)}]}function normalizeSlackConnectorSlug(e){return toSlackConnectorSlug((e.trim().replace(/^@/,``).split(`/`).at(-1)??``).toLowerCase().replace(/[^a-z0-9_-]+/g,`-`).replace(/^[^a-z0-9]+/,``).replace(/[^a-z0-9]+$/,``).slice(0,100).replace(/[^a-z0-9]+$/,``)||`my-agent`)}async function deriveSlackConnectorSlug(e,t){if(t!==void 0&&t.length>0&&t!==`.`)return normalizeSlackConnectorSlug(t);try{let t=await readFile(join(e,`package.json`),`utf8`),n=JSON.parse(t);if(typeof n.name==`string`&&n.name.length>0)return normalizeSlackConnectorSlug(n.name)}catch{}return normalizeSlackConnectorSlug(basename(resolve(e))||`my-agent`)}function buildSlackTemplate(e){return`import { connectSlackCredentials } from "@vercel/connect/ash";
2
2
  import { slackChannel } from "experimental-ash/channels/slack";
3
3
 
4
4
  export default slackChannel({
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator}from"#public/channels/discord/api.js";import{buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent}from"#public/channels/discord/hitl.js";import{defaultEvents,defaultOnCommand}from"#public/channels/discord/defaults.js";import{DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,parseDiscordInteraction,prependDiscordContext}from"#public/channels/discord/inbound.js";import{discordDeferredJson,discordJson,discordJsonBody,readMessageContent}from"#public/channels/discord/responses.js";import{verifyDiscordInbound}from"#public/channels/discord/verifyInbound.js";const log=createLogger(`discord.channel`);function discordChannel(e={}){let t=e.onCommand??defaultOnCommand,a={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/ash/v1/discord`,async(r,{send:i,waitUntil:a})=>{let o=await verifyDiscordInbound(r,e.credentials);if(o===null)return new Response(`unauthorized`,{status:401});let s;try{s=parseJsonObject(JSON.parse(o))}catch(e){return log.warn(`inbound Discord body is not valid JSON`,{error:e}),discordJson({content:`invalid request`,ephemeral:!0})}if(s.type===DISCORD_INTERACTION_TYPE.PING)return discordJson({type:DISCORD_INTERACTION_RESPONSE_TYPE.PONG});let c=parseDiscordInteraction(s);return c===null?discordJson({content:`Unsupported Discord interaction.`,ephemeral:!0}):handleInteraction({config:e,interaction:c,onCommand:t,send:i,waitUntil:a})})],async receive(t,{send:n}){let r=t.args,i=readString(r.channelId);if(!i)throw Error(`discordChannel().receive requires args.channelId.`);let a=readString(r.conversationId),o=r.initialMessage;if(o!==void 0&&a!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=a??``,l=a!==void 0;if(o!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:i}}).sendChannelMessage(o);c=t.id,l=t.id.length>0}return n(t.message,{auth:t.auth,continuationToken:discordContinuationToken(i,c),state:{applicationId:null,channelId:i,conversationId:c||null,guildId:null,hasMessageAnchor:l,initialResponseSent:!0,interactionToken:null}})},events:a})}function rebuildDiscordContext(e,t,n){return{discord:buildDiscordHandle({config:n,session:t,state:e}),state:e}}function buildDiscordHandle(e){let n=e.config.api,r=e.state,i=mergeCredentials(e.config.credentials,r);function anchor(t){!t.id||r.hasMessageAnchor||(r.conversationId=t.id,r.hasMessageAnchor=!0,r.channelId&&e.session?.setContinuationToken(discordContinuationToken(r.channelId,t.id)))}async function sendViaChannel(e){let t=r.channelId??``;if(!t)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,channelId:t});return anchor(a),a}async function editOriginal(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return r.initialResponseSent=!0,anchor(a),a}async function followup(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for followup message.`);let a=await createDiscordFollowupMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return anchor(a),a}async function startTyping(){let e=r.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:n?.apiBaseUrl,credentials:i,fetch:n?.fetch,channelId:e})}catch(n){logError(log,`Discord typing indicator failed — swallowed`,n,{channelId:e})}}return{applicationId:r.applicationId??void 0,channelId:r.channelId??``,conversationId:r.conversationId??``,guildId:r.guildId??void 0,interactionToken:r.interactionToken??void 0,request(e,t,r){return callDiscordApi({apiBaseUrl:n?.apiBaseUrl,body:t,botToken:r?.botAuth===!0?i.botToken:void 0,fetch:n?.fetch,method:r?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),n;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:r});n===void 0&&(n=t)}return n??{id:``,raw:null}},editOriginalResponse:editOriginal,followup,sendChannelMessage:sendViaChannel,startTyping}}async function postOne(e){if(e.state.interactionToken&&e.state.applicationId)try{return e.state.initialResponseSent?await e.followup(e.body):await e.editOriginal(e.body)}catch(e){log.warn(`Discord interaction-token delivery failed, falling back to channel message`,{error:e})}return e.sendViaChannel(e.body)}async function handleInteraction(e){return e.interaction.type===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?handleCommandInteraction({config:e.config,interaction:e.interaction,onCommand:e.onCommand,send:e.send,waitUntil:e.waitUntil}):e.interaction.type===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?handleComponentInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil}):handleModalSubmitInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil})}async function handleCommandInteraction(e){let t=stateFromInteraction(e.interaction,{conversationId:e.interaction.id,hasMessageAnchor:!1,initialResponseSent:!1}),n={discord:buildDiscordHandle({config:e.config,state:t})},r;try{r=await e.onCommand(n,e.interaction)}catch(e){return log.error(`command handler failed`,{error:e}),discordJson({content:`The Discord command handler failed.`,ephemeral:!0})}return r==null?discordJson({content:`Command ignored.`,ephemeral:!0}):(e.waitUntil(dispatchCommand({interaction:e.interaction,result:r,send:e.send,state:t})),discordDeferredJson(r.ephemeral===!0))}function handleComponentInteraction(e){if(isDiscordFreeformComponent(e.interaction.customId)){let t=readMessageContent(e.interaction.raw);return discordJsonBody(buildFreeformModalResponse({customId:e.interaction.customId,prompt:t}))}let t=deriveComponentInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId,inputResponses:t,interaction:e.interaction,send:e.send})),discordJsonBody({type:DISCORD_INTERACTION_RESPONSE_TYPE.DEFERRED_UPDATE_MESSAGE})}function handleModalSubmitInteraction(e){let t=deriveModalInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId??e.interaction.id,inputResponses:t,interaction:e.interaction,send:e.send})),discordJson({content:`Answer received.`,ephemeral:!0})}async function dispatchCommand(e){let t=prependDiscordContext(commandInteractionMessage(e.interaction),{channelId:e.interaction.channelId,commandName:e.interaction.commandName,guildId:e.interaction.guildId,interactionId:e.interaction.id,userId:e.interaction.user.id,username:e.interaction.user.username});try{await e.send({message:t,context:e.result.context},{auth:e.result.auth,continuationToken:discordContinuationToken(e.interaction.channelId,e.interaction.id),state:e.state})}catch(e){log.error(`command delivery failed`,{error:e})}}async function dispatchInputResponses(e){try{await e.send({inputResponses:e.inputResponses},{auth:null,continuationToken:discordContinuationToken(e.interaction.channelId,e.conversationId),state:stateFromInteraction(e.interaction,{conversationId:e.conversationId,hasMessageAnchor:!0,initialResponseSent:!0})})}catch(e){log.error(`interaction response delivery failed`,{error:e})}}function stateFromInteraction(e,t){return{applicationId:e.applicationId,channelId:e.channelId,conversationId:t.conversationId,guildId:e.guildId??null,hasMessageAnchor:t.hasMessageAnchor,initialResponseSent:t.initialResponseSent,interactionToken:e.token}}function initialDiscordState(){return{applicationId:null,channelId:null,conversationId:null,guildId:null,hasMessageAnchor:!1,initialResponseSent:!1,interactionToken:null}}function mergeCredentials(e,t){return{applicationId:t.applicationId??e?.applicationId,botToken:e?.botToken,publicKey:e?.publicKey,webhookVerifier:e?.webhookVerifier}}function normalizePostInput(e){return typeof e==`string`?{content:e}:e}function expandPostBodies(e){return typeof e.content==`string`?splitDiscordMessageContent(e.content).map((t,n)=>n===0?{...e,content:t}:{allowed_mentions:e.allowed_mentions,content:t}):[e]}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{discordChannel};
1
+ import{createLogger,logError}from"#internal/logging.js";import{parseJsonObject}from"#shared/json.js";import{POST,defineChannel}from"#public/definitions/defineChannel.js";import"#public/channels/discord/verify.js";import{callDiscordApi,createDiscordFollowupMessage,discordContinuationToken,editDiscordOriginalResponse,sendDiscordChannelMessage,splitDiscordMessageContent,triggerDiscordTypingIndicator}from"#public/channels/discord/api.js";import{buildFreeformModalResponse,deriveComponentInputResponses,deriveModalInputResponses,isDiscordFreeformComponent}from"#public/channels/discord/hitl.js";import{defaultEvents,defaultOnCommand}from"#public/channels/discord/defaults.js";import{DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction}from"#public/channels/discord/inbound.js";import{discordDeferredJson,discordJson,discordJsonBody,readMessageContent}from"#public/channels/discord/responses.js";import{verifyDiscordInbound}from"#public/channels/discord/verifyInbound.js";const log=createLogger(`discord.channel`);function discordChannel(e={}){let t=e.onCommand??defaultOnCommand,a={...defaultEvents,...e.events};return defineChannel({kindHint:`discord`,state:initialDiscordState(),context(t,n){return rebuildDiscordContext(t,n,e)},routes:[POST(e.route??`/ash/v1/discord`,async(r,{send:i,waitUntil:a})=>{let o=await verifyDiscordInbound(r,e.credentials);if(o===null)return new Response(`unauthorized`,{status:401});let s;try{s=parseJsonObject(JSON.parse(o))}catch(e){return log.warn(`inbound Discord body is not valid JSON`,{error:e}),discordJson({content:`invalid request`,ephemeral:!0})}if(s.type===DISCORD_INTERACTION_TYPE.PING)return discordJson({type:DISCORD_INTERACTION_RESPONSE_TYPE.PONG});let c=parseDiscordInteraction(s);return c===null?discordJson({content:`Unsupported Discord interaction.`,ephemeral:!0}):handleInteraction({config:e,interaction:c,onCommand:t,send:i,waitUntil:a})})],async receive(t,{send:n}){let r=t.args,i=readString(r.channelId);if(!i)throw Error(`discordChannel().receive requires args.channelId.`);let a=readString(r.conversationId),o=r.initialMessage;if(o!==void 0&&a!==void 0)throw Error("discordChannel().receive: `conversationId` and `initialMessage` are mutually exclusive.");let c=a??``,l=a!==void 0;if(o!==void 0){let t=await buildDiscordHandle({config:e,state:{...initialDiscordState(),channelId:i}}).sendChannelMessage(o);c=t.id,l=t.id.length>0}return n(t.message,{auth:t.auth,continuationToken:discordContinuationToken(i,c),state:{applicationId:null,channelId:i,conversationId:c||null,guildId:null,hasMessageAnchor:l,initialResponseSent:!0,interactionToken:null}})},events:a})}function rebuildDiscordContext(e,t,n){return{discord:buildDiscordHandle({config:n,session:t,state:e}),state:e}}function buildDiscordHandle(e){let n=e.config.api,r=e.state,i=mergeCredentials(e.config.credentials,r);function anchor(t){!t.id||r.hasMessageAnchor||(r.conversationId=t.id,r.hasMessageAnchor=!0,r.channelId&&e.session?.setContinuationToken(discordContinuationToken(r.channelId,t.id)))}async function sendViaChannel(e){let t=r.channelId??``;if(!t)throw Error(`discordChannel: missing channel id for outbound message.`);let a=await sendDiscordChannelMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,channelId:t});return anchor(a),a}async function editOriginal(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for original response edit.`);let a=await editDiscordOriginalResponse({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return r.initialResponseSent=!0,anchor(a),a}async function followup(e){let t=r.interactionToken??``;if(!t)throw Error(`discordChannel: missing interaction token for followup message.`);let a=await createDiscordFollowupMessage({apiBaseUrl:n?.apiBaseUrl,body:normalizePostInput(e),credentials:i,fetch:n?.fetch,interactionToken:t});return anchor(a),a}async function startTyping(){let e=r.channelId??``;if(e)try{await triggerDiscordTypingIndicator({apiBaseUrl:n?.apiBaseUrl,credentials:i,fetch:n?.fetch,channelId:e})}catch(n){logError(log,`Discord typing indicator failed — swallowed`,n,{channelId:e})}}return{applicationId:r.applicationId??void 0,channelId:r.channelId??``,conversationId:r.conversationId??``,guildId:r.guildId??void 0,interactionToken:r.interactionToken??void 0,request(e,t,r){return callDiscordApi({apiBaseUrl:n?.apiBaseUrl,body:t,botToken:r?.botAuth===!0?i.botToken:void 0,fetch:n?.fetch,method:r?.method,path:e})},async post(e){let t=expandPostBodies(normalizePostInput(e)),n;for(let e of t){let t=await postOne({body:e,editOriginal,followup,sendViaChannel,state:r});n===void 0&&(n=t)}return n??{id:``,raw:null}},editOriginalResponse:editOriginal,followup,sendChannelMessage:sendViaChannel,startTyping}}async function postOne(e){if(e.state.interactionToken&&e.state.applicationId)try{return e.state.initialResponseSent?await e.followup(e.body):await e.editOriginal(e.body)}catch(e){log.warn(`Discord interaction-token delivery failed, falling back to channel message`,{error:e})}return e.sendViaChannel(e.body)}async function handleInteraction(e){return e.interaction.type===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?handleCommandInteraction({config:e.config,interaction:e.interaction,onCommand:e.onCommand,send:e.send,waitUntil:e.waitUntil}):e.interaction.type===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?handleComponentInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil}):handleModalSubmitInteraction({interaction:e.interaction,send:e.send,waitUntil:e.waitUntil})}async function handleCommandInteraction(e){let t=stateFromInteraction(e.interaction,{conversationId:e.interaction.id,hasMessageAnchor:!1,initialResponseSent:!1}),n={discord:buildDiscordHandle({config:e.config,state:t})},r;try{r=await e.onCommand(n,e.interaction)}catch(e){return log.error(`command handler failed`,{error:e}),discordJson({content:`The Discord command handler failed.`,ephemeral:!0})}return r==null?discordJson({content:`Command ignored.`,ephemeral:!0}):(e.waitUntil(dispatchCommand({interaction:e.interaction,result:r,send:e.send,state:t})),discordDeferredJson(r.ephemeral===!0))}function handleComponentInteraction(e){if(isDiscordFreeformComponent(e.interaction.customId)){let t=readMessageContent(e.interaction.raw);return discordJsonBody(buildFreeformModalResponse({customId:e.interaction.customId,prompt:t}))}let t=deriveComponentInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId,inputResponses:t,interaction:e.interaction,send:e.send})),discordJsonBody({type:DISCORD_INTERACTION_RESPONSE_TYPE.DEFERRED_UPDATE_MESSAGE})}function handleModalSubmitInteraction(e){let t=deriveModalInputResponses(e.interaction);return t.length>0&&e.waitUntil(dispatchInputResponses({conversationId:e.interaction.messageId??e.interaction.id,inputResponses:t,interaction:e.interaction,send:e.send})),discordJson({content:`Answer received.`,ephemeral:!0})}async function dispatchCommand(e){let t=commandInteractionMessage(e.interaction),n=formatDiscordContextBlock({channelId:e.interaction.channelId,commandName:e.interaction.commandName,guildId:e.interaction.guildId,interactionId:e.interaction.id,userId:e.interaction.user.id,username:e.interaction.user.username}),r=e.result.context??[];try{await e.send({message:t,context:[n,...r]},{auth:e.result.auth,continuationToken:discordContinuationToken(e.interaction.channelId,e.interaction.id),state:e.state})}catch(e){log.error(`command delivery failed`,{error:e})}}async function dispatchInputResponses(e){try{await e.send({inputResponses:e.inputResponses},{auth:null,continuationToken:discordContinuationToken(e.interaction.channelId,e.conversationId),state:stateFromInteraction(e.interaction,{conversationId:e.conversationId,hasMessageAnchor:!0,initialResponseSent:!0})})}catch(e){log.error(`interaction response delivery failed`,{error:e})}}function stateFromInteraction(e,t){return{applicationId:e.applicationId,channelId:e.channelId,conversationId:t.conversationId,guildId:e.guildId??null,hasMessageAnchor:t.hasMessageAnchor,initialResponseSent:t.initialResponseSent,interactionToken:e.token}}function initialDiscordState(){return{applicationId:null,channelId:null,conversationId:null,guildId:null,hasMessageAnchor:!1,initialResponseSent:!1,interactionToken:null}}function mergeCredentials(e,t){return{applicationId:t.applicationId??e?.applicationId,botToken:e?.botToken,publicKey:e?.publicKey,webhookVerifier:e?.webhookVerifier}}function normalizePostInput(e){return typeof e==`string`?{content:e}:e}function expandPostBodies(e){return typeof e.content==`string`?splitDiscordMessageContent(e.content).map((t,n)=>n===0?{...e,content:t}:{allowed_mentions:e.allowed_mentions,content:t}):[e]}function readString(e){return typeof e==`string`&&e.length>0?e:void 0}export{discordChannel};
@@ -4,7 +4,6 @@
4
4
  * The channel owns small, documented data shapes instead of exposing
5
5
  * Discord's raw interaction payloads as the primary public API.
6
6
  */
7
- import type { UserContent } from "ai";
8
7
  /** Discord interaction type values used by the native channel. */
9
8
  export declare const DISCORD_INTERACTION_TYPE: {
10
9
  readonly APPLICATION_COMMAND: 2;
@@ -93,5 +92,3 @@ export declare function parseDiscordInteraction(value: unknown): DiscordInteract
93
92
  export declare function commandInteractionMessage(interaction: DiscordCommandInteraction): string;
94
93
  /** Renders one {@link DiscordInboundContext} as a deterministic context block. */
95
94
  export declare function formatDiscordContextBlock(context: DiscordInboundContext): string;
96
- /** Prepends a `<discord_context>` block to the inbound turn message. */
97
- export declare function prependDiscordContext(message: string | UserContent, context: DiscordInboundContext): string | UserContent;
@@ -1,2 +1,2 @@
1
1
  import{isNonEmptyString,isObject}from"#shared/guards.js";const DISCORD_INTERACTION_TYPE={APPLICATION_COMMAND:2,MESSAGE_COMPONENT:3,MODAL_SUBMIT:5,PING:1},DISCORD_INTERACTION_RESPONSE_TYPE={CHANNEL_MESSAGE_WITH_SOURCE:4,DEFERRED_CHANNEL_MESSAGE_WITH_SOURCE:5,DEFERRED_UPDATE_MESSAGE:6,MODAL:9,PONG:1},DISCORD_EPHEMERAL_MESSAGE_FLAG=64;function parseDiscordInteraction(e){if(!isObject(e))return null;let r=e.type;return r===DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND?parseCommandInteraction(e):r===DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT?parseComponentInteraction(e):r===DISCORD_INTERACTION_TYPE.MODAL_SUBMIT?parseModalSubmitInteraction(e):null}function commandInteractionMessage(e){let t=findOptionValue(e.options,`message`);if(typeof t==`string`&&t.trim().length>0)return t;let n=formatCommandOptions(e.options);return n?`/${e.commandName} ${n}`:`/${e.commandName}`}function formatDiscordContextBlock(e){return[`<discord_context>`,`response_medium: discord`,`response_instructions: Reply for Discord in concise Markdown. Avoid mass mentions, long tables, and messages that need more than a few short posts.`,`user_id: ${e.userId}`,...e.username?[`username: ${e.username}`]:[],`channel_id: ${e.channelId}`,...e.guildId?[`guild_id: ${e.guildId}`]:[],`interaction_id: ${e.interactionId}`,...e.commandName?[`command_name: ${e.commandName}`]:[],`</discord_context>`].join(`
2
- `)}function prependDiscordContext(e,t){let n=formatDiscordContextBlock(t);return typeof e==`string`?e.length>0?`${n}\n\n${e}`:n:[{type:`text`,text:n},...e]}function parseCommandInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null;return!i||!a||!isNonEmptyString(a.name)?null:{...i,commandId:isNonEmptyString(a.id)?a.id:void 0,commandName:a.name,options:parseOptions(a.options),type:DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND}}function parseComponentInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null,o=isObject(r.message)?r.message:null;if(!i||!a||!isNonEmptyString(a.custom_id))return null;let s=isNonEmptyString(o?.id)?o.id:``;return s?{...i,componentType:typeof a.component_type==`number`?a.component_type:0,customId:a.custom_id,messageId:s,type:DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT,values:Array.isArray(a.values)?a.values.filter(e=>typeof e==`string`):[]}:null}function parseModalSubmitInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null;if(!i||!a||!isNonEmptyString(a.custom_id))return null;let o=isObject(r.message)?r.message:null;return{...i,customId:a.custom_id,messageId:isNonEmptyString(o?.id)?o.id:void 0,textInputs:parseTextInputs(a.components),type:DISCORD_INTERACTION_TYPE.MODAL_SUBMIT}}function parseInteractionBase(t){if(!isNonEmptyString(t.id)||!isNonEmptyString(t.application_id)||!isNonEmptyString(t.channel_id)||!isNonEmptyString(t.token))return null;let n=parseInteractionUser(t);return n?{applicationId:t.application_id,channelId:t.channel_id,guildId:isNonEmptyString(t.guild_id)?t.guild_id:void 0,id:t.id,member:parseMember(t.member),raw:t,token:t.token,user:n}:null}function parseInteractionUser(e){return parseUser(e.user)||(parseMember(e.member)?.user??null)}function parseMember(n){if(!isObject(n))return;let r=parseUser(n.user);if(r)return{nick:isNonEmptyString(n.nick)?n.nick:void 0,roles:Array.isArray(n.roles)?n.roles.filter(e=>typeof e==`string`):[],user:r}}function parseUser(n){return!isObject(n)||!isNonEmptyString(n.id)||!isNonEmptyString(n.username)?null:{avatar:isNonEmptyString(n.avatar)?n.avatar:void 0,discriminator:isNonEmptyString(n.discriminator)?n.discriminator:void 0,globalName:isNonEmptyString(n.global_name)?n.global_name:void 0,id:n.id,isBot:n.bot===!0,username:n.username}}function parseOptions(n){if(!Array.isArray(n))return[];let r=[];for(let i of n){if(!isObject(i)||!isNonEmptyString(i.name))continue;let n={name:i.name,options:parseOptions(i.options),value:parseOptionValue(i.value)};r.push(n)}return r}function parseOptionValue(e){if(typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e}function parseTextInputs(n){let r={};if(!Array.isArray(n))return r;for(let i of n)if(!(!isObject(i)||!Array.isArray(i.components)))for(let n of i.components)isObject(n)&&isNonEmptyString(n.custom_id)&&typeof n.value==`string`&&(r[n.custom_id]=n.value);return r}function findOptionValue(e,t){for(let n of e){if(n.name===t&&n.value!==void 0)return n.value;let e=findOptionValue(n.options,t);if(e!==void 0)return e}}function formatCommandOptions(e){return e.map(formatOption).filter(e=>e.length>0).join(` `)}function formatOption(e){if(e.value!==void 0)return`${e.name}:${String(e.value)}`;let t=formatCommandOptions(e.options);return t?`${e.name} ${t}`:e.name}export{DISCORD_EPHEMERAL_MESSAGE_FLAG,DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction,prependDiscordContext};
2
+ `)}function parseCommandInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null;return!i||!a||!isNonEmptyString(a.name)?null:{...i,commandId:isNonEmptyString(a.id)?a.id:void 0,commandName:a.name,options:parseOptions(a.options),type:DISCORD_INTERACTION_TYPE.APPLICATION_COMMAND}}function parseComponentInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null,o=isObject(r.message)?r.message:null;if(!i||!a||!isNonEmptyString(a.custom_id))return null;let s=isNonEmptyString(o?.id)?o.id:``;return s?{...i,componentType:typeof a.component_type==`number`?a.component_type:0,customId:a.custom_id,messageId:s,type:DISCORD_INTERACTION_TYPE.MESSAGE_COMPONENT,values:Array.isArray(a.values)?a.values.filter(e=>typeof e==`string`):[]}:null}function parseModalSubmitInteraction(r){let i=parseInteractionBase(r),a=isObject(r.data)?r.data:null;if(!i||!a||!isNonEmptyString(a.custom_id))return null;let o=isObject(r.message)?r.message:null;return{...i,customId:a.custom_id,messageId:isNonEmptyString(o?.id)?o.id:void 0,textInputs:parseTextInputs(a.components),type:DISCORD_INTERACTION_TYPE.MODAL_SUBMIT}}function parseInteractionBase(t){if(!isNonEmptyString(t.id)||!isNonEmptyString(t.application_id)||!isNonEmptyString(t.channel_id)||!isNonEmptyString(t.token))return null;let n=parseInteractionUser(t);return n?{applicationId:t.application_id,channelId:t.channel_id,guildId:isNonEmptyString(t.guild_id)?t.guild_id:void 0,id:t.id,member:parseMember(t.member),raw:t,token:t.token,user:n}:null}function parseInteractionUser(e){return parseUser(e.user)||(parseMember(e.member)?.user??null)}function parseMember(n){if(!isObject(n))return;let r=parseUser(n.user);if(r)return{nick:isNonEmptyString(n.nick)?n.nick:void 0,roles:Array.isArray(n.roles)?n.roles.filter(e=>typeof e==`string`):[],user:r}}function parseUser(n){return!isObject(n)||!isNonEmptyString(n.id)||!isNonEmptyString(n.username)?null:{avatar:isNonEmptyString(n.avatar)?n.avatar:void 0,discriminator:isNonEmptyString(n.discriminator)?n.discriminator:void 0,globalName:isNonEmptyString(n.global_name)?n.global_name:void 0,id:n.id,isBot:n.bot===!0,username:n.username}}function parseOptions(n){if(!Array.isArray(n))return[];let r=[];for(let i of n){if(!isObject(i)||!isNonEmptyString(i.name))continue;let n={name:i.name,options:parseOptions(i.options),value:parseOptionValue(i.value)};r.push(n)}return r}function parseOptionValue(e){if(typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e}function parseTextInputs(n){let r={};if(!Array.isArray(n))return r;for(let i of n)if(!(!isObject(i)||!Array.isArray(i.components)))for(let n of i.components)isObject(n)&&isNonEmptyString(n.custom_id)&&typeof n.value==`string`&&(r[n.custom_id]=n.value);return r}function findOptionValue(e,t){for(let n of e){if(n.name===t&&n.value!==void 0)return n.value;let e=findOptionValue(n.options,t);if(e!==void 0)return e}}function formatCommandOptions(e){return e.map(formatOption).filter(e=>e.length>0).join(` `)}function formatOption(e){if(e.value!==void 0)return`${e.name}:${String(e.value)}`;let t=formatCommandOptions(e.options);return t?`${e.name} ${t}`:e.name}export{DISCORD_EPHEMERAL_MESSAGE_FLAG,DISCORD_INTERACTION_RESPONSE_TYPE,DISCORD_INTERACTION_TYPE,commandInteractionMessage,formatDiscordContextBlock,parseDiscordInteraction};
@@ -1,7 +1,7 @@
1
1
  export type { ModelMessage } from "ai";
2
2
  export { discordChannel, type DiscordChannel, type DiscordChannelConfig, type DiscordChannelCredentials, type DiscordChannelEvents, type DiscordChannelState, type DiscordCommandResult, type DiscordCommandResultOrPromise, type DiscordContext, type DiscordEventContext, type DiscordHandle, type DiscordReceiveArgs, type DiscordRequestOptions, } from "#public/channels/discord/discordChannel.js";
3
3
  export { callDiscordApi, createDiscordFollowupMessage, discordContinuationToken, DISCORD_MESSAGE_CONTENT_MAX_LENGTH, DISCORD_NO_MENTIONS, editDiscordOriginalResponse, resolveDiscordApplicationId, resolveDiscordBotToken, resolveDiscordPublicKey, sendDiscordChannelMessage, splitDiscordMessageContent, triggerDiscordTypingIndicator, type DiscordApiOptions, type DiscordApiResponse, type DiscordApplicationId, type DiscordBotToken, type DiscordCredentials, type DiscordFetch, type DiscordMessageBody, type DiscordPostedMessage, } from "#public/channels/discord/api.js";
4
- export { DISCORD_EPHEMERAL_MESSAGE_FLAG, DISCORD_INTERACTION_RESPONSE_TYPE, DISCORD_INTERACTION_TYPE, commandInteractionMessage, formatDiscordContextBlock, parseDiscordInteraction, prependDiscordContext, type DiscordCommandInteraction, type DiscordCommandOption, type DiscordComponentInteraction, type DiscordInboundContext, type DiscordInteraction, type DiscordInteractionBase, type DiscordMember, type DiscordModalSubmitInteraction, type DiscordUser, } from "#public/channels/discord/inbound.js";
4
+ export { DISCORD_EPHEMERAL_MESSAGE_FLAG, DISCORD_INTERACTION_RESPONSE_TYPE, DISCORD_INTERACTION_TYPE, commandInteractionMessage, formatDiscordContextBlock, parseDiscordInteraction, type DiscordCommandInteraction, type DiscordCommandOption, type DiscordComponentInteraction, type DiscordInboundContext, type DiscordInteraction, type DiscordInteractionBase, type DiscordMember, type DiscordModalSubmitInteraction, type DiscordUser, } from "#public/channels/discord/inbound.js";
5
5
  export { DISCORD_COMPONENT_TYPE, DISCORD_HITL_CUSTOM_ID_PREFIX, DISCORD_HITL_FREEFORM_CUSTOM_ID_PREFIX, DISCORD_HITL_FREEFORM_TEXT_INPUT_ID, buildFreeformModalResponse, deriveComponentInputResponses, deriveModalInputResponses, isDiscordFreeformComponent, renderInputRequestComponents, } from "#public/channels/discord/hitl.js";
6
6
  export { defaultDiscordAuth } from "#public/channels/discord/defaults.js";
7
7
  export { verifyDiscordRequest, verifyDiscordSignature, type DiscordPublicKey, type DiscordVerifyOptions, type DiscordWebhookVerifier, } from "#public/channels/discord/verify.js";