eve 0.77.0 → 0.78.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/context/keys.d.ts +16 -0
- package/dist/src/context/keys.js +1 -1
- package/dist/src/execution/agent-sessions/steps.d.ts +2 -0
- package/dist/src/execution/agent-sessions/steps.js +1 -1
- package/dist/src/execution/cancelled-model-call-batch.js +1 -1
- package/dist/src/execution/catalog/search.js +1 -1
- package/dist/src/execution/catalog/step-catalog.d.ts +12 -3
- package/dist/src/execution/catalog/step-catalog.js +1 -1
- package/dist/src/execution/coordination-dispatch-shared.d.ts +1 -2
- package/dist/src/execution/coordination-dispatch-shared.js +1 -1
- package/dist/src/execution/coordination-dispatch-step.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker-container.js +1 -1
- package/dist/src/execution/sandbox/bindings/docker.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/just-bash.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/execution/sandbox/session.d.ts +6 -0
- package/dist/src/execution/sandbox/session.js +2 -2
- package/dist/src/execution/session/active-turn.d.ts +9 -1
- package/dist/src/execution/session/active-turn.js +1 -1
- package/dist/src/execution/session/checkpoint-migrations.js +1 -1
- package/dist/src/execution/session/handoff.d.ts +1 -1
- package/dist/src/execution/session/handoff.js +1 -1
- package/dist/src/execution/session/next-input.js +1 -1
- package/dist/src/execution/session/turn.d.ts +11 -4
- package/dist/src/execution/session/turn.js +1 -1
- package/dist/src/execution/session-inbox/inbox.d.ts +3 -0
- package/dist/src/execution/session-inbox/inbox.js +1 -1
- package/dist/src/execution/session-workflow-tool-run.d.ts +14 -12
- package/dist/src/execution/session-workflow-tool-run.js +1 -1
- package/dist/src/execution/tasks/start.d.ts +14 -1
- package/dist/src/execution/tasks/start.js +1 -1
- package/dist/src/execution/tasks/steps.d.ts +7 -4
- package/dist/src/execution/tasks/steps.js +1 -1
- package/dist/src/execution/tools/agent-router-workflow.js +1 -1
- package/dist/src/execution/tools/workflow/apply-run-messages-step.d.ts +20 -0
- package/dist/src/execution/tools/workflow/apply-run-messages-step.js +1 -0
- package/dist/src/execution/tools/workflow/ask.d.ts +0 -1
- package/dist/src/execution/tools/workflow/ask.js +1 -1
- package/dist/src/execution/tools/workflow/interrupt.d.ts +5 -2
- package/dist/src/execution/tools/workflow/interrupt.js +1 -1
- package/dist/src/execution/tools/workflow/messages.d.ts +14 -0
- package/dist/src/execution/tools/workflow/messages.js +1 -1
- package/dist/src/execution/tools/workflow/owner.d.ts +18 -6
- package/dist/src/execution/tools/workflow/owner.js +1 -1
- package/dist/src/execution/tools/workflow/start.d.ts +10 -0
- package/dist/src/execution/tools/workflow/start.js +1 -1
- package/dist/src/execution/tools/workflow/step.js +1 -1
- package/dist/src/execution/tools/workflow/workflow-owner-blocking.d.ts +12 -0
- package/dist/src/execution/tools/workflow/workflow-owner-blocking.js +1 -1
- package/dist/src/execution/tools/workflow/workflow.js +1 -1
- package/dist/src/execution/workflow-runtime.d.ts +18 -3
- package/dist/src/execution/workflow-runtime.js +1 -1
- package/dist/src/harness/hitl/approvals.d.ts +4 -7
- package/dist/src/harness/hitl/approvals.js +1 -1
- package/dist/src/harness/hitl/approved-calls.d.ts +11 -0
- package/dist/src/harness/hitl/approved-calls.js +1 -1
- package/dist/src/harness/hitl/candidates.d.ts +0 -4
- package/dist/src/harness/hitl/candidates.js +1 -1
- package/dist/src/harness/hitl/delivery.d.ts +0 -1
- package/dist/src/harness/hitl/delivery.js +1 -1
- package/dist/src/harness/hitl/index.d.ts +2 -2
- package/dist/src/harness/hitl/index.js +1 -1
- package/dist/src/harness/hitl/intake.d.ts +2 -2
- package/dist/src/harness/hitl/intake.js +1 -1
- package/dist/src/harness/model-call/call.js +1 -1
- package/dist/src/harness/model-call/run.js +1 -1
- package/dist/src/harness/session-machine/state.d.ts +0 -2
- package/dist/src/harness/session-machine/view.d.ts +0 -3
- package/dist/src/harness/session-machine/view.js +1 -1
- package/dist/src/harness/step/after-model.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/stamped-package-version.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/tools/provided/ask-question-workflow.js +1 -1
- package/dist/src/tools/provided/sleep-workflow.js +1 -1
- package/docs/agent-config.md +12 -4
- package/docs/concepts/built-in-tools.md +9 -9
- package/docs/guides/dynamic-capabilities.md +6 -2
- package/docs/sandbox/index.mdx +2 -0
- package/docs/tools/human-in-the-loop.md +1 -1
- package/package.json +1 -1
- package/dist/src/context/caller-scope.d.ts +0 -7
- package/dist/src/context/caller-scope.js +0 -1
- package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.d.ts +0 -13
- package/dist/src/execution/tools/workflow/emit-workflow-tool-run-report-step.js +0 -1
- package/dist/src/harness/hitl/approved-call-callers.d.ts +0 -14
- package/dist/src/harness/hitl/approved-call-callers.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{runMessageBatchBudget}from"#execution/tools/workflow/messages.js";import{createChannelReader}from"#execution/tools/workflow/owner-channels.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";function openWorkflowToolRunOwnerInbox(){let e=[],t,n=0;async function*read(){for(;;){if(e.length>0){let t=runMessageBatchBudget(),n=e.findIndex(e=>!t(e));yield e.splice(0,n===-1?e.length:n);continue}await new Promise(e=>{t=e})}}return{owner:{get sent(){return n},async send(r){e.push(r),n+=1;let i=t;t=void 0,i?.()}},reader:createChannelReader(`workflow`,read())}}async function deliverWorkflowAuthorization(e,t){await t(),e.request.event.childSessionId===e.from.runId&&await resumeHookStep(e.replyTo,null,{ifPresent:!0})}export{deliverWorkflowAuthorization,openWorkflowToolRunOwnerInbox};
|
|
@@ -19,9 +19,19 @@ export interface StartWorkflowTaskInput {
|
|
|
19
19
|
};
|
|
20
20
|
readonly owner: WorkflowToolRunOwner;
|
|
21
21
|
readonly parentSession: SessionParent | undefined;
|
|
22
|
+
/**
|
|
23
|
+
* The call's run, when its batch already started it alongside the others.
|
|
24
|
+
* The dispatch records it in place of starting one.
|
|
25
|
+
*/
|
|
26
|
+
readonly prestarted?: PrestartedWorkflowToolRun;
|
|
22
27
|
readonly session: HarnessSessionBase;
|
|
23
28
|
readonly task: RuntimeWorkflowTaskRequest;
|
|
24
29
|
}
|
|
30
|
+
/** A call's run its batch started early, and the entry it was started with. */
|
|
31
|
+
export interface PrestartedWorkflowToolRun {
|
|
32
|
+
readonly entry: WorkflowToolRunEntry;
|
|
33
|
+
readonly run: Promise<WorkflowToolRunAddress>;
|
|
34
|
+
}
|
|
25
35
|
/** Starts the run for one call, which invokes `entry`. */
|
|
26
36
|
export declare function startWorkflowToolCallRun(input: StartWorkflowTaskInput, entry: WorkflowToolRunEntry): Promise<WorkflowToolRunAddress>;
|
|
27
37
|
/** Starts the run of an `execute` call the turn waits on and records it on the owning session. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{toError}from"#shared/errors.js";import{startWorkflowOnCurrentDeployment,workflowToolRunWorkflowReference}from"#execution/workflow-runtime.js";import{registerWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";const log=createLogger(`execution.workflow-tool-run`);async function startWorkflowToolRun(e){let t=e.entry.entryPoint===`execute`?crypto.randomUUID():taskRunHookToken(e.session.id,e.entry.taskId);return{hookToken:t,runId:(await startWorkflowOnCurrentDeployment(workflowToolRunWorkflowReference,[{...e,hookToken:t}])).runId}}function taskRunHookToken(e,t){return`eve:task:${e}:${t}`}async function startWorkflowToolCallRun(e,t){let{
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{toError}from"#shared/errors.js";import{startWorkflowOnCurrentDeployment,workflowToolRunWorkflowReference}from"#execution/workflow-runtime.js";import{registerWorkflowToolRun}from"#harness/workflow-tool-runs.js";import{createRuntimeToolResultFromValue}from"#harness/action-result-helpers.js";const log=createLogger(`execution.workflow-tool-run`);async function startWorkflowToolRun(e){let t=e.entry.entryPoint===`execute`?crypto.randomUUID():taskRunHookToken(e.session.id,e.entry.taskId);return{hookToken:t,runId:(await startWorkflowOnCurrentDeployment(workflowToolRunWorkflowReference,[{...e,hookToken:t}])).runId}}function taskRunHookToken(e,t){return`eve:task:${e}:${t}`}async function startWorkflowToolCallRun(e,t){let{prestarted:n}=e;if(n!==void 0){if(!isSameRunEntry(n.entry,t))throw Error(`Call "${e.task.callId}" was started for a different entry point.`);return await n.run}let{task:r,batchEvent:i,session:a}=e;return await startWorkflowToolRun({agentContext:e.agentContext,callId:r.callId,entry:t,executeInput:r.executeInput,input:r.input,owner:e.owner,session:{auth:e.auth,id:a.sessionId,parent:e.parentSession,turn:{id:i.turnId,sequence:i.sequence}},stepIndex:i.stepIndex,toolName:r.toolName,workflowId:r.workflowId})}function isSameRunEntry(e,t){return e.entryPoint===`execute`||t.entryPoint===`execute`?e.entryPoint===t.entryPoint:e.entryPoint===t.entryPoint&&e.taskId===t.taskId}async function startWorkflowTask(e){let{task:t,batchEvent:n,session:r}=e;try{let i=await startWorkflowToolCallRun(e,{entryPoint:`execute`});return{session:registerWorkflowToolRun(r,{callId:t.callId,origin:{turnId:n.turnId,stepIndex:n.stepIndex},address:i,toolName:t.toolName})}}catch(e){return logError(log,`workflow tool run failed to start`,e,{callId:t.callId,toolName:t.toolName}),{result:startFailureResult(t,e),session:r}}}function startFailureResult(e,t){return createRuntimeToolResultFromValue({callId:e.callId,isError:!0,output:toError(t),toolName:e.toolName})}export{startFailureResult,startWorkflowTask,startWorkflowToolCallRun,startWorkflowToolRun};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{disposeHook}from"#execution/hook-ownership.js";import{runSignIn}from"#harness/session-machine/transitions.js";import{findWorkflowToolRunContext}from"#execution/tools/workflow/ask.js";function workflowToolStep(e,t){return new Proxy(e,{apply(e,n,r){let i=findWorkflowContextArgument(r);return i===void 0?Reflect.apply(e,n,r):executeAuthorizedStep(t,n,r,i)}})}function findWorkflowContextArgument(e){for(let t of e){let e=findWorkflowToolRunContext(t);if(e!==void 0)return{ctx:t,run:e}}}async function executeAuthorizedStep(e,t,n,r){let{ctx:i,run:a}=r,o=[],s=new Map;for(;;){let r=createHook();try{let c;try{c=await invokeAuthorizedStep({args:n,authorizationResults:o,callbackToken:r.token,ctx:i,execute:e,receiver:t})}catch(e){throw i.abortSignal.aborted||await reportPendingAsFailed(a,i.abortSignal,s),e}if(await reconcileCompletedAuthorizations(a,i.abortSignal,s,o,c.authorized),c.kind===`result`)return await reportPendingAsFailed(a,i.abortSignal,s),c.output;await collectAuthorizationCallbacks({authorizationResults:o,callback:r,challenges:c.signal.challenges,ctx:i,pending:s,run:a})}finally{await disposeHook(r)}}}async function invokeAuthorizedStep(e){let{args:t,authorizationResults:n,callbackToken:r,ctx:i,execute:a,receiver:o}=e,s={callId:i.callId,toolName:i.toolName,session:i.session,abortSignal:i.abortSignal,baseUrl:getWorkflowMetadata().url,token:r,authorizationResults:n},c={args:t.map(e=>e===i?null:e),context:s,contextIndexes:t.flatMap((e,t)=>e===i?[t]:[])};return await a.call(o,c)}async function reconcileCompletedAuthorizations(e,t,n,r,i){let a=new Set(i);for(let r of a){let i=n.get(r);i!==void 0&&await reportAuthorization(e,t,i,`authorized`),n.delete(r)}for(let e=r.length-1;e>=0;e--){let t=r[e];t!==void 0&&a.has(t.attemptId)&&r.splice(e,1)}}async function collectAuthorizationCallbacks(e){let{authorizationResults:t,callback:n,challenges:r,ctx:i,pending:a,run:o}=e;for(let e of r){let r=requireAttemptId(e);a.set(r.attemptId,r),await reportAuthorization(o,i.abortSignal,r);try{let e=await waitForCallback(n,r,i.abortSignal);t.push({name:r.name,instanceId:r.instanceId,attemptId:r.attemptId,hookUrl:r.hookUrl,principal:r.principal,resume:r.resume,callback:e})}catch(e){throw i.abortSignal.aborted||await reportAuthorization(o,i.abortSignal,r,`failed`),e}}}function requireAttemptId(e){if(e.attemptId===void 0)throw Error(`Workflow authorization challenge "${e.name}" has no attempt id.`);return e}async function reportPendingAsFailed(e,t,n){for(let r of n.values())await reportAuthorization(e,t,r,`failed`)}async function reportAuthorization(e,t,n,r){let i=runSignIn(e.from,n,r),a=createHook();try{await withAbort(e.owner.send({kind:`request`,from:e.from,replyTo:a.token,request:{kind:`authorization-request`,event:{kind:`subagent-authorization-event`,callId:e.from.callId,childSessionId:e.from.runId,subagentName:e.from.toolName,event:i}}}),t),await withAbort(a,t)}finally{await disposeHook(a)}}async function waitForCallback(e,t,n){let r=e[Symbol.asyncIterator]();for(;;){let e=await withAbort(r.next(),n);if(e.done)throw Error(`Authorization callback closed before sign-in completed.`);let i=readCallback(e.value,t);if(i!==void 0)return i}}async function withAbort(e,t){let abort,n=new Promise((e,n)=>{abort=()=>n(t.reason??Error(`Workflow authorization cancelled.`)),t.addEventListener(`abort`,abort,{once:!0}),t.aborted&&abort()});try{return await Promise.race([e,n])}finally{t.removeEventListener(`abort`,abort)}}function readCallback(e,t){if(typeof e==`object`&&e&&`payloads`in e&&Array.isArray(e.payloads))for(let n of e.payloads){let e=n?.authorizationCallback;if(e?.attemptId!==t.attemptId||e?.connectionName!==t.name)continue;let r=e.callback;if(!(typeof r?.method!=`string`||typeof r.params!=`object`||r.params===null||Array.isArray(r.params))&&Object.values(r.params).every(e=>typeof e==`string`)&&(r.body===void 0||typeof r.body==`string`))return r}}export{workflowToolStep};
|
|
1
|
+
import{createHook,getWorkflowMetadata}from"#compiled/@workflow/core/index.js";import{disposeHook}from"#execution/hook-ownership.js";import{runSignIn}from"#harness/session-machine/transitions.js";import{findWorkflowToolRunContext}from"#execution/tools/workflow/ask.js";function workflowToolStep(e,t){return new Proxy(e,{apply(e,n,r){let i=findWorkflowContextArgument(r);return i===void 0?Reflect.apply(e,n,r):executeAuthorizedStep(t,n,r,i)}})}function findWorkflowContextArgument(e){for(let t of e){let e=findWorkflowToolRunContext(t);if(e!==void 0)return{ctx:t,run:e}}}async function executeAuthorizedStep(e,t,n,r){let{ctx:i,run:a}=r,o=[],s=new Map;for(;;){let r=createHook();try{let c;try{c=await invokeAuthorizedStep({args:n,authorizationResults:o,callbackToken:r.token,ctx:i,execute:e,receiver:t})}catch(e){throw i.abortSignal.aborted||await reportPendingAsFailed(a,i.abortSignal,s),e}if(await reconcileCompletedAuthorizations(a,i.abortSignal,s,o,c.authorized),c.kind===`result`)return await reportPendingAsFailed(a,i.abortSignal,s),c.output;await collectAuthorizationCallbacks({authorizationResults:o,callback:r,challenges:c.signal.challenges,ctx:i,pending:s,run:a})}finally{await disposeHook(r)}}}async function invokeAuthorizedStep(e){let{args:t,authorizationResults:n,callbackToken:r,ctx:i,execute:a,receiver:o}=e,s={callId:i.callId,toolName:i.toolName,session:i.session,abortSignal:i.abortSignal,baseUrl:getWorkflowMetadata().url,token:r,authorizationResults:n},c={args:t.map(e=>e===i?null:e),context:s,contextIndexes:t.flatMap((e,t)=>e===i?[t]:[])};return await a.call(o,c)}async function reconcileCompletedAuthorizations(e,t,n,r,i){let a=new Set(i);for(let r of a){let i=n.get(r);i!==void 0&&await reportAuthorization(e,t,i,`authorized`),n.delete(r)}for(let e=r.length-1;e>=0;e--){let t=r[e];t!==void 0&&a.has(t.attemptId)&&r.splice(e,1)}}async function collectAuthorizationCallbacks(e){let{authorizationResults:t,callback:n,challenges:r,ctx:i,pending:a,run:o}=e;for(let e of r){let r=requireAttemptId(e);a.set(r.attemptId,r),await reportAuthorization(o,i.abortSignal,r);try{let e=await waitForCallback(n,r,i.abortSignal);t.push({name:r.name,instanceId:r.instanceId,attemptId:r.attemptId,hookUrl:r.hookUrl,principal:r.principal,resume:r.resume,callback:e})}catch(e){throw i.abortSignal.aborted||await reportAuthorization(o,i.abortSignal,r,`failed`),e}}}function requireAttemptId(e){if(e.attemptId===void 0)throw Error(`Workflow authorization challenge "${e.name}" has no attempt id.`);return e}async function reportPendingAsFailed(e,t,n){for(let r of n.values())await reportAuthorization(e,t,r,`failed`)}async function reportAuthorization(e,t,n,r){let i=runSignIn(e.from,n,r),a=createHook();try{await a.getConflict(),await withAbort(e.owner.send({kind:`request`,from:e.from,replyTo:a.token,request:{kind:`authorization-request`,event:{kind:`subagent-authorization-event`,callId:e.from.callId,childSessionId:e.from.runId,subagentName:e.from.toolName,event:i}}}),t),await withAbort(a,t)}finally{await disposeHook(a)}}async function waitForCallback(e,t,n){let r=e[Symbol.asyncIterator]();for(;;){let e=await withAbort(r.next(),n);if(e.done)throw Error(`Authorization callback closed before sign-in completed.`);let i=readCallback(e.value,t);if(i!==void 0)return i}}async function withAbort(e,t){let abort,n=new Promise((e,n)=>{abort=()=>n(t.reason??Error(`Workflow authorization cancelled.`)),t.addEventListener(`abort`,abort,{once:!0}),t.aborted&&abort()});try{return await Promise.race([e,n])}finally{t.removeEventListener(`abort`,abort)}}function readCallback(e,t){if(typeof e==`object`&&e&&`payloads`in e&&Array.isArray(e.payloads))for(let n of e.payloads){let e=n?.authorizationCallback;if(e?.attemptId!==t.attemptId||e?.connectionName!==t.name)continue;let r=e.callback;if(!(typeof r?.method!=`string`||typeof r.params!=`object`||r.params===null||Array.isArray(r.params))&&Object.values(r.params).every(e=>typeof e==`string`)&&(r.body===void 0||typeof r.body==`string`))return r}}export{workflowToolStep};
|
|
@@ -4,7 +4,19 @@ import type { WorkflowToolRunInput } from "#execution/tools/workflow/types.js";
|
|
|
4
4
|
export interface BlockingWorkflowOwner {
|
|
5
5
|
/** The session's commands, from the run's control hook. */
|
|
6
6
|
readonly commands: ChannelReader<"control", WorkflowToolRunControlMessage>;
|
|
7
|
+
/**
|
|
8
|
+
* Waits until the control hook is registered, so the session's commands
|
|
9
|
+
* reach the run, and resolves `false` when another run already holds its
|
|
10
|
+
* token. A pending wait keeps the suspension that registers the hook from
|
|
11
|
+
* running its steps inline, so call it only once the run needs the answer.
|
|
12
|
+
*/
|
|
13
|
+
register(): Promise<boolean>;
|
|
7
14
|
handleMessage(message: WorkflowToolRunMessage): Promise<void>;
|
|
15
|
+
/**
|
|
16
|
+
* Relays the body's messages to the session in one delivery, which is one
|
|
17
|
+
* durable write: the session gets all of them or none, never a prefix.
|
|
18
|
+
*/
|
|
19
|
+
relay(messages: readonly WorkflowToolRunMessage[]): Promise<void>;
|
|
8
20
|
}
|
|
9
21
|
/** The run's link to its session: commands arrive on its control hook, and its messages go to the session's inbox. */
|
|
10
22
|
export declare function createBlockingWorkflow(input: WorkflowToolRunInput): BlockingWorkflowOwner;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHook}from"#compiled/@workflow/core/index.js";import{
|
|
1
|
+
import{createHook}from"#compiled/@workflow/core/index.js";import{isHookConflictError}from"#execution/hook-ownership.js";import{createChannelReader}from"#execution/tools/workflow/owner-channels.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";function createBlockingWorkflow(e){let t=createHook({token:e.hookToken}),n,handleMessage=t=>resumeHookStep(e.owner.inbox,t,{ifPresent:t.kind===`outcome`&&t.result.status===`cancelled`});return{commands:createChannelReader(`control`,t),register(){return n??=t.getConflict().then(e=>e===null,e=>{if(isHookConflictError(e))return!1;throw e}),n},handleMessage,relay(t){if(t.length===1)return handleMessage(t[0]);let n={kind:`workflow-batch`,messages:t};return resumeHookStep(e.owner.inbox,n)}}}export{createBlockingWorkflow};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{sleep}from"#compiled/@workflow/core/index.js";import{
|
|
1
|
+
import{sleep}from"#compiled/@workflow/core/index.js";import{isWorkflowToolRunAskDecision,isWorkflowToolRunControlMessage}from"#execution/tools/workflow/messages.js";import{normalizeSerializableError}from"#execution/workflow-errors.js";import{openWorkflowToolRunOwnerInbox}from"#execution/tools/workflow/owner.js";import{WORKFLOW_CANCELLATION_CLEANUP_MS}from"#execution/tools/workflow/cancellation-policy.js";import{createChannelReader,raceChannelReads}from"#execution/tools/workflow/owner-channels.js";import{resumeHookStep}from"#execution/tools/workflow/resume-hook-step.js";import{createWorkflowBodyRef,startCallBody}from"#execution/tools/workflow/body.js";import{createBlockingWorkflow}from"#execution/tools/workflow/workflow-owner-blocking.js";import{startServeBody}from"#execution/tools/workflow/serve.js";async function workflowToolRunWorkflow(e){"use workflow";let t=createBlockingWorkflow(e),n=openWorkflowToolRunOwnerInbox(),r=e.entry.entryPoint!==`execute`;if(r&&!await t.register()){await reportTaskStarted(e);return}let i=startWorkflowBody({...e,owner:n.owner}),a=r?reportTaskStarted(e):void 0,o=i.control.runSignal,s=createChannelReader(`body`,awaitBodyOutcome(i.outcome)),c=!0,l=0,u,d,f;try{for(await a;;){if(i.control.unwinding&&(d??=sleep(WORKFLOW_CANCELLATION_CLEANUP_MS).then(()=>`cancel`)),u!==void 0&&l>=n.owner.sent&&t.commands.landed.length===0&&t.commands.failure===void 0){f=u;break}let e;try{let r=[];c&&r.push(t.commands),r.push(n.reader),u===void 0&&r.push(s),e=await raceChannelReads(r,d)}catch(e){if(t.commands.failure!==void 0)throw e;f={status:`failed`,error:normalizeSerializableError(e)};break}if(e===`cancel`){if(!i.control.unwinding){d=void 0;continue}o.aborted||i.control.apply({kind:`end`,reason:`The task was cancelled and its serve body didn't return to receive() within 30 seconds.`});break}if(e.next.done){if(e.channel===`control`){c=!1;continue}f={status:`failed`,error:`Workflow body ended without an outcome.`};break}if(e.channel===`control`){i.control.unwinding||(d=void 0),applyControlMessage(i,e.next.value);continue}if(e.channel===`body`){u=e.next.value;continue}let r=e.next.value;l+=r.length,r.some(isAnsweredOnControlHook)&&await t.register(),await t.relay(r)}}finally{await i.close()}if(o.aborted&&(f={status:`cancelled`,reason:o.reason instanceof Error?o.reason.message:String(o.reason??``)}),f!==void 0){let n=i.usage.total();await t.handleMessage({from:createWorkflowBodyRef(e),kind:`outcome`,result:f,...n!==void 0&&{usage:n}})}}async function reportTaskStarted(e){await resumeHookStep(e.owner.inbox,{from:createWorkflowBodyRef(e),kind:`started`},{ifPresent:!0})}function applyControlMessage(e,t){if(isWorkflowToolRunControlMessage(t)){if(isWorkflowToolRunAskDecision(t)){e.asks.settle(t);return}e.control.apply(t)}}function isAnsweredOnControlHook(e){return e.kind===`withdraw`||e.kind===`request`&&e.request.kind===`ask`}function startWorkflowBody(e){switch(e.entry.entryPoint){case`execute`:case`task`:return startCallBody(e);case`serve`:return startServeBody(e)}}async function*awaitBodyOutcome(e){yield await e}workflowToolRunWorkflow.workflowId=`workflow//eve//workflowToolRunWorkflow`;export{workflowToolRunWorkflow};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { DispatchSessionInput, Runtime, SessionCommand, SessionCommandResult } from "#channel/types.js";
|
|
2
2
|
import { type Run, type StartOptionsWithoutDeploymentId, type WorkflowFunction, type WorkflowMetadata } from "#internal/workflow/runtime.js";
|
|
3
3
|
import type { RuntimeCompiledArtifactsSource } from "#runtime/compiled-artifacts-source.js";
|
|
4
4
|
import { type SessionHandoffStart } from "#execution/session/entry-input.js";
|
|
@@ -48,14 +48,29 @@ export declare function startSessionOwnerStep(input: SessionOwnerStartInput): Pr
|
|
|
48
48
|
* stranded one is refused rather than replaced.
|
|
49
49
|
*/
|
|
50
50
|
export declare function dispatchWorkflowSessionCommand<TCommand extends SessionCommand>(input: DispatchSessionInput<TCommand>): Promise<SessionCommandResult<TCommand>>;
|
|
51
|
-
/**
|
|
52
|
-
export declare function
|
|
51
|
+
/** The session holding a continuation token's inbox, if any does. */
|
|
52
|
+
export declare function resolveContinuation(continuationToken: string): Promise<{
|
|
53
|
+
sessionId: string;
|
|
54
|
+
} | undefined>;
|
|
53
55
|
/**
|
|
54
56
|
* Resolves hook ownership for replay-idempotent work already running inside a
|
|
55
57
|
* durable step. Request handlers must return from start/resume acceptance and
|
|
56
58
|
* leave ownership arbitration to the workflow.
|
|
57
59
|
*/
|
|
58
60
|
export declare function waitForCommandHookOwner(token: string): Promise<WorkflowHookRecord>;
|
|
61
|
+
/**
|
|
62
|
+
* Waits until a started session claims its inbox, which it does when its run
|
|
63
|
+
* first suspends. Resolves `false` when the run ended without an inbox, so
|
|
64
|
+
* there is nothing left to command.
|
|
65
|
+
*/
|
|
66
|
+
export declare function waitForSessionInbox(sessionId: string): Promise<boolean>;
|
|
67
|
+
/**
|
|
68
|
+
* Calls `check` until it returns a value, backing off from 20 ms to 200 ms
|
|
69
|
+
* between calls, and resolves `undefined` once `timeoutMs` passes without one.
|
|
70
|
+
*/
|
|
71
|
+
export declare function pollUntil<T>(check: () => Promise<T | undefined>, timeoutMs: number): Promise<T | undefined>;
|
|
72
|
+
/** A run `start()` accepted may not be readable yet, which is not an ended run. */
|
|
73
|
+
export declare function hasRunEnded(runId: string): Promise<boolean>;
|
|
59
74
|
/** Starts a workflow on the deployment executing this call. */
|
|
60
75
|
export declare function startWorkflowOnCurrentDeployment<TArgs extends unknown[], TResult>(workflow: WorkflowFunction<TArgs, TResult> | WorkflowMetadata, args: TArgs, options?: StartOptionsWithoutDeploymentId): Promise<Run<unknown> | Run<TResult>>;
|
|
61
76
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{SessionPredecessorKey}from"#context/keys.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{validateToolStubTargets}from"#tool-stubs/validate-targets.js";import{getHookByToken,getRun,getWorld,start}from"#internal/workflow/runtime.js";import{SessionStrandedError,describeStrandedSession}from"#channel/session-stranded-error.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{serializeContext}from"#context/serialize.js";import{AcceptedSessionIdentityError,SessionHandoffPendingError,logicalSessionToken,resolveSessionInbox,resumeSessionInbox}from"#execution/session-inbox/resume.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{context,trace}from"#compiled/@opentelemetry/api/index.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{StrandedSessionOwnerError,assertRunnableSessionInbox}from"#execution/session-inbox/owner.js";import{initializeSessionInstrumentation}from"#instrumentation/runtime.js";import{EVE_VERSION_ATTRIBUTE,buildSessionAttributes,buildSubagentRootAttributes,readParentLineage}from"#execution/eve-workflow-attributes.js";import{endStrandedSession}from"#execution/session-inbox/end-stranded-session.js";import{SESSION_HOOK_HANDOVER_TIMEOUT_MS,waitForSessionHooksRelease}from"#execution/session-inbox/hook-release.js";import{SESSION_TIMEOUT_WORKFLOW_NAME,WORKFLOW_ENTRY_NAME,WORKFLOW_TOOL_RUN_WORKFLOW_NAME}from"#execution/stable-workflow-names.js";import{normalizeEveAttributes}from"#runtime/attributes/normalize.js";import{buildRunContext}from"#execution/runtime-context.js";import{readSessionEventHistory,readSessionEventStream,readSessionStreamTailIndex}from"#execution/session-event-stream.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";import{buildInvocationAttributes}from"#internal/invocation/metadata.js";import{isAgentTraceContext}from"#tracing/agent-trace-context.js";const EVE_PACKAGE_INFO=resolveInstalledPackageInfo(),STABLE_ID_BASE=EVE_PACKAGE_INFO.name,log=createLogger(`execution.workflow-runtime`),workflowEntryReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_ENTRY_NAME}`},sessionTimeoutWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${SESSION_TIMEOUT_WORKFLOW_NAME}`},workflowToolRunWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_TOOL_RUN_WORKFLOW_NAME}`};function createWorkflowRuntime(e){let startSession=async(t,n)=>{let r=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId});t.toolStubs!==void 0&&t.toolStubs.rootSessionId===void 0&&validateToolStubTargets(t.toolStubs.rules,r.graph);let i=buildRunContext({bundle:r,dynamicSubagentAgentConfig:e.dynamicSubagentAgentConfig,run:t});n!==void 0&&i.set(SessionPredecessorKey,n);let a=resolveEffectiveAgentRuntime(r,i);initializeSessionInstrumentation({agentName:a.turnAgent.id,ctx:i});let o=a.limits?.sessionTimeoutMs,s=r.resolvedAgent.config?.experimental?.workflow?.retention,c=serializeContext(i),l=readParentLineage(c),u={kind:`initial`,input:t.input,ownerDeploymentId:await resolveCurrentWorkflowDeploymentId(),serializedContext:c};t.limits!==void 0&&(u.limits=t.limits),t.continuationConflictCommand!==void 0&&(u.continuationConflictCommand=t.continuationConflictCommand),o!==void 0&&(u.sessionTimeoutMs=o),s!==void 0&&(u.retention=s);let d={...l.sessionId===void 0?buildSessionAttributes({serializedContext:c}):buildSubagentRootAttributes({identity:{nodeId:r.nodeId??ROOT_RUNTIME_AGENT_NODE_ID},parentCallId:l.callId,parentSessionId:l.sessionId,parentTurnId:l.turnId,rootSessionId:l.rootSessionId??l.sessionId,serializedContext:c}),...t.externalInvocation===void 0?{}:buildInvocationAttributes(t.externalInvocation)},f;try{let e={allowReservedAttributes:!0,attributes:normalizeEveAttributes(d)};s!==void 0&&(e.experimental_retention=s),f=await startWorkflowOnDeployment(workflowEntryReference,[u],u.ownerDeploymentId,e)}catch(e){throw logError(log,`failed to start workflow run`,e,{continuationToken:t.continuationToken}),e}let p,getEvents=()=>(p??=readSessionEventStream(f.runId),p);return{get events(){return getEvents()},sessionId:f.runId}};return{async createSession(e){return await startSession(e)},async dispatchContinuation(e){let{command:t,continuationToken:n,successor:r}=e;try{return await dispatchWorkflowCommand(n,t)}catch(e){if(!(e instanceof StrandedSessionOwnerError))throw e;if(t.kind!==`send`||r===void 0)return await settleStrandedCommand(n,t,e);if((t.payload.inputResponses?.length??0)>0)throw sessionStrandedError(e,`Its pending requests can no longer be answered; send a new message to start a fresh session.`);let i=await endStrandedSession(e,n,`message`);return{sessionId:(await startSession(r,{sessionId:i})).sessionId,status:`accepted`}}},async dispatchSession(e){return await dispatchWorkflowSessionCommand(e)},async getEventStream(e,t){if(t?.follow===!1)return readSessionEventHistory(e,t.startIndex);try{await assertRunnableSessionInbox(sessionInboxHookToken(sessionCommandHookToken(e)))}catch(e){throw e instanceof StrandedSessionOwnerError?sessionStrandedError(e):e}return readSessionEventStream(e,t?.startIndex)},async getStreamTailIndex(e){return await readSessionStreamTailIndex(e)},async resolveContinuation(e){try{return await resolveSessionInbox(e)}catch(t){if(HookNotFoundError.is(t))return;throw logError(log,`failed to resolve session by continuation token`,t,{continuationToken:e}),t}}}}async function startSessionOwnerStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,o={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};await startWorkflowOnDeployment(workflowEntryReference,[o],i,r.retention===void 0?void 0:{experimental_retention:r.retention})}async function dispatchWorkflowCommand(e,t){let n;try{let r=await resumeSessionInbox(e,t);n={runId:r.ownerRunId,sessionId:await r.sessionId}}catch(n){if(n instanceof StrandedSessionOwnerError)throw n;let r=t.kind===`send`&&typeof e!=`string`,i={status:`session_not_active`,retryable:!0};if(n instanceof SessionHandoffPendingError){if(r)return i;throw n}if(isInactiveCommandTarget(n))return r&&await isRunActive(e.sessionId)?i:inactiveCommandResult(t);throw logError(log,`failed to dispatch session command`,n,{command:t.kind,token:e}),n}return t.kind===`reset`&&await waitForSessionHooksRelease([sessionCommandHookToken(n.sessionId),logicalSessionToken(e)],n.runId),activeCommandResult(t,n.sessionId)}async function settleStrandedCommand(e,t,n){switch(t.kind){case`reset`:return{previousSessionId:await endStrandedSession(n,e,`reset`),status:`reset`};case`send`:case`clear`:throw sessionStrandedError(n);default:return inactiveCommandResult(t)}}function sessionStrandedError(e,t){let n=e.eveVersion===void 0?{}:{eveVersion:e.eveVersion};return new SessionStrandedError(n,describeStrandedSession(n,t))}function activeCommandResult(e,t){return e.kind===`reset`?{previousSessionId:t,status:`reset`}:e.kind===`send`&&e.delivery!==void 0?{sessionId:t,status:`accepted`,deliveryId:e.delivery.deliveryId}:{sessionId:t,status:`accepted`}}function inactiveCommandResult(e){return e.kind===`send`?{status:`session_not_active`}:e.kind===`cancel`?{status:`no_active_turn`}:{status:`no_active_session`}}async function dispatchWorkflowSessionCommand(e){let t={sessionId:e.sessionId};try{return await dispatchWorkflowCommand(t,e.command)}catch(n){if(!(n instanceof StrandedSessionOwnerError))throw n;return await settleStrandedCommand(t,e.command,n)}}async function requestWorkflowTurnCancellation(e){let t={kind:`cancel`};return e.turnId!==void 0&&(t.turnId=e.turnId),await dispatchWorkflowSessionCommand({command:t,sessionId:e.sessionId})}async function isRunActive(e){try{let t=await getRun(e).status;return t===`pending`||t===`running`}catch(e){if(isInactiveCommandTarget(e))return!1;throw e}}function isInactiveCommandTarget(e){if(e instanceof AcceptedSessionIdentityError)return!1;if(HookNotFoundError.is(e))return!0;for(let t of walkCauseChain(e))if(WorkflowRunNotFoundError.is(t)||RunExpiredError.is(t)||EntityConflictError.is(t))return!0;return!1}async function waitForCommandHookOwner(e){let t=Date.now()+SESSION_HOOK_HANDOVER_TIMEOUT_MS;for(;;)try{return normalizeWorkflowHook(await getHookByToken(e))}catch(e){if(!HookNotFoundError.is(e)||Date.now()>=t)throw e;await new Promise(e=>setTimeout(e,20))}}async function startWorkflowOnCurrentDeployment(e,t,n){return await startWorkflowOnDeployment(e,t,await resolveCurrentWorkflowDeploymentId(),n)}async function startWorkflowOnDeployment(e,t,n,r){return await withWorkflowStartContext(async()=>{if(n.length===0||n===`latest`)throw Error(`Workflow starts require an exact deployment id.`);return await start(e,t,{...r,allowReservedAttributes:!0,attributes:{...r?.attributes,[EVE_VERSION_ATTRIBUTE]:EVE_PACKAGE_INFO.version},deploymentId:n})})}async function resolveCurrentWorkflowDeploymentId(){let e=process.env.VERCEL_DEPLOYMENT_ID?.trim()||await(await getWorld()).getDeploymentId();if(e.length===0||e===`latest`)throw Error(`Workflow runtime could not resolve an exact deployment id.`);return e}async function withWorkflowStartContext(e){let t=context.active(),n=isAgentTraceContext(t)?trace.deleteSpan(t):t;return await context.with(n,e)}function normalizeWorkflowHook(e){if(typeof e!=`object`||!e||!(`runId`in e))throw Error(`Workflow hook did not include a run id.`);let t=e.runId;if(typeof t!=`string`||t.length===0)throw Error(`Workflow hook did not include a run id.`);return{runId:t}}export{createWorkflowRuntime,dispatchWorkflowSessionCommand,requestWorkflowTurnCancellation,sessionTimeoutWorkflowReference,startSessionOwnerStep,startWorkflowOnCurrentDeployment,waitForCommandHookOwner,workflowEntryReference,workflowToolRunWorkflowReference};
|
|
1
|
+
import{createLogger,logError}from"#internal/logging.js";import{sessionCommandHookToken,sessionInboxHookToken}from"#execution/session-inbox/address.js";import{SessionPredecessorKey}from"#context/keys.js";import{resolveInstalledPackageInfo}from"#internal/application/package.js";import{walkCauseChain}from"#shared/errors.js";import{validateToolStubTargets}from"#tool-stubs/validate-targets.js";import{getHookByToken,getRun,getWorld,start}from"#internal/workflow/runtime.js";import{SessionStrandedError,describeStrandedSession}from"#channel/session-stranded-error.js";import{getCompiledRuntimeAgentBundle}from"#runtime/sessions/compiled-agent-cache.js";import{ROOT_RUNTIME_AGENT_NODE_ID}from"#runtime/graph.js";import{serializeContext}from"#context/serialize.js";import{AcceptedSessionIdentityError,SessionHandoffPendingError,logicalSessionToken,resolveSessionInbox,resumeSessionInbox}from"#execution/session-inbox/resume.js";import{resolveEffectiveAgentRuntime}from"#execution/effective-agent-config.js";import{context,trace}from"#compiled/@opentelemetry/api/index.js";import{EntityConflictError,HookNotFoundError,RunExpiredError,WorkflowRunNotFoundError}from"#compiled/@workflow/errors/index.js";import{StrandedSessionOwnerError,assertRunnableSessionInbox,findSessionHookHolder}from"#execution/session-inbox/owner.js";import{initializeSessionInstrumentation}from"#instrumentation/runtime.js";import{EVE_VERSION_ATTRIBUTE,buildSessionAttributes,buildSubagentRootAttributes,readParentLineage}from"#execution/eve-workflow-attributes.js";import{endStrandedSession}from"#execution/session-inbox/end-stranded-session.js";import{SESSION_HOOK_HANDOVER_TIMEOUT_MS,waitForSessionHooksRelease}from"#execution/session-inbox/hook-release.js";import{SESSION_TIMEOUT_WORKFLOW_NAME,WORKFLOW_ENTRY_NAME,WORKFLOW_TOOL_RUN_WORKFLOW_NAME}from"#execution/stable-workflow-names.js";import{normalizeEveAttributes}from"#runtime/attributes/normalize.js";import{buildRunContext}from"#execution/runtime-context.js";import{readSessionEventHistory,readSessionEventStream,readSessionStreamTailIndex}from"#execution/session-event-stream.js";import{SESSION_HANDOFF_VERSION}from"#execution/session/entry-input.js";import{buildInvocationAttributes}from"#internal/invocation/metadata.js";import{isAgentTraceContext}from"#tracing/agent-trace-context.js";const EVE_PACKAGE_INFO=resolveInstalledPackageInfo(),STABLE_ID_BASE=EVE_PACKAGE_INFO.name,log=createLogger(`execution.workflow-runtime`),workflowEntryReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_ENTRY_NAME}`},sessionTimeoutWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${SESSION_TIMEOUT_WORKFLOW_NAME}`},workflowToolRunWorkflowReference={workflowId:`workflow//${STABLE_ID_BASE}//${WORKFLOW_TOOL_RUN_WORKFLOW_NAME}`};function createWorkflowRuntime(e){let startSession=async(t,n)=>{let r=await getCompiledRuntimeAgentBundle({compiledArtifactsSource:e.compiledArtifactsSource,nodeId:e.nodeId});t.toolStubs!==void 0&&t.toolStubs.rootSessionId===void 0&&validateToolStubTargets(t.toolStubs.rules,r.graph);let i=buildRunContext({bundle:r,dynamicSubagentAgentConfig:e.dynamicSubagentAgentConfig,run:t});n!==void 0&&i.set(SessionPredecessorKey,n);let a=resolveEffectiveAgentRuntime(r,i);initializeSessionInstrumentation({agentName:a.turnAgent.id,ctx:i});let o=a.limits?.sessionTimeoutMs,s=r.resolvedAgent.config?.experimental?.workflow?.retention,c=serializeContext(i),l=readParentLineage(c),u={kind:`initial`,input:t.input,ownerDeploymentId:await resolveCurrentWorkflowDeploymentId(),serializedContext:c};t.limits!==void 0&&(u.limits=t.limits),t.continuationConflictCommand!==void 0&&(u.continuationConflictCommand=t.continuationConflictCommand),o!==void 0&&(u.sessionTimeoutMs=o),s!==void 0&&(u.retention=s);let d={...l.sessionId===void 0?buildSessionAttributes({serializedContext:c}):buildSubagentRootAttributes({identity:{nodeId:r.nodeId??ROOT_RUNTIME_AGENT_NODE_ID},parentCallId:l.callId,parentSessionId:l.sessionId,parentTurnId:l.turnId,rootSessionId:l.rootSessionId??l.sessionId,serializedContext:c}),...t.externalInvocation===void 0?{}:buildInvocationAttributes(t.externalInvocation)},f;try{let e={allowReservedAttributes:!0,attributes:normalizeEveAttributes(d)};s!==void 0&&(e.experimental_retention=s),f=await startWorkflowOnDeployment(workflowEntryReference,[u],u.ownerDeploymentId,e)}catch(e){throw logError(log,`failed to start workflow run`,e,{continuationToken:t.continuationToken}),e}let p,getEvents=()=>(p??=readSessionEventStream(f.runId),p);return{get events(){return getEvents()},sessionId:f.runId}};return{async createSession(e){return await startSession(e)},async dispatchContinuation(e){let{command:t,continuationToken:n,successor:r}=e;try{return await dispatchWorkflowCommand(n,t)}catch(e){if(!(e instanceof StrandedSessionOwnerError))throw e;if(t.kind!==`send`||r===void 0)return await settleStrandedCommand(n,t,e);if((t.payload.inputResponses?.length??0)>0)throw sessionStrandedError(e,`Its pending requests can no longer be answered; send a new message to start a fresh session.`);let i=await endStrandedSession(e,n,`message`);return{sessionId:(await startSession(r,{sessionId:i})).sessionId,status:`accepted`}}},async dispatchSession(e){return await dispatchWorkflowSessionCommand(e)},async getEventStream(e,t){if(t?.follow===!1)return readSessionEventHistory(e,t.startIndex);try{await assertRunnableSessionInbox(sessionInboxHookToken(sessionCommandHookToken(e)))}catch(e){throw e instanceof StrandedSessionOwnerError?sessionStrandedError(e):e}return readSessionEventStream(e,t?.startIndex)},async getStreamTailIndex(e){return await readSessionStreamTailIndex(e)},resolveContinuation}}async function startSessionOwnerStep(e){"use step";let{activationToken:t,anchorRunId:n,checkpoint:r,targetDeploymentId:i,...a}=e,o={...a,activationToken:t,checkpoint:r,handoffVersion:SESSION_HANDOFF_VERSION,kind:`handoff`,ownerDeploymentId:i,sessionWritable:getRun(n).getWritable(),sessionId:n};await startWorkflowOnDeployment(workflowEntryReference,[o],i,r.retention===void 0?void 0:{experimental_retention:r.retention})}async function dispatchWorkflowCommand(e,t){let n;try{let r=await resumeSessionInbox(e,t);n={runId:r.ownerRunId,sessionId:await r.sessionId}}catch(n){if(n instanceof StrandedSessionOwnerError)throw n;let r=t.kind===`send`&&typeof e!=`string`,i={status:`session_not_active`,retryable:!0};if(n instanceof SessionHandoffPendingError){if(r)return i;throw n}if(isInactiveCommandTarget(n))return r&&await isRunActive(e.sessionId)?i:inactiveCommandResult(t);throw logError(log,`failed to dispatch session command`,n,{command:t.kind,token:e}),n}return t.kind===`reset`&&await waitForSessionHooksRelease([sessionCommandHookToken(n.sessionId),logicalSessionToken(e)],n.runId),activeCommandResult(t,n.sessionId)}async function settleStrandedCommand(e,t,n){switch(t.kind){case`reset`:return{previousSessionId:await endStrandedSession(n,e,`reset`),status:`reset`};case`send`:case`clear`:throw sessionStrandedError(n);default:return inactiveCommandResult(t)}}function sessionStrandedError(e,t){let n=e.eveVersion===void 0?{}:{eveVersion:e.eveVersion};return new SessionStrandedError(n,describeStrandedSession(n,t))}function activeCommandResult(e,t){return e.kind===`reset`?{previousSessionId:t,status:`reset`}:e.kind===`send`&&e.delivery!==void 0?{sessionId:t,status:`accepted`,deliveryId:e.delivery.deliveryId}:{sessionId:t,status:`accepted`}}function inactiveCommandResult(e){return e.kind===`send`?{status:`session_not_active`}:e.kind===`cancel`?{status:`no_active_turn`}:{status:`no_active_session`}}async function dispatchWorkflowSessionCommand(e){let t={sessionId:e.sessionId};try{return await dispatchWorkflowCommand(t,e.command)}catch(n){if(!(n instanceof StrandedSessionOwnerError))throw n;return await settleStrandedCommand(t,e.command,n)}}async function isRunActive(e){try{let t=await getRun(e).status;return t===`pending`||t===`running`}catch(e){if(isInactiveCommandTarget(e))return!1;throw e}}function isInactiveCommandTarget(e){if(e instanceof AcceptedSessionIdentityError)return!1;if(HookNotFoundError.is(e))return!0;for(let t of walkCauseChain(e))if(WorkflowRunNotFoundError.is(t)||RunExpiredError.is(t)||EntityConflictError.is(t))return!0;return!1}async function resolveContinuation(e){try{return await resolveSessionInbox(e)}catch(t){if(HookNotFoundError.is(t))return;throw logError(log,`failed to resolve session by continuation token`,t,{continuationToken:e}),t}}async function waitForCommandHookOwner(e){let t=await pollUntil(async()=>{try{return normalizeWorkflowHook(await getHookByToken(e))}catch(e){if(!HookNotFoundError.is(e))throw e;return}},SESSION_HOOK_HANDOVER_TIMEOUT_MS);if(t===void 0)throw new HookNotFoundError(e);return t}async function waitForSessionInbox(e){let t=sessionInboxHookToken(sessionCommandHookToken(e)),n=await pollUntil(async()=>await findSessionHookHolder(t)!==void 0||!await hasRunEnded(e)&&void 0,SESSION_HOOK_HANDOVER_TIMEOUT_MS);if(n===void 0)throw Error(`Session "${e}" did not start taking commands within ${SESSION_HOOK_HANDOVER_TIMEOUT_MS/1e3} seconds.`);return n}async function pollUntil(e,t){let n=Date.now()+t;for(let t=20;;t=Math.min(t*2,200)){let r=await e();if(r!==void 0||Date.now()>=n)return r;await new Promise(e=>setTimeout(e,t))}}async function hasRunEnded(e){try{let t=await getRun(e).status;return t!==`pending`&&t!==`running`}catch(e){for(let t of walkCauseChain(e))if(WorkflowRunNotFoundError.is(t))return!1;if(isInactiveCommandTarget(e))return!0;throw e}}async function startWorkflowOnCurrentDeployment(e,t,n){return await startWorkflowOnDeployment(e,t,await resolveCurrentWorkflowDeploymentId(),n)}async function startWorkflowOnDeployment(e,t,n,r){return await withWorkflowStartContext(async()=>{if(n.length===0||n===`latest`)throw Error(`Workflow starts require an exact deployment id.`);return await start(e,t,{...r,allowReservedAttributes:!0,attributes:{...r?.attributes,[EVE_VERSION_ATTRIBUTE]:EVE_PACKAGE_INFO.version},deploymentId:n})})}async function resolveCurrentWorkflowDeploymentId(){let e=process.env.VERCEL_DEPLOYMENT_ID?.trim()||await(await getWorld()).getDeploymentId();if(e.length===0||e===`latest`)throw Error(`Workflow runtime could not resolve an exact deployment id.`);return e}async function withWorkflowStartContext(e){let t=context.active(),n=isAgentTraceContext(t)?trace.deleteSpan(t):t;return await context.with(n,e)}function normalizeWorkflowHook(e){if(typeof e!=`object`||!e||!(`runId`in e))throw Error(`Workflow hook did not include a run id.`);let t=e.runId;if(typeof t!=`string`||t.length===0)throw Error(`Workflow hook did not include a run id.`);return{runId:t}}export{createWorkflowRuntime,dispatchWorkflowSessionCommand,hasRunEnded,pollUntil,resolveContinuation,sessionTimeoutWorkflowReference,startSessionOwnerStep,startWorkflowOnCurrentDeployment,waitForCommandHookOwner,waitForSessionInbox,workflowEntryReference,workflowToolRunWorkflowReference};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import type { SessionAuthContext } from "#channel/types.js";
|
|
2
1
|
import type { ModelMessage } from "ai";
|
|
3
2
|
import type { getApprovalAuditState } from "#harness/hitl/candidates.js";
|
|
4
3
|
import { type AuthorizationChallenge } from "#harness/authorization.js";
|
|
@@ -22,9 +21,8 @@ export declare function parkOnApprovals(view: SessionView, input: {
|
|
|
22
21
|
readonly responseAuthRequiredRequestIds?: readonly string[];
|
|
23
22
|
readonly requester?: SuspendedStep["requester"];
|
|
24
23
|
}): Transition;
|
|
25
|
-
/** Approved workflow and agent calls join the runs their steps wait on
|
|
24
|
+
/** Approved workflow and agent calls join the runs their requesting steps wait on. */
|
|
26
25
|
export declare function dispatch(view: SessionView, input: {
|
|
27
|
-
readonly approvers: Readonly<Record<string, SessionAuthContext>>;
|
|
28
26
|
readonly tasks: readonly RuntimeWorkflowTaskRequest[];
|
|
29
27
|
}): Transition;
|
|
30
28
|
/**
|
|
@@ -48,10 +46,9 @@ export interface Answered extends Transition {
|
|
|
48
46
|
/**
|
|
49
47
|
* `continue`: the step goes on. `park`: nothing can run until more input arrives.
|
|
50
48
|
* `repeat`: a policy pass committed, so the next pass runs in a fresh step. `sign-in`: a
|
|
51
|
-
* responder must sign in first.
|
|
52
|
-
* prompt is open; it waits in its turn for the prompt.
|
|
49
|
+
* responder must sign in first.
|
|
53
50
|
*/
|
|
54
|
-
readonly next: "continue" | "park" | "repeat" | "sign-in"
|
|
51
|
+
readonly next: "continue" | "park" | "repeat" | "sign-in";
|
|
55
52
|
/** The turn's input, without the answers `answer` consumed. */
|
|
56
53
|
readonly input?: StepInput;
|
|
57
54
|
/** Whether a plain-text answer consumed the message. */
|
|
@@ -100,7 +97,7 @@ export declare function stepForRequest(view: SessionView, requestId: string): Su
|
|
|
100
97
|
export declare function withdrawSignIns(view: SessionView, reason: string): Transition;
|
|
101
98
|
/**
|
|
102
99
|
* The session spent its budget: it asks whether to continue instead of calling the model, and
|
|
103
|
-
* the turn
|
|
100
|
+
* the turn holds for input. The prompt is the projection's open request; `answer` grants a
|
|
104
101
|
* fresh budget or declines it.
|
|
105
102
|
*/
|
|
106
103
|
export declare function requestLimit(view: SessionView, input: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{canonicalize,compactInput,hasInput,isEmptyInput,resolveTextInput,withoutResponses,withoutTurnInput}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{finishTurn,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));if(r.length===0)return e;let i=withoutApproved(e,new Set(r.map(e=>e.callId))),a={...e.approvers};for(let{callId:e}of r){let n=t.approvers[e];n!==void 0&&(a[e]=n)}return{...i,tasks:[...e.tasks,...r],...Object.keys(a).length>0&&{approvers:a}}});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 hasInput(s)?(queue(withoutTurnInput(u)),done({input:u,next:`defer-message`})):(queue(compactInput(u)),done({next:`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;if(t.message!==void 0||(t.context?.length??0)>0||readClientContext(t)!==void 0||t.outputSchema!==void 0||(t.runtimeActionResults?.length??0)>0)return!0;let n=[...t.inputResponses??[],...(t.attributedInputResponses??[]).map(({response:e})=>e)];if(n.length===0)return!1;let r=new Set(n.map(e=>e.requestId)),i=openInputs(e.projection).find(e=>e.request.kind===`session-limit`);return i===void 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}),...finishTurn(e).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{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};
|
|
@@ -37,4 +37,15 @@ export declare function runApprovedCalls(input: {
|
|
|
37
37
|
readonly settled: readonly ApprovedCallResult[];
|
|
38
38
|
readonly toolResults: readonly TypedToolResult<ToolSet>[];
|
|
39
39
|
}>;
|
|
40
|
+
/** Records an approved call refused by its final request-policy check. */
|
|
41
|
+
export declare function rejectApprovedCall(input: {
|
|
42
|
+
readonly request: InputRequest;
|
|
43
|
+
readonly reason?: string;
|
|
44
|
+
readonly position: {
|
|
45
|
+
readonly sequence: number;
|
|
46
|
+
readonly stepIndex: number;
|
|
47
|
+
readonly turnId: string;
|
|
48
|
+
};
|
|
49
|
+
readonly publish: HandleEventFn;
|
|
50
|
+
}): Promise<ApprovedCallResult>;
|
|
40
51
|
export {};
|
|
@@ -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
|
|
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};
|
|
@@ -23,8 +23,6 @@ export interface ApprovalResponderIdentity {
|
|
|
23
23
|
}
|
|
24
24
|
export interface ApprovalSettlementAuditRecord {
|
|
25
25
|
readonly actor: ApprovalResponderIdentity;
|
|
26
|
-
/** The approver's full auth, which the approved call runs as. Present only when allowed. */
|
|
27
|
-
readonly approver?: SessionAuthContext;
|
|
28
26
|
/** `unavailable`: the request's entry was gone, so its call is reported unavailable, never run. */
|
|
29
27
|
readonly outcome: "allowed" | "cancelled" | "unavailable";
|
|
30
28
|
readonly requestId: string;
|
|
@@ -119,6 +117,4 @@ export declare function retireActiveCandidates(state: SessionStateMap | undefine
|
|
|
119
117
|
readonly completedAt: number;
|
|
120
118
|
readonly reason: string;
|
|
121
119
|
}): SessionStateMap | undefined;
|
|
122
|
-
/** The full auth of whoever approved `requestId`, when it was allowed. */
|
|
123
|
-
export declare function approverOfRequest(state: SessionStateMap | undefined, requestId: string): SessionAuthContext | undefined;
|
|
124
120
|
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)
|
|
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};
|
|
@@ -34,7 +34,6 @@ export declare function resolveTextInput(batch: Pick<SuspendedStep, "requests">,
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function resolveTypedApproval(view: Pick<SessionView, "projection" | "turn">, stepInput: StepInput | undefined): ResolvedStepInput | undefined;
|
|
36
36
|
export declare function canonicalize(responses: readonly InputResponse[]): readonly InputResponse[];
|
|
37
|
-
export declare function hasInput(input: StepInput | undefined): boolean;
|
|
38
37
|
export declare function isEmptyInput(input: StepInput): boolean;
|
|
39
38
|
export declare function withoutResponses(input: ResolvedStepInput | undefined): StepInput | undefined;
|
|
40
39
|
/** The turn's own input: the message a plain-text answer didn't consume, and its context. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{attachClientContext,readClientContext}from"#internal/client-context.js";import{readAnswerText}from"#internal/input-text.js";import{firstOpenInput}from"#harness/open-input-request.js";import{resolveTextToResponse,resolveTextToResponses}from"#channel/resolve-text.js";import{coalesceTurnInputs}from"#harness/messages.js";import{ownOpenRequestIds}from"#harness/session-machine/transitions.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{convertStaleResponsesToUserMessage,dropStaleSessionLimitContinuationResponses}from"#harness/hitl/stale-responses.js";function deliver(e,t,n){let r=n.takeQueued?e.turn.queued:void 0,i=r
|
|
1
|
+
import{openInputs}from"#protocol/session-projection.js";import{attachClientContext,readClientContext}from"#internal/client-context.js";import{readAnswerText}from"#internal/input-text.js";import{firstOpenInput}from"#harness/open-input-request.js";import{resolveTextToResponse,resolveTextToResponses}from"#channel/resolve-text.js";import{coalesceTurnInputs}from"#harness/messages.js";import{ownOpenRequestIds}from"#harness/session-machine/transitions.js";import{isApprovalRequest}from"#harness/input-request-class.js";import{convertStaleResponsesToUserMessage,dropStaleSessionLimitContinuationResponses}from"#harness/hitl/stale-responses.js";function deliver(e,t,n){let r=n.takeQueued?e.turn.queued:void 0,i=openInputs(e.projection).find(e=>e.request.kind===`session-limit`),a=r!==void 0&&i!==void 0?resolveTextInput({requests:[i.request]},t):t,o=r===void 0?a:a===void 0?r:coalesceTurnInputs(r,a),s=new Set([...ownOpenRequestIds(e),...e.turn.suspended.flatMap(e=>e.requests.map(e=>e.requestId))]),c=new Map(Object.values(e.projection.inputs).map(e=>[e.request.requestId,e.request])),l=convertStaleResponsesToUserMessage({pendingRequestIds:s,requests:c,stepInput:dropStaleSessionLimitContinuationResponses({pendingRequestIds:s,stepInput:o})});return l.kind===`converted`?{displayMessage:l.displayMessage,input:l.stepInput,takeQueued:n.takeQueued}:{input:l.stepInput,takeQueued:n.takeQueued}}function resolveTextInput(e,t){let n=readAnswerText(t);if(t===void 0||n===void 0)return t;let r=new Set(e.requests.map(e=>e.requestId));if(t.inputResponses?.some(e=>r.has(e.requestId)))return t;let i=resolveTextToResponses(n,e.requests);return i.length===0?t:compactInput({...t,context:void 0,inputResponses:[...t.inputResponses??[],...i],message:void 0,messageConsumed:!0})}function resolveTypedApproval(e,t){let n=readAnswerText(t);if(t===void 0||n===void 0)return t;let r=new Set([...t.inputResponses??[],...(t.attributedInputResponses??[]).map(({response:e})=>e)].map(({requestId:e})=>e)),i=firstOpenInput(e.projection,e=>r.has(e))?.request,a=e.turn.suspended.some(e=>e.requests.some(e=>e.requestId===i?.requestId));if(i===void 0||!a||!isApprovalRequest(i))return t;let o=resolveTextToResponse(n,i);return o===void 0?t:{...t,context:void 0,inputResponses:[...t.inputResponses??[],o],message:void 0,messageConsumed:!0}}function canonicalize(e){let t=new Map;for(let n of e)t.set(n.requestId,n);return[...t.values()]}function isEmptyInput(e){return Object.keys(compactInput(e)).length===0}function withoutResponses(e){if(e===void 0)return;let{attributedInputResponses:t,inputResponses:n,messageConsumed:r,...i}=e;return i}function turnInputOnly(e){if(e===void 0)return;let t={};(e.context?.length??0)>0&&(t.context=e.context),e.message!==void 0&&e.messageConsumed!==!0&&(t.message=e.message);let n=attachClientContext(t,readClientContext(e));return isEmptyInput(n)?void 0:n}function withoutTurnInput(e){let t={};return(e?.inputResponses?.length??0)>0&&(t.inputResponses=e.inputResponses),e?.outputSchema!==void 0&&(t.outputSchema=e.outputSchema),t}function compactInput(e){if(e===void 0)return{};let t={};return(e.context?.length??0)>0&&(t.context=e.context),(e.inputResponses?.length??0)>0&&(t.inputResponses=e.inputResponses),e.message!==void 0&&(t.message=e.message),e.messageConsumed===!0&&(t.messageConsumed=!0),e.outputSchema!==void 0&&(t.outputSchema=e.outputSchema),attachClientContext(t,readClientContext(e))}export{canonicalize,compactInput,deliver,isEmptyInput,resolveTextInput,resolveTypedApproval,turnInputOnly,withoutResponses,withoutTurnInput};
|
|
@@ -20,8 +20,8 @@ export declare function parkOnApprovals(step: Step, input: {
|
|
|
20
20
|
readonly tasks: readonly RuntimeWorkflowTaskRequest[];
|
|
21
21
|
/** The entries the step's calls ran, whose approvals the requests ask for. */
|
|
22
22
|
readonly tools: HarnessToolLookup;
|
|
23
|
-
/**
|
|
24
|
-
readonly
|
|
23
|
+
/** Runtime calls run first, or the caller will report a sibling sign-in hold. */
|
|
24
|
+
readonly waitsOn: "runtime" | "sign-in" | undefined;
|
|
25
25
|
}): Promise<StepResult>;
|
|
26
26
|
/**
|
|
27
27
|
* A call the model step ran needs a sign-in: the calls that need it stop, and the model calls
|
|
@@ -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{
|
|
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,5 +1,5 @@
|
|
|
1
1
|
import type { SuspendedStep } from "#harness/session-machine/view.js";
|
|
2
|
-
import {
|
|
2
|
+
import type { Step } from "#harness/step/context.js";
|
|
3
3
|
import type { HarnessToolLookup, StepInput, StepResult } from "#harness/types.js";
|
|
4
4
|
import type { InstrumentationAttempt } from "#instrumentation/runtime.js";
|
|
5
5
|
/**
|
|
@@ -56,7 +56,7 @@ export declare function dispatchApprovedWorkflows(step: Step, work: ApprovedWork
|
|
|
56
56
|
/**
|
|
57
57
|
* Runs approved local calls once the step has started and its budget allows it, as the AI SDK ran
|
|
58
58
|
* them before the model read their results: each with the tools of the step that asked, as
|
|
59
|
-
*
|
|
59
|
+
* the turn's requester, and in the step's first attempt. A call that needs a sign-in holds the
|
|
60
60
|
* turn.
|
|
61
61
|
*/
|
|
62
62
|
export declare function runApprovedLocalCalls(step: Step, work: ApprovedWork, setAttemptScope: (scope: InstrumentationAttempt | undefined) => void): Promise<StepResult | undefined>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{deliver,resolveTypedApproval,turnInputOnly,withoutTurnInput}from"./delivery.js";import{answer,approvingSteps,deferInput,dispatch,grantedApprovalKeys,requireSignIn,stepForRequest,withdrawSignIns}from"./approvals.js";import{
|
|
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 +1 @@
|
|
|
1
|
-
import{buildGatewayAttributionHeaders}from"./model.js";import{isEmptyModelResponse,rethrowNoOutputAsEmptyResponse}from"./recovery.js";import{modelInstructions,requestMessages,withTrailingUserNote}from"./request.js";import{answerSkippedToolCalls,appendMissingToolResultMessages,extractToolResultCallIds,withAccumulatedResponseMessages}from"./response.js";import{runModelCallWithRetries}from"./retry.js";import{logToolExecutionError,prepareModelTools}from"./tools.js";import{extractGatewayCostUsd,extractTokenUsageDelta}from"./usage.js";import{ToolLoopAgent,isStepCount}from"ai";import{createLogger,logError}from"#internal/logging.js";import{AuthKey,HistoryStateKey}from"#context/keys.js";import{REPLY_TOOL_NAME}from"#protocol/reply-tool.js";import{createStepCompletedEvent}from"#protocol/message.js";import{activeTurnId}from"#harness/session-machine/view.js";import{addTurnUsage}from"#harness/turn-tag-state.js";import{hydrateSandboxAttachments,moveToolResultFilesToUserMessages}from"#harness/attachment-staging.js";import{workingTaskIds}from"#execution/tasks/model-step.js";import{toEntryStep,toEntryStream,toEntryTelemetry}from"#harness/execute-call.js";import{discardAttempt}from"#harness/session-machine/transitions.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{summarizeKnownError}from"#harness/semantic-errors/index.js";import{estimateTokens}from"#harness/token-estimate.js";import{requireSessionModelReference}from"#harness/types.js";import{ContentFilteredModelResponseError,EmptyModelResponseError,ModelStreamStalledError}from"#harness/model-call/errors.js";import{resolveModelProfile}from"#harness/model-profile.js";import{estimateRequestEnvelope}from"#harness/request-envelope.js";import{interruptStreamOnFailure}from"#harness/interruptible-stream.js";import{buildToolApproval}from"#harness/tools.js";import{
|
|
1
|
+
import{buildGatewayAttributionHeaders}from"./model.js";import{isEmptyModelResponse,rethrowNoOutputAsEmptyResponse}from"./recovery.js";import{modelInstructions,requestMessages,withTrailingUserNote}from"./request.js";import{answerSkippedToolCalls,appendMissingToolResultMessages,extractToolResultCallIds,withAccumulatedResponseMessages}from"./response.js";import{runModelCallWithRetries}from"./retry.js";import{logToolExecutionError,prepareModelTools}from"./tools.js";import{extractGatewayCostUsd,extractTokenUsageDelta}from"./usage.js";import{ToolLoopAgent,isStepCount}from"ai";import{createLogger,logError}from"#internal/logging.js";import{AuthKey,HistoryStateKey}from"#context/keys.js";import{REPLY_TOOL_NAME}from"#protocol/reply-tool.js";import{createStepCompletedEvent}from"#protocol/message.js";import{activeTurnId}from"#harness/session-machine/view.js";import{addTurnUsage}from"#harness/turn-tag-state.js";import{hydrateSandboxAttachments,moveToolResultFilesToUserMessages}from"#harness/attachment-staging.js";import{workingTaskIds}from"#execution/tasks/model-step.js";import{toEntryStep,toEntryStream,toEntryTelemetry}from"#harness/execute-call.js";import{discardAttempt}from"#harness/session-machine/transitions.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{summarizeKnownError}from"#harness/semantic-errors/index.js";import{estimateTokens}from"#harness/token-estimate.js";import{requireSessionModelReference}from"#harness/types.js";import{ContentFilteredModelResponseError,EmptyModelResponseError,ModelStreamStalledError}from"#harness/model-call/errors.js";import{resolveModelProfile}from"#harness/model-profile.js";import{estimateRequestEnvelope}from"#harness/request-envelope.js";import{interruptStreamOnFailure}from"#harness/interruptible-stream.js";import{buildToolApproval}from"#harness/tools.js";import{emitStreamContent}from"#harness/emission.js";import{compactPrompt,projectPrompt,withClientContext}from"#harness/step/prompt.js";import{buildStepHooks,emitStepActions,readGatewayGenerationId}from"#harness/step-hooks.js";import{maybeCompact}from"#harness/compaction/step.js";const environment=process.env.NODE_ENV??`unknown`,log=createLogger(`harness.tool-loop`),MODEL_OUTPUT_TIMEOUT_MS=6e5;var ModelCaller=class{profile;attributionHeaders;projectedMessages;request;modelMessages=[];requestEnvelopeTokens=0;interruptedUsage;compactionFailure;attemptIndex=0;step;prompt;input;constructor(e,t,n){this.step=e,this.prompt=t,this.input=n,this.profile=resolveModelProfile(n.model,requireSessionModelReference(e.session).promptCache),this.attributionHeaders=buildGatewayAttributionHeaders(this.profile,e.config.runtimeIdentity),this.projectedMessages=n.projectedMessages,this.request=this.buildRequest()}async call(e){let t=new Map;return await runModelCallWithRetries(async n=>(n>1&&(await this.settleRetriedActions(t),t=new Map),await this.attempt({...e,suppressStepStartedEmission:n!==1||e.suppressStepStartedEmission},t)),{canRetry:()=>this.compactionFailure===void 0,sessionId:this.step.session.sessionId,turnId:this.step.position().turnId},this.input.generation.signal)}async settleRetriedActions(e){for(let[t,n]of e)await this.step.apply(discardAttempt(this.step.view(),{calls:[{callId:t,toolName:n}]})),e.delete(t)}throwIfCompactionFailed(){if(this.compactionFailure!==void 0)throw this.compactionFailure.error}async steered(){let{step:e}=this;return throwIfTurnAborted(e.config.abortSignal),e.ctx?.set(HistoryStateKey,this.request.historyState),this.interruptedUsage!==void 0&&(e.session=addTurnUsage(e.session,e.position().turnId,this.interruptedUsage)),await e.emit?.(createStepCompletedEvent({...e.position(),finishReason:`other`,usage:this.interruptedUsage})),{next:e.runStep,session:{...e.session,history:[...this.request.history]},steered:!0}}clearInterruptedUsage(){this.interruptedUsage=void 0}buildRequest(){return requestMessages(this.step,{catalog:this.input.catalog,hidesHeldText:this.input.hidesHeldText,messages:this.prompt.messages,pendingApprovalsNote:this.input.pendingApprovalsNote,projectedMessages:this.projectedMessages,turnMessages:this.input.turnMessages})}instructions(e){return modelInstructions({anthropicCache:this.profile.anthropicCache,extraSystemNote:e,session:this.step.session,systemMessages:this.request.systemMessages})}async prepare(e){let t=await prepareModelTools(this.step,{catalog:this.input.catalog,disabledProviderTools:e.disabledProviderTools,generation:this.input.generation,profile:this.profile});return this.request=this.buildRequest(),this.requestEnvelopeTokens=await estimateRequestEnvelope({history:this.projectedMessages,instructions:this.instructions(e.extraSystemNote),messages:withTrailingUserNote(this.request.nonSystemMessages,e.trailingUserNote),tools:t}),t}async compact(e,t){let{step:n,prompt:r}=this,{config:i}=n,a;try{if(a=await maybeCompact({abortSignal:i.abortSignal,auth:n.ctx?.get(AuthKey)??null,emissionState:n.position(),historyProjector:i.historyProjector,messages:[...r.messages],model:this.input.model,promptMessages:withClientContext(r),publish:n.publish,requestEnvelopeTokens:this.requestEnvelopeTokens,resolveModel:i.resolveModel,runtimeIdentity:i.runtimeIdentity,session:n.session,telemetry:n.instrumentation?.telemetry()}),a.failure!==void 0)throw a.failure.error}catch(e){throw this.compactionFailure={error:e},e}if(n.session=a.session,!a.compacted)return t;compactPrompt(n,r,a.messages);let{compaction:o}=n.session;return n.session={...n.session,compaction:{recentWindowSize:o.recentWindowSize,threshold:o.threshold,thresholdPercent:o.thresholdPercent}},this.projectedMessages=projectPrompt(n,r),await this.prepare(e)}async attempt(e,t){let{step:n}=this,{catalog:r,generation:i,model:a}=this.input,o=await this.compact(e,await this.prepare(e));this.requestEnvelopeTokens=Math.max(0,this.requestEnvelopeTokens-(estimateTokens(this.request.history)-estimateTokens(this.prompt.messages))),i.begin(),this.modelMessages=await hydrateSandboxAttachments(this.request.nonSystemMessages),this.profile.filesOutsideToolResults&&(this.modelMessages=moveToolResultFilesToUserMessages(this.modelMessages));let s=this.instructions(e.extraSystemNote),c=n.instrumentation?.resolveRuntimeContext({emissionState:n.position(),environment,modelInput:{instructions:s,messages:this.modelMessages},session:n.session})??{};e.retryReason&&(c[`eve.retry.reason`]=e.retryReason);let l=withTrailingUserNote(this.modelMessages,e.trailingUserNote),u=n.position(),d=n.instrumentation?.prepareAttempt({isFrameworkTool:e=>n.frameworkToolNames.has(e),attemptIndex:this.attemptIndex++,runtimeContext:c,stepIndex:u.stepIndex,turnId:activeTurnId(u)});this.input.setAttemptScope(d?.scope);let f=buildStepHooks({auth:n.ctx?.get(AuthKey)??null,profile:this.profile,session:n.session,startStep:e.suppressStepStartedEmission===!0?void 0:this.input.startStep}),p={headers:this.attributionHeaders,instructions:s,model:a,onLanguageModelCallEnd:e=>{i.interrupted||(this.interruptedUsage=extractTokenUsageDelta({costUsd:extractGatewayCostUsd(e.providerMetadata),usage:e.usage}))},onToolExecutionEnd:e=>logToolExecutionError(e,r.resolve),onError(e){i.interrupted||summarizeKnownError(e.error)?.tags.includes(`config`)!==!0&&logError(log,`tool-loop stream error`,e.error)},onStepEnd:f.onStepEnd,onStepStart:f.onStepStart,prepareStep:f.prepareStep,reasoning:n.session.agent.modelReference?.reasoning??n.session.agent.reasoning,runtimeContext:c,stopWhen:isStepCount(1),telemetry:toEntryTelemetry(d?.telemetry,r.resolve),timeout:{chunkMs:MODEL_OUTPUT_TIMEOUT_MS,firstChunkMs:MODEL_OUTPUT_TIMEOUT_MS},toolApproval:buildToolApproval({abortSignal:i.signal,approvedTools:this.input.approvedTools,resolve:r.resolve}),tools:o},m=new ToolLoopAgent(p);try{let e=await this.stream(m,l,f.stepResult,t);return await d?.complete(),e}catch(e){if(i.interrupted?await d?.complete():await d?.fail(e),i.check(),isAbortError(e)&&!i.signal.aborted)throw new ModelStreamStalledError({cause:e});return rethrowNoOutputAsEmptyResponse(e)}}async stream(e,t,n,r){let{step:i}=this,{catalog:a,generation:o}=this.input,s=new Set([REPLY_TOOL_NAME]),c=await e.stream({abortSignal:o.signal,messages:t}),{emittedActionCallIds:l,handledInlineToolResultCallIds:u,invalidInputToolCallIds:d,inlineAuthorizationResults:f,trailingInlineToolResultParts:p}=await emitStreamContent(i.publish,i.position(),toEntryStream(interruptStreamOnFailure(c.fullStream,o.signal),a.resolve),{excludedActionToolNames:s,hidesHeldText:this.input.hidesHeldText&&workingTaskIds(i.session).length>0,tools:a,unsettledActionToolNames:r});throwIfTurnAborted(i.config.abortSignal),o.check();let[m,h]=toEntryStep(...await Promise.all([n,c.responseMessages]),a.resolve);assertUsableResponse(m,h,f.length>0||p.length>0);let g=answerSkippedToolCalls(m,a);await emitStepActions(i.publish,i.position(),g.length===0?m:withAccumulatedResponseMessages({stepResult:m,responseMessages:appendMissingToolResultMessages({append:g,responseMessages:m.response.messages})}),{emittedActionCallIds:l,excludedActionCallIds:d,excludedActionToolNames:s,handledInlineToolResultCallIds:u,tools:a});let _=new Map(m.toolResults.map(e=>[e.toolCallId,e]));for(let e of f)_.set(e.toolCallId,e);return withAccumulatedResponseMessages({invalidInputToolCallIds:d,responseMessages:appendMissingToolResultMessages({append:[...p,...answerSkippedToolCalls(m,a)],responseMessages:h}),stepResult:m,toolResults:[..._.values()]})}};function assertUsableResponse(e,t,n){if(e.finishReason===`content-filter`)throw new ContentFilteredModelResponseError(readGatewayGenerationId(e.providerMetadata));if(isEmptyModelResponse(e)&&extractToolResultCallIds(t).size===0&&!n)throw new EmptyModelResponseError}function isAbortError(e){return e instanceof Error&&(e.name===`AbortError`||e.name===`TimeoutError`)}export{ModelCaller};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{resolveEffectiveRuntimeModel}from"./model.js";import{recoverModelCall}from"./recovery.js";import{endsTurnTools,frameworkToolNames}from"./tools.js";import{recordModelUsage}from"./usage.js";import{ModelCaller}from"./call.js";import{reportModelCallFailure}from"./failure.js";import{HistoryStateKey}from"#context/keys.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{activeTurnId}from"#harness/session-machine/view.js";import{dispatchApprovedWorkflows,enforceBudget,hasApprovedWork,humanInputContext,runApprovedLocalCalls}from"#harness/hitl/index.js";import{startStep}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{requireSessionModelReference}from"#harness/types.js";import{buildStepCatalog}from"#execution/catalog/step-catalog.js";import{
|
|
1
|
+
import{resolveEffectiveRuntimeModel}from"./model.js";import{recoverModelCall}from"./recovery.js";import{endsTurnTools,frameworkToolNames}from"./tools.js";import{recordModelUsage}from"./usage.js";import{ModelCaller}from"./call.js";import{reportModelCallFailure}from"./failure.js";import{HistoryStateKey}from"#context/keys.js";import{validateHarnessModelMessages}from"#harness/messages.js";import{activeTurnId}from"#harness/session-machine/view.js";import{dispatchApprovedWorkflows,enforceBudget,hasApprovedWork,humanInputContext,runApprovedLocalCalls}from"#harness/hitl/index.js";import{startStep}from"#harness/session-machine/transitions.js";import{stepStartedForResolvers}from"#harness/session-machine/resolver-events.js";import{throwIfTurnAborted}from"#harness/turn-cancellation.js";import{requireSessionModelReference}from"#harness/types.js";import{buildStepCatalog,recordOfferedCatalogTools}from"#execution/catalog/step-catalog.js";import{buildPrompt,previewPrompt,projectPrompt,withClientContext}from"#harness/step/prompt.js";import{failBoundaryEvent,failModelSelection}from"#harness/step/context.js";async function runModelStep(e,t){let{generation:n}=t,r=hasApprovedWork(e),i=r?previewPrompt(e,t.turn):await buildPrompt(e,t.turn),a=await selectModel(e,i);if(!(`model`in a))return a.failed;let start=t=>e.apply(startStep(e.view(),{modelId:requireSessionModelReference(e.session).id}),t),o=projectPrompt(e,i);try{await start(o)}catch(t){return failBoundaryEvent(e,t)}if(r&&await dispatchApprovedWorkflows(e,t.approved))return{next:null,session:e.session};let s=await enforceBudget(e,i.messages);if(s!==void 0)return s;if(r){let n=await runApprovedLocalCalls(e,t.approved,t.setAttemptScope);if(n!==void 0)return n;i=await buildPrompt(e,t.turn),o=projectPrompt(e,i)}let c=!e.hasDelegatedCaller&&e.session.outputSchema===void 0,l=buildStepCatalog({agentTools:e.config.tools,ctx:e.ctx,endsTurn:c,session:e.session});recordOfferedCatalogTools(e.ctx,l),e.frameworkToolNames=frameworkToolNames(l);let{approvedTools:u,pendingApprovalsNote:d}=humanInputContext(e,l),f=new ModelCaller(e,i,{approvedTools:u,catalog:l,generation:n,hidesHeldText:t.hidesHeldText,model:a.model,pendingApprovalsNote:d,projectedMessages:o,setAttemptScope:t.setAttemptScope,startStep:start,turnMessages:t.turn.messages}),p;try{p=await f.call({suppressStepStartedEmission:!0})}catch(t){if(f.throwIfCompactionFailed(),throwIfTurnAborted(e.config.abortSignal),n.interrupted)return f.steered();let r=await recoverModelCall({call:e=>f.call(e),error:t,sessionId:e.session.sessionId,turnId:e.position().turnId});if(f.throwIfCompactionFailed(),throwIfTurnAborted(e.config.abortSignal),n.interrupted)return f.steered();if(!(`result`in r))return reportModelCallFailure(e,r.error);p=r.result}await recordModelUsage(e,{model:a.model,result:p}),f.clearInterruptedUsage();let m;try{n.check(),m=await t.onResponse({catalog:l,durableModelPromptMessageCount:i.clientContext===void 0||i.clientContext.messages.length===0?f.modelMessages.length:void 0,endsTurnTools:endsTurnTools(l,c),promptMessages:f.request.history,requestEnvelopeTokens:f.requestEnvelopeTokens,result:p})}catch(t){if(throwIfTurnAborted(e.config.abortSignal),n.interrupted)return f.steered();throw t}return e.ctx?.set(HistoryStateKey,f.request.historyState),m}async function selectModel(e,t){let{config:n,ctx:r}=e;try{if(r!==void 0&&n.dispatchDynamicModelEvent!==void 0){let i=e.position();await n.dispatchDynamicModelEvent({ctx:r,event:stepStartedForResolvers({modelId:e.session.agent.modelReference?.id??`dynamic`,sequence:i.sequence,stepIndex:i.stepIndex,turnId:activeTurnId(i)}),messages:validateHarnessModelMessages(e.projectHistory(withClientContext(t)))})}let i=await resolveEffectiveRuntimeModel({config:n,ctx:r,session:e.session});return e.session=i.session,{model:i.model}}catch(t){return{failed:await failModelSelection(e,t)}}}export{runModelStep};
|