What problem are you trying to solve?
An authored tool that starts a long-running external job (a
workflow run, a batch job) has no way to wait for the result
without holding execute open on an in-process Promise. That is
not durable: a host restart loses the waiter, and recovery is
author-built polling. We ship exactly that workaround today (an
in-memory Promise keyed by callId plus a 30s status-poll
fallback).
Eve already solves this internally for subagents: runtime
actions. The turn persists eve.runtime.pendingActionBatch, the
driver returns action: "park" with pendingRuntimeActionKeys,
the parent turn workflow waits on the turn's durable inbox hook,
and the child settles via resumeHook with a
runtime-action-result. None of this is exposed to authored
tools; ToolContext has only session metadata, abortSignal,
callId, and token helpers.
Proposed solution
Add execution: "delegated" to defineTool:
import { defineTool } from "eve/tools";
import { z } from "zod";
const JobResult = z.object({
status: z.enum(["succeeded", "failed"]),
detail: z.string(),
});
export default defineTool({
execution: "delegated",
description: "Run a durable external job.",
inputSchema: z.object({ spec: z.string() }),
outputSchema: JobResult,
async execute({ spec }, ctx, action) {
await enqueueJob({
spec,
completion: action.completion, // opaque { id, url }
idempotencyKey: action.id, // stable across replays
});
return action.pending(); // typed sentinel; never reaches the model
},
});
The worker completes via an SDK helper (raw HTTP to the
completion URL as an escape hatch):
import { completeAction } from "eve/actions";
await completeAction({
completion: job.completion,
output: { status: "succeeded", detail: "Report generated" },
});
Eve validates the output against outputSchema, settles it as an
ordinary action.result, the same turn continues, and the model
sees a normal typed tool result.
Expected mapping to existing machinery:
- The call becomes a runtime action — a sibling of
subagent-call — with a stable action id registered in the
pending batch BEFORE execute runs, so a fast completion
cannot race registration.
- The driver parks exactly as it does for subagents.
- Completion routes through the active turn inbox via
resumeHook.
- Settlement reuses batch resolution, history synthesis, and
toModelOutput.
Reliability semantics requested:
- Duplicate-safe completion: idempotent by action id.
- At-least-once client:
completeAction() retries retryable
failures with the idempotency key; if Eve is down, the worker
keeps its durable result and retries — no exactly-once
requirement.
- Optional per-action deadline that settles as a failed tool
result instead of parking forever.
- Cancellation terminally settles the action and revokes the
completion capability; a late completion must not revive it.
Open questions for maintainers: hook payload retention across
long outages, completion credential expiry, and a planned
status/reconciliation lookup.
Suggested implementation prompt
No response
Alternatives considered
approval / ask_question: wait for humans, not machine
events.
sleep: a timer, not a callback.
execution: "background" plus task.send: in-process,
documented as not restart-safe.
- DevKit
createHook: throws inside turnStep's "use step",
so authors cannot build this themselves.
- Our current workaround: an in-memory Promise plus polling.
What problem are you trying to solve?
An authored tool that starts a long-running external job (a
workflow run, a batch job) has no way to wait for the result
without holding
executeopen on an in-process Promise. That isnot durable: a host restart loses the waiter, and recovery is
author-built polling. We ship exactly that workaround today (an
in-memory Promise keyed by callId plus a 30s status-poll
fallback).
Eve already solves this internally for subagents: runtime
actions. The turn persists
eve.runtime.pendingActionBatch, thedriver returns
action: "park"withpendingRuntimeActionKeys,the parent turn workflow waits on the turn's durable inbox hook,
and the child settles via
resumeHookwith aruntime-action-result. None of this is exposed to authoredtools;
ToolContexthas only session metadata,abortSignal,callId, and token helpers.Proposed solution
Add
execution: "delegated"todefineTool:The worker completes via an SDK helper (raw HTTP to the
completion URL as an escape hatch):
Eve validates the output against
outputSchema, settles it as anordinary
action.result, the same turn continues, and the modelsees a normal typed tool result.
Expected mapping to existing machinery:
subagent-call— with a stable action id registered in thepending batch BEFORE
executeruns, so a fast completioncannot race registration.
resumeHook.toModelOutput.Reliability semantics requested:
completeAction()retries retryablefailures with the idempotency key; if Eve is down, the worker
keeps its durable result and retries — no exactly-once
requirement.
result instead of parking forever.
completion capability; a late completion must not revive it.
Open questions for maintainers: hook payload retention across
long outages, completion credential expiry, and a planned
status/reconciliation lookup.
Suggested implementation prompt
No response
Alternatives considered
approval/ask_question: wait for humans, not machineevents.
sleep: a timer, not a callback.execution: "background"plustask.send: in-process,documented as not restart-safe.
createHook: throws insideturnStep's"use step",so authors cannot build this themselves.