eve 0.79.0 → 0.79.2

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 (201) hide show
  1. package/CHANGELOG.md +47 -0
  2. package/dist/src/channel/pending-authorization.d.ts +10 -0
  3. package/dist/src/channel/pending-authorization.js +1 -0
  4. package/dist/src/chunks/{use-eve-agent-BSYe_Re7.js → use-eve-agent-Ch-Q-s12.js} +43 -13
  5. package/dist/src/chunks/{use-eve-agent-B8brxCk-.js → use-eve-agent-Vsl-S0yI.js} +43 -13
  6. package/dist/src/client/abort-signal.d.ts +2 -0
  7. package/dist/src/client/abort-signal.js +1 -0
  8. package/dist/src/client/conversation-client.d.ts +2 -0
  9. package/dist/src/client/conversation-client.js +1 -1
  10. package/dist/src/client/eve-agent-store-state.d.ts +9 -0
  11. package/dist/src/client/eve-agent-store.js +1 -1
  12. package/dist/src/client/ndjson.js +1 -1
  13. package/dist/src/client/open-stream.js +1 -1
  14. package/dist/src/client/session-turn-dispatch.js +1 -1
  15. package/dist/src/client/session-utils.js +1 -1
  16. package/dist/src/client/session.js +1 -1
  17. package/dist/src/compiled/.vendor-stamp.json +2 -2
  18. package/dist/src/compiled/@eve/tracing/adapters/serialization.d.ts +2 -2
  19. package/dist/src/compiled/@eve/tracing/core/types.d.ts +6 -1
  20. package/dist/src/compiled/@eve/tracing/index.js +1 -1
  21. package/dist/src/compiled/@eve/tracing/otel.js +1 -1
  22. package/dist/src/compiled/_chunks/workflow/mcp-Bwx_LQ4q.js +5 -0
  23. package/dist/src/compiler/extension-compatibility.d.ts +18 -18
  24. package/dist/src/compiler/extension-compatibility.js +1 -1
  25. package/dist/src/compiler/project-sources.js +1 -1
  26. package/dist/src/context/memory-tools.js +1 -1
  27. package/dist/src/evals/runner/reporters/assertion-scores.d.ts +6 -4
  28. package/dist/src/evals/runner/reporters/assertion-scores.js +1 -1
  29. package/dist/src/evals/runner/reporters/braintrust.js +1 -1
  30. package/dist/src/eve-channel/request.js +1 -1
  31. package/dist/src/execution/authorization-callback-match.d.ts +2 -2
  32. package/dist/src/execution/authorization-callback-match.js +1 -1
  33. package/dist/src/execution/durable-session-store.js +1 -1
  34. package/dist/src/execution/dynamic-workflow/tool.js +1 -1
  35. package/dist/src/execution/forward-session-input.js +1 -1
  36. package/dist/src/execution/proxied-deliver-step.js +1 -1
  37. package/dist/src/execution/publish-session-events.d.ts +26 -5
  38. package/dist/src/execution/publish-session-events.js +1 -1
  39. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  40. package/dist/src/execution/sandbox/bindings/vercel-create-sdk.js +1 -1
  41. package/dist/src/execution/sandbox/bindings/vercel-credentials.d.ts +2 -0
  42. package/dist/src/execution/sandbox/bindings/vercel-credentials.js +1 -1
  43. package/dist/src/execution/sandbox/bindings/vercel-lifecycle.js +1 -1
  44. package/dist/src/execution/sandbox/bindings/vercel-lookup.js +1 -1
  45. package/dist/src/execution/sandbox/bindings/vercel.d.ts +3 -6
  46. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  47. package/dist/src/execution/session/active-turn.d.ts +2 -1
  48. package/dist/src/execution/session/active-turn.js +1 -1
  49. package/dist/src/execution/session/checkpoint-migrations.js +1 -1
  50. package/dist/src/execution/session/handoff-steps.js +1 -1
  51. package/dist/src/execution/session/handoff.d.ts +1 -1
  52. package/dist/src/execution/session/handoff.js +1 -1
  53. package/dist/src/execution/session/input-queue.d.ts +13 -6
  54. package/dist/src/execution/session/input-queue.js +1 -1
  55. package/dist/src/execution/session/pending-turn-state.js +1 -1
  56. package/dist/src/execution/session/turn-step.js +1 -1
  57. package/dist/src/execution/session/turn.d.ts +5 -1
  58. package/dist/src/execution/session/turn.js +1 -1
  59. package/dist/src/execution/tasks/steps.d.ts +1 -1
  60. package/dist/src/execution/tasks/steps.js +1 -1
  61. package/dist/src/execution/tasks/task-id-input.js +1 -1
  62. package/dist/src/execution/tool-auth.js +1 -1
  63. package/dist/src/execution/tools/agent-router-workflow.js +1 -1
  64. package/dist/src/execution/tools/workflow/answer.d.ts +1 -1
  65. package/dist/src/execution/tools/workflow/apply-run-messages-step.d.ts +6 -2
  66. package/dist/src/execution/tools/workflow/apply-run-messages-step.js +1 -1
  67. package/dist/src/execution/tools/workflow/body.d.ts +10 -1
  68. package/dist/src/execution/tools/workflow/body.js +1 -1
  69. package/dist/src/execution/tools/workflow/owner-inbox.js +1 -1
  70. package/dist/src/execution/tools/workflow/serve.js +1 -1
  71. package/dist/src/execution/tools/workflow/withdraw-step.d.ts +2 -2
  72. package/dist/src/execution/tools/workflow/withdraw-step.js +1 -1
  73. package/dist/src/execution/workflow-callback-url.d.ts +10 -1
  74. package/dist/src/execution/workflow-callback-url.js +1 -1
  75. package/dist/src/harness/action-result-helpers.js +1 -1
  76. package/dist/src/harness/attachment-staging.js +1 -1
  77. package/dist/src/harness/authorization.d.ts +3 -13
  78. package/dist/src/harness/authorization.js +1 -1
  79. package/dist/src/harness/compaction/engine.js +3 -1
  80. package/dist/src/harness/compaction/prompt.d.ts +7 -0
  81. package/dist/src/harness/compaction/prompt.js +1 -1
  82. package/dist/src/harness/compaction/step.d.ts +1 -0
  83. package/dist/src/harness/compaction/step.js +1 -1
  84. package/dist/src/harness/coordination.js +1 -1
  85. package/dist/src/harness/hitl/approvals.d.ts +1 -1
  86. package/dist/src/harness/hitl/approvals.js +1 -1
  87. package/dist/src/harness/hitl/approved-calls.d.ts +3 -0
  88. package/dist/src/harness/hitl/approved-calls.js +1 -1
  89. package/dist/src/harness/hitl/candidates.d.ts +13 -0
  90. package/dist/src/harness/hitl/candidates.js +1 -1
  91. package/dist/src/harness/hitl/coordinator.js +1 -1
  92. package/dist/src/harness/hitl/index.d.ts +2 -5
  93. package/dist/src/harness/hitl/index.js +1 -1
  94. package/dist/src/harness/hitl/intake.js +1 -1
  95. package/dist/src/harness/{proxy-input-requests.d.ts → hitl/relays.d.ts} +3 -39
  96. package/dist/src/harness/hitl/relays.js +1 -0
  97. package/dist/src/harness/hitl/requests.d.ts +64 -0
  98. package/dist/src/harness/hitl/requests.js +1 -0
  99. package/dist/src/harness/hitl/sign-ins.d.ts +9 -0
  100. package/dist/src/harness/hitl/sign-ins.js +1 -0
  101. package/dist/src/harness/inline-tool-authorization.js +1 -1
  102. package/dist/src/harness/input-request-resolution.d.ts +2 -1
  103. package/dist/src/harness/input-request-resolution.js +1 -1
  104. package/dist/src/harness/model-call/call.js +1 -1
  105. package/dist/src/harness/model-call/model.d.ts +3 -1
  106. package/dist/src/harness/model-call/model.js +1 -1
  107. package/dist/src/harness/session-machine/commit.d.ts +14 -3
  108. package/dist/src/harness/session-machine/commit.js +1 -1
  109. package/dist/src/harness/session-machine/transitions.d.ts +16 -0
  110. package/dist/src/harness/session-machine/transitions.js +1 -1
  111. package/dist/src/instrumentation/native-events.js +1 -1
  112. package/dist/src/instrumentation/runtime.d.ts +1 -0
  113. package/dist/src/instrumentation/runtime.js +1 -1
  114. package/dist/src/internal/application/optional-package-import.d.ts +5 -0
  115. package/dist/src/internal/application/optional-package-import.js +1 -1
  116. package/dist/src/internal/application/stamped-package-version.js +1 -1
  117. package/dist/src/internal/authored-definition/source-identity.d.ts +6 -0
  118. package/dist/src/internal/authored-definition/source-identity.js +1 -1
  119. package/dist/src/internal/authored-module-map-loader.js +1 -1
  120. package/dist/src/internal/helpers/markdown.js +1 -1
  121. package/dist/src/internal/nitro/host/start-production-server.js +2 -2
  122. package/dist/src/internal/workflow/is-inactive-workflow-run-error.d.ts +2 -0
  123. package/dist/src/internal/workflow/is-inactive-workflow-run-error.js +1 -1
  124. package/dist/src/protocol/baggage.d.ts +1 -0
  125. package/dist/src/protocol/baggage.js +1 -1
  126. package/dist/src/protocol/message.d.ts +2 -0
  127. package/dist/src/protocol/message.js +1 -1
  128. package/dist/src/public/channels/teams/authorization.d.ts +53 -0
  129. package/dist/src/public/channels/teams/authorization.js +1 -0
  130. package/dist/src/public/channels/teams/defaults.js +2 -2
  131. package/dist/src/public/channels/teams/hitl.d.ts +2 -1
  132. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  133. package/dist/src/public/channels/telegram/authorization-callback.js +1 -1
  134. package/dist/src/public/definitions/connections/mcp.js +1 -1
  135. package/dist/src/public/definitions/connections/openapi.js +1 -1
  136. package/dist/src/public/next/index.js +1 -1
  137. package/dist/src/public/next/server.d.ts +11 -2
  138. package/dist/src/public/next/server.js +1 -1
  139. package/dist/src/public/sandbox/vercel.d.ts +2 -0
  140. package/dist/src/public/tools/index.d.ts +1 -1
  141. package/dist/src/public/tools/result.d.ts +10 -7
  142. package/dist/src/react/use-eve-agent.d.ts +6 -0
  143. package/dist/src/react/use-eve-agent.js +1 -1
  144. package/dist/src/runtime/authorization-context.d.ts +5 -0
  145. package/dist/src/runtime/authorization-context.js +1 -1
  146. package/dist/src/runtime/connections/mcp-tracing.js +1 -1
  147. package/dist/src/runtime/connections/openapi-operations.js +1 -1
  148. package/dist/src/runtime/connections/scoped-authorization.d.ts +6 -0
  149. package/dist/src/runtime/connections/scoped-authorization.js +1 -1
  150. package/dist/src/runtime/resolve-connection.js +1 -1
  151. package/dist/src/setup/scaffold/create/project.js +1 -1
  152. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  153. package/dist/src/setup/scaffold/create/web-template.js +18 -10
  154. package/dist/src/shared/action-types.d.ts +1 -0
  155. package/dist/src/shared/action-types.js +1 -1
  156. package/dist/src/shared/git.js +1 -1
  157. package/dist/src/shared/instrumentation-content.d.ts +1 -1
  158. package/dist/src/shared/instrumentation-content.js +1 -1
  159. package/dist/src/shared/instrumentation-decision.d.ts +3 -0
  160. package/dist/src/shared/instrumentation-decision.js +1 -1
  161. package/dist/src/shared/skill-package.js +1 -1
  162. package/dist/src/shared/trace-policy.js +1 -1
  163. package/dist/src/subagents/adapter.js +1 -1
  164. package/dist/src/subagents/event-proxy-step.d.ts +1 -1
  165. package/dist/src/subagents/event-proxy-step.js +1 -1
  166. package/dist/src/subagents/hitl-proxy.d.ts +1 -1
  167. package/dist/src/subagents/hitl-proxy.js +1 -1
  168. package/dist/src/svelte/index.js +1 -1
  169. package/dist/src/svelte/use-eve-agent.d.ts +6 -0
  170. package/dist/src/svelte/use-eve-agent.js +1 -1
  171. package/dist/src/tools/definition.d.ts +38 -1
  172. package/dist/src/tools/provided/ask-question-workflow.js +1 -1
  173. package/dist/src/tools/provided/sleep-workflow.js +1 -1
  174. package/dist/src/tools/signature.d.ts +4 -2
  175. package/dist/src/tools/signature.js +1 -1
  176. package/dist/src/tracing/eve/agent-otel-provider.js +1 -1
  177. package/dist/src/tracing/eve/gateway.d.ts +2 -1
  178. package/dist/src/tracing/eve/gateway.js +1 -1
  179. package/dist/src/tracing/eve/invoke-tool-span.js +1 -1
  180. package/dist/src/tracing/eve/otel-declaration.d.ts +9 -8
  181. package/dist/src/tracing/eve/policy.js +1 -1
  182. package/dist/src/vue/index.js +1 -1
  183. package/dist/src/vue/use-eve-agent.d.ts +6 -0
  184. package/dist/src/vue/use-eve-agent.js +1 -1
  185. package/docs/agent-config.md +48 -0
  186. package/docs/channels/eve.mdx +2 -0
  187. package/docs/channels/teams.mdx +6 -0
  188. package/docs/concepts/built-in-tools.md +1 -1
  189. package/docs/connections/overview.mdx +9 -6
  190. package/docs/guides/frontend/overview.mdx +10 -1
  191. package/docs/guides/hooks.md +6 -2
  192. package/docs/guides/instrumentation/instrumentation.mdx +2 -0
  193. package/docs/guides/instrumentation/otel.mdx +3 -0
  194. package/docs/reference/cli.md +1 -1
  195. package/docs/reference/typescript-api.md +7 -6
  196. package/docs/sandbox/vercel.mdx +9 -0
  197. package/docs/skills.mdx +1 -1
  198. package/docs/tools/human-in-the-loop.md +21 -0
  199. package/package.json +1 -1
  200. package/dist/src/compiled/_chunks/workflow/mcp-CrGp4EC8.js +0 -5
  201. package/dist/src/harness/proxy-input-requests.js +0 -1
@@ -1 +1,3 @@
1
- import{createFrameworkUserMessage,isFrameworkUserMessage}from"#harness/messages.js";import{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt,sliceUtf16Safe,stubContentOutputFileParts}from"#harness/compaction/prompt.js";import{estimateTokens}from"#harness/token-estimate.js";const COMPACTION_PROMPT_OVERHEAD_TOKENS=estimateTokens([{content:COMPACTION_PROMPT_ENVELOPE.system,role:`system`},createFrameworkUserMessage(`context.compaction`,COMPACTION_PROMPT_ENVELOPE.prompt)]);function getInputTokenCount(e,t,n=0,r=0){let i=t.lastKnownInputTokens,a=t.lastKnownPromptMessageCount;return i===void 0||a===void 0||!Number.isInteger(a)||a<0||a>e.length?estimateTokens(e)+n:i+estimateTokens(e.slice(a))+Math.max(0,n-r)}function shouldCompact(e,t,n=0,r=0){return e.length>0&&getInputTokenCount(e,t,n,r)+COMPACTION_PROMPT_OVERHEAD_TOKENS>t.threshold}const COMPACTION_HEURISTICS=[toolResultCapHeuristic];function toolResultCapHeuristic(e){let t=withResumptionGuard([...e.previousCheckpoint===void 0?[]:[createFrameworkUserMessage(`context.compaction`,COMPACTION_CHECKPOINT_MARKER),{content:e.previousCheckpoint,role:`assistant`}],...capToolResults(e.older),...e.recent],e.conversation,e.config.threshold);return evaluateThreshold(t,e.config,`should-compact`,e.tokenEstimateAdjustment).type===`within-limit`?{messages:t,type:`within-limit`}:{type:`insufficient`}}function evaluateThreshold(e,t,n,r=0){let i=n===`should-compact`?COMPACTION_PROMPT_OVERHEAD_TOKENS:0,a=estimateTokens(e)+i+r;return{estimatedTokens:a,type:a<=t.threshold?`within-limit`:`over-limit`}}async function compactMessages(e,t,n,r=!1,i){let{conversation:a,previousCheckpoint:o}=extractPreviousCheckpoint(e),s=selectRecentWindowSize(a,r?{...t,recentWindowSize:1}:t);if(!r){let{older:n,recent:r}=splitMessagesForCompaction(a,s);if(n.length===0&&o===void 0)return keepNonToolResultMessages(r);let c=Math.max(0,(i??getInputTokenCount(e,t))-estimateTokens(e));for(let e of COMPACTION_HEURISTICS){let i=e({config:t,conversation:a,older:n,previousCheckpoint:o,recent:r,tokenEstimateAdjustment:c});if(i.type===`within-limit`)return i.messages}}for(;;){let{older:e,recent:r}=splitMessagesForCompaction(a,s),i=createCompactionPrompt({messages:e,previousCheckpoint:o,transcriptBudgetTokens:t.threshold}),c=await n({messages:[createFrameworkUserMessage(`context.compaction`,i.prompt)],system:i.system}),l=[createFrameworkUserMessage(`context.compaction`,COMPACTION_CHECKPOINT_MARKER),{content:c,role:`assistant`}],u=withResumptionGuard([...l,...r],a,t.threshold);if(evaluateThreshold(u,t,`estimate`).type===`within-limit`)return u;let d=withResumptionGuard([...l,...keepNonToolResultMessages(r)],a,t.threshold);if(evaluateThreshold(d,t,`estimate`).type===`within-limit`||s===0)return d;--s}}function capToolResults(e){return e.map(e=>{if(e.role!==`tool`||typeof e.content==`string`)return e;let t=!1,n=e.content.map(e=>{if(e.type!==`tool-result`)return e;let n=stubContentOutputFileParts(e.output),r=JSON.stringify(n)??``;return r.length<=TRANSCRIPT_PAYLOAD_LIMIT?n===e.output?e:(t=!0,{...e,output:n}):(t=!0,{...e,output:{type:`text`,value:`[Truncated by eve: tool result reduced during context compaction. Re-run the tool if you need the full output.]\n\n${sliceUtf16Safe(r,TRANSCRIPT_PAYLOAD_LIMIT)}`}})});return t?{...e,content:n}:e})}function withResumptionGuard(e,t,n){let r=e.at(-1)?.role,i=findLastRealUserMessage(t),a=i!==void 0&&e.some(e=>e.role===`user`&&e.content===i.content);return r!==void 0&&r!==`assistant`?r===`tool`&&i!==void 0&&!a&&estimateTokens([i])<=n?[...e,i]:e:[...e,i!==void 0&&!a?i:createFrameworkUserMessage(`execution.continuation`,COMPACTION_RESUMPTION_MESSAGE)]}function findLastRealUserMessage(e){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n?.role===`user`&&typeof n.content==`string`&&!isFrameworkUserMessage(n))return n}}function extractPreviousCheckpoint(e){let t=e[0],n=e[1];return t?.role!==`user`||t.content!==COMPACTION_CHECKPOINT_MARKER||n?.role!==`assistant`?{conversation:[...e],previousCheckpoint:void 0}:{conversation:e.slice(2),previousCheckpoint:assistantMessageText(n)}}function keepNonToolResultMessages(e){let t=[];for(let n of e)if(n.role!==`tool`){if(n.role===`assistant`){let e=assistantMessageText(n);e.length>0&&t.push({content:e,role:`assistant`});continue}t.push(n)}return t}function assistantMessageText(e){return typeof e.content==`string`?e.content.trim():e.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}function selectRecentWindowSize(e,t){let n=Math.min(t.recentWindowSize,Math.max(e.length-1,0)),r=resolveCompactionSummaryReserve(t),i=0,a=0;for(let o=e.length-1;o>=0&&i<n;--o){let n=e[o];if(n===void 0)continue;let s=estimateTokens([n]);if(a+s+r>t.threshold)break;a+=s,i+=1}return i}function resolveCompactionSummaryReserve(e){return Math.min(2048,Math.max(64,Math.floor(e.threshold/4)))}function splitMessagesForCompaction(e,t){if(t<=0)return{older:[...e],recent:[]};let n=e.length-t;for(;n<e.length&&e[n]?.role===`tool`;)n+=1;return{older:e.slice(0,n),recent:e.slice(n)}}export{compactMessages,getInputTokenCount,shouldCompact};
1
+ import{createFrameworkUserMessage,isFrameworkUserMessage}from"#harness/messages.js";import{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt,serializeToolResultOutput,sliceUtf16Safe,stubContentOutputFileParts}from"#harness/compaction/prompt.js";import{estimateTokens}from"#harness/token-estimate.js";const COMPACTION_PROMPT_OVERHEAD_TOKENS=estimateTokens([{content:COMPACTION_PROMPT_ENVELOPE.system,role:`system`},createFrameworkUserMessage(`context.compaction`,COMPACTION_PROMPT_ENVELOPE.prompt)]);function getInputTokenCount(e,t,n=0,r=0){let i=t.lastKnownInputTokens,a=t.lastKnownPromptMessageCount;return i===void 0||a===void 0||!Number.isInteger(a)||a<0||a>e.length?estimateTokens(e)+n:i+estimateTokens(e.slice(a))+Math.max(0,n-r)}function shouldCompact(e,t,n=0,r=0){return e.length>0&&getInputTokenCount(e,t,n,r)+COMPACTION_PROMPT_OVERHEAD_TOKENS>t.threshold}const COMPACTION_HEURISTICS=[toolResultCapHeuristic];function toolResultCapHeuristic(e){let t=withResumptionGuard([...e.previousCheckpoint===void 0?[]:[createFrameworkUserMessage(`context.compaction`,COMPACTION_CHECKPOINT_MARKER),{content:e.previousCheckpoint,role:`assistant`}],...capToolResults(e.older),...e.recent],e.conversation,e.config.threshold);return evaluateThreshold(t,e.config,`should-compact`,e.tokenEstimateAdjustment).type===`within-limit`?{messages:t,type:`within-limit`}:{type:`insufficient`}}function evaluateThreshold(e,t,n,r=0){let i=n===`should-compact`?COMPACTION_PROMPT_OVERHEAD_TOKENS:0,a=estimateTokens(e)+i+r;return{estimatedTokens:a,type:a<=t.threshold?`within-limit`:`over-limit`}}async function compactMessages(e,t,n,r=!1,i){let{conversation:a,previousCheckpoint:o}=extractPreviousCheckpoint(e),s=selectRecentWindowSize(a,r?{...t,recentWindowSize:1}:t);if(!r){let{older:n,recent:r}=splitMessagesForCompaction(a,s);if(n.length===0&&o===void 0)return keepNonToolResultMessages(r);let c=Math.max(0,(i??getInputTokenCount(e,t))-estimateTokens(e));for(let e of COMPACTION_HEURISTICS){let i=e({config:t,conversation:a,older:n,previousCheckpoint:o,recent:r,tokenEstimateAdjustment:c});if(i.type===`within-limit`)return i.messages}}for(;;){let{older:e,recent:r}=splitMessagesForCompaction(a,s),i=createCompactionPrompt({messages:e,previousCheckpoint:o,transcriptBudgetTokens:t.threshold}),c=await n({messages:[createFrameworkUserMessage(`context.compaction`,i.prompt)],system:i.system}),l=[createFrameworkUserMessage(`context.compaction`,COMPACTION_CHECKPOINT_MARKER),{content:c,role:`assistant`}],u=withResumptionGuard([...l,...r],a,t.threshold);if(evaluateThreshold(u,t,`estimate`).type===`within-limit`)return u;let d=withResumptionGuard([...l,...keepNonToolResultMessages(r)],a,t.threshold);if(evaluateThreshold(d,t,`estimate`).type===`within-limit`||s===0)return d;--s}}function capToolResults(e){return e.map(e=>{if(e.role!==`tool`||typeof e.content==`string`)return e;let t=!1,n=e.content.map(e=>{if(e.type!==`tool-result`)return e;let n=stubContentOutputFileParts(e.output),r=serializeToolResultOutput(n);return r.length<=TRANSCRIPT_PAYLOAD_LIMIT?n===e.output?e:(t=!0,{...e,output:n}):(t=!0,{...e,output:{type:`text`,value:`[Truncated by eve: tool result reduced during context compaction. Re-run the tool if you need the full output.]
2
+
3
+ ${sliceUtf16Safe(r,TRANSCRIPT_PAYLOAD_LIMIT-113)}`}})});return t?{...e,content:n}:e})}function withResumptionGuard(e,t,n){let r=e.at(-1)?.role,i=findLastRealUserMessage(t),a=i!==void 0&&e.some(e=>e.role===`user`&&e.content===i.content);return r!==void 0&&r!==`assistant`?r===`tool`&&i!==void 0&&!a&&estimateTokens([i])<=n?[...e,i]:e:[...e,i!==void 0&&!a?i:createFrameworkUserMessage(`execution.continuation`,COMPACTION_RESUMPTION_MESSAGE)]}function findLastRealUserMessage(e){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n?.role===`user`&&typeof n.content==`string`&&!isFrameworkUserMessage(n))return n}}function extractPreviousCheckpoint(e){let t=e[0],n=e[1];return t?.role!==`user`||t.content!==COMPACTION_CHECKPOINT_MARKER||n?.role!==`assistant`?{conversation:[...e],previousCheckpoint:void 0}:{conversation:e.slice(2),previousCheckpoint:assistantMessageText(n)}}function keepNonToolResultMessages(e){let t=[];for(let n of e)if(n.role!==`tool`){if(n.role===`assistant`){let e=assistantMessageText(n);e.length>0&&t.push({content:e,role:`assistant`});continue}t.push(n)}return t}function assistantMessageText(e){return typeof e.content==`string`?e.content.trim():e.content.filter(e=>e.type===`text`).map(e=>e.text).join(``).trim()}function selectRecentWindowSize(e,t){let n=Math.min(t.recentWindowSize,Math.max(e.length-1,0)),r=resolveCompactionSummaryReserve(t),i=0,a=0;for(let o=e.length-1;o>=0&&i<n;--o){let n=e[o];if(n===void 0)continue;let s=estimateTokens([n]);if(a+s+r>t.threshold)break;a+=s,i+=1}return i}function resolveCompactionSummaryReserve(e){return Math.min(2048,Math.max(64,Math.floor(e.threshold/4)))}function splitMessagesForCompaction(e,t){if(t<=0)return{older:[...e],recent:[]};let n=e.length-t;for(;n<e.length&&e[n]?.role===`tool`;)n+=1;return{older:e.slice(0,n),recent:e.slice(n)}}export{compactMessages,getInputTokenCount,shouldCompact};
@@ -26,6 +26,13 @@ export declare function createCompactionPrompt(input: {
26
26
  readonly transcriptBudgetTokens?: number;
27
27
  }): CompactionPrompt;
28
28
  export declare const TRANSCRIPT_PAYLOAD_LIMIT = 2000;
29
+ /**
30
+ * The text a tool-result output is measured and clipped by, in history
31
+ * capping and in the summarizer transcript alike: a text output is its
32
+ * value, any other output its JSON. Sharing it keeps a capped history
33
+ * result whole when the summarizer renders it.
34
+ */
35
+ export declare function serializeToolResultOutput(output: unknown): string;
29
36
  /**
30
37
  * Replaces the file parts of a `content` tool output with their text stubs,
31
38
  * leaving every other output shape untouched. History capping uses this so a
@@ -23,4 +23,4 @@ Make completed work explicit so the next model does not repeat it. Keep complete
23
23
  Large tool outputs are the main thing to compress: reduce each to the findings the next model needs — what was searched or read, what it established, and the exact identifiers involved — rather than reproducing the output. The next model cannot see the originals, so nothing it would need to act on may be lost.`}function formatCompactionTranscript(e){let t=e.filter(e=>e.content.trim().length>0).map(e=>`### ${e.role}\n${e.content.trim()}`);return t.length===0?`(empty)`:t.join(`
24
24
 
25
25
  `)}function renderCompactionMessageContent(e,t){return typeof e.content==`string`?renderConversationText(e.content,t):e.content.map(e=>renderCompactionContentPart(e,t)).filter(e=>e.length>0).join(`
26
- `).trim()}function renderCompactionContentPart(e,t){switch(e.type){case`text`:return renderConversationText(e.text,t);case`reasoning`:return``;case`file`:return renderAttachedFileStub(e.filename,e.mediaType);case`tool-call`:return renderTranscriptToolCall(e,t);case`tool-result`:return renderTranscriptToolResult(e,t);default:return``}}const TRANSCRIPT_PAYLOAD_LIMIT=2e3;function renderTranscriptToolCall(e,t){return renderToolCall(e,t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280)}function renderTranscriptToolResult(e,t){let n=t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280,r=e.isError?`errored`:`returned`,i=renderToolResultOutput(e.output,n);return i?`Tool ${e.toolName} ${r} ${i}`:`Tool ${e.toolName} ${r}`}function renderToolResultOutput(e,t){let n=contentToolOutputParts(e);return n===void 0?renderPayload(e,t):capText(n.map(e=>renderContentToolOutputPart(e,t)).filter(e=>e.length>0).join(` `),t)}function contentToolOutputParts(e){if(typeof e!=`object`||!e)return;let t=e;return t.type===`content`&&Array.isArray(t.value)?t.value:void 0}function stubContentOutputFileParts(e){let t=contentToolOutputParts(e);if(t===void 0)return e;let n=!1,r=t.map(e=>{if(typeof e!=`object`||!e)return e;let t=e;return t.type!==`file`&&t.type!==`media`?e:(n=!0,{text:renderAttachedFileStub(contentFileName(e),typeof t.mediaType==`string`?t.mediaType:`unknown`),type:`text`})});return n?{type:`content`,value:r}:e}function renderContentToolOutputPart(e,t){if(typeof e!=`object`||!e)return renderPayload(e,t);let n=e;return n.type===`text`&&typeof n.text==`string`?n.text:n.type===`file`||n.type===`media`?renderAttachedFileStub(contentFileName(e),typeof n.mediaType==`string`?n.mediaType:`unknown`):renderPayload(e,t)}function contentFileName(e){let{data:t,filename:n}=e,r=t;return r?.type===`url`&&isSandboxRefUrl(r.url)?decodeSandboxRef(r.url).path:typeof n==`string`?n:void 0}function renderToolCall(e,t){let n=renderPayload(e.input,t);return n?`Called ${e.toolName} with ${n}`:`Called ${e.toolName}`}function renderPayload(e,t){return e===void 0?``:capText(JSON.stringify(e)??``,t)}function renderAttachedFileStub(e,t){return`Attached file ${e??`attachment`} (${t})`}function renderConversationText(e,t){return t===void 0?e.trim():capText(e,t)}function sliceUtf16Safe(e,t){if(t<=0)return``;if(e.length<=t)return e;let n=t,r=e.charCodeAt(n-1);return r>=55296&&r<=56319&&--n,e.slice(0,n)}function capText(e,t){let n=e.replace(/\s+/g,` `).trim();return n.length<=t?n:`${sliceUtf16Safe(n,t).trimEnd()}…`}export{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt,sliceUtf16Safe,stubContentOutputFileParts};
26
+ `).trim()}function renderCompactionContentPart(e,t){switch(e.type){case`text`:return renderConversationText(e.text,t);case`reasoning`:return``;case`file`:return renderAttachedFileStub(e.filename,e.mediaType);case`tool-call`:return renderTranscriptToolCall(e,t);case`tool-result`:return renderTranscriptToolResult(e,t);default:return``}}const TRANSCRIPT_PAYLOAD_LIMIT=2e3;function renderTranscriptToolCall(e,t){return renderToolCall(e,t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280)}function renderTranscriptToolResult(e,t){let n=t===void 0?TRANSCRIPT_PAYLOAD_LIMIT:280,r=e.isError?`errored`:`returned`,i=renderToolResultOutput(e.output,n);return i?`Tool ${e.toolName} ${r} ${i}`:`Tool ${e.toolName} ${r}`}function renderToolResultOutput(e,t){let n=contentToolOutputParts(e);return capText(n===void 0?serializeToolResultOutput(e):n.map(e=>renderContentToolOutputPart(e,t)).filter(e=>e.length>0).join(` `),t)}function serializeToolResultOutput(e){if(typeof e==`object`&&e){let t=e;if(t.type===`text`&&typeof t.value==`string`)return t.value}return JSON.stringify(e)??``}function contentToolOutputParts(e){if(typeof e!=`object`||!e)return;let t=e;return t.type===`content`&&Array.isArray(t.value)?t.value:void 0}function stubContentOutputFileParts(e){let t=contentToolOutputParts(e);if(t===void 0)return e;let n=!1,r=t.map(e=>{if(typeof e!=`object`||!e)return e;let t=e;return t.type!==`file`&&t.type!==`media`?e:(n=!0,{text:renderAttachedFileStub(contentFileName(e),typeof t.mediaType==`string`?t.mediaType:`unknown`),type:`text`})});return n?{type:`content`,value:r}:e}function renderContentToolOutputPart(e,t){if(typeof e!=`object`||!e)return renderPayload(e,t);let n=e;return n.type===`text`&&typeof n.text==`string`?n.text:n.type===`file`||n.type===`media`?renderAttachedFileStub(contentFileName(e),typeof n.mediaType==`string`?n.mediaType:`unknown`):renderPayload(e,t)}function contentFileName(e){let{data:t,filename:n}=e,r=t;return r?.type===`url`&&isSandboxRefUrl(r.url)?decodeSandboxRef(r.url).path:typeof n==`string`?n:void 0}function renderToolCall(e,t){let n=renderPayload(e.input,t);return n?`Called ${e.toolName} with ${n}`:`Called ${e.toolName}`}function renderPayload(e,t){return e===void 0?``:capText(JSON.stringify(e)??``,t)}function renderAttachedFileStub(e,t){return`Attached file ${e??`attachment`} (${t})`}function renderConversationText(e,t){return t===void 0?e.trim():capText(e,t)}function sliceUtf16Safe(e,t){if(t<=0)return``;if(e.length<=t)return e;let n=t,r=e.charCodeAt(n-1);return r>=55296&&r<=56319&&--n,e.slice(0,n)}function capText(e,t){let n=e.replace(/\s+/g,` `).trim();return n.length<=t?n:`${sliceUtf16Safe(n,t).trimEnd()}…`}export{COMPACTION_CHECKPOINT_MARKER,COMPACTION_PROMPT_ENVELOPE,COMPACTION_RESUMPTION_MESSAGE,TRANSCRIPT_PAYLOAD_LIMIT,createCompactionPrompt,serializeToolResultOutput,sliceUtf16Safe,stubContentOutputFileParts};
@@ -41,6 +41,7 @@ export declare function maybeCompact(input: {
41
41
  readonly runtimeIdentity?: ToolLoopHarnessConfig["runtimeIdentity"];
42
42
  readonly session: HarnessSession;
43
43
  readonly telemetry?: TelemetryOptions;
44
+ readonly traceContextHeaders?: () => Record<string, string> | undefined;
44
45
  }): Promise<{
45
46
  readonly compacted: boolean;
46
47
  /** The summary failed; `session` still counts the summary calls that finished. */
@@ -1 +1 @@
1
- import{streamText}from"ai";import{createLogger,logError}from"#internal/logging.js";import{contextStorage}from"#context/container.js";import{AuthKey,HistoryStateKey}from"#context/keys.js";import{createCompactionCompletedEvent,createCompactionRequestedEvent}from"#protocol/message.js";import{isUserModelMessage,validateHarnessModelMessages}from"#harness/messages.js";import{drainMemoryCommit,prepareMemoryCompaction}from"#context/memory-lifecycle.js";import{canonicalizeMemoryRecords,shouldCanonicalizeMemory}from"#shared/memory-state.js";import{activeTurnId}from"#harness/session-machine/view.js";import{addTurnUsage,addUsageOutsideTurns}from"#harness/turn-tag-state.js";import{idle}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{requireSessionModelReference}from"#harness/types.js";import{buildGatewayAttributionHeaders,resolveEffectiveRuntimeModel}from"#harness/model-call/model.js";import{compactMessages,getInputTokenCount,shouldCompact}from"#harness/compaction/engine.js";import{normalizeModelStreamError}from"#harness/model-call/errors.js";import{runModelCallWithRetries}from"#harness/model-call/retry.js";import{extractGatewayCostUsd,extractTokenUsageDelta,gatewayModelId}from"#harness/model-call/usage.js";import{resolveModelProfile}from"#harness/model-profile.js";import{getRequestEnvelopeTokens}from"#harness/request-envelope.js";import{resolveCallProviderOptions}from"#harness/provider-safety.js";const log=createLogger(`harness.tool-loop`);async function compactHistory(e){let{config:t}=e;if(e.session.history.length>0)try{if(e.ctx!==void 0&&t.dispatchDynamicModelEvent!==void 0){let n=e.position();await t.dispatchDynamicModelEvent({ctx:e.ctx,event:stepStartedForResolvers({modelId:e.session.agent.modelReference?.id??`dynamic`,sequence:n.sequence,stepIndex:n.stepIndex,turnId:activeTurnId(n)}),messages:validateHarnessModelMessages(e.projectHistory(e.session.history))})}let n=await resolveEffectiveRuntimeModel({config:t,ctx:e.ctx,session:e.session});e.session=n.session;let r=e.position(),i=await maybeCompact({abortSignal:t.abortSignal,auth:e.ctx?.get(AuthKey)??null,betweenTurns:!0,emissionState:{...r,turnId:activeTurnId(r)},force:!0,historyProjector:t.historyProjector,messages:[...e.session.history],model:n.model,publish:e.publish,requestEnvelopeTokens:getRequestEnvelopeTokens(e.session),resolveModel:t.resolveModel,runtimeIdentity:t.runtimeIdentity,session:e.session,telemetry:e.instrumentation?.telemetry()});if(e.session=i.session,i.failure!==void 0)throw i.failure.error}catch(t){logError(log,`manual session compaction failed`,t,{sessionId:e.session.sessionId})}return await e.apply(idle(e.view())),{next:null,session:e.session}}function replaceSessionHistory(e,t){return contextStorage.getStore()?.delete(HistoryStateKey),{...e,history:t,compaction:{recentWindowSize:e.compaction.recentWindowSize,threshold:e.compaction.threshold,thresholdPercent:e.compaction.thresholdPercent}}}async function maybeCompact(e){let{emissionState:t,publish:n}=e,r=e.messages,i=e.session,a=e.promptMessages??r,o=validateHarnessModelMessages(e.historyProjector?.({messages:a,state:i.state})??a),s=e.force===!0||shouldCompact(o,i.compaction,e.requestEnvelopeTokens,getRequestEnvelopeTokens(i)),c=shouldCanonicalizeMemory(r);if(!s&&!c)return{compacted:!1,messages:r,session:i};let l=requireSessionModelReference(i),u=i.agent.compactionModelReference??l,d=u===l?e.model:await e.resolveModel(u),f=resolveModelProfile(d),p=resolveCallProviderOptions({auth:e.auth,profile:f,providerOptions:u.providerOptions,session:i}),m={abortSignal:e.abortSignal,headers:buildGatewayAttributionHeaders(f,e.runtimeIdentity),model:d,providerOptions:p,telemetry:e.telemetry&&{...e.telemetry,functionId:`eve.compaction`}},h=[],summarize=async n=>{let r=await runModelCallWithRetries(()=>streamCompactionSummary({...m,...n}),{sessionId:i.sessionId,turnId:t.turnId},e.abortSignal);if(h.push(r.usage),r.text.trim().length===0)throw Error(`The compaction model returned an empty summary. Finish reason: ${r.finishReason}.`);return r.text};{let a=contextStorage.getStore();a!==void 0&&prepareMemoryCompaction(a,{history:r,state:i.state}),await n(createCompactionRequestedEvent({modelId:gatewayModelId(d)??`unknown`,sequence:t.sequence,sessionId:i.sessionId,stepIndex:t.stepIndex,turnId:t.turnId,usageInputTokens:getInputTokenCount(o,i.compaction,e.requestEnvelopeTokens,getRequestEnvelopeTokens(i))}),o)}let g=canonicalizeMemoryRecords(r),_=validateHarnessModelMessages(e.historyProjector?.({messages:g.ordinary,state:i.state})??g.ordinary),v=e.requestEnvelopeTokens??0,y={...i.compaction,threshold:Math.max(1,i.compaction.threshold-v),lastKnownInputTokens:i.compaction.lastKnownInputTokens===void 0?void 0:Math.max(0,i.compaction.lastKnownInputTokens-Math.min(getRequestEnvelopeTokens(i)??0,v))},b=[..._],x;try{s&&(b=await compactMessages([..._],y,summarize,e.force===!0,e.requestEnvelopeTokens===void 0?void 0:Math.max(0,getInputTokenCount(o,i.compaction,v,getRequestEnvelopeTokens(i))-v)))}catch(e){x={error:e}}for(let n of h)i=e.betweenTurns===!0?addUsageOutsideTurns(i,n):addTurnUsage(i,t.turnId,n);if(x!==void 0)return{compacted:!1,failure:x,messages:e.messages,session:i};r=validateHarnessModelMessages([...g.memory,...b]);{let a=contextStorage.getStore();if(a!==void 0&&prepareMemoryCompaction(a,{history:r,state:i.state}),await n(createCompactionCompletedEvent({modelId:gatewayModelId(d)??`unknown`,sequence:t.sequence,sessionId:i.sessionId,stepIndex:t.stepIndex,turnId:t.turnId}),e.historyProjector?.({messages:r,state:i.state})??r),a!==void 0){let t=drainMemoryCommit(a);t!==void 0&&(r=validateHarnessModelMessages(placeRecalledMemory(r,t.recalledMessages,e.betweenTurns===!0)),i={...i,state:t.state})}}return{compacted:!0,messages:r,session:replaceSessionHistory(i,r)}}function placeRecalledMemory(e,t,n){let r=n?-1:e.findLastIndex(e=>isUserModelMessage(e)&&e.kind===`user`);return r===-1?[...e,...t]:[...e.slice(0,r),...t,...e.slice(r)]}async function streamCompactionSummary(e){let t=streamText({...e,onError:()=>{}});for await(let e of t.fullStream)if(e.type===`error`)throw normalizeModelStreamError(e.error);let[n,r,i,a]=await Promise.all([t.text,t.finishReason,t.usage,t.providerMetadata]);return{finishReason:r,text:n,usage:extractTokenUsageDelta({costUsd:extractGatewayCostUsd(a),usage:i})}}export{compactHistory,maybeCompact,replaceSessionHistory};
1
+ import{streamText}from"ai";import{createLogger,logError}from"#internal/logging.js";import{contextStorage}from"#context/container.js";import{AuthKey,HistoryStateKey}from"#context/keys.js";import{createCompactionCompletedEvent,createCompactionRequestedEvent}from"#protocol/message.js";import{isUserModelMessage,validateHarnessModelMessages}from"#harness/messages.js";import{drainMemoryCommit,prepareMemoryCompaction}from"#context/memory-lifecycle.js";import{canonicalizeMemoryRecords,shouldCanonicalizeMemory}from"#shared/memory-state.js";import{activeTurnId}from"#harness/session-machine/view.js";import{addTurnUsage,addUsageOutsideTurns}from"#harness/turn-tag-state.js";import{idle}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{requireSessionModelReference}from"#harness/types.js";import{buildGatewayAttributionHeaders,resolveEffectiveRuntimeModel,withGatewayTraceContext}from"#harness/model-call/model.js";import{compactMessages,getInputTokenCount,shouldCompact}from"#harness/compaction/engine.js";import{normalizeModelStreamError}from"#harness/model-call/errors.js";import{runModelCallWithRetries}from"#harness/model-call/retry.js";import{extractGatewayCostUsd,extractTokenUsageDelta,gatewayModelId}from"#harness/model-call/usage.js";import{resolveModelProfile}from"#harness/model-profile.js";import{getRequestEnvelopeTokens}from"#harness/request-envelope.js";import{resolveCallProviderOptions}from"#harness/provider-safety.js";const log=createLogger(`harness.tool-loop`);async function compactHistory(e){let{config:t}=e;if(e.session.history.length>0)try{if(e.ctx!==void 0&&t.dispatchDynamicModelEvent!==void 0){let n=e.position();await t.dispatchDynamicModelEvent({ctx:e.ctx,event:stepStartedForResolvers({modelId:e.session.agent.modelReference?.id??`dynamic`,sequence:n.sequence,stepIndex:n.stepIndex,turnId:activeTurnId(n)}),messages:validateHarnessModelMessages(e.projectHistory(e.session.history))})}let n=await resolveEffectiveRuntimeModel({config:t,ctx:e.ctx,session:e.session});e.session=n.session;let r=e.position(),i=await maybeCompact({abortSignal:t.abortSignal,auth:e.ctx?.get(AuthKey)??null,betweenTurns:!0,emissionState:{...r,turnId:activeTurnId(r)},force:!0,historyProjector:t.historyProjector,messages:[...e.session.history],model:n.model,publish:e.publish,requestEnvelopeTokens:getRequestEnvelopeTokens(e.session),resolveModel:t.resolveModel,runtimeIdentity:t.runtimeIdentity,session:e.session,telemetry:e.instrumentation?.telemetry(),traceContextHeaders:e.instrumentation?.gatewayTraceContextHeaders});if(e.session=i.session,i.failure!==void 0)throw i.failure.error}catch(t){logError(log,`manual session compaction failed`,t,{sessionId:e.session.sessionId})}return await e.apply(idle(e.view())),{next:null,session:e.session}}function replaceSessionHistory(e,t){return contextStorage.getStore()?.delete(HistoryStateKey),{...e,history:t,compaction:{recentWindowSize:e.compaction.recentWindowSize,threshold:e.compaction.threshold,thresholdPercent:e.compaction.thresholdPercent}}}async function maybeCompact(e){let{emissionState:t,publish:n}=e,r=e.messages,i=e.session,a=e.promptMessages??r,o=validateHarnessModelMessages(e.historyProjector?.({messages:a,state:i.state})??a),s=e.force===!0||shouldCompact(o,i.compaction,e.requestEnvelopeTokens,getRequestEnvelopeTokens(i)),c=shouldCanonicalizeMemory(r);if(!s&&!c)return{compacted:!1,messages:r,session:i};let l=requireSessionModelReference(i),u=i.agent.compactionModelReference??l,d=u===l?e.model:await e.resolveModel(u),f=resolveModelProfile(d),p=resolveCallProviderOptions({auth:e.auth,profile:f,providerOptions:u.providerOptions,session:i}),m={abortSignal:e.abortSignal,headers:buildGatewayAttributionHeaders(f,e.runtimeIdentity),model:withGatewayTraceContext(d,f,e.traceContextHeaders),providerOptions:p,telemetry:e.telemetry&&{...e.telemetry,functionId:`eve.compaction`}},h=[],summarize=async n=>{let r=await runModelCallWithRetries(()=>streamCompactionSummary({...m,...n}),{sessionId:i.sessionId,turnId:t.turnId},e.abortSignal);if(h.push(r.usage),r.text.trim().length===0)throw Error(`The compaction model returned an empty summary. Finish reason: ${r.finishReason}.`);return r.text};{let a=contextStorage.getStore();a!==void 0&&prepareMemoryCompaction(a,{history:r,state:i.state}),await n(createCompactionRequestedEvent({modelId:gatewayModelId(d)??`unknown`,sequence:t.sequence,sessionId:i.sessionId,stepIndex:t.stepIndex,turnId:t.turnId,usageInputTokens:getInputTokenCount(o,i.compaction,e.requestEnvelopeTokens,getRequestEnvelopeTokens(i))}),o)}let g=canonicalizeMemoryRecords(r),_=validateHarnessModelMessages(e.historyProjector?.({messages:g.ordinary,state:i.state})??g.ordinary),v=e.requestEnvelopeTokens??0,y={...i.compaction,threshold:Math.max(1,i.compaction.threshold-v),lastKnownInputTokens:i.compaction.lastKnownInputTokens===void 0?void 0:Math.max(0,i.compaction.lastKnownInputTokens-Math.min(getRequestEnvelopeTokens(i)??0,v))},b=[..._],x;try{s&&(b=await compactMessages([..._],y,summarize,e.force===!0,e.requestEnvelopeTokens===void 0?void 0:Math.max(0,getInputTokenCount(o,i.compaction,v,getRequestEnvelopeTokens(i))-v)))}catch(e){x={error:e}}for(let n of h)i=e.betweenTurns===!0?addUsageOutsideTurns(i,n):addTurnUsage(i,t.turnId,n);if(x!==void 0)return{compacted:!1,failure:x,messages:e.messages,session:i};r=validateHarnessModelMessages([...g.memory,...b]);{let a=contextStorage.getStore();if(a!==void 0&&prepareMemoryCompaction(a,{history:r,state:i.state}),await n(createCompactionCompletedEvent({modelId:gatewayModelId(d)??`unknown`,sequence:t.sequence,sessionId:i.sessionId,stepIndex:t.stepIndex,turnId:t.turnId}),e.historyProjector?.({messages:r,state:i.state})??r),a!==void 0){let t=drainMemoryCommit(a);t!==void 0&&(r=validateHarnessModelMessages(placeRecalledMemory(r,t.recalledMessages,e.betweenTurns===!0)),i={...i,state:t.state})}}return{compacted:!0,messages:r,session:replaceSessionHistory(i,r)}}function placeRecalledMemory(e,t,n){let r=n?-1:e.findLastIndex(e=>isUserModelMessage(e)&&e.kind===`user`);return r===-1?[...e,...t]:[...e.slice(0,r),...t,...e.slice(r)]}async function streamCompactionSummary(e){let t=streamText({...e,onError:()=>{}});for await(let e of t.fullStream)if(e.type===`error`)throw normalizeModelStreamError(e.error);let[n,r,i,a]=await Promise.all([t.text,t.finishReason,t.usage,t.providerMetadata]);return{finishReason:r,text:n,usage:extractTokenUsageDelta({costUsd:extractGatewayCostUsd(a),usage:i})}}export{compactHistory,maybeCompact,replaceSessionHistory};
@@ -1 +1 @@
1
- import{skillTarget}from"#shared/action-request-name.js";import{SKILL_ENTRY_NAME,SKILL_TOOL_NAME}from"#protocol/catalog-tools.js";import{parseJsonObject}from"#shared/json.js";import{findBlockingWorkflowToolRun,removeBlockingWorkflowToolRuns}from"#harness/workflow-tool-runs.js";import{startsTasks}from"#execution/tasks/tool-entry-point.js";import{commitCallEntry,isTaskTool}from"#execution/tasks/model-step.js";import{getProxyInputRequests}from"#harness/proxy-input-requests.js";import{normalizeToolModelOutput}from"#harness/tool-model-output.js";import{observeToolOutput}from"#tool-stubs/execute.js";import{markRuntimeWorkflowToolAction}from"#shared/action-types.js";function assertUniqueCoordinationCallIds(e){let t=new Set;for(let n of e){if(t.has(n.callId))throw Error(`Coordination batch contains duplicate callId "${n.callId}".`);t.add(n.callId)}}function forgetFinishedRuns(e,t,n){let r=e,i=[];for(let e of t){if(e.kind!==`tool-result`)continue;let t=findBlockingWorkflowToolRun(r.state,e.callId,n);if(t!==void 0){for(let[e,n]of getProxyInputRequests(r.state))n.runId===t.address.runId&&i.push(e);r=removeBlockingWorkflowToolRuns(r,n,t.callId)}}return{requestIds:i,session:r}}async function runtimeResultCalls(e,t){let n=[];for(let r of e){switch(r.kind){case`load-skill-result`:n.push({part:toolResult(r,SKILL_TOOL_NAME,toToolResultOutput(r)),result:r});continue;case`subagent-result`:n.push({part:toolResult(r,r.subagentName,toToolResultOutput(r)),result:r});continue;case`tool-result`:n.push({part:toolResult(r,r.toolName,await projectToolResultOutput(r,t?.get(r.toolName))),result:r});continue}throw Error(`Unsupported runtime action result kind "${String(r)}".`)}return n}function toolResult(e,t,n){return{output:n,toolCallId:e.callId,toolName:t,type:`tool-result`}}function collectWorkflowCalls(e){let{session:t}=e,n=[];for(let r of e.toolCalls){let i=e.tools.get(r.toolName);if(isTaskTool(i))continue;let a=commitCallEntry(t,{callId:r.toolCallId,definition:i,input:resolveToolCallInputObject(r.input,{callId:r.toolCallId,toolName:r.toolName}),toolName:r.toolName,turnId:e.turnId});t=a.session,n.push(createCoordinationRequestFromToolCall({entry:a.entry,input:a.input,toolCall:r,tools:e.tools}))}return{session:t,workflowRequests:n}}function createRuntimeActionRequestFromToolCall(e){let t=e.tools.get(e.toolCall.toolName),n=resolveToolCallInputObject(e.toolCall.input,{callId:e.toolCall.toolCallId,toolName:e.toolCall.toolName}),r=e.toolCall.toolName===SKILL_ENTRY_NAME?skillTarget(n):void 0;if(r!==void 0)return{callId:e.toolCall.toolCallId,input:n,kind:`load-skill`,name:r};let i=t?.behavior?.handling;if(t!==void 0&&i?.kind===`dispatch`&&i.target.kind!==`workflow-tool-call`){let r=i.target,a={callId:e.toolCall.toolCallId,description:t.description,input:n,name:e.toolCall.toolName,nodeId:r.nodeId};return r.kind===`remote-agent-call`?{...a,kind:`remote-agent-call`,remoteAgentName:r.remoteAgentName}:{...a,kind:`subagent-call`,subagentName:r.subagentName}}let a={callId:e.toolCall.toolCallId,input:n,kind:`tool-call`,toolName:e.toolCall.toolName};return t?.workflowId===void 0?a:markRuntimeWorkflowToolAction(a)}function createCoordinationRequestFromToolCall(e){let t=e.tools.get(e.toolCall.toolName);if(t?.workflowId===void 0)throw Error(`Workflow tool "${e.toolCall.toolName}" has no workflow.`);return{callId:e.toolCall.toolCallId,entry:e.entry,executeInput:t.executeInput?.(e.input),input:e.input,kind:`workflow-task`,toolName:e.toolCall.toolName,workflowId:t.workflowId}}function resolveToolCallInputObject(e,t){if(e==null||typeof e==`string`&&e.trim()===``)return{};try{return parseJsonObject(typeof e==`string`?parseJsonStringInput(e):e)}catch(e){let n=e instanceof Error?e.message:String(e);throw TypeError(`Failed to parse tool-call arguments for "${t.toolName}" (${t.callId}): ${n}`,{cause:e})}}function parseJsonStringInput(e){return JSON.parse(e)}async function projectToolResultOutput(e,t){return e.isError===!0||t?.toModelOutput===void 0||startsTasks(t)?toToolResultOutput(e):await observeToolOutput(e.toolName,[{callId:e.callId}],async()=>normalizeToolModelOutput({output:await t.toModelOutput(e.output),toolCallId:e.callId,toolName:e.toolName}))}function toToolResultOutput(e){return typeof e.output==`string`?e.isError===!0?{type:`error-text`,value:e.output}:{type:`text`,value:e.output}:e.isError===!0?{type:`error-json`,value:toMutableJsonValue(e.output)}:{type:`json`,value:toMutableJsonValue(e.output)}}function toMutableJsonValue(e){if(e===null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e;if(Array.isArray(e))return e.map(e=>toMutableJsonValue(e));let t={};for(let[n,r]of Object.entries(e))t[n]=toMutableJsonValue(r);return t}export{assertUniqueCoordinationCallIds,collectWorkflowCalls,createCoordinationRequestFromToolCall,createRuntimeActionRequestFromToolCall,forgetFinishedRuns,resolveToolCallInputObject,runtimeResultCalls};
1
+ import{skillTarget}from"#shared/action-request-name.js";import{SKILL_ENTRY_NAME,SKILL_TOOL_NAME}from"#protocol/catalog-tools.js";import{parseJsonObject}from"#shared/json.js";import{findBlockingWorkflowToolRun,removeBlockingWorkflowToolRuns}from"#harness/workflow-tool-runs.js";import{readHitlState}from"#harness/hitl/index.js";import{startsTasks}from"#execution/tasks/tool-entry-point.js";import{commitCallEntry,isTaskTool}from"#execution/tasks/model-step.js";import{normalizeToolModelOutput}from"#harness/tool-model-output.js";import{observeToolOutput}from"#tool-stubs/execute.js";import{markRuntimeWorkflowToolAction}from"#shared/action-types.js";function assertUniqueCoordinationCallIds(e){let t=new Set;for(let n of e){if(t.has(n.callId))throw Error(`Coordination batch contains duplicate callId "${n.callId}".`);t.add(n.callId)}}function forgetFinishedRuns(e,t,n){let r=e,i=[];for(let e of t){if(e.kind!==`tool-result`)continue;let t=findBlockingWorkflowToolRun(r.state,e.callId,n);if(t!==void 0){for(let[e,n]of readHitlState(r.state).relays)n.runId===t.address.runId&&i.push(e);r=removeBlockingWorkflowToolRuns(r,n,t.callId)}}return{requestIds:i,session:r}}async function runtimeResultCalls(e,t){let n=[];for(let r of e){switch(r.kind){case`load-skill-result`:n.push({part:toolResult(r,SKILL_TOOL_NAME,toToolResultOutput(r)),result:r});continue;case`subagent-result`:n.push({part:toolResult(r,r.subagentName,toToolResultOutput(r)),result:r});continue;case`tool-result`:n.push({part:toolResult(r,r.toolName,await projectToolResultOutput(r,t?.get(r.toolName))),result:r});continue}throw Error(`Unsupported runtime action result kind "${String(r)}".`)}return n}function toolResult(e,t,n){return{output:n,toolCallId:e.callId,toolName:t,type:`tool-result`}}function collectWorkflowCalls(e){let{session:t}=e,n=[];for(let r of e.toolCalls){let i=e.tools.get(r.toolName);if(isTaskTool(i))continue;let a=commitCallEntry(t,{callId:r.toolCallId,definition:i,input:resolveToolCallInputObject(r.input,{callId:r.toolCallId,toolName:r.toolName}),toolName:r.toolName,turnId:e.turnId});t=a.session,n.push(createCoordinationRequestFromToolCall({entry:a.entry,input:a.input,toolCall:r,tools:e.tools}))}return{session:t,workflowRequests:n}}function createRuntimeActionRequestFromToolCall(e){let t=e.tools.get(e.toolCall.toolName),n=resolveToolCallInputObject(e.toolCall.input,{callId:e.toolCall.toolCallId,toolName:e.toolCall.toolName}),r=e.toolCall.toolName===SKILL_ENTRY_NAME?skillTarget(n):void 0;if(r!==void 0)return{callId:e.toolCall.toolCallId,input:n,kind:`load-skill`,name:r};let i=t?.behavior?.handling;if(t!==void 0&&i?.kind===`dispatch`&&i.target.kind!==`workflow-tool-call`){let r=i.target,a={callId:e.toolCall.toolCallId,description:t.description,input:n,name:e.toolCall.toolName,nodeId:r.nodeId};return r.kind===`remote-agent-call`?{...a,kind:`remote-agent-call`,remoteAgentName:r.remoteAgentName}:{...a,kind:`subagent-call`,subagentName:r.subagentName}}let a={callId:e.toolCall.toolCallId,input:n,kind:`tool-call`,toolName:e.toolCall.toolName};return t?.workflowId===void 0?a:markRuntimeWorkflowToolAction(a)}function createCoordinationRequestFromToolCall(e){let t=e.tools.get(e.toolCall.toolName);if(t?.workflowId===void 0)throw Error(`Workflow tool "${e.toolCall.toolName}" has no workflow.`);return{callId:e.toolCall.toolCallId,entry:e.entry,executeInput:t.executeInput?.(e.input),input:e.input,kind:`workflow-task`,toolName:e.toolCall.toolName,workflowId:t.workflowId}}function resolveToolCallInputObject(e,t){if(e==null||typeof e==`string`&&e.trim()===``)return{};try{return parseJsonObject(typeof e==`string`?parseJsonStringInput(e):e)}catch(e){let n=e instanceof Error?e.message:String(e);throw TypeError(`Failed to parse tool-call arguments for "${t.toolName}" (${t.callId}): ${n}`,{cause:e})}}function parseJsonStringInput(e){return JSON.parse(e)}async function projectToolResultOutput(e,t){return e.isError===!0||t?.toModelOutput===void 0||startsTasks(t)?toToolResultOutput(e):await observeToolOutput(e.toolName,[{callId:e.callId}],async()=>normalizeToolModelOutput({output:await t.toModelOutput(e.output),toolCallId:e.callId,toolName:e.toolName}))}function toToolResultOutput(e){return typeof e.output==`string`?e.isError===!0?{type:`error-text`,value:e.output}:{type:`text`,value:e.output}:e.isError===!0?{type:`error-json`,value:toMutableJsonValue(e.output)}:{type:`json`,value:toMutableJsonValue(e.output)}}function toMutableJsonValue(e){if(e===null||typeof e==`string`||typeof e==`number`||typeof e==`boolean`)return e;if(Array.isArray(e))return e.map(e=>toMutableJsonValue(e));let t={};for(let[n,r]of Object.entries(e))t[n]=toMutableJsonValue(r);return t}export{assertUniqueCoordinationCallIds,collectWorkflowCalls,createCoordinationRequestFromToolCall,createRuntimeActionRequestFromToolCall,forgetFinishedRuns,resolveToolCallInputObject,runtimeResultCalls};
@@ -1,6 +1,6 @@
1
1
  import type { ModelMessage } from "ai";
2
2
  import type { getApprovalAuditState } from "#harness/hitl/candidates.js";
3
- import { type AuthorizationChallenge } from "#harness/authorization.js";
3
+ import type { AuthorizationChallenge } from "#harness/authorization.js";
4
4
  import { type ResolvedInputBatch } from "#harness/input-request-resolution.js";
5
5
  import type { StepInput } from "#harness/types.js";
6
6
  import type { RuntimeWorkflowTaskRequest } from "#shared/action-types.js";
@@ -1 +1 @@
1
- import{canonicalize,compactInput,isEmptyInput,resolveTextInput,withoutResponses}from"./delivery.js";import{openInputs,turnCoordinates}from"#protocol/session-projection.js";import{readClientContext}from"#internal/client-context.js";import{createActionResultEvent,createApprovalCandidateEvent,createApprovalSettledEvent,createAuthorizationCompletedEvent,createAuthorizationRequiredEvent,createInputRequestedEvent,createInputResolvedEvent,createMessageCompletedEvent}from"#protocol/message.js";import{coalesceTurnInputs,createFrameworkUserMessage}from"#harness/messages.js";import{turnPosition}from"#harness/session-machine/view.js";import{renderPendingApprovalsSnippet}from"#harness/hitl/approval-prompt.js";import{supersededChallenges,withSignIns}from"#harness/authorization.js";import{hold,ownOpenRequestIds,settle,stepCallIds,suspend,withResult,withoutApproved}from"#harness/session-machine/transitions.js";import{withoutCalls}from"#harness/inline-tool-authorization.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{authorizationEventFields}from"#harness/authorization-event-fields.js";import{TOOL_EXECUTION_DENIED_MESSAGE,failedCall,resolveApprovalOutcome,resolveInputOutcome,unavailableToolMessage}from"#harness/input-request-resolution.js";import{resolveSessionLimitContinuation}from"#harness/hitl/budget-request.js";import{signInWithdrawn}from"#harness/session-machine/events.js";function parkOnApprovals(e,t){let n=t.requester?.principalType===`anonymous`?null:t.requester,r=t.messages.findIndex(e=>e.role!==`tool`),i=r===-1?t.messages:t.messages.slice(0,r),a=renderPendingApprovalsSnippet(t.requests),o=suspend(e.turn,{event:t.event,messages:t.messages.slice(i.length),requester:n,requests:t.requests,responseAuthRequiredRequestIds:t.responseAuthRequiredRequestIds,tasks:t.tasks});return{commit:[...i,...a===void 0?[]:[createFrameworkUserMessage(`context.state`,a)]],events:t.tasks.length>0?[]:[createInputRequestedEvent({requests:t.requests,...t.event})],turn:o}}function dispatch(e,t){let n=e.turn.suspended.map(e=>{let n=stepCallIds(e),r=t.tasks.filter(e=>n.has(e.callId));return r.length===0?e:{...withoutApproved(e,new Set(r.map(e=>e.callId))),tasks:[...e.tasks,...r]}});return{events:[],turn:{...e.turn,suspended:n}}}function deferInput(e,t){return{events:[],turn:withQueued(e.turn,t)}}function withQueued(e,t){return t===void 0||isEmptyInput(t)?e:{...e,queued:e.queued===void 0?t:coalesceTurnInputs(e.queued,t)}}function answer(e,t){let{policy:n}=t,{projection:r}=e,i=turnPosition(r),a=[...n.feedback.map(e=>createMessageCompletedEvent({message:e,sequence:i.sequence,stepIndex:i.stepIndex,turnId:i.turnId})),...reportApprovalProgress(r,n.audit,n.challengesAtStart)],o=t.takeQueued?{...e.turn,queued:void 0}:e.turn,done=e=>({events:a,resolved:[],turn:o,...e}),queue=e=>{o=withQueued(o,e)};if(n.kind===`park`)return done({next:`park`});if(n.kind===`continue-coordination`)return queue(n.stepInput),done({next:`repeat`});if(n.challenges.length>0)return done({next:`sign-in`});let s=t.delivery,c=openInputs(r).find(t=>t.request.kind===`session-limit`&&ownOpenRequestIds(e).has(t.request.requestId)),l=o.suspended.filter(e=>e.requests.length>0);if(c===void 0&&l.length===0)return done({input:s,next:`continue`});let u=c===void 0?s:resolveTextInput({requests:[c.request]},s),d=canonicalize(u?.inputResponses??[]),f=new Map(d.map(e=>[e.requestId,e])),p=l.filter(e=>e.requests.every(e=>f.has(e.requestId))),leftoverFor=e=>d.filter(t=>e.some(e=>e.requests.some(e=>e.requestId===t.requestId))),park=()=>(queue(compactInput(u)),done({next:`park`}));if(d.length===0&&u?.message===void 0)return park();if(c!==void 0){let e=f.get(c.request.requestId);if(e===void 0)return park();let t={event:{sequence:c.sequence,stepIndex:c.stepIndex,turnId:c.turnId},inputs:[{outcome:resolveInputOutcome(c.request.kind,e),request:c.request,response:e}]};a.push(resolvedEvent(t));let n=leftoverFor(l);return n.length>0&&queue({inputResponses:n}),done({consumedMessage:u?.messageConsumed,input:withoutResponses(u),limit:resolveSessionLimitContinuation({requests:[c.request],responses:d}),next:`continue`,resolved:[t]})}if(p.length===0&&u?.message===void 0)return park();p.length===0&&p.push(l[0]);let m=leftoverFor(l.filter(e=>!p.includes(e)));m.length>0&&queue({inputResponses:m});let h=new Set(o.grants),g=[],_=[],v=new Set(n.audit.settlements.filter(e=>e.outcome===`unavailable`).map(e=>e.requestId)),y=o.suspended.map(e=>{if(!p.includes(e))return e;let n=e.messages,r=[];for(let i of e.requests){let{callId:a,toolName:o}=i.action;if(v.has(i.requestId)){let r=failedCall({callId:a,message:unavailableToolMessage(o,t.searchable(i)),toolName:o});n=withResult(n,r.part),_.push(createActionResultEvent({result:r.result,...e.event}));continue}let{approved:s,reason:c,status:l}=resolveApprovalOutcome(f.get(i.requestId));if(s){h.add(t.approvalKey(i)??o),r.push(i);continue}n=withResult(n,{output:{reason:c,type:`execution-denied`},toolCallId:a,toolName:o,type:`tool-result`}),_.push(createActionResultEvent({rejected:!0,result:{callId:a,isError:!0,kind:`tool-result`,output:{approval:{requestId:i.requestId,status:l},code:`TOOL_EXECUTION_DENIED`,message:c??TOOL_EXECUTION_DENIED_MESSAGE,tool:{result:`not_run`}},toolName:o},...e.event}))}g.push({event:e.event,inputs:e.requests.map(e=>{let t=f.get(e.requestId);return{outcome:resolveInputOutcome(e.kind,t),request:e,response:t}})});let i=[...e.approved??[],...r];return{...e,messages:n,requests:[],...i.length>0&&{approved:i}}});return a.push(...g.map(resolvedEvent),..._),o={...o,grants:[...h],suspended:y},done({consumedMessage:u?.messageConsumed,input:withoutResponses(u),next:`continue`,resolved:g})}function resolvedEvent(e){return createInputResolvedEvent({resolutions:e.inputs.map(e=>{let t={kind:e.request.kind,outcome:e.outcome,requestId:e.request.requestId};return e.response===void 0?t:{...t,response:e.response}}),...e.event})}function reportApprovalProgress(e,t,n){let r=turnCoordinates(e),isOpen=t=>{let n=e.inputs[t];return n!==void 0&&n.status!==`settled`},i=[];for(let a of n){let n=t.candidateHistory.some(e=>e.candidateId===a.candidateId&&e.status===`timed-out`),o=e.authorizations[a.attemptId??a.name];n&&o?.status===`required`&&i.push(createAuthorizationCompletedEvent({...authorizationEventFields(a),outcome:`failed`,reason:`The approval response expired. Please submit a new response.`,...r}))}for(let n of t.activeCandidates)e.candidates[n.candidateId]===void 0&&isOpen(n.requestId)&&i.push(createApprovalCandidateEvent({candidateId:n.candidateId,outcome:`pending`,requestId:n.requestId,responderPrincipalId:n.responder.principalId,...r}));for(let n of t.candidateHistory)n.status!==`allowed`&&n.status!==`authorization-required`&&e.inputs[n.requestId]!==void 0&&e.candidates[n.candidateId]?.outcome!==n.status&&i.push(createApprovalCandidateEvent({candidateId:n.candidateId,outcome:n.status,requestId:n.requestId,responderPrincipalId:n.responder.principalId,reason:n.reason,...r}));for(let e of t.settlements)isOpen(e.requestId)&&e.outcome!==`unavailable`&&i.push(createApprovalSettledEvent({outcome:e.outcome===`allowed`?`approved`:`cancelled`,requestId:e.requestId,responderPrincipalId:e.actor.principalId,...r}));return i}function hasRunnableQueue(e){let t=e.turn.queued;if(t===void 0)return!1;let n=[...t.inputResponses??[],...(t.attributedInputResponses??[]).map(({response:e})=>e)],r=new Set(n.map(e=>e.requestId)),i=openInputs(e.projection).find(e=>e.request.kind===`session-limit`);return i===void 0?t.message!==void 0||(t.context?.length??0)>0||readClientContext(t)!==void 0||t.outputSchema!==void 0||(t.runtimeActionResults?.length??0)>0||n.length!==0&&e.turn.suspended.some(e=>e.requests.length>0&&e.requests.every(e=>r.has(e.requestId))):r.has(i.request.requestId)}function grantedApprovalKeys(e,t){let n=new Set(e.turn.grants);for(let r of e.turn.suspended)for(let e of r.requests)isApprovalRequest(e)&&n.delete(t(e)??e.action.toolName);return n}function approvingSteps(e,t){let n=e.turn.suspended.filter(e=>e.requests.length>0),r=new Map((t?.inputResponses??[]).map(e=>[e.requestId,e.optionId]));return n.filter(e=>e.requests.every(e=>r.has(e.requestId))&&e.requests.some(e=>isApprovalRequest(e)&&r.get(e.requestId)===`approve`))}function stepForRequest(e,t){return e.turn.suspended.find(e=>e.requests.some(e=>e.requestId===t))}function withdrawSignIns(e,t){return{events:e.signIns.flatMap(n=>{let r=e.projection.authorizations[n.attemptId??n.name];return r?.status===`required`?[signInWithdrawn(r,t)]:[]}),signIns:[],turn:e.turn}}function requestLimit(e,t){let n=turnPosition(e.projection);return{events:[createInputRequestedEvent({requests:[t.request],sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId}),...hold(e,{on:`input`}).events],turn:e.turn}}function requireSignIn(e,t){let n=turnPosition(e.projection),r={sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId},i=[...supersededChallenges(e.signIns,t.challenges).map(e=>createAuthorizationCompletedEvent({...authorizationEventFields(e),outcome:`failed`,reason:`Superseded by a newer authorization attempt.`,...r})),...t.challenges.map(e=>createAuthorizationRequiredEvent({...authorizationEventFields(e),description:e.challenge.instructions??`Authorization required for ${e.name}`,webhookUrl:e.hookUrl,...r}))];i.push(...hold(e,{on:`input`}).events);let a=t.queued===void 0?e.turn.queued:e.turn.queued===void 0?t.queued:coalesceTurnInputs(e.turn.queued,t.queued),o=withSignIns(e.signIns,t.challenges),s=new Set([...t.callIdsByName?.values()??[]].flat()),c=e.turn.suspended.map(e=>[...stepCallIds(e)].some(e=>s.has(e))?{...e,messages:withoutCalls(e.messages,s)}:e);if(c.every((t,n)=>t===e.turn.suspended[n]))return{events:i,signIns:o,turn:{...e.turn,queued:a}};let l=settle({...e,turn:{...e.turn,queued:a,suspended:c}},{results:[]});return{commit:l.commit,events:i,signIns:o,turn:l.turn}}export{answer,approvingSteps,deferInput,dispatch,grantedApprovalKeys,hasRunnableQueue,parkOnApprovals,requestLimit,requireSignIn,stepForRequest,withdrawSignIns};
1
+ import{supersededChallenges,withSignIns}from"./sign-ins.js";import{canonicalize,compactInput,isEmptyInput,resolveTextInput,withoutResponses}from"./delivery.js";import{openInputs,turnCoordinates}from"#protocol/session-projection.js";import{readClientContext}from"#internal/client-context.js";import{createActionResultEvent,createApprovalCandidateEvent,createApprovalSettledEvent,createAuthorizationCompletedEvent,createAuthorizationRequiredEvent,createInputRequestedEvent,createInputResolvedEvent,createMessageCompletedEvent}from"#protocol/message.js";import{coalesceTurnInputs,createFrameworkUserMessage}from"#harness/messages.js";import{turnPosition}from"#harness/session-machine/view.js";import{renderPendingApprovalsSnippet}from"#harness/hitl/approval-prompt.js";import{hold,ownOpenRequestIds,settle,stepCallIds,suspend,withResult,withoutApproved}from"#harness/session-machine/transitions.js";import{withoutCalls}from"#harness/inline-tool-authorization.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{authorizationEventFields}from"#harness/authorization-event-fields.js";import{TOOL_EXECUTION_DENIED_MESSAGE,failedCall,resolveApprovalOutcome,resolveInputOutcome,unavailableToolMessage}from"#harness/input-request-resolution.js";import{resolveSessionLimitContinuation}from"#harness/hitl/budget-request.js";import{signInWithdrawn}from"#harness/session-machine/events.js";function parkOnApprovals(e,t){let n=t.requester?.principalType===`anonymous`?null:t.requester,r=t.messages.findIndex(e=>e.role!==`tool`),i=r===-1?t.messages:t.messages.slice(0,r),a=renderPendingApprovalsSnippet(t.requests),o=suspend(e.turn,{event:t.event,messages:t.messages.slice(i.length),requester:n,requests:t.requests,responseAuthRequiredRequestIds:t.responseAuthRequiredRequestIds,tasks:t.tasks});return{commit:[...i,...a===void 0?[]:[createFrameworkUserMessage(`context.state`,a)]],events:t.tasks.length>0?[]:[createInputRequestedEvent({requests:t.requests,...t.event})],turn:o}}function dispatch(e,t){let n=e.turn.suspended.map(e=>{let n=stepCallIds(e),r=t.tasks.filter(e=>n.has(e.callId));return r.length===0?e:{...withoutApproved(e,new Set(r.map(e=>e.callId))),tasks:[...e.tasks,...r]}});return{events:[],turn:{...e.turn,suspended:n}}}function deferInput(e,t){return{events:[],turn:withQueued(e.turn,t)}}function withQueued(e,t){return t===void 0||isEmptyInput(t)?e:{...e,queued:e.queued===void 0?t:coalesceTurnInputs(e.queued,t)}}function answer(e,t){let{policy:n}=t,{projection:r}=e,i=turnPosition(r),a=[...n.feedback.map(e=>createMessageCompletedEvent({message:e,sequence:i.sequence,stepIndex:i.stepIndex,turnId:i.turnId})),...reportApprovalProgress(r,n.audit,n.challengesAtStart)],o=t.takeQueued?{...e.turn,queued:void 0}:e.turn,done=e=>({events:a,resolved:[],turn:o,...e}),queue=e=>{o=withQueued(o,e)};if(n.kind===`park`)return done({next:`park`});if(n.kind===`continue-coordination`)return queue(n.stepInput),done({next:`repeat`});if(n.challenges.length>0)return done({next:`sign-in`});let s=t.delivery,c=openInputs(r).find(t=>t.request.kind===`session-limit`&&ownOpenRequestIds(e).has(t.request.requestId)),l=o.suspended.filter(e=>e.requests.length>0);if(c===void 0&&l.length===0)return done({input:s,next:`continue`});let u=c===void 0?s:resolveTextInput({requests:[c.request]},s),d=canonicalize(u?.inputResponses??[]),f=new Map(d.map(e=>[e.requestId,e])),p=l.filter(e=>e.requests.every(e=>f.has(e.requestId))),leftoverFor=e=>d.filter(t=>e.some(e=>e.requests.some(e=>e.requestId===t.requestId))),park=()=>(queue(compactInput(u)),done({next:`park`}));if(d.length===0&&u?.message===void 0)return park();if(c!==void 0){let e=f.get(c.request.requestId);if(e===void 0)return park();let t={event:{sequence:c.sequence,stepIndex:c.stepIndex,turnId:c.turnId},inputs:[{outcome:resolveInputOutcome(c.request.kind,e),request:c.request,response:e}]};a.push(resolvedEvent(t));let n=leftoverFor(l);return n.length>0&&queue({inputResponses:n}),done({consumedMessage:u?.messageConsumed,input:withoutResponses(u),limit:resolveSessionLimitContinuation({requests:[c.request],responses:d}),next:`continue`,resolved:[t]})}if(p.length===0&&u?.message===void 0)return park();p.length===0&&p.push(l[0]);let m=leftoverFor(l.filter(e=>!p.includes(e)));m.length>0&&queue({inputResponses:m});let h=new Set(o.grants),g=[],_=[],v=new Set(n.audit.settlements.filter(e=>e.outcome===`unavailable`).map(e=>e.requestId)),y=o.suspended.map(e=>{if(!p.includes(e))return e;let n=e.messages,r=[];for(let i of e.requests){let{callId:a,toolName:o}=i.action;if(v.has(i.requestId)){let r=failedCall({callId:a,failure:unavailableToolMessage(o,t.searchable(i)),toolName:o});n=withResult(n,r.part),_.push(createActionResultEvent({result:r.result,...e.event}));continue}let{approved:s,reason:c,status:l}=resolveApprovalOutcome(f.get(i.requestId));if(s){h.add(t.approvalKey(i)??o),r.push(i);continue}n=withResult(n,{output:{reason:c,type:`execution-denied`},toolCallId:a,toolName:o,type:`tool-result`}),_.push(createActionResultEvent({rejected:!0,result:{callId:a,isError:!0,kind:`tool-result`,output:{approval:{requestId:i.requestId,status:l},code:`TOOL_EXECUTION_DENIED`,message:c??TOOL_EXECUTION_DENIED_MESSAGE,tool:{result:`not_run`}},toolName:o},...e.event}))}g.push({event:e.event,inputs:e.requests.map(e=>{let t=f.get(e.requestId);return{outcome:resolveInputOutcome(e.kind,t),request:e,response:t}})});let i=[...e.approved??[],...r];return{...e,messages:n,requests:[],...i.length>0&&{approved:i}}});return a.push(...g.map(resolvedEvent),..._),o={...o,grants:[...h],suspended:y},done({consumedMessage:u?.messageConsumed,input:withoutResponses(u),next:`continue`,resolved:g})}function resolvedEvent(e){return createInputResolvedEvent({resolutions:e.inputs.map(e=>{let t={kind:e.request.kind,outcome:e.outcome,requestId:e.request.requestId};return e.response===void 0?t:{...t,response:e.response}}),...e.event})}function reportApprovalProgress(e,t,n){let r=turnCoordinates(e),isOpen=t=>{let n=e.inputs[t];return n!==void 0&&n.status!==`settled`},i=[];for(let a of n){let n=t.candidateHistory.some(e=>e.candidateId===a.candidateId&&e.status===`timed-out`),o=e.authorizations[a.attemptId??a.name];n&&o?.status===`required`&&i.push(createAuthorizationCompletedEvent({...authorizationEventFields(a),outcome:`failed`,reason:`The approval response expired. Please submit a new response.`,...r}))}for(let n of t.activeCandidates)e.candidates[n.candidateId]===void 0&&isOpen(n.requestId)&&i.push(createApprovalCandidateEvent({candidateId:n.candidateId,outcome:`pending`,requestId:n.requestId,responderPrincipalId:n.responder.principalId,...r}));for(let n of t.candidateHistory)n.status!==`allowed`&&n.status!==`authorization-required`&&e.inputs[n.requestId]!==void 0&&e.candidates[n.candidateId]?.outcome!==n.status&&i.push(createApprovalCandidateEvent({candidateId:n.candidateId,outcome:n.status,requestId:n.requestId,responderPrincipalId:n.responder.principalId,reason:n.reason,...r}));for(let e of t.settlements)isOpen(e.requestId)&&e.outcome!==`unavailable`&&i.push(createApprovalSettledEvent({outcome:e.outcome===`allowed`?`approved`:`cancelled`,requestId:e.requestId,responderPrincipalId:e.actor.principalId,...r}));return i}function hasRunnableQueue(e){let t=e.turn.queued;if(t===void 0)return!1;let n=[...t.inputResponses??[],...(t.attributedInputResponses??[]).map(({response:e})=>e)],r=new Set(n.map(e=>e.requestId)),i=openInputs(e.projection).find(e=>e.request.kind===`session-limit`);return i===void 0?t.message!==void 0||(t.context?.length??0)>0||readClientContext(t)!==void 0||t.outputSchema!==void 0||(t.runtimeActionResults?.length??0)>0||n.length!==0&&e.turn.suspended.some(e=>e.requests.length>0&&e.requests.every(e=>r.has(e.requestId))):r.has(i.request.requestId)}function grantedApprovalKeys(e,t){let n=new Set(e.turn.grants);for(let r of e.turn.suspended)for(let e of r.requests)isApprovalRequest(e)&&n.delete(t(e)??e.action.toolName);return n}function approvingSteps(e,t){let n=e.turn.suspended.filter(e=>e.requests.length>0),r=new Map((t?.inputResponses??[]).map(e=>[e.requestId,e.optionId]));return n.filter(e=>e.requests.every(e=>r.has(e.requestId))&&e.requests.some(e=>isApprovalRequest(e)&&r.get(e.requestId)===`approve`))}function stepForRequest(e,t){return e.turn.suspended.find(e=>e.requests.some(e=>e.requestId===t))}function withdrawSignIns(e,t){return{events:e.signIns.flatMap(n=>{let r=e.projection.authorizations[n.attemptId??n.name];return r?.status===`required`?[signInWithdrawn(r,t)]:[]}),signIns:[],turn:e.turn}}function requestLimit(e,t){let n=turnPosition(e.projection);return{events:[createInputRequestedEvent({requests:[t.request],sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId}),...hold(e,{on:`input`}).events],turn:e.turn}}function requireSignIn(e,t){let n=turnPosition(e.projection),r={sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId},i=[...supersededChallenges(e.signIns,t.challenges).map(e=>createAuthorizationCompletedEvent({...authorizationEventFields(e),outcome:`failed`,reason:`Superseded by a newer authorization attempt.`,...r})),...t.challenges.map(e=>createAuthorizationRequiredEvent({...authorizationEventFields(e),description:e.challenge.instructions??`Authorization required for ${e.name}`,webhookUrl:e.hookUrl,...r}))];i.push(...hold(e,{on:`input`}).events);let a=t.queued===void 0?e.turn.queued:e.turn.queued===void 0?t.queued:coalesceTurnInputs(e.turn.queued,t.queued),o=withSignIns(e.signIns,t.challenges),s=new Set([...t.callIdsByName?.values()??[]].flat()),c=e.turn.suspended.map(e=>[...stepCallIds(e)].some(e=>s.has(e))?{...e,messages:withoutCalls(e.messages,s)}:e);if(c.every((t,n)=>t===e.turn.suspended[n]))return{events:i,signIns:o,turn:{...e.turn,queued:a}};let l=settle({...e,turn:{...e.turn,queued:a,suspended:c}},{results:[]});return{commit:l.commit,events:i,signIns:o,turn:l.turn}}export{answer,approvingSteps,deferInput,dispatch,grantedApprovalKeys,hasRunnableQueue,parkOnApprovals,requestLimit,requireSignIn,stepForRequest,withdrawSignIns};
@@ -1,4 +1,5 @@
1
1
  import { type ModelMessage, type TelemetryOptions, type ToolSet, type TypedToolResult } from "ai";
2
+ import type { SessionAuthContext } from "#channel/types.js";
2
3
  import type { HarnessToolLookup } from "#harness/types.js";
3
4
  import type { InputRequest } from "#shared/input.js";
4
5
  import type { HandleEventFn } from "#harness/types.js";
@@ -33,6 +34,8 @@ export declare function runApprovedCalls(input: {
33
34
  readonly abortSignal: AbortSignal | undefined;
34
35
  /** The step attempt's telemetry, which hears each execution as the AI SDK reports it. */
35
36
  readonly telemetry?: TelemetryOptions;
37
+ /** Who approved each request, which the call reads as `ctx.approval`; it still runs as the requester. */
38
+ readonly responderOf: (request: InputRequest) => SessionAuthContext | undefined;
36
39
  }): Promise<{
37
40
  readonly settled: readonly ApprovedCallResult[];
38
41
  readonly toolResults: readonly TypedToolResult<ToolSet>[];
@@ -1 +1 @@
1
- import{asSchema}from"ai";import{createLogger,logError}from"#internal/logging.js";import{toError}from"#shared/errors.js";import{createActionPartialEvent,createActionResultEvent}from"#protocol/message.js";import{SEARCH_TOOL_NAME}from"#protocol/catalog-tools.js";import{toModelSchema}from"#tools/schema.js";import{parseJsonObject}from"#shared/json.js";import{toolCallModelOutput}from"#harness/tool-call-io.js";import{isAsyncIterable}from"#shared/async-iterable.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";import{projectDeltaPresentation,projectResultPresentation}from"#harness/tool-presentation.js";import{isInlineAuthorizationToolResult}from"#harness/inline-tool-authorization.js";import{TOOL_EXECUTION_DENIED_MESSAGE,failedCall,unavailableToolMessage}from"#harness/input-request-resolution.js";import{recheckApprovedCall,wrapToolExecute}from"#harness/tools.js";const log=createLogger(`harness.tool-loop`),APPROVED_CALL_INTERRUPTED_MESSAGE=`The turn was cancelled while this approved tool call was running. It may have partially run; it was not retried.`;async function runApprovedCalls(e){let t={sequence:e.position.sequence,stepIndex:e.position.stepIndex,turnId:e.position.turnId},settleFailure=async(n,r,i)=>{let a=failedCall({callId:n,message:i,toolName:r});return await e.publish(createActionResultEvent({...t,result:a.result})),{part:a.part}},n=await Promise.allSettled(e.requests.map(async n=>{let r=[],i=[],{callId:a,toolName:o,input:s}=n.action,c=e.tools.get(o),l=c===void 0?void 0:wrapToolExecute(c),u=!1,d;try{if(throwIfTurnAborted(e.abortSignal),c===void 0||l===void 0)return{settled:[await settleFailure(a,o,unavailableToolMessage(o,e.tools.get(SEARCH_TOOL_NAME)!==void 0))],toolResults:i};if((await asSchema(toModelSchema(c.inputSchema,`input`)).validate?.(s))?.success===!1){let e=`The approved input is no longer valid for tool "${o}". Request a new tool call and approval.`;return{settled:[await settleFailure(a,o,e)],toolResults:i}}let f=await recheckApprovedCall(c,{abortSignal:e.abortSignal,callId:a,input:s,approvedTools:e.approvedTools});if(f.denied)return r.push(await rejectApprovedCall({request:n,reason:f.reason,position:t,publish:e.publish})),{settled:r,toolResults:i};let p,m=!1,h=toolTelemetry(e.telemetry,{messages:[...e.messages],toolCall:{input:s,toolCallId:a,toolName:o,type:`tool-call`}});await h.started();let g=0;try{await h.execute(async()=>{let n=performance.now();try{u=!0;let n=l(s,{abortSignal:e.abortSignal,messages:[...e.messages],toolCallId:a});if(isAsyncIterable(n))for await(let r of n)p=r,await e.publish(createActionPartialEvent({...t,presentation:projectDeltaPresentation(c,a,parseJsonObject(s),r),result:createRuntimeToolResultFromValue({callId:a,output:r,toolName:o})}));else p=await n}finally{g=performance.now()-n}})}catch(t){await h.ended({error:t,input:s,toolCallId:a,toolName:o,type:`tool-error`},g),throwIfTurnAborted(e.abortSignal),logError(log,`tool execution failed`,t,{toolName:o,toolCallId:a}),m=!0,p=toError(t).message}m||await h.ended({input:s,output:p,toolCallId:a,toolName:o,type:`tool-result`},g);let _={input:s,output:p,toolCallId:a,toolName:o,type:`tool-result`};return i.push(_),isInlineAuthorizationToolResult(_)?{settled:r,toolResults:i}:(d={part:{output:m?{type:`error-text`,value:String(p)}:await toolCallModelOutput(c,p,a),toolCallId:a,toolName:o,type:`tool-result`}},r.push(d),await e.publish(createActionResultEvent({...t,presentation:m?void 0:projectResultPresentation(c,a,parseJsonObject(s),p),result:createRuntimeToolResultFromValue({callId:a,isError:m,output:p,toolName:o})})),{settled:r,toolResults:i})}catch(t){return e.abortSignal?.aborted===!0?(u||throwIfTurnAborted(e.abortSignal),d===void 0?{settled:[interruptedResult(a,o)],toolResults:i}:{settled:[d],toolResults:i}):(logError(log,`approved tool failed`,t,{toolName:o,toolCallId:a}),{settled:[await settleFailure(a,o,toError(t).message)],toolResults:i})}})),r=n.find(e=>e.status===`rejected`);if(r?.status===`rejected`&&e.abortSignal?.aborted!==!0)throw r.reason;let i=n.flatMap(e=>e.status===`fulfilled`?[e.value]:[]);return{settled:i.flatMap(e=>e.settled),toolResults:i.flatMap(e=>e.toolResults)}}function interruptedResult(e,t){return{part:{output:{type:`error-text`,value:APPROVED_CALL_INTERRUPTED_MESSAGE},toolCallId:e,toolName:t,type:`tool-result`}}}async function rejectApprovedCall(e){let{callId:t,toolName:n}=e.request.action;return await e.publish(createActionResultEvent({...e.position,rejected:!0,result:{callId:t,isError:!0,kind:`tool-result`,toolName:n,output:{code:`TOOL_EXECUTION_DENIED`,message:e.reason??TOOL_EXECUTION_DENIED_MESSAGE,tool:{result:`not_run`}}}})),{part:{output:{reason:e.reason,type:`execution-denied`},toolCallId:t,toolName:n,type:`tool-result`}}}function toolTelemetry(e,t){let n=e===void 0||e.isEnabled===!1?[]:[e.integrations??[]].flat(),r={...t,callId:`approved:${t.toolCall.toolCallId}`,functionId:e?.functionId,recordInputs:e?.recordInputs,recordOutputs:e?.recordOutputs,toolContext:void 0},notify=async e=>{await Promise.allSettled(n.map(async t=>await e(t)))};return{started:()=>notify(e=>e.onToolExecutionStart?.(r)),execute:async e=>{let wrapped=e;for(let e of n){if(e.executeTool===void 0)continue;let n=wrapped;wrapped=()=>e.executeTool({...r,execute:n,toolCallId:t.toolCall.toolCallId})}await wrapped()},ended:(e,t)=>notify(n=>n.onToolExecutionEnd?.({...r,toolExecutionMs:t,toolOutput:e}))}}export{APPROVED_CALL_INTERRUPTED_MESSAGE,rejectApprovedCall,runApprovedCalls};
1
+ import{asSchema}from"ai";import{createLogger,logError}from"#internal/logging.js";import{toError}from"#shared/errors.js";import{createActionPartialEvent,createActionResultEvent}from"#protocol/message.js";import{SEARCH_TOOL_NAME}from"#protocol/catalog-tools.js";import{toModelSchema}from"#tools/schema.js";import{parseJsonObject}from"#shared/json.js";import{toolCallModelOutput}from"#harness/tool-call-io.js";import{isAsyncIterable}from"#shared/async-iterable.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";import{projectDeltaPresentation,projectResultPresentation}from"#harness/tool-presentation.js";import{isInlineAuthorizationToolResult}from"#harness/inline-tool-authorization.js";import{TOOL_EXECUTION_DENIED_MESSAGE,failedCall,unavailableToolMessage}from"#harness/input-request-resolution.js";import{recheckApprovedCall,wrapToolExecute}from"#harness/tools.js";const log=createLogger(`harness.tool-loop`),APPROVED_CALL_INTERRUPTED_MESSAGE=`The turn was cancelled while this approved tool call was running. It may have partially run; it was not retried.`;async function runApprovedCalls(e){let t={sequence:e.position.sequence,stepIndex:e.position.stepIndex,turnId:e.position.turnId},settleFailure=async(n,r,i)=>{let a=failedCall({callId:n,failure:i,toolName:r});return await e.publish(createActionResultEvent({...t,result:a.result})),{part:a.part}},n=await Promise.allSettled(e.requests.map(async n=>{let r=[],i=[],{callId:a,toolName:o,input:s}=n.action,c=e.tools.get(o),l=c===void 0?void 0:wrapToolExecute(c),u=!1,d;try{if(throwIfTurnAborted(e.abortSignal),c===void 0||l===void 0)return{settled:[await settleFailure(a,o,unavailableToolMessage(o,e.tools.get(SEARCH_TOOL_NAME)!==void 0))],toolResults:i};if((await asSchema(toModelSchema(c.inputSchema,`input`)).validate?.(s))?.success===!1){let e=`The approved input is no longer valid for tool "${o}". Request a new tool call and approval.`;return{settled:[await settleFailure(a,o,e)],toolResults:i}}let f=await recheckApprovedCall(c,{abortSignal:e.abortSignal,callId:a,input:s,approvedTools:e.approvedTools});if(f.denied)return r.push(await rejectApprovedCall({request:n,reason:f.reason,position:t,publish:e.publish})),{settled:r,toolResults:i};let p,m,h=toolTelemetry(e.telemetry,{messages:[...e.messages],toolCall:{input:s,toolCallId:a,toolName:o,type:`tool-call`}});await h.started();let g=0;try{await h.execute(async()=>{let r=performance.now();try{u=!0;let r=e.responderOf(n),i=l(s,{...r!==void 0&&{approval:{responder:r}},abortSignal:e.abortSignal,messages:[...e.messages],toolCallId:a});if(isAsyncIterable(i))for await(let n of i)p=n,await e.publish(createActionPartialEvent({...t,presentation:projectDeltaPresentation(c,a,parseJsonObject(s),n),result:createRuntimeToolResultFromValue({callId:a,output:n,toolName:o})}));else p=await i}finally{g=performance.now()-r}})}catch(t){await h.ended({error:t,input:s,toolCallId:a,toolName:o,type:`tool-error`},g),throwIfTurnAborted(e.abortSignal),logError(log,`tool execution failed`,t,{toolName:o,toolCallId:a}),m=toError(t),p=m.message}m===void 0&&await h.ended({input:s,output:p,toolCallId:a,toolName:o,type:`tool-result`},g);let _={input:s,output:p,toolCallId:a,toolName:o,type:`tool-result`};return i.push(_),isInlineAuthorizationToolResult(_)?{settled:r,toolResults:i}:(d={part:{output:m===void 0?await toolCallModelOutput(c,p,a):{type:`error-text`,value:m.message},toolCallId:a,toolName:o,type:`tool-result`}},r.push(d),await e.publish(createActionResultEvent({...t,presentation:m===void 0?projectResultPresentation(c,a,parseJsonObject(s),p):void 0,result:createRuntimeToolResultFromValue({callId:a,isError:m!==void 0,output:m??p,toolName:o})})),{settled:r,toolResults:i})}catch(t){return e.abortSignal?.aborted===!0?(u||throwIfTurnAborted(e.abortSignal),d===void 0?{settled:[interruptedResult(a,o)],toolResults:i}:{settled:[d],toolResults:i}):(logError(log,`approved tool failed`,t,{toolName:o,toolCallId:a}),{settled:[await settleFailure(a,o,toError(t))],toolResults:i})}})),r=n.find(e=>e.status===`rejected`);if(r?.status===`rejected`&&e.abortSignal?.aborted!==!0)throw r.reason;let i=n.flatMap(e=>e.status===`fulfilled`?[e.value]:[]);return{settled:i.flatMap(e=>e.settled),toolResults:i.flatMap(e=>e.toolResults)}}function interruptedResult(e,t){return{part:{output:{type:`error-text`,value:APPROVED_CALL_INTERRUPTED_MESSAGE},toolCallId:e,toolName:t,type:`tool-result`}}}async function rejectApprovedCall(e){let{callId:t,toolName:n}=e.request.action;return await e.publish(createActionResultEvent({...e.position,rejected:!0,result:{callId:t,isError:!0,kind:`tool-result`,toolName:n,output:{code:`TOOL_EXECUTION_DENIED`,message:e.reason??TOOL_EXECUTION_DENIED_MESSAGE,tool:{result:`not_run`}}}})),{part:{output:{reason:e.reason,type:`execution-denied`},toolCallId:t,toolName:n,type:`tool-result`}}}function toolTelemetry(e,t){let n=e===void 0||e.isEnabled===!1?[]:[e.integrations??[]].flat(),r={...t,callId:`approved:${t.toolCall.toolCallId}`,functionId:e?.functionId,recordInputs:e?.recordInputs,recordOutputs:e?.recordOutputs,toolContext:void 0},notify=async e=>{await Promise.allSettled(n.map(async t=>await e(t)))};return{started:()=>notify(e=>e.onToolExecutionStart?.(r)),execute:async e=>{let wrapped=e;for(let e of n){if(e.executeTool===void 0)continue;let n=wrapped;wrapped=()=>e.executeTool({...r,execute:n,toolCallId:t.toolCall.toolCallId})}await wrapped()},ended:(e,t)=>notify(n=>n.onToolExecutionEnd?.({...r,toolExecutionMs:t,toolOutput:e}))}}export{APPROVED_CALL_INTERRUPTED_MESSAGE,rejectApprovedCall,runApprovedCalls};
@@ -23,6 +23,11 @@ export interface ApprovalResponderIdentity {
23
23
  }
24
24
  export interface ApprovalSettlementAuditRecord {
25
25
  readonly actor: ApprovalResponderIdentity;
26
+ /**
27
+ * The full auth of the person who approved, present only when allowed. The approved call reads
28
+ * it as `ctx.approval.responder`; it never runs as it.
29
+ */
30
+ readonly responder?: SessionAuthContext;
26
31
  /** `unavailable`: the request's entry was gone, so its call is reported unavailable, never run. */
27
32
  readonly outcome: "allowed" | "cancelled" | "unavailable";
28
33
  readonly requestId: string;
@@ -39,6 +44,12 @@ export interface ActiveApprovalCandidate {
39
44
  readonly expiresAt: number;
40
45
  readonly authorizationChallenges?: readonly AuthorizationChallenge[];
41
46
  }
47
+ export interface DurableApprovalState {
48
+ readonly activeCandidates: Readonly<Record<string, ActiveApprovalCandidate>>;
49
+ readonly nextCandidateSequence: number;
50
+ readonly candidateHistory: readonly ApprovalCandidateAuditRecord[];
51
+ readonly settlements: Readonly<Record<string, ApprovalSettlementAuditRecord>>;
52
+ }
42
53
  interface ApprovalStateTransition {
43
54
  readonly changed: boolean;
44
55
  readonly state: SessionStateMap | undefined;
@@ -117,4 +128,6 @@ export declare function retireActiveCandidates(state: SessionStateMap | undefine
117
128
  readonly completedAt: number;
118
129
  readonly reason: string;
119
130
  }): SessionStateMap | undefined;
131
+ /** The full auth of whoever approved `requestId`, when a person allowed it. */
132
+ export declare function responderOfRequest(state: SessionStateMap | undefined, requestId: string): SessionAuthContext | undefined;
120
133
  export {};
@@ -1 +1 @@
1
- const APPROVAL_STATE_KEY=`eve.runtime.hitl.approvalState`;function createApprovalCandidate(e){let t=expireApprovalCandidates({now:e.createdAt,state:e.state}),n=readApprovalState(t);if(n.settlements[e.requestId]!==void 0)return{changed:!1,state:t};let r=e.responder;if(Object.values(n.activeCandidates).find(t=>t.requestId===e.requestId&&t.decision===e.decision&&sameResponder(t.responder,r))!==void 0)return{changed:!1,state:t};let i=n.activeCandidates[e.candidateIdPrefix]!==void 0||n.candidateHistory.some(t=>t.candidateId===e.candidateIdPrefix)?`${e.candidateIdPrefix}.${n.nextCandidateSequence.toString(36)}`:e.candidateIdPrefix;if(n.activeCandidates[i]!==void 0||n.candidateHistory.some(e=>e.candidateId===i))throw Error(`Approval candidate id collision: "${i}".`);let a={candidateId:i,createdAt:e.createdAt,decision:e.decision,expiresAt:e.expiresAt,requestId:e.requestId,responder:r,status:`pending`};return{changed:!0,state:writeApprovalState(t,{...n,activeCandidates:{...n.activeCandidates,[a.candidateId]:a},nextCandidateSequence:n.nextCandidateSequence+1})}}function markApprovalCandidateAuthorizationRequired(e){let t=readApprovalState(e.state),n=t.activeCandidates[e.candidateId];if(n===void 0)return e.state;let r={...n,authorizationChallenges:e.authorizationChallenges,expiresAt:e.expiresAt??n.expiresAt,status:`authorization-required`};return writeApprovalState(e.state,{...t,activeCandidates:{...t.activeCandidates,[e.candidateId]:r}})}function finishApprovalCandidate(e){let t=readApprovalState(e.state),n=t.activeCandidates[e.candidateId];if(n===void 0)return e.state;let r={...t.activeCandidates};return delete r[e.candidateId],writeApprovalState(e.state,{...t,activeCandidates:r,candidateHistory:[...t.candidateHistory,toCandidateAuditRecord({candidate:n,completedAt:e.completedAt,reason:e.reason,status:e.status})]})}function expireApprovalCandidates(e){let t=e.state,n=Object.values(readApprovalState(t).activeCandidates);for(let r of n)r.expiresAt>e.now||(t=finishApprovalCandidate({candidateId:r.candidateId,completedAt:e.now,state:t,status:`timed-out`}));return t}function settleAllowedCandidate(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state}),n=readApprovalState(t),r=n.activeCandidates[e.candidateId];if(r===void 0){let r=n.candidateHistory.find(t=>t.candidateId===e.candidateId);if((r&&n.settlements[r.requestId])!==void 0)return{changed:!1,state:t};throw Error(`Unknown approval candidate "${e.candidateId}".`)}return settleRequest({candidateId:r.candidateId,outcome:r.decision===`cancel`?`cancelled`:`allowed`,requestId:r.requestId,responder:r.responder,settledAt:e.settledAt,state:t})}function settleUnavailableCandidate(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state}),n=readApprovalState(t).activeCandidates[e.candidateId];return n===void 0?{changed:!1,state:t}:settleRequest({candidateId:n.candidateId,outcome:`unavailable`,reason:e.reason,requestId:n.requestId,responder:n.responder,settledAt:e.settledAt,state:t})}function settleDirectApprovalResponse(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state});return settleRequest({outcome:e.outcome,requestId:e.requestId,responder:e.actor,settledAt:e.settledAt,state:t})}function getActiveApprovalCandidate(e,t){return readApprovalState(e).activeCandidates[t]}function getApprovalAuditState(e){let t=readApprovalState(e);return{activeCandidates:Object.values(t.activeCandidates),candidateHistory:t.candidateHistory,settlements:Object.values(t.settlements)}}function settleRequest(e){let t=readApprovalState(e.state);if(t.settlements[e.requestId]!==void 0)return{changed:!1,state:e.state};let n={actor:projectResponder(e.responder),candidateId:e.candidateId,outcome:e.outcome,requestId:e.requestId,settledAt:e.settledAt},r={},i=[...t.candidateHistory];for(let n of Object.values(t.activeCandidates)){if(n.requestId!==e.requestId){r[n.candidateId]=n;continue}let t=n.candidateId===e.candidateId;i.push(toCandidateAuditRecord({candidate:n,completedAt:e.settledAt,reason:t?e.reason:void 0,status:t?e.outcome===`unavailable`?`failed`:`allowed`:`stale`}))}let a={activeCandidates:r,candidateHistory:i,nextCandidateSequence:t.nextCandidateSequence,settlements:{...t.settlements,[e.requestId]:n}};return{changed:!0,state:writeApprovalState(e.state,a)}}function toCandidateAuditRecord(e){let{authorizationChallenges:t,responder:n,...r}=e.candidate;return{...r,completedAt:e.completedAt,responder:projectResponder(n),reason:e.reason,status:e.status}}function projectResponder(e){return{authenticator:e.authenticator,issuer:e.issuer,principalId:e.principalId,principalType:e.principalType}}function sameResponder(e,t){return e.authenticator===t.authenticator&&e.issuer===t.issuer&&e.principalId===t.principalId&&e.principalType===t.principalType}function readActiveCandidates(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,{...t,decision:t.decision===`cancel`?`cancel`:`approve`}]))}function readApprovalState(e){let t=e?.[APPROVAL_STATE_KEY];if(typeof t!=`object`||!t)return{activeCandidates:{},candidateHistory:[],nextCandidateSequence:0,settlements:{}};let n=t;return{activeCandidates:typeof n.activeCandidates==`object`&&n.activeCandidates!==null?readActiveCandidates(n.activeCandidates):{},candidateHistory:Array.isArray(n.candidateHistory)?n.candidateHistory:[],nextCandidateSequence:typeof n.nextCandidateSequence==`number`&&Number.isSafeInteger(n.nextCandidateSequence)&&n.nextCandidateSequence>=0?n.nextCandidateSequence:deriveNextCandidateSequence(n),settlements:typeof n.settlements==`object`&&n.settlements!==null?n.settlements:{}}}function deriveNextCandidateSequence(e){return Object.keys(e.activeCandidates??{}).length+(Array.isArray(e.candidateHistory)?e.candidateHistory.length:0)}function writeApprovalState(e,t){return{...e,[APPROVAL_STATE_KEY]:t}}function retireActiveCandidates(e,t){let n=e;for(let e of getApprovalAuditState(n).activeCandidates)n=finishApprovalCandidate({candidateId:e.candidateId,completedAt:t.completedAt,reason:t.reason,state:n,status:`stale`});return n}export{createApprovalCandidate,expireApprovalCandidates,finishApprovalCandidate,getActiveApprovalCandidate,getApprovalAuditState,markApprovalCandidateAuthorizationRequired,retireActiveCandidates,sameResponder,settleAllowedCandidate,settleDirectApprovalResponse,settleUnavailableCandidate};
1
+ import{readApprovalState,writeApprovalState}from"./requests.js";function createApprovalCandidate(e){let t=expireApprovalCandidates({now:e.createdAt,state:e.state}),n=readApprovalState(t);if(n.settlements[e.requestId]!==void 0)return{changed:!1,state:t};let r=e.responder;if(Object.values(n.activeCandidates).find(t=>t.requestId===e.requestId&&t.decision===e.decision&&sameResponder(t.responder,r))!==void 0)return{changed:!1,state:t};let i=n.activeCandidates[e.candidateIdPrefix]!==void 0||n.candidateHistory.some(t=>t.candidateId===e.candidateIdPrefix)?`${e.candidateIdPrefix}.${n.nextCandidateSequence.toString(36)}`:e.candidateIdPrefix;if(n.activeCandidates[i]!==void 0||n.candidateHistory.some(e=>e.candidateId===i))throw Error(`Approval candidate id collision: "${i}".`);let a={candidateId:i,createdAt:e.createdAt,decision:e.decision,expiresAt:e.expiresAt,requestId:e.requestId,responder:r,status:`pending`},o={...n,activeCandidates:{...n.activeCandidates,[a.candidateId]:a},nextCandidateSequence:n.nextCandidateSequence+1};return{changed:!0,state:writeApprovalState(t,o)}}function markApprovalCandidateAuthorizationRequired(e){let t=readApprovalState(e.state),n=t.activeCandidates[e.candidateId];if(n===void 0)return e.state;let r={...n,authorizationChallenges:e.authorizationChallenges,expiresAt:e.expiresAt??n.expiresAt,status:`authorization-required`};return writeApprovalState(e.state,{...t,activeCandidates:{...t.activeCandidates,[e.candidateId]:r}})}function finishApprovalCandidate(e){let t=readApprovalState(e.state),n=t.activeCandidates[e.candidateId];if(n===void 0)return e.state;let r={...t.activeCandidates};return delete r[e.candidateId],writeApprovalState(e.state,{...t,activeCandidates:r,candidateHistory:[...t.candidateHistory,toCandidateAuditRecord({candidate:n,completedAt:e.completedAt,reason:e.reason,status:e.status})]})}function expireApprovalCandidates(e){let t=e.state,n=Object.values(readApprovalState(t).activeCandidates);for(let r of n)r.expiresAt>e.now||(t=finishApprovalCandidate({candidateId:r.candidateId,completedAt:e.now,state:t,status:`timed-out`}));return t}function settleAllowedCandidate(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state}),n=readApprovalState(t),r=n.activeCandidates[e.candidateId];if(r===void 0){let r=n.candidateHistory.find(t=>t.candidateId===e.candidateId);if((r&&n.settlements[r.requestId])!==void 0)return{changed:!1,state:t};throw Error(`Unknown approval candidate "${e.candidateId}".`)}return settleRequest({candidateId:r.candidateId,outcome:r.decision===`cancel`?`cancelled`:`allowed`,requestId:r.requestId,responder:r.responder,settledAt:e.settledAt,state:t})}function settleUnavailableCandidate(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state}),n=readApprovalState(t).activeCandidates[e.candidateId];return n===void 0?{changed:!1,state:t}:settleRequest({candidateId:n.candidateId,outcome:`unavailable`,reason:e.reason,requestId:n.requestId,responder:n.responder,settledAt:e.settledAt,state:t})}function settleDirectApprovalResponse(e){let t=expireApprovalCandidates({now:e.settledAt,state:e.state});return settleRequest({outcome:e.outcome,requestId:e.requestId,responder:e.actor,settledAt:e.settledAt,state:t})}function getActiveApprovalCandidate(e,t){return readApprovalState(e).activeCandidates[t]}function getApprovalAuditState(e){let t=readApprovalState(e);return{activeCandidates:Object.values(t.activeCandidates),candidateHistory:t.candidateHistory,settlements:Object.values(t.settlements)}}function settleRequest(e){let t=readApprovalState(e.state);if(t.settlements[e.requestId]!==void 0)return{changed:!1,state:e.state};let n={actor:projectResponder(e.responder),...e.outcome===`allowed`&&{responder:e.responder},candidateId:e.candidateId,outcome:e.outcome,requestId:e.requestId,settledAt:e.settledAt},r={},i=[...t.candidateHistory];for(let n of Object.values(t.activeCandidates)){if(n.requestId!==e.requestId){r[n.candidateId]=n;continue}let t=n.candidateId===e.candidateId;i.push(toCandidateAuditRecord({candidate:n,completedAt:e.settledAt,reason:t?e.reason:void 0,status:t?e.outcome===`unavailable`?`failed`:`allowed`:`stale`}))}let a={activeCandidates:r,candidateHistory:i,nextCandidateSequence:t.nextCandidateSequence,settlements:{...t.settlements,[e.requestId]:n}};return{changed:!0,state:writeApprovalState(e.state,a)}}function toCandidateAuditRecord(e){let{authorizationChallenges:t,responder:n,...r}=e.candidate;return{...r,completedAt:e.completedAt,responder:projectResponder(n),reason:e.reason,status:e.status}}function projectResponder(e){return{authenticator:e.authenticator,issuer:e.issuer,principalId:e.principalId,principalType:e.principalType}}function sameResponder(e,t){return e.authenticator===t.authenticator&&e.issuer===t.issuer&&e.principalId===t.principalId&&e.principalType===t.principalType}function retireActiveCandidates(e,t){let n=e;for(let e of getApprovalAuditState(n).activeCandidates)n=finishApprovalCandidate({candidateId:e.candidateId,completedAt:t.completedAt,reason:t.reason,state:n,status:`stale`});return n}function responderOfRequest(e,t){return readApprovalState(e).settlements[t]?.responder}export{createApprovalCandidate,expireApprovalCandidates,finishApprovalCandidate,getActiveApprovalCandidate,getApprovalAuditState,markApprovalCandidateAuthorizationRequired,responderOfRequest,retireActiveCandidates,sameResponder,settleAllowedCandidate,settleDirectApprovalResponse,settleUnavailableCandidate};
@@ -1 +1 @@
1
- import{createLogger,logError}from"#internal/logging.js";import{contextStorage}from"#context/container.js";import{AuthKey,SessionKey}from"#context/keys.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{buildApprovalResponseAuth,handleApprovalResponsePolicyError}from"#execution/tool-auth.js";import{suspendedSteps}from"#harness/session-machine/view.js";import{clearPendingAuthorization,getAuthorizationResult,getPendingAuthorization,isAuthorizationSignal}from"#harness/authorization.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{createApprovalCandidate,expireApprovalCandidates,finishApprovalCandidate,getActiveApprovalCandidate,getApprovalAuditState,markApprovalCandidateAuthorizationRequired,sameResponder,settleAllowedCandidate,settleDirectApprovalResponse,settleUnavailableCandidate}from"#harness/hitl/candidates.js";const TEMPORARILY_UNAVAILABLE_APPROVAL_REASON=`Approval authorization is temporarily unavailable. Please try again.`,log=createLogger(`harness.hitl`);async function coordinateApprovalDelivery(e){let t=e.now??Date.now(),n=getApprovalAuditState(e.session.state).activeCandidates.filter(e=>e.expiresAt<=t),r=n.flatMap(e=>e.authorizationChallenges?.map(e=>e.attemptId??e.candidateId??e.name)??[]),i=expireApprovalCandidates({now:t,state:e.session.state}),a={...e.session,state:clearPendingAuthorization(i,r)},o=getApprovalAuditState(a.state),s=suspendedSteps(a.state).filter(e=>e.requests.length>0),c=new Set(s.flatMap(e=>e.requests.map(e=>e.requestId))),l=o.settlements.filter(e=>c.has(e.requestId)),u=new Set(o.settlements.map(e=>e.requestId)),d=new Set([...u].filter(e=>!c.has(e))),f=hasResponseForRequest(e.stepInput,d),p=f?removeConsumedResponses(e.stepInput,d):e.stepInput;if(f&&l.length===0&&!hasMeaningfulInput(p))return deliveryResult(a,p,`park`);if(s.length===0)return deliveryResult(a,p);let m=p,h=new Set(s.flatMap(e=>e.responseAuthRequiredRequestIds??[])),g=s.flatMap(e=>e.requests),_=new Map(g.map(e=>[e.requestId,e])),v=[],y=[],b=new Set,x=!1,S=getApprovalAuditState(a.state).activeCandidates,C=[...m?.attributedInputResponses??[],...(m?.inputResponses??[]).map(e=>({auth:void 0,response:e}))];for(let{auth:e,response:n}of C){let r=_.get(n.requestId);if(r===void 0||!isApprovalRequest(r))continue;if(!h.has(n.requestId)){let r=contextStorage.getStore(),i=e===void 0?r?.get(AuthKey)??r?.get(SessionKey)?.auth.current??null:e,o=toCandidateDecision(n.optionId),s=suspendedSteps(a.state).find(e=>e.requests.some(e=>e.requestId===n.requestId))?.requester??null;if(i!==null&&o!==void 0&&s!==null&&!sameResponder(s,i)){b.add(n.requestId),y.push(`Only the person who requested this action can respond to this approval.`);continue}if(i!==null&&o!==void 0){let e=settleDirectApprovalResponse({actor:i,outcome:o===`approve`?`allowed`:`cancelled`,requestId:n.requestId,settledAt:t,state:a.state});a={...a,state:e.state},x||=e.changed}continue}b.add(n.requestId);let i=toCandidateDecision(n.optionId);if(i===void 0)continue;let o=e===void 0?buildCallbackContext().session.auth.current:e;if(o===null){y.push(`Authentication is required to respond to this approval.`);continue}let s=createApprovalCandidate({candidateIdPrefix:approvalCandidateIdPrefix(r.requestId,o,i),createdAt:t,decision:i,expiresAt:t+6e5,requestId:r.requestId,responder:o,state:a.state});a={...a,state:s.state},x||=s.changed}let w=removeConsumedResponses(m,b);if(b.size>0)return deliveryResult(a,w,x?`continue-coordination`:`continue`,[],y);if(x)return deliveryResult(a,w,`continue`,[],y);let T=new Set(getPendingAuthorization(a.state)?.challenges.map(e=>e.name)??[]);for(let n of S){if(n.status===`authorization-required`){let e=n.authorizationChallenges??[];if(!e.some(e=>getAuthorizationResult(e.name)!==void 0)){v.push(...e.filter(e=>!T.has(e.name)));continue}}let r=_.get(n.requestId);if(r===void 0||getActiveApprovalCandidate(a.state,n.candidateId)===void 0)continue;let i=await authorizeCandidate({candidateId:n.candidateId,decision:n.decision,now:t,request:r,responder:n.responder,restoreTools:async()=>await e.prepareTools?.(r)??e.tools,session:a});a=i.session,x||=i.didCommit,v.push(...i.challenges);let o=getApprovalAuditState(a.state).settlements.find(e=>e.requestId===n.requestId);o!==void 0&&l.push(o)}let E=appendSettledResponses(w,l);return(x||n.length>0)&&getApprovalAuditState(a.state).activeCandidates.length===0?deliveryResult(a,E,`responses-completed`):l.length>0?deliveryResult(a,E,`continue`):x?deliveryResult(a,E,`continue-coordination`):deliveryResult(a,E,v.length>0?`authorization-required`:`continue`,v)}async function authorizeCandidate(e){let t={...e.session,state:expireApprovalCandidates({now:e.now,state:e.session.state})};if(getActiveApprovalCandidate(t.state,e.candidateId)===void 0)return{challenges:[],didCommit:!1,session:t};let n;try{n=await e.restoreTools()}catch(n){return logError(log,`approval tools could not be restored`,n,{requestId:e.request.requestId}),failCandidate({...e,reason:TEMPORARILY_UNAVAILABLE_APPROVAL_REASON,session:t})}let r=n.get(e.request.action.toolName);if(r===void 0){let n=settleUnavailableCandidate({candidateId:e.candidateId,reason:`The tool this approval was for is no longer available, so the call won't run.`,settledAt:e.now,state:t.state});return{challenges:[],didCommit:n.changed,session:{...t,state:n.state}}}let{approval:i}=r,a=i!==void 0&&typeof i!=`function`?i.response:void 0;if(a===void 0)return failCandidate({...e,reason:TEMPORARILY_UNAVAILABLE_APPROVAL_REASON,session:t});try{let n=buildCallbackContext(),r=await withAuthorizerTimeout(a({auth:buildApprovalResponseAuth({responder:e.responder,scope:e.candidateId}),request:{callId:e.request.action.callId,requestId:e.request.requestId,principal:suspendedSteps(t.state).find(t=>t.requests.some(t=>t.requestId===e.request.requestId))?.requester??null,toolInput:e.request.action.input,toolName:e.request.action.toolName},response:{decision:e.decision,principal:e.responder},session:{id:n.session.id,initiator:n.session.auth.initiator,parent:n.session.parent,turn:n.session.turn}}));if(r.status===`rejected`)return t={...t,state:finishApprovalCandidate({candidateId:e.candidateId,completedAt:e.now,reason:r.reason,state:t.state,status:`rejected`})},{challenges:[],didCommit:!0,session:t};if(r.status!==`allowed`)return failCandidate({...e,session:t});let i=settleAllowedCandidate({candidateId:e.candidateId,settledAt:e.now,state:t.state});return{challenges:[],didCommit:i.changed,session:{...t,state:i.state}}}catch(n){let r=await handleApprovalResponsePolicyError(n).catch(()=>void 0);if(isAuthorizationSignal(r)){let n=r.challenges.map(e=>Date.parse(e.challenge.expiresAt??``)).filter(Number.isFinite).sort((e,t)=>e-t)[0];return t={...t,state:markApprovalCandidateAuthorizationRequired({authorizationChallenges:r.challenges.map(t=>({...t,candidateId:e.candidateId})),candidateId:e.candidateId,expiresAt:n,state:t.state})},{challenges:r.challenges.map(t=>({...t,candidateId:e.candidateId})),didCommit:!0,session:t}}return failCandidate({...e,session:t})}}function failCandidate(e){let t=e.reason??`We couldn’t verify your response. Please try again.`;return{challenges:[],didCommit:!0,session:{...e.session,state:finishApprovalCandidate({candidateId:e.candidateId,completedAt:e.now,reason:t,state:e.session.state,status:`failed`})}}}function hasResponseForRequest(e,t){return e?.attributedInputResponses?.some(({response:e})=>t.has(e.requestId))===!0||e?.inputResponses?.some(e=>t.has(e.requestId))===!0}function hasMeaningfulInput(e){return e?.message!==void 0||(e?.attributedInputResponses?.length??0)>0||(e?.inputResponses?.length??0)>0||(e?.runtimeActionResults?.length??0)>0}function appendSettledResponses(e,t){if(t.length===0)return e;let n=new Set([...(e?.inputResponses??[]).map(e=>e.requestId),...(e?.attributedInputResponses??[]).map(({response:e})=>e.requestId)]),r=t.filter(e=>!n.has(e.requestId));return r.length===0?e:{...e,inputResponses:[...e?.inputResponses??[],...r.map(e=>({optionId:e.outcome===`allowed`?`approve`:`cancel`,requestId:e.requestId}))]}}function removeConsumedResponses(e,t){if(e===void 0)return;let n=(e.attributedInputResponses??[]).filter(({response:e})=>!t.has(e.requestId)),r=[...(e.inputResponses??[]).filter(e=>!t.has(e.requestId)),...n.map(({response:e})=>e)];return{...e,attributedInputResponses:void 0,inputResponses:r}}function deliveryResult(e,t,n=`continue`,r=[],i=[]){return{challenges:r,feedback:i,kind:n,session:e,stepInput:t}}function toCandidateDecision(e){if(e===`approve`)return`approve`;if(e===`cancel`||e===`deny`)return`cancel`}function approvalCandidateIdPrefix(e,t,n){let r=[t.authenticator,t.issuer??``,t.principalType,t.principalId].join(`:`),i=`${encodeCandidateIdPart(e)}.${encodeCandidateIdPart(r)}`;return n===`approve`?i:`${i}.${encodeCandidateIdPart(n)}`}function encodeCandidateIdPart(e){return Array.from(e,e=>e.codePointAt(0).toString(36)).join(`-`)}async function withAuthorizerTimeout(e){let t;try{return await Promise.race([Promise.resolve(e),new Promise((e,n)=>{t=setTimeout(()=>n(Error(`Approval response authorizer timed out.`)),1e4)})])}finally{t!==void 0&&clearTimeout(t)}}export{coordinateApprovalDelivery};
1
+ import{signInAttemptKey}from"./sign-ins.js";import{readHitlState}from"./requests.js";import{createLogger,logError}from"#internal/logging.js";import{contextStorage}from"#context/container.js";import{AuthKey,SessionKey}from"#context/keys.js";import{buildCallbackContext}from"#context/build-callback-context.js";import{buildApprovalResponseAuth,handleApprovalResponsePolicyError}from"#execution/tool-auth.js";import{storedProjection,suspendedSteps}from"#harness/session-machine/view.js";import{getAuthorizationResult,isAuthorizationSignal}from"#harness/authorization.js";import{saveTransition,sessionView}from"#harness/session-machine/commit.js";import{matchSignIns}from"#harness/session-machine/transitions.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{createApprovalCandidate,expireApprovalCandidates,finishApprovalCandidate,getActiveApprovalCandidate,getApprovalAuditState,markApprovalCandidateAuthorizationRequired,sameResponder,settleAllowedCandidate,settleDirectApprovalResponse,settleUnavailableCandidate}from"#harness/hitl/candidates.js";const TEMPORARILY_UNAVAILABLE_APPROVAL_REASON=`Approval authorization is temporarily unavailable. Please try again.`,log=createLogger(`harness.hitl`);async function coordinateApprovalDelivery(e){let t=e.now??Date.now(),n=getApprovalAuditState(e.session.state).activeCandidates.filter(e=>e.expiresAt<=t),r=new Set(n.flatMap(e=>e.authorizationChallenges?.map(signInAttemptKey)??[])),i=expireApprovalCandidates({now:t,state:e.session.state}),a={...e.session,state:i};if(r.size>0){let e=sessionView(storedProjection(a.state),a.state);a=saveTransition(a,matchSignIns(e,{attemptIds:[...r]}))}let o=getApprovalAuditState(a.state),s=suspendedSteps(a.state).filter(e=>e.requests.length>0),c=new Set(s.flatMap(e=>e.requests.map(e=>e.requestId))),l=o.settlements.filter(e=>c.has(e.requestId)),u=new Set(o.settlements.map(e=>e.requestId)),d=new Set([...u].filter(e=>!c.has(e))),f=hasResponseForRequest(e.stepInput,d),p=f?removeConsumedResponses(e.stepInput,d):e.stepInput;if(f&&l.length===0&&!hasMeaningfulInput(p))return deliveryResult(a,p,`park`);if(s.length===0)return deliveryResult(a,p);let m=p,h=new Set(s.flatMap(e=>e.responseAuthRequiredRequestIds??[])),g=s.flatMap(e=>e.requests),_=new Map(g.map(e=>[e.requestId,e])),v=[],y=[],b=new Set,x=!1,S=getApprovalAuditState(a.state).activeCandidates,C=[...m?.attributedInputResponses??[],...(m?.inputResponses??[]).map(e=>({auth:void 0,response:e}))];for(let{auth:e,response:n}of C){let r=_.get(n.requestId);if(r===void 0||!isApprovalRequest(r))continue;if(!h.has(n.requestId)){let r=contextStorage.getStore(),i=e===void 0?r?.get(AuthKey)??r?.get(SessionKey)?.auth.current??null:e,o=toCandidateDecision(n.optionId),s=suspendedSteps(a.state).find(e=>e.requests.some(e=>e.requestId===n.requestId))?.requester??null;if(i!==null&&o!==void 0&&s!==null&&!sameResponder(s,i)){b.add(n.requestId),y.push(`Only the person who requested this action can respond to this approval.`);continue}if(i!==null&&o!==void 0){let e=settleDirectApprovalResponse({actor:i,outcome:o===`approve`?`allowed`:`cancelled`,requestId:n.requestId,settledAt:t,state:a.state});a={...a,state:e.state},x||=e.changed}continue}b.add(n.requestId);let i=toCandidateDecision(n.optionId);if(i===void 0)continue;let o=e===void 0?buildCallbackContext().session.auth.current:e;if(o===null){y.push(`Authentication is required to respond to this approval.`);continue}let s=createApprovalCandidate({candidateIdPrefix:approvalCandidateIdPrefix(r.requestId,o,i),createdAt:t,decision:i,expiresAt:t+6e5,requestId:r.requestId,responder:o,state:a.state});a={...a,state:s.state},x||=s.changed}let w=removeConsumedResponses(m,b);if(b.size>0)return deliveryResult(a,w,x?`continue-coordination`:`continue`,[],y);if(x)return deliveryResult(a,w,`continue`,[],y);let T=new Set(readHitlState(a.state).signIns.map(e=>e.name));for(let n of S){if(n.status===`authorization-required`){let e=n.authorizationChallenges??[];if(!e.some(e=>getAuthorizationResult(e.name)!==void 0)){v.push(...e.filter(e=>!T.has(e.name)));continue}}let r=_.get(n.requestId);if(r===void 0||getActiveApprovalCandidate(a.state,n.candidateId)===void 0)continue;let i=await authorizeCandidate({candidateId:n.candidateId,decision:n.decision,now:t,request:r,responder:n.responder,restoreTools:async()=>await e.prepareTools?.(r)??e.tools,session:a});a=i.session,x||=i.didCommit,v.push(...i.challenges);let o=getApprovalAuditState(a.state).settlements.find(e=>e.requestId===n.requestId);o!==void 0&&l.push(o)}let E=appendSettledResponses(w,l);return(x||n.length>0)&&getApprovalAuditState(a.state).activeCandidates.length===0?deliveryResult(a,E,`responses-completed`):l.length>0?deliveryResult(a,E,`continue`):x?deliveryResult(a,E,`continue-coordination`):deliveryResult(a,E,v.length>0?`authorization-required`:`continue`,v)}async function authorizeCandidate(e){let t={...e.session,state:expireApprovalCandidates({now:e.now,state:e.session.state})};if(getActiveApprovalCandidate(t.state,e.candidateId)===void 0)return{challenges:[],didCommit:!1,session:t};let n;try{n=await e.restoreTools()}catch(n){return logError(log,`approval tools could not be restored`,n,{requestId:e.request.requestId}),failCandidate({...e,reason:TEMPORARILY_UNAVAILABLE_APPROVAL_REASON,session:t})}let r=n.get(e.request.action.toolName);if(r===void 0){let n=settleUnavailableCandidate({candidateId:e.candidateId,reason:`The tool this approval was for is no longer available, so the call won't run.`,settledAt:e.now,state:t.state});return{challenges:[],didCommit:n.changed,session:{...t,state:n.state}}}let{approval:i}=r,a=i!==void 0&&typeof i!=`function`?i.response:void 0;if(a===void 0)return failCandidate({...e,reason:TEMPORARILY_UNAVAILABLE_APPROVAL_REASON,session:t});try{let n=buildCallbackContext(),r=await withAuthorizerTimeout(a({auth:buildApprovalResponseAuth({responder:e.responder,scope:e.candidateId}),request:{callId:e.request.action.callId,requestId:e.request.requestId,principal:suspendedSteps(t.state).find(t=>t.requests.some(t=>t.requestId===e.request.requestId))?.requester??null,toolInput:e.request.action.input,toolName:e.request.action.toolName},response:{decision:e.decision,principal:e.responder},session:{id:n.session.id,initiator:n.session.auth.initiator,parent:n.session.parent,turn:n.session.turn}}));if(r.status===`rejected`)return t={...t,state:finishApprovalCandidate({candidateId:e.candidateId,completedAt:e.now,reason:r.reason,state:t.state,status:`rejected`})},{challenges:[],didCommit:!0,session:t};if(r.status!==`allowed`)return failCandidate({...e,session:t});let i=settleAllowedCandidate({candidateId:e.candidateId,settledAt:e.now,state:t.state});return{challenges:[],didCommit:i.changed,session:{...t,state:i.state}}}catch(n){let r=await handleApprovalResponsePolicyError(n).catch(()=>void 0);if(isAuthorizationSignal(r)){let n=r.challenges.map(e=>Date.parse(e.challenge.expiresAt??``)).filter(Number.isFinite).sort((e,t)=>e-t)[0];return t={...t,state:markApprovalCandidateAuthorizationRequired({authorizationChallenges:r.challenges.map(t=>({...t,candidateId:e.candidateId})),candidateId:e.candidateId,expiresAt:n,state:t.state})},{challenges:r.challenges.map(t=>({...t,candidateId:e.candidateId})),didCommit:!0,session:t}}return failCandidate({...e,session:t})}}function failCandidate(e){let t=e.reason??`We couldn’t verify your response. Please try again.`;return{challenges:[],didCommit:!0,session:{...e.session,state:finishApprovalCandidate({candidateId:e.candidateId,completedAt:e.now,reason:t,state:e.session.state,status:`failed`})}}}function hasResponseForRequest(e,t){return e?.attributedInputResponses?.some(({response:e})=>t.has(e.requestId))===!0||e?.inputResponses?.some(e=>t.has(e.requestId))===!0}function hasMeaningfulInput(e){return e?.message!==void 0||(e?.attributedInputResponses?.length??0)>0||(e?.inputResponses?.length??0)>0||(e?.runtimeActionResults?.length??0)>0}function appendSettledResponses(e,t){if(t.length===0)return e;let n=new Set([...(e?.inputResponses??[]).map(e=>e.requestId),...(e?.attributedInputResponses??[]).map(({response:e})=>e.requestId)]),r=t.filter(e=>!n.has(e.requestId));return r.length===0?e:{...e,inputResponses:[...e?.inputResponses??[],...r.map(e=>({optionId:e.outcome===`allowed`?`approve`:`cancel`,requestId:e.requestId}))]}}function removeConsumedResponses(e,t){if(e===void 0)return;let n=(e.attributedInputResponses??[]).filter(({response:e})=>!t.has(e.requestId)),r=[...(e.inputResponses??[]).filter(e=>!t.has(e.requestId)),...n.map(({response:e})=>e)];return{...e,attributedInputResponses:void 0,inputResponses:r}}function deliveryResult(e,t,n=`continue`,r=[],i=[]){return{challenges:r,feedback:i,kind:n,session:e,stepInput:t}}function toCandidateDecision(e){if(e===`approve`)return`approve`;if(e===`cancel`||e===`deny`)return`cancel`}function approvalCandidateIdPrefix(e,t,n){let r=[t.authenticator,t.issuer??``,t.principalType,t.principalId].join(`:`),i=`${encodeCandidateIdPart(e)}.${encodeCandidateIdPart(r)}`;return n===`approve`?i:`${i}.${encodeCandidateIdPart(n)}`}function encodeCandidateIdPart(e){return Array.from(e,e=>e.codePointAt(0).toString(36)).join(`-`)}async function withAuthorizerTimeout(e){let t;try{return await Promise.race([Promise.resolve(e),new Promise((e,n)=>{t=setTimeout(()=>n(Error(`Approval response authorizer timed out.`)),1e4)})])}finally{t!==void 0&&clearTimeout(t)}}export{coordinateApprovalDelivery};
@@ -8,6 +8,7 @@ import type { InputRequest } from "#shared/input.js";
8
8
  export { acceptHumanInput, admitApprovedWork, dispatchApprovedWorkflows, hasApprovedWork, runApprovedLocalCalls, type ApprovedWork, type HumanInputIntake, } from "./intake.js";
9
9
  export { extractToolApprovalInputRequests } from "#harness/input-extraction.js";
10
10
  export { hasRunnableQueue } from "./approvals.js";
11
+ export { discardClearedHitlState as discardClearedHumanInput } from "./requests.js";
11
12
  /**
12
13
  * A model step made calls that need a person's approval: the step parks on them beside any
13
14
  * runtime calls it made. The turn holds for the answers, unless the runtime runs calls for it
@@ -42,11 +43,6 @@ export declare function humanInputContext(step: Step, tools: HarnessToolLookup):
42
43
  readonly approvedTools: ReadonlySet<string>;
43
44
  readonly pendingApprovalsNote?: string;
44
45
  };
45
- /**
46
- * Drops what a cleared context owned: sign-in attempts and responders' approval progress. `clear`
47
- * reported each close; relay routes for live tasks stay.
48
- */
49
- export declare function discardClearedHumanInput<T extends HarnessSessionBase>(session: T): T;
50
46
  /** The cancelled turn's responders stop checking its approvals: their candidates stale. */
51
47
  export declare function retireCancelledCandidates<T extends HarnessSessionBase>(session: T): T;
52
48
  /**
@@ -57,3 +53,4 @@ export declare function takeDeferredMessage<T extends HarnessSessionBase>(sessio
57
53
  readonly message?: StepInput["message"];
58
54
  readonly session: T;
59
55
  };
56
+ export { readHitlState, holdsHitlRequests } from "./requests.js";
@@ -1 +1 @@
1
- import{renderPendingApprovalsInstruction}from"./approval-prompt.js";import{isEmptyInput}from"./delivery.js";import{grantedApprovalKeys,hasRunnableQueue,parkOnApprovals as parkOnApprovals$1,requestLimit,requireSignIn}from"./approvals.js";import{checkSessionUsageLimit}from"./budget.js";import{retireActiveCandidates}from"./candidates.js";import{acceptHumanInput,admitApprovedWork,dispatchApprovedWorkflows,hasApprovedWork,holdForInput,runApprovedLocalCalls}from"./intake.js";import{AuthKey,SessionKey}from"#context/keys.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{clearPendingAuthorization}from"#harness/authorization.js";import{fail,hold}from"#harness/session-machine/transitions.js";import{readTurnState,writeTurnState}from"#harness/session-machine/state.js";import{extractToolApprovalInputRequests}from"#harness/input-extraction.js";async function parkOnApprovals(e,t){let n=parkOnApprovals$1(e.view(),{event:t.event,messages:t.messages,requests:t.requests,tasks:t.tasks,requester:currentRequester(e),responseAuthRequiredRequestIds:responsePolicyRequestIds(t.tools,t.requests)});return await e.apply(n,[...e.session.history,...n.commit??[]]),t.waitsOn===void 0?hasRunnableQueue(e.view())?{next:e.runStep,session:e.session}:holdForInput(e):(t.waitsOn===`runtime`&&t.tasks.some(e=>e.entry.entryPoint===`execute`)&&await e.apply(hold(e.view(),{on:`tasks`})),{next:null,session:e.session})}async function stopForToolSignIn(e,t){return e.session={...e.session,history:validateHarnessModelMessages(t.history)},await e.apply(requireSignIn(e.view(),{callIdsByName:t.callIdsByName,challenges:t.challenges}),e.session.history),{held:{kind:`request`},next:null,session:e.session}}async function enforceBudget(e,t){let n=checkSessionUsageLimit({canAsk:e.emit!==void 0&&e.config.capabilities?.requestInput===!0,session:e.session,turnSequence:e.position().sequence});if(n.kind!==`within`)return n.kind===`ask`?(e.session={...e.session,history:validateHarnessModelMessages([...t])},await e.apply(requestLimit(e.view(),{request:n.request}),e.session.history),{next:null,session:e.session}):(await e.apply(fail(e.view(),{code:n.code,details:n.details,message:n.message,terminal:{sessionId:e.session.sessionId}})),{next:{done:!0,output:``},session:e.session})}function humanInputContext(e,t){let n=e.view();return{approvedTools:grantedApprovalKeys(n,e=>t.get(e.action.toolName)?.approvalKey?.(e.action.input)),pendingApprovalsNote:renderPendingApprovalsInstruction(n.turn.suspended.flatMap(e=>e.requests))}}function discardClearedHumanInput(e){let{"eve.runtime.hitl.approvalState":t,...n}=clearPendingAuthorization(e.state)??{};return{...e,state:Object.keys(n).length>0?n:void 0}}function responsePolicyRequestIds(e,t){return t.filter(t=>{let n=e.get(t.action.toolName)?.approval;return n!==void 0&&typeof n!=`function`&&n.response!==void 0}).map(e=>e.requestId)}function currentRequester(e){return e.ctx?.get(AuthKey)??e.ctx?.get(SessionKey)?.auth.current??null}function retireCancelledCandidates(e){return{...e,state:retireActiveCandidates(e.state,{completedAt:Date.now(),reason:`Cancelled.`})}}function takeDeferredMessage(e){let{queued:t,...n}=readTurnState(e.state);if(t?.message===void 0)return{session:e};let{message:r,...i}=t;return{message:r,session:writeTurnState(e,isEmptyInput(i)?n:{...n,queued:i})}}export{acceptHumanInput,admitApprovedWork,discardClearedHumanInput,dispatchApprovedWorkflows,enforceBudget,extractToolApprovalInputRequests,hasApprovedWork,hasRunnableQueue,humanInputContext,parkOnApprovals,retireCancelledCandidates,runApprovedLocalCalls,stopForToolSignIn,takeDeferredMessage};
1
+ import{renderPendingApprovalsInstruction}from"./approval-prompt.js";import{isEmptyInput}from"./delivery.js";import{grantedApprovalKeys,hasRunnableQueue,parkOnApprovals as parkOnApprovals$1,requestLimit,requireSignIn}from"./approvals.js";import{checkSessionUsageLimit}from"./budget.js";import{discardClearedHitlState,holdsHitlRequests,readHitlState}from"./requests.js";import{retireActiveCandidates}from"./candidates.js";import{acceptHumanInput,admitApprovedWork,dispatchApprovedWorkflows,hasApprovedWork,holdForInput,runApprovedLocalCalls}from"./intake.js";import{AuthKey,SessionKey}from"#context/keys.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{fail,hold}from"#harness/session-machine/transitions.js";import{readTurnState,writeTurnState}from"#harness/session-machine/state.js";import{extractToolApprovalInputRequests}from"#harness/input-extraction.js";async function parkOnApprovals(e,t){let n=parkOnApprovals$1(e.view(),{event:t.event,messages:t.messages,requests:t.requests,tasks:t.tasks,requester:currentRequester(e),responseAuthRequiredRequestIds:responsePolicyRequestIds(t.tools,t.requests)});return await e.apply(n,[...e.session.history,...n.commit??[]]),t.waitsOn===void 0?hasRunnableQueue(e.view())?{next:e.runStep,session:e.session}:holdForInput(e):(t.waitsOn===`runtime`&&t.tasks.some(e=>e.entry.entryPoint===`execute`)&&await e.apply(hold(e.view(),{on:`tasks`})),{next:null,session:e.session})}async function stopForToolSignIn(e,t){return e.session={...e.session,history:validateHarnessModelMessages(t.history)},await e.apply(requireSignIn(e.view(),{callIdsByName:t.callIdsByName,challenges:t.challenges}),e.session.history),{held:{kind:`request`},next:null,session:e.session}}async function enforceBudget(e,t){let n=checkSessionUsageLimit({canAsk:e.emit!==void 0&&e.config.capabilities?.requestInput===!0,session:e.session,turnSequence:e.position().sequence});if(n.kind!==`within`)return n.kind===`ask`?(e.session={...e.session,history:validateHarnessModelMessages([...t])},await e.apply(requestLimit(e.view(),{request:n.request}),e.session.history),{next:null,session:e.session}):(await e.apply(fail(e.view(),{code:n.code,details:n.details,message:n.message,terminal:{sessionId:e.session.sessionId}})),{next:{done:!0,output:``},session:e.session})}function humanInputContext(e,t){let n=e.view();return{approvedTools:grantedApprovalKeys(n,e=>t.get(e.action.toolName)?.approvalKey?.(e.action.input)),pendingApprovalsNote:renderPendingApprovalsInstruction(n.turn.suspended.flatMap(e=>e.requests))}}function responsePolicyRequestIds(e,t){return t.filter(t=>{let n=e.get(t.action.toolName)?.approval;return n!==void 0&&typeof n!=`function`&&n.response!==void 0}).map(e=>e.requestId)}function currentRequester(e){return e.ctx?.get(AuthKey)??e.ctx?.get(SessionKey)?.auth.current??null}function retireCancelledCandidates(e){return{...e,state:retireActiveCandidates(e.state,{completedAt:Date.now(),reason:`Cancelled.`})}}function takeDeferredMessage(e){let{queued:t,...n}=readTurnState(e.state);if(t?.message===void 0)return{session:e};let{message:r,...i}=t;return{message:r,session:writeTurnState(e,isEmptyInput(i)?n:{...n,queued:i})}}export{acceptHumanInput,admitApprovedWork,discardClearedHitlState as discardClearedHumanInput,dispatchApprovedWorkflows,enforceBudget,extractToolApprovalInputRequests,hasApprovedWork,hasRunnableQueue,holdsHitlRequests,humanInputContext,parkOnApprovals,readHitlState,retireCancelledCandidates,runApprovedLocalCalls,stopForToolSignIn,takeDeferredMessage};
@@ -1 +1 @@
1
- import{deliver,resolveTypedApproval,turnInputOnly,withoutTurnInput}from"./delivery.js";import{answer,approvingSteps,deferInput,dispatch,grantedApprovalKeys,requireSignIn,stepForRequest,withdrawSignIns}from"./approvals.js";import{rejectApprovedCall,runApprovedCalls}from"./approved-calls.js";import{getApprovalAuditState,retireActiveCandidates}from"./candidates.js";import{coordinateApprovalDelivery}from"./coordinator.js";import{SEARCH_TOOL_NAME}from"#protocol/catalog-tools.js";import{activeTurnId}from"#harness/session-machine/view.js";import{bumpSessionRuntimeUsageLimits}from"#harness/turn-tag-state.js";import{collectWorkflowCalls}from"#harness/coordination.js";import{approvedCalls,completeSignIn,hold,settle}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{SessionLimitDeclinedError,throwIfTurnAborted}from"#harness/turn-cancellation.js";import{resolveInlineAuthorizationInterrupt}from"#harness/inline-tool-authorization.js";import{recheckApprovedCall}from"#harness/tools.js";import{buildStepCatalog}from"#execution/catalog/step-catalog.js";async function acceptHumanInput(e,t,n){let{config:r,ctx:i}=e,a=r.signInCompletions??[];a.length>0&&await e.apply(completeSignIn(e.view(),{completions:a}));let o=deliver(e.view(),t,n),s=resolveTypedApproval(e.view(),o.input),c=t?.message!==void 0&&s?.message!==void 0||o.displayMessage!==void 0?await withdrawSteeredSignIns(e,s):s,l=new Map,u,restoreTools=async t=>{let n=t?.event??e.position(),a=`${n.turnId}:${n.stepIndex}`,o=l.get(a);if(o!==void 0&&u===a)return o;t!==void 0&&await r.prepareApprovalTurn?.(t.event),i!==void 0&&await r.resolveStepDynamicTools?.({ctx:i,event:stepStartedForResolvers({modelId:e.session.agent.modelReference?.id??`dynamic`,sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId}),messages:e.projectHistory(e.session.history)});let s=buildStepCatalog({agentTools:r.tools,ctx:i,endsTurn:!1,session:e.session});return l.set(a,s),u=a,s},toolsOf=e=>(e&&l.get(`${e.event.turnId}:${e.event.stepIndex}`))??r.tools,d=e.view().signIns,f=await coordinateApprovalDelivery({session:e.session,stepInput:c,tools:r.tools,prepareTools:t=>restoreTools(stepForRequest(e.view(),t.requestId))});e.session=f.session;for(let t of approvingSteps(e.view(),f.stepInput))await restoreTools(t);let p=answer(e.view(),{approvalKey:t=>toolsOf(stepForRequest(e.view(),t.requestId)).get(t.action.toolName)?.approvalKey?.(t.action.input),delivery:f.stepInput,searchable:t=>toolsOf(stepForRequest(e.view(),t.requestId)).get(SEARCH_TOOL_NAME)!==void 0,policy:{...f,audit:getApprovalAuditState(e.session.state),challengesAtStart:d},takeQueued:o.takeQueued});for(let t of p.resolved)await e.instrumentation?.publishInputResolutions({batch:t,sessionId:e.session.sessionId});await e.apply(p);let stop=e=>({kind:`stop`,result:e});switch(p.next){case`park`:return e.view().projection.activeTurnId===void 0?stop({next:null,session:e.session}):stop(await holdForInput(e));case`repeat`:return stop({next:e.runStep,session:e.session});case`sign-in`:return await e.apply(requireSignIn(e.view(),{challenges:f.challenges,queued:f.stepInput})),stop(held(e))}for(let t of e.view().turn.suspended)(t.approved?.length??0)>0&&await restoreTools(t);let m=p.resolved.some(e=>e.inputs.some(e=>e.request.kind===`tool-approval`)&&e.inputs.every(e=>e.response!==void 0))||approvedCalls(e.view().turn).length>0?turnInputOnly(p.input):void 0;return m!==void 0&&await e.apply(deferInput(e.view(),m)),{approved:{limit:p.limit,toolsOf},consumedMessage:p.consumedMessage===!0,input:m===void 0?p.input:withoutTurnInput(p.input),message:p.consumedMessage===!0||m!==void 0?void 0:o.displayMessage??o.input?.message,kind:`run`,opensTurn:hasTurnInput(o.input)||hasTurnInput(f.stepInput)}}async function admitApprovedWork(e,t){if(t.limit!==void 0){if(!t.limit.granted)throw new SessionLimitDeclinedError;e.session=bumpSessionRuntimeUsageLimits(e.session)}await e.apply(settle(e.view(),{results:[]}))}function hasApprovedWork(e){return approvedCalls(e.view().turn).length>0}async function dispatchApprovedWorkflows(e,t){let n=[],r=[];for(let i of e.view().turn.suspended){let a=t.toolsOf(i),o=[];for(let t of i.approved??[]){let n=a.get(t.action.toolName);if(n?.workflowId===void 0)continue;let i=await recheckApprovedCall(n,{abortSignal:e.config.abortSignal,callId:t.action.callId,input:t.action.input,approvedTools:grantedApprovalKeys(e.view(),e=>a.get(e.action.toolName)?.approvalKey?.(e.action.input))});i.denied?r.push(await rejectApprovedCall({request:t,reason:i.reason,position:e.position(),publish:e.publish})):o.push(t)}if(o.length===0)continue;let s=collectWorkflowCalls({session:e.session,toolCalls:o.map(({action:e})=>({input:e.input,toolCallId:e.callId,toolName:e.toolName})),tools:a,turnId:i.event.turnId});e.session=s.session,n.push(...s.workflowRequests)}return r.length>0&&await e.apply(settle(e.view(),{results:r})),n.length!==0&&(await e.apply(dispatch(e.view(),{tasks:n})),n.some(e=>e.entry.entryPoint===`execute`)&&await e.apply(hold(e.view(),{on:`tasks`})),!0)}async function runApprovedLocalCalls(e,t,n){let r=e.view().turn.suspended.map(e=>{let n=t.toolsOf(e);return{requests:(e.approved??[]).filter(e=>n.get(e.action.toolName)?.workflowId===void 0),tools:n}}),i=r.flatMap(({requests:e})=>e);e.frameworkToolNames=new Set(r.flatMap(({requests:e,tools:t})=>e.map(e=>e.action.toolName).filter(e=>t.get(e)?.frameworkTool===!0)));let a=e.position(),o=i.length===0?void 0:e.instrumentation?.prepareAttempt({isFrameworkTool:t=>e.frameworkToolNames.has(t),attemptIndex:0,stepIndex:a.stepIndex,turnId:activeTurnId(a)});o!==void 0&&n(o.scope);let s=await Promise.all(r.map(async({requests:t,tools:n})=>t.length===0?{settled:[],toolResults:[]}:await runApprovedCalls({abortSignal:e.config.abortSignal,approvedTools:grantedApprovalKeys(e.view(),e=>n.get(e.action.toolName)?.approvalKey?.(e.action.input)),messages:e.projectHistory(e.session.history),position:e.position(),publish:e.publish,requests:t,telemetry:o?.telemetry,tools:n})));await e.apply(settle(e.view(),{results:s.flatMap(e=>e.settled)})),throwIfTurnAborted(e.config.abortSignal);let c=resolveInlineAuthorizationInterrupt({messages:[],toolResults:s.flatMap(e=>e.toolResults)});if(c!==void 0)return await e.apply(requireSignIn(e.view(),{callIdsByName:c.callIdsByName,challenges:c.challenges}),e.session.history),held(e)}const STEERED_SIGN_IN_REASON=`Cancelled because a new message arrived.`;async function holdForInput(e){return await e.apply(hold(e.view(),{on:`input`})),held(e)}function held(e){return{held:{kind:`request`},next:null,session:e.session}}async function withdrawSteeredSignIns(e,t){let n=[...new Set(e.view().signIns.map(e=>e.name))];return e.session={...e.session,state:retireActiveCandidates(e.session.state,{completedAt:Date.now(),reason:STEERED_SIGN_IN_REASON})},n.length===0?t:(await e.apply(withdrawSignIns(e.view(),STEERED_SIGN_IN_REASON)),{...t,context:[...t?.context??[],`Sign-in to ${n.join(`, `)} was cancelled because the user sent a new message instead. Ask to sign in again only if the new message still needs it.`]})}function hasTurnInput(e){return e===void 0?!1:e.message!==void 0||(e.inputResponses?.length??0)>0}export{acceptHumanInput,admitApprovedWork,dispatchApprovedWorkflows,hasApprovedWork,holdForInput,runApprovedLocalCalls};
1
+ import{deliver,resolveTypedApproval,turnInputOnly,withoutTurnInput}from"./delivery.js";import{answer,approvingSteps,deferInput,dispatch,grantedApprovalKeys,requireSignIn,stepForRequest,withdrawSignIns}from"./approvals.js";import{rejectApprovedCall,runApprovedCalls}from"./approved-calls.js";import{getApprovalAuditState,responderOfRequest,retireActiveCandidates}from"./candidates.js";import{coordinateApprovalDelivery}from"./coordinator.js";import{SEARCH_TOOL_NAME}from"#protocol/catalog-tools.js";import{activeTurnId}from"#harness/session-machine/view.js";import{bumpSessionRuntimeUsageLimits}from"#harness/turn-tag-state.js";import{collectWorkflowCalls}from"#harness/coordination.js";import{approvedCalls,completeSignIn,hold,settle}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{SessionLimitDeclinedError,throwIfTurnAborted}from"#harness/turn-cancellation.js";import{resolveInlineAuthorizationInterrupt}from"#harness/inline-tool-authorization.js";import{recheckApprovedCall}from"#harness/tools.js";import{buildStepCatalog}from"#execution/catalog/step-catalog.js";async function acceptHumanInput(e,t,n){let{config:r,ctx:i}=e,a=r.signInCompletions??[];a.length>0&&await e.apply(completeSignIn(e.view(),{completions:a}));let o=deliver(e.view(),t,n),s=resolveTypedApproval(e.view(),o.input),c=t?.message!==void 0&&s?.message!==void 0||o.displayMessage!==void 0?await withdrawSteeredSignIns(e,s):s,l=new Map,u,restoreTools=async t=>{let n=t?.event??e.position(),a=`${n.turnId}:${n.stepIndex}`,o=l.get(a);if(o!==void 0&&u===a)return o;t!==void 0&&await r.prepareApprovalTurn?.(t.event),i!==void 0&&await r.resolveStepDynamicTools?.({ctx:i,event:stepStartedForResolvers({modelId:e.session.agent.modelReference?.id??`dynamic`,sequence:n.sequence,stepIndex:n.stepIndex,turnId:n.turnId}),messages:e.projectHistory(e.session.history)});let s=buildStepCatalog({agentTools:r.tools,ctx:i,endsTurn:!1,session:e.session});return l.set(a,s),u=a,s},toolsOf=e=>(e&&l.get(`${e.event.turnId}:${e.event.stepIndex}`))??r.tools,d=e.view().signIns,f=await coordinateApprovalDelivery({session:e.session,stepInput:c,tools:r.tools,prepareTools:t=>restoreTools(stepForRequest(e.view(),t.requestId))});e.session=f.session;for(let t of approvingSteps(e.view(),f.stepInput))await restoreTools(t);let p=answer(e.view(),{approvalKey:t=>toolsOf(stepForRequest(e.view(),t.requestId)).get(t.action.toolName)?.approvalKey?.(t.action.input),delivery:f.stepInput,searchable:t=>toolsOf(stepForRequest(e.view(),t.requestId)).get(SEARCH_TOOL_NAME)!==void 0,policy:{...f,audit:getApprovalAuditState(e.session.state),challengesAtStart:d},takeQueued:o.takeQueued});for(let t of p.resolved)await e.instrumentation?.publishInputResolutions({batch:t,sessionId:e.session.sessionId});await e.apply(p);let stop=e=>({kind:`stop`,result:e});switch(p.next){case`park`:return e.view().projection.activeTurnId===void 0?stop({next:null,session:e.session}):stop(await holdForInput(e));case`repeat`:return stop({next:e.runStep,session:e.session});case`sign-in`:return await e.apply(requireSignIn(e.view(),{challenges:f.challenges,queued:f.stepInput})),stop(held(e))}for(let t of e.view().turn.suspended)(t.approved?.length??0)>0&&await restoreTools(t);let m=p.resolved.some(e=>e.inputs.some(e=>e.request.kind===`tool-approval`)&&e.inputs.every(e=>e.response!==void 0))||approvedCalls(e.view().turn).length>0?turnInputOnly(p.input):void 0;return m!==void 0&&await e.apply(deferInput(e.view(),m)),{approved:{limit:p.limit,toolsOf},consumedMessage:p.consumedMessage===!0,input:m===void 0?p.input:withoutTurnInput(p.input),message:p.consumedMessage===!0||m!==void 0?void 0:o.displayMessage??o.input?.message,kind:`run`,opensTurn:hasTurnInput(o.input)||hasTurnInput(f.stepInput)}}async function admitApprovedWork(e,t){if(t.limit!==void 0){if(!t.limit.granted)throw new SessionLimitDeclinedError;e.session=bumpSessionRuntimeUsageLimits(e.session)}await e.apply(settle(e.view(),{results:[]}))}function hasApprovedWork(e){return approvedCalls(e.view().turn).length>0}async function dispatchApprovedWorkflows(e,t){let n=[],r=[];for(let i of e.view().turn.suspended){let a=t.toolsOf(i),o=[];for(let t of i.approved??[]){let n=a.get(t.action.toolName);if(n?.workflowId===void 0)continue;let i=await recheckApprovedCall(n,{abortSignal:e.config.abortSignal,callId:t.action.callId,input:t.action.input,approvedTools:grantedApprovalKeys(e.view(),e=>a.get(e.action.toolName)?.approvalKey?.(e.action.input))});i.denied?r.push(await rejectApprovedCall({request:t,reason:i.reason,position:e.position(),publish:e.publish})):o.push(t)}if(o.length===0)continue;let s=collectWorkflowCalls({session:e.session,toolCalls:o.map(({action:e})=>({input:e.input,toolCallId:e.callId,toolName:e.toolName})),tools:a,turnId:i.event.turnId});e.session=s.session,n.push(...s.workflowRequests)}return r.length>0&&await e.apply(settle(e.view(),{results:r})),n.length!==0&&(await e.apply(dispatch(e.view(),{tasks:n})),n.some(e=>e.entry.entryPoint===`execute`)&&await e.apply(hold(e.view(),{on:`tasks`})),!0)}async function runApprovedLocalCalls(e,t,n){let r=e.view().turn.suspended.map(e=>{let n=t.toolsOf(e);return{requests:(e.approved??[]).filter(e=>n.get(e.action.toolName)?.workflowId===void 0),tools:n}}),i=r.flatMap(({requests:e})=>e);e.frameworkToolNames=new Set(r.flatMap(({requests:e,tools:t})=>e.map(e=>e.action.toolName).filter(e=>t.get(e)?.frameworkTool===!0)));let a=e.position(),o=i.length===0?void 0:e.instrumentation?.prepareAttempt({isFrameworkTool:t=>e.frameworkToolNames.has(t),attemptIndex:0,stepIndex:a.stepIndex,turnId:activeTurnId(a)});o!==void 0&&n(o.scope);let s=await Promise.all(r.map(async({requests:t,tools:n})=>t.length===0?{settled:[],toolResults:[]}:await runApprovedCalls({abortSignal:e.config.abortSignal,approvedTools:grantedApprovalKeys(e.view(),e=>n.get(e.action.toolName)?.approvalKey?.(e.action.input)),messages:e.projectHistory(e.session.history),position:e.position(),publish:e.publish,requests:t,responderOf:t=>responderOfRequest(e.session.state,t.requestId),telemetry:o?.telemetry,tools:n})));await e.apply(settle(e.view(),{results:s.flatMap(e=>e.settled)})),throwIfTurnAborted(e.config.abortSignal);let c=resolveInlineAuthorizationInterrupt({messages:[],toolResults:s.flatMap(e=>e.toolResults)});if(c!==void 0)return await e.apply(requireSignIn(e.view(),{callIdsByName:c.callIdsByName,challenges:c.challenges}),e.session.history),held(e)}const STEERED_SIGN_IN_REASON=`Cancelled because a new message arrived.`;async function holdForInput(e){return await e.apply(hold(e.view(),{on:`input`})),held(e)}function held(e){return{held:{kind:`request`},next:null,session:e.session}}async function withdrawSteeredSignIns(e,t){let n=[...new Set(e.view().signIns.map(e=>e.name))];return e.session={...e.session,state:retireActiveCandidates(e.session.state,{completedAt:Date.now(),reason:STEERED_SIGN_IN_REASON})},n.length===0?t:(await e.apply(withdrawSignIns(e.view(),STEERED_SIGN_IN_REASON)),{...t,context:[...t?.context??[],`Sign-in to ${n.join(`, `)} was cancelled because the user sent a new message instead. Ask to sign in again only if the new message still needs it.`]})}function hasTurnInput(e){return e===void 0?!1:e.message!==void 0||(e.inputResponses?.length??0)>0}export{acceptHumanInput,admitApprovedWork,dispatchApprovedWorkflows,hasApprovedWork,holdForInput,runApprovedLocalCalls};
@@ -1,8 +1,7 @@
1
1
  import type { SubagentInputRequestHookPayload } from "#channel/types.js";
2
2
  import type { InputResolvedStreamEvent } from "#protocol/message.js";
3
3
  import type { StepCoordinates as PendingInputBatchEvent } from "#harness/session-machine/view.js";
4
- import type { HarnessSessionBase, SessionStateMap } from "#harness/types.js";
5
- import { type InputOption, type InputRequestKind } from "#shared/input.js";
4
+ import type { InputOption, InputRequestKind } from "#shared/input.js";
6
5
  import { type SessionInboxAddress } from "#execution/session-inbox/address.js";
7
6
  import type { RemoteAgentBinding } from "#eve-channel/support.js";
8
7
  /**
@@ -60,45 +59,10 @@ export declare function resolvedByChild(kind: InputRequestKind): boolean;
60
59
  * the child to close. `undefined` when the parent already closed all of them.
61
60
  */
62
61
  export declare function resolvedForParent(data: InputResolvedStreamEvent["data"]): InputResolvedStreamEvent["data"] | undefined;
63
- /**
64
- * Returns the proxy-routing map as a fresh `Map`. Never returns a live
65
- * reference so accidental mutation cannot corrupt session state.
66
- */
67
- export declare function getProxyInputRequests(state: SessionStateMap | undefined): ReadonlyMap<string, ProxyInputRequest>;
68
- /**
69
- * Returns true when the session is currently proxying one or more
70
- * HITL requests on behalf of a descendant subagent.
71
- */
72
- export declare function hasProxyInputRequests(state: SessionStateMap | undefined): boolean;
73
- /**
74
- * Replaces prior entries for the destination and input source with the provided
75
- * ones. A child raising a fresh batch overwrites its prior batch so the
76
- * parent never keeps stale request metadata. Other sources' routes stay
77
- * independently answerable.
78
- */
79
- export declare function upsertProxyInputRequests<S extends HarnessSessionBase>(input: {
80
- readonly inputSource?: string;
81
- readonly entries: readonly (readonly [requestId: string, route: ProxyInputRequest])[];
82
- readonly forChildContinuationToken: string;
83
- readonly session: S;
84
- }): S;
85
- /** State-only variant for control-plane steps that already hold a durable projection. */
86
- export declare function upsertProxyInputRequestState(input: {
87
- readonly inputSource?: string;
88
- readonly entries: readonly (readonly [requestId: string, route: ProxyInputRequest])[];
89
- readonly forChildContinuationToken: string;
90
- readonly state: SessionStateMap | undefined;
91
- }): SessionStateMap | undefined;
92
- /** Removes every proxy route the predicate selects. */
93
- export declare function clearProxyInputRequestsWhere<T extends {
94
- readonly state?: SessionStateMap;
95
- }>(session: T, select: (route: ProxyInputRequest, requestId: string) => boolean): T;
96
- /** Removes only the request IDs whose responses were successfully forwarded. */
97
- export declare function retireProxyInputRequests<T extends {
98
- readonly state?: SessionStateMap;
99
- }>(session: T, requestIds: readonly string[]): T;
100
62
  /**
101
63
  * Projects a {@link SubagentInputRequestHookPayload} into the
102
64
  * `(requestId, route)` tuples the session stores.
103
65
  */
104
66
  export declare function toProxyInputRequestEntries(payload: SubagentInputRequestHookPayload): readonly (readonly [requestId: string, route: ProxyInputRequest])[];
67
+ /** Reads one stored route, or `undefined` when it is malformed. */
68
+ export declare function parseProxyInputRequest(value: unknown, requestId: string): ProxyInputRequest | undefined;
@@ -0,0 +1 @@
1
+ import{isSessionInboxAddress}from"#execution/session-inbox/address.js";const PROXY_INPUT_REQUEST_KINDS={question:!0,"session-limit":!0,"tool-approval":!0};function resolvedByChild(e){return e===`tool-approval`}function resolvedForParent(e){let t=e.resolutions.filter(({kind:e})=>resolvedByChild(e));return t.length===0?void 0:{...e,resolutions:t}}function toProxyInputRequestEntries(e){let t={approvalRequestIds:e.event.requests.flatMap(e=>e.kind===`tool-approval`?[e.requestId]:[]),requestIds:e.event.requests.map(e=>e.requestId)},n={sequence:e.event.sequence,stepIndex:e.event.stepIndex,turnId:e.event.turnId};return e.event.requests.map(r=>{let i={batch:t,childContinuationToken:e.childContinuationToken,...e.inputSource!==void 0&&{inputSource:e.inputSource},...e.remote!==void 0&&{remote:e.remote},event:n,kind:r.kind,reply:{...r.allowFreeform!==void 0&&{allowFreeform:r.allowFreeform},...r.options!==void 0&&{options:[...r.options]}}};return e.childSessionInbox?.sessionId===e.childSessionId&&(i.childSessionInbox=e.childSessionInbox),[r.requestId,i]})}function parseProxyInputRequest(e,t){if(typeof e!=`object`||!e||Array.isArray(e)||!(`childContinuationToken`in e)||!(`kind`in e)||typeof e.childContinuationToken!=`string`||!isInputRequestKind(e.kind))return;let n=`remote`in e?parseRemoteAgentBinding(e.remote):void 0;if(`remote`in e&&n===void 0)return;let r=`inputSource`in e?e.inputSource:void 0;if(r!==void 0&&(typeof r!=`string`||r.length===0))return;let i=`event`in e?parseInputRequestEvent(e.event):void 0;if(i===void 0)return;let a=`batch`in e?parseProxyInputRequestBatch(e.batch):void 0,o=`workflowAsk`in e?parseWorkflowAskRoute(e.workflowAsk):void 0;if(`workflowAsk`in e&&o===void 0)return;let s=`runId`in e?e.runId:void 0;if(s!==void 0&&(typeof s!=`string`||s.length===0))return;let c=`reply`in e?parseProxyInputReply(e.reply):void 0;if(`reply`in e&&c===void 0)return;let l=`childSessionInbox`in e?e.childSessionInbox:void 0;if(l!==void 0&&!isSessionInboxAddress(l))return;let u={childContinuationToken:e.childContinuationToken,event:i,kind:e.kind};return typeof r==`string`&&(u.inputSource=r),n!==void 0&&(u.remote=n),o!==void 0&&(u.workflowAsk=o),typeof s==`string`&&(u.runId=s),l!==void 0&&(u.childSessionInbox=l),a!==void 0&&a.requestIds.includes(t)&&(u.batch=a),c!==void 0&&(u.reply=c),u}function parseInputRequestEvent(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=Reflect.get(e,`sequence`),n=Reflect.get(e,`stepIndex`),r=Reflect.get(e,`turnId`);if(typeof t==`number`&&typeof n==`number`&&typeof r==`string`)return{sequence:t,stepIndex:n,turnId:r}}function parseWorkflowAskRoute(e){if(typeof e!=`object`||!e)return;let t=Reflect.get(e,`control`);if(typeof t==`string`&&t.length!==0)return{control:t}}function parseRemoteAgentBinding(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=Reflect.get(e,`name`),n=Reflect.get(e,`url`),r=Reflect.get(e,`resolverId`),i=Reflect.get(e,`forwardPrincipal`),a=Reflect.get(e,`sessionId`);if(typeof t==`string`&&t&&typeof n==`string`&&n&&typeof a==`string`&&a&&(r===void 0||typeof r==`string`&&r)&&(i===void 0||typeof i==`boolean`))return{name:t,url:n,sessionId:a,...r!==void 0&&{resolverId:r},...i!==void 0&&{forwardPrincipal:i}}}function parseProxyInputReply(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t={},n=Reflect.get(e,`allowFreeform`);if(n!==void 0){if(typeof n!=`boolean`)return;t.allowFreeform=n}let r=Reflect.get(e,`options`);if(r!==void 0){if(!Array.isArray(r)||!Array.from(r).every(isInputOption))return;t.options=r}return t}function parseProxyInputRequestBatch(e){if(typeof e!=`object`||!e||Array.isArray(e)||!(`approvalRequestIds`in e)||!(`requestIds`in e)||!isStringArray(e.approvalRequestIds)||!isStringArray(e.requestIds))return;let t=new Set(e.requestIds);if(!(t.size!==e.requestIds.length||e.approvalRequestIds.some(e=>!t.has(e))))return{approvalRequestIds:e.approvalRequestIds,requestIds:e.requestIds}}const INPUT_OPTION_FIELDS={description:e=>e===void 0||typeof e==`string`,id:e=>typeof e==`string`,label:e=>typeof e==`string`,style:e=>e===void 0||e===`primary`||e===`danger`||e==="default"};function isInputOption(e){return typeof e!=`object`||!e||Array.isArray(e)?!1:Object.keys(e).every(e=>Object.hasOwn(INPUT_OPTION_FIELDS,e))&&Object.entries(INPUT_OPTION_FIELDS).every(([t,n])=>n(Reflect.get(e,t)))}function isStringArray(e){return Array.isArray(e)&&e.every(e=>typeof e==`string`)}function isInputRequestKind(e){return typeof e==`string`&&Object.hasOwn(PROXY_INPUT_REQUEST_KINDS,e)}export{parseProxyInputRequest,resolvedByChild,resolvedForParent,toProxyInputRequestEntries};
@@ -0,0 +1,64 @@
1
+ import type { AuthorizationChallenge } from "#harness/authorization.js";
2
+ import type { HarnessSessionBase, SessionStateMap } from "#harness/types.js";
3
+ import type { DurableApprovalState } from "./candidates.js";
4
+ import { type ProxyInputRequest } from "./relays.js";
5
+ /** Where builds before checkpoint version 15 kept the requests. Only checkpoint upgrades read them. */
6
+ export declare const LEGACY_HITL_STATE_KEYS: {
7
+ readonly approvals: "eve.runtime.hitl.approvalState";
8
+ readonly signIns: "eve.runtime.pendingAuthorization";
9
+ readonly relays: "eve.runtime.proxyInputRequests";
10
+ };
11
+ /**
12
+ * A read-only snapshot of the human-in-the-loop records, the one way code outside `harness/hitl/`
13
+ * reads them.
14
+ */
15
+ export interface HitlState {
16
+ /** The sign-in attempts the session waits on. */
17
+ readonly signIns: readonly AuthorizationChallenge[];
18
+ /** Requests this session relays for a child session or a workflow run, by `requestId`. */
19
+ readonly relays: ReadonlyMap<string, ProxyInputRequest>;
20
+ }
21
+ /** Each record is parsed on first read: most readers want one. */
22
+ export declare function readHitlState(state: SessionStateMap | undefined): HitlState;
23
+ /**
24
+ * Whether the session holds a sign-in or relayed request, or a record of them it can't read.
25
+ * Settling the last one deletes its record; a malformed record that ordinary readers read as
26
+ * empty must not let a session hand off.
27
+ */
28
+ export declare function holdsHitlRequests(state: SessionStateMap | undefined): boolean;
29
+ /** What a session-machine transition changes in these records. */
30
+ export interface HitlStateChange {
31
+ /** Every sign-in the session waits on once the change applies; `[]` withdraws them all. */
32
+ readonly signIns?: readonly AuthorizationChallenge[];
33
+ readonly relays?: RelayChange;
34
+ }
35
+ /** Relay routes a transition records or retires. */
36
+ export interface RelayChange {
37
+ /** A child's fresh batch: it replaces the routes that child's input source held. */
38
+ readonly upsert?: {
39
+ readonly entries: readonly (readonly [requestId: string, route: ProxyInputRequest])[];
40
+ readonly forChildContinuationToken: string;
41
+ readonly inputSource?: string;
42
+ };
43
+ /** Routes whose answers went down to the asker, or whose request closed. */
44
+ readonly retire?: readonly string[];
45
+ }
46
+ /** Writes a transition's change. Production callers are the machine save and its closed-route cleanup. */
47
+ export declare function writeHitlState<T extends {
48
+ readonly state?: SessionStateMap;
49
+ }>(session: T, change: HitlStateChange): T;
50
+ /**
51
+ * Moves the records builds before checkpoint version 15 kept under
52
+ * {@link LEGACY_HITL_STATE_KEYS} into the requests record as they were stored; each reader is as
53
+ * lenient as its old one. Only the checkpoint upgrade calls it.
54
+ */
55
+ export declare function upgradeLegacyHitlState(state: Readonly<Record<string, unknown>>): Record<string, unknown>;
56
+ /** The approval records. Only `candidates.ts` calls it. */
57
+ export declare function readApprovalState(state: SessionStateMap | undefined): DurableApprovalState;
58
+ /** Saves the approval records. Only `candidates.ts` calls it. */
59
+ export declare function writeApprovalState(state: SessionStateMap | undefined, approvalState: DurableApprovalState): SessionStateMap;
60
+ /**
61
+ * Drops what a cleared context owned: sign-in attempts and responders' approval progress. `clear`
62
+ * reported each close; relay routes for live tasks stay.
63
+ */
64
+ export declare function discardClearedHitlState<T extends HarnessSessionBase>(session: T): T;
@@ -0,0 +1 @@
1
+ import{resolveActiveAuthorizationChallenges}from"./sign-ins.js";import{parseProxyInputRequest}from"./relays.js";import{isObject}from"#shared/guards.js";const REQUESTS_KEY=`eve.runtime.hitl.requests`,LEGACY_HITL_STATE_KEYS={approvals:`eve.runtime.hitl.approvalState`,signIns:`eve.runtime.pendingAuthorization`,relays:`eve.runtime.proxyInputRequests`};function readHitlState(e){let t,n;return{get signIns(){return t??=readSignIns(e)},get relays(){return n??=new Map(Object.entries(readRelays(e)))}}}function holdsHitlRequests(e){let t=e?.[REQUESTS_KEY];if(t===void 0)return!1;if(!isObject(t)||Array.isArray(t))return!0;let{signIns:n,relays:r}=t;return n!==void 0||r!==void 0&&(!isObject(r)||Object.keys(r).length>0)}function writeHitlState(e,t){let n=e.state;return t.signIns!==void 0&&(n=writeSignIns(n,resolveActiveAuthorizationChallenges(t.signIns))),t.relays?.upsert!==void 0&&(n=upsertRelays(n,t.relays.upsert)),t.relays?.retire!==void 0&&(n=retireRelays(n,t.relays.retire)),n===e.state?e:{...e,state:n}}function readRequests(e){let t=e?.[REQUESTS_KEY];return isObject(t)?t:{}}function writeRequests(e,t,n){let{[t]:r,...i}=readRequests(e);if(r===void 0&&n===void 0)return e;let a=n===void 0?i:{...i,[t]:n},{[REQUESTS_KEY]:o,...s}=e??{};return Object.keys(a).length>0?{...s,[REQUESTS_KEY]:a}:Object.keys(s).length>0?s:void 0}function upgradeLegacyHitlState(e){let{[LEGACY_HITL_STATE_KEYS.approvals]:t,[LEGACY_HITL_STATE_KEYS.signIns]:n,[LEGACY_HITL_STATE_KEYS.relays]:r,...i}=e,a=i;a=writeRequests(a,`approvals`,t),a=writeRequests(a,`signIns`,isObject(n)&&n.challenges!==void 0?n.challenges:n);let o=isObject(r)&&Object.keys(r).length===0;return a=writeRequests(a,`relays`,o?void 0:r),a??{}}function readActiveCandidates(e){return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,{...t,decision:t.decision===`cancel`?`cancel`:`approve`}]))}function readApprovalState(e){let t=readRequests(e).approvals;if(typeof t!=`object`||!t)return{activeCandidates:{},candidateHistory:[],nextCandidateSequence:0,settlements:{}};let n=t;return{activeCandidates:typeof n.activeCandidates==`object`&&n.activeCandidates!==null?readActiveCandidates(n.activeCandidates):{},candidateHistory:Array.isArray(n.candidateHistory)?n.candidateHistory:[],nextCandidateSequence:typeof n.nextCandidateSequence==`number`&&Number.isSafeInteger(n.nextCandidateSequence)&&n.nextCandidateSequence>=0?n.nextCandidateSequence:deriveNextCandidateSequence(n),settlements:typeof n.settlements==`object`&&n.settlements!==null?n.settlements:{}}}function deriveNextCandidateSequence(e){return Object.keys(e.activeCandidates??{}).length+(Array.isArray(e.candidateHistory)?e.candidateHistory.length:0)}function writeApprovalState(e,t){return writeRequests(e,`approvals`,t)??{}}function discardClearedHitlState(e){let t=writeRequests(writeSignIns(e.state,[]),`approvals`,void 0);return{...e,state:t}}function readSignIns(e){let t=readRequests(e).signIns;return Array.isArray(t)?t:[]}function writeSignIns(e,t){return writeRequests(e,`signIns`,t.length>0?t:void 0)}function readRelays(e){let t=readRequests(e).relays;if(typeof t!=`object`||!t||Array.isArray(t))return{};let n={};for(let[e,r]of Object.entries(t)){let t=parseProxyInputRequest(r,e);t!==void 0&&(n[e]=t)}return n}function writeRelays(e,t){return writeRequests(e,`relays`,Object.keys(t).length>0?t:void 0)}function upsertRelays(e,t){let n=Object.entries(readRelays(e)).filter(([,e])=>e.childContinuationToken!==t.forChildContinuationToken||e.inputSource!==t.inputSource);return writeRelays(e,Object.fromEntries([...n,...t.entries]))}function retireRelays(e,t){let n=readRelays(e);return t.some(e=>Object.hasOwn(n,e))?writeRelays(e,Object.fromEntries(Object.entries(n).filter(([e])=>!t.includes(e)))):e}export{LEGACY_HITL_STATE_KEYS,discardClearedHitlState,holdsHitlRequests,readApprovalState,readHitlState,upgradeLegacyHitlState,writeApprovalState,writeHitlState};
@@ -0,0 +1,9 @@
1
+ import type { AuthorizationChallenge } from "#harness/authorization.js";
2
+ /** The pending sign-ins once `challenges` are asked for: each replaces the attempt it supersedes. */
3
+ export declare function withSignIns(previous: readonly AuthorizationChallenge[], challenges: readonly AuthorizationChallenge[]): readonly AuthorizationChallenge[];
4
+ /** Keeps the last challenge for each sign-in and principal. */
5
+ export declare function resolveActiveAuthorizationChallenges(challenges: readonly AuthorizationChallenge[]): readonly AuthorizationChallenge[];
6
+ /** The attempts in `previous` that `replacements` replace: the same sign-in and principal. */
7
+ export declare function supersededChallenges(previous: readonly AuthorizationChallenge[], replacements: readonly AuthorizationChallenge[]): readonly AuthorizationChallenge[];
8
+ /** The key a sign-in callback names its attempt by. */
9
+ export declare function signInAttemptKey(challenge: AuthorizationChallenge): string;