eve 0.51.1 → 0.52.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (123) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/dist/src/cli/dev/boot-progress.d.ts +3 -0
  3. package/dist/src/cli/dev/boot-progress.js +1 -0
  4. package/dist/src/cli/run.d.ts +4 -0
  5. package/dist/src/cli/run.js +3 -3
  6. package/dist/src/cli/telemetry/command.d.ts +9 -0
  7. package/dist/src/cli/telemetry/command.js +1 -0
  8. package/dist/src/cli/telemetry/flush.d.ts +2 -0
  9. package/dist/src/cli/telemetry/flush.js +1 -0
  10. package/dist/src/cli/telemetry/identity.d.ts +13 -0
  11. package/dist/src/cli/telemetry/identity.js +1 -0
  12. package/dist/src/cli/telemetry/index.d.ts +25 -0
  13. package/dist/src/cli/telemetry/index.js +3 -0
  14. package/dist/src/cli/telemetry/preference.d.ts +9 -0
  15. package/dist/src/cli/telemetry/preference.js +1 -0
  16. package/dist/src/client/types.d.ts +3 -2
  17. package/dist/src/compiled/.vendor-stamp.json +2 -2
  18. package/dist/src/compiled/@eve/catalog/index.js +1 -1
  19. package/dist/src/compiled/@modelcontextprotocol/server/index.d.ts +1 -0
  20. package/dist/src/compiler/extension-compatibility.d.ts +22 -4
  21. package/dist/src/compiler/extension-compatibility.js +1 -1
  22. package/dist/src/compiler/manifest.js +1 -1
  23. package/dist/src/compiler/normalize-channel.js +1 -1
  24. package/dist/src/compiler/normalize-schedule.js +1 -1
  25. package/dist/src/compiler/normalize-tool.js +1 -1
  26. package/dist/src/context/dynamic-tool-lifecycle.js +1 -1
  27. package/dist/src/execution/activity-collector.js +1 -1
  28. package/dist/src/execution/continuation-conflict-step.js +1 -1
  29. package/dist/src/execution/coordination-dispatch-shared.d.ts +2 -2
  30. package/dist/src/execution/coordination-dispatch-step.js +1 -1
  31. package/dist/src/execution/durable-session-migrations/turn-workflow.d.ts +1 -1
  32. package/dist/src/execution/inline-turn.d.ts +2 -2
  33. package/dist/src/execution/inline-turn.js +1 -1
  34. package/dist/src/execution/tasks/child/steps.d.ts +11 -1
  35. package/dist/src/execution/tasks/child/steps.js +1 -1
  36. package/dist/src/execution/tasks/child/workflow.js +1 -1
  37. package/dist/src/execution/tasks/parent/tool-execution.js +1 -1
  38. package/dist/src/execution/tools/sleep-workflow.js +1 -1
  39. package/dist/src/execution/tools/subagent/invoke-agent.d.ts +1 -7
  40. package/dist/src/execution/tools/subagent/invoke-agent.js +1 -1
  41. package/dist/src/execution/tools/workflow/ask.d.ts +1 -2
  42. package/dist/src/execution/tools/workflow/ask.js +1 -1
  43. package/dist/src/execution/tools/workflow/body.d.ts +6 -1
  44. package/dist/src/execution/tools/workflow/body.js +1 -1
  45. package/dist/src/execution/tools/workflow/cancel.js +1 -1
  46. package/dist/src/execution/tools/workflow/messages.d.ts +9 -8
  47. package/dist/src/execution/tools/workflow/messages.js +1 -1
  48. package/dist/src/execution/tools/workflow/owner-inbox.d.ts +2 -2
  49. package/dist/src/execution/tools/workflow/owner-inbox.js +1 -1
  50. package/dist/src/execution/tools/workflow/owner.d.ts +5 -11
  51. package/dist/src/execution/tools/workflow/owner.js +1 -1
  52. package/dist/src/execution/tools/workflow/run-control.d.ts +0 -4
  53. package/dist/src/execution/tools/workflow/run-control.js +1 -1
  54. package/dist/src/execution/tools/workflow/start.d.ts +5 -14
  55. package/dist/src/execution/tools/workflow/start.js +1 -1
  56. package/dist/src/execution/tools/workflow/workflow.d.ts +1 -1
  57. package/dist/src/execution/tools/workflow/workflow.js +1 -1
  58. package/dist/src/execution/turn-dispatch.js +1 -1
  59. package/dist/src/execution/turn-workflow-tool-run.d.ts +2 -8
  60. package/dist/src/execution/turn-workflow-tool-run.js +1 -1
  61. package/dist/src/execution/turn-workflow.d.ts +1 -0
  62. package/dist/src/execution/turn-workflow.js +1 -1
  63. package/dist/src/execution/wire/session-inbox-resume.js +1 -1
  64. package/dist/src/execution/workflow-runtime.js +1 -1
  65. package/dist/src/execution/workflow-steps.js +1 -1
  66. package/dist/src/harness/emission-state.js +1 -1
  67. package/dist/src/harness/tool-loop.js +2 -2
  68. package/dist/src/harness/turn-client-context.d.ts +9 -0
  69. package/dist/src/harness/turn-client-context.js +1 -0
  70. package/dist/src/harness/workflow-tool-runs.d.ts +0 -1
  71. package/dist/src/harness/workflow-tool-runs.js +1 -1
  72. package/dist/src/internal/application/package.js +1 -1
  73. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  74. package/dist/src/internal/invocation/workflow-execution.js +1 -1
  75. package/dist/src/internal/mcp/streamable-http-server.d.ts +29 -1
  76. package/dist/src/internal/mcp/streamable-http-server.js +1 -1
  77. package/dist/src/internal/nitro/host/build-application.js +1 -1
  78. package/dist/src/internal/workflow/runtime.d.ts +6 -0
  79. package/dist/src/internal/workflow/runtime.js +1 -1
  80. package/dist/src/internal/workflow-bundle/authored-workflow-directives.d.ts +1 -3
  81. package/dist/src/internal/workflow-bundle/authored-workflow-directives.js +1 -1
  82. package/dist/src/internal/workflow-bundle/authored-workflow-modules.d.ts +1 -2
  83. package/dist/src/internal/workflow-bundle/authored-workflow-modules.js +1 -1
  84. package/dist/src/internal/workflow-bundle/dynamic-tool-transform.js +1 -1
  85. package/dist/src/internal/workflow-bundle/workflow-builders.d.ts +0 -2
  86. package/dist/src/internal/workflow-bundle/workflow-builders.js +1 -1
  87. package/dist/src/internal/workflow-bundle/workflow-transformer.js +1 -1
  88. package/dist/src/protocol/message.d.ts +3 -2
  89. package/dist/src/public/channels/mcp.js +1 -1
  90. package/dist/src/public/models/openai/chatgpt/model.js +2 -2
  91. package/dist/src/public/models/openai/chatgpt/transport.js +1 -1
  92. package/dist/src/public/tools/index.d.ts +3 -1
  93. package/dist/src/public/tools/index.js +1 -1
  94. package/dist/src/setup/scaffold/create/project.js +1 -1
  95. package/dist/src/shared/workflow-tool-context.d.ts +2 -0
  96. package/dist/src/shared/workflow-tool-context.js +1 -0
  97. package/dist/src/tasks/types.d.ts +17 -1
  98. package/dist/src/tasks/types.js +1 -1
  99. package/dist/src/tools/behavior.d.ts +5 -0
  100. package/dist/src/tools/definition.d.ts +16 -12
  101. package/dist/src/tools/definition.js +1 -1
  102. package/dist/src/tools/dynamic.d.ts +2 -2
  103. package/dist/src/tools/provided/sleep.d.ts +2 -2
  104. package/dist/src/tools/provided/sleep.js +1 -1
  105. package/dist/src/tools/task.d.ts +28 -80
  106. package/dist/src/tools/task.js +1 -1
  107. package/dist/src/tools/workflow-definition.d.ts +60 -0
  108. package/dist/src/tools/workflow-definition.js +1 -0
  109. package/docs/channels/mcp.mdx +25 -3
  110. package/docs/concepts/execution-model-and-durability.mdx +13 -2
  111. package/docs/guides/client/messages.mdx +1 -1
  112. package/docs/guides/deployment/vercel.mdx +2 -0
  113. package/docs/guides/frontend/overview.mdx +1 -1
  114. package/docs/memory/overview.mdx +40 -11
  115. package/docs/reference/cli.md +31 -33
  116. package/docs/reference/meta.json +1 -4
  117. package/docs/reference/telemetry.md +56 -0
  118. package/docs/reference/typescript-api.md +38 -35
  119. package/docs/tools/overview.mdx +59 -18
  120. package/docs/tools/workflows.mdx +146 -70
  121. package/package.json +1 -7
  122. package/dist/src/public/workflow/index.d.ts +0 -5
  123. package/dist/src/public/workflow/index.js +0 -1
@@ -1,4 +1,4 @@
1
- import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.51.1`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,n){let r=parseChatGptModelSelection(e);return r===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(r)}),\n${reasoningTemplateLine(n)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,n){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(n.model)!==void 0?renderAgentTemplate(n.model,n.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,n.appName).replaceAll(`__EVE_INIT_MODEL__`,n.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(n.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(n.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(n.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,n.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,n.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,n.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,n.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,n.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,n.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
1
+ import{pinnedNodeEngineMajor}from"../../node-engine.js";import{parseChatGptModelSelection}from"../../../shared/chatgpt-model.js";import{SUPPORTED_AUTHORED_MODULE_FILE_EXTENSIONS}from"../update/module-files.js";import{pathExists,writeTextFile}from"../files.js";import{blockingCreateInPlaceEntries}from"../create-in-place.js";import{resolveVersionToken}from"../version-tokens.js";import{applyPackageManagerWorkspaceConfiguration,isPackageManagerWorkspaceMember,patchWorkspaceRootPackageJson}from"../workspace-root.js";import{WEB_APP_TEMPLATE_FILES}from"./web-template.js";import{mkdir,readdir,stat}from"node:fs/promises";import{basename,join,resolve}from"node:path";const CURRENT_DIRECTORY_PROJECT_NAME=`.`,DEFAULT_AI_PACKAGE_VERSION=`^7.0.82`,DEFAULT_CONNECT_PACKAGE_VERSION=`1.0.0`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.52.0`,nodeEngine:`>=24`};function resolveEvePackageContract(e=DEFAULT_EVE_PACKAGE_CONTRACT){return{version:resolveVersionToken(`evePackage.version`,e.version),nodeEngine:resolveVersionToken(`evePackage.nodeEngine`,e.nodeEngine)}}function modelProviderSlug(e){let t=(e.split(`/`)[0]??``).replaceAll(/[^A-Za-z0-9._-]/gu,``);return t.length>0?t:`anthropic`}function byokProviderEnvVar(e){let t=modelProviderSlug(e).toUpperCase().replaceAll(/[^A-Z0-9]/gu,`_`);return`${/^[0-9]/.test(t)?`_`:``}${t}_API_KEY`}function agentTemplateFiles(e,t){return{"agent/agent.ts":renderAgentTemplate(e,t),"agent/channels/eve.ts":WEB_APP_TEMPLATE_FILES[`agent/channels/eve.ts`],"agent/instructions.md":AGENT_INSTRUCTIONS_TEMPLATE}}function renderAgentTemplate(e,n){let r=parseChatGptModelSelection(e);return r===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(r)}),\n${reasoningTemplateLine(n)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,n){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(n.model)!==void 0?renderAgentTemplate(n.model,n.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,n.appName).replaceAll(`__EVE_INIT_MODEL__`,n.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(n.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(n.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(n.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(n.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,n.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,n.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,n.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,n.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,n.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,n.nodeEngine)}function formatEveDependencySpecifier(e){return/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z-.]+)?$/.test(e)?`^${e}`:e}const BASE_AGENT_TEMPLATE=`import { defineAgent } from "eve";
2
2
 
3
3
  export default defineAgent({
4
4
  model: "__EVE_INIT_MODEL__",
@@ -0,0 +1,2 @@
1
+ export declare function workflowToolContextErrorMessage(helper: "agent" | "ask"): string;
2
+ export declare function workflowCallbackErrorMessage(kind: "channel" | "schedule"): string;
@@ -0,0 +1 @@
1
+ function workflowToolContextErrorMessage(e){return`ctx.${e}() requires a defineWorkflowTool() executor context. Call it inside the workflow tool body.`}function workflowCallbackErrorMessage(e){return`"use workflow" is not supported on ${e} callbacks. Use defineWorkflowTool() from "eve/tools" to author a workflow tool.`}export{workflowCallbackErrorMessage,workflowToolContextErrorMessage};
@@ -97,6 +97,14 @@ export interface TaskCommandHookPayload {
97
97
  readonly kind: "task-command";
98
98
  readonly command: TaskCommand;
99
99
  }
100
+ /** One authored message delivered to the parent as a new turn. */
101
+ export interface TaskInboundMessage {
102
+ readonly callId: string;
103
+ readonly kind: "task-message";
104
+ readonly message: string;
105
+ readonly messageIndex: number;
106
+ readonly messageEpoch: string;
107
+ }
100
108
  /** Intermediate progress reported by an executor. */
101
109
  export interface TaskInboundUpdate {
102
110
  readonly callId: string;
@@ -127,7 +135,7 @@ export interface TaskInboundAnswerInput {
127
135
  readonly kind: "input-response";
128
136
  readonly taskId: string;
129
137
  }
130
- export type TaskRunInboundPayload = TaskCommandHookPayload | TaskInboundAnswerInput | TaskInboundUpdate;
138
+ export type TaskRunInboundPayload = TaskCommandHookPayload | TaskInboundAnswerInput | TaskInboundMessage | TaskInboundUpdate;
131
139
  /** Generic task-owned request sent through the parent session payload. */
132
140
  interface TaskInputRequestDeliveryBase {
133
141
  readonly replyTo: string;
@@ -162,6 +170,14 @@ export interface TaskAgentRequestDelivery {
162
170
  readonly request: WorkflowToolAgentRequest;
163
171
  readonly taskId: string;
164
172
  }
173
+ export interface TaskProgress {
174
+ readonly callId: string;
175
+ readonly kind: "task-progress";
176
+ readonly taskId: string;
177
+ readonly update: JsonValue;
178
+ readonly updateIndex: number;
179
+ }
180
+ export declare const TASK_PROGRESS_STREAM_NAMESPACE = "eve.task.progress";
165
181
  export declare const TASK_VIEW_STREAM_NAMESPACE = "eve.task";
166
182
  export declare function isTerminalTaskStatus(status: TaskStatus): boolean;
167
183
  export declare function isReadyTaskStatus(status: TaskStatus): boolean;
@@ -1 +1 @@
1
- import{jsonValuesEqual}from"#shared/json.js";function sameTaskMetadata(t,n){return jsonValuesEqual(t,n)}function readTaskUsage(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=readUsageAxis(e,`cacheReadTokens`),n=readUsageAxis(e,`cacheWriteTokens`),r=readUsageAxis(e,`costUsd`),i=readUsageAxis(e,`inputTokens`),a=readUsageAxis(e,`outputTokens`);if(t===void 0||n===void 0||i===void 0||a===void 0)return;let o={cacheReadTokens:t,cacheWriteTokens:n,inputTokens:i,outputTokens:a};return r!==void 0&&(o.costUsd=r),o}function readUsageAxis(e,t){let n=Reflect.get(e,t);return typeof n==`number`&&Number.isFinite(n)&&n>=0?n:void 0}function readTaskInputRequestId(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=Reflect.get(e,`requestId`);return typeof t==`string`?t:void 0}const TASK_AUTHORIZATION_REQUEST_ID_PREFIX=`task:authorization`;function taskAuthorizationRequestId(e){return e.type===`approval.candidate`||e.type===`approval.settled`?`${TASK_AUTHORIZATION_REQUEST_ID_PREFIX}:${e.data.requestId}`:`${TASK_AUTHORIZATION_REQUEST_ID_PREFIX}:${e.data.attemptId??e.data.name}`}const TASK_VIEW_STREAM_NAMESPACE=`eve.task`;function isTerminalTaskStatus(e){return e===`completed`||e===`failed`||e===`cancelled`}function isReadyTaskStatus(e){return e===`input_required`||isTerminalTaskStatus(e)}export{TASK_VIEW_STREAM_NAMESPACE,isReadyTaskStatus,isTerminalTaskStatus,readTaskInputRequestId,readTaskUsage,sameTaskMetadata,taskAuthorizationRequestId};
1
+ import{jsonValuesEqual}from"#shared/json.js";function sameTaskMetadata(t,n){return jsonValuesEqual(t,n)}function readTaskUsage(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=readUsageAxis(e,`cacheReadTokens`),n=readUsageAxis(e,`cacheWriteTokens`),r=readUsageAxis(e,`costUsd`),i=readUsageAxis(e,`inputTokens`),a=readUsageAxis(e,`outputTokens`);if(t===void 0||n===void 0||i===void 0||a===void 0)return;let o={cacheReadTokens:t,cacheWriteTokens:n,inputTokens:i,outputTokens:a};return r!==void 0&&(o.costUsd=r),o}function readUsageAxis(e,t){let n=Reflect.get(e,t);return typeof n==`number`&&Number.isFinite(n)&&n>=0?n:void 0}function readTaskInputRequestId(e){if(typeof e!=`object`||!e||Array.isArray(e))return;let t=Reflect.get(e,`requestId`);return typeof t==`string`?t:void 0}const TASK_AUTHORIZATION_REQUEST_ID_PREFIX=`task:authorization`;function taskAuthorizationRequestId(e){return e.type===`approval.candidate`||e.type===`approval.settled`?`${TASK_AUTHORIZATION_REQUEST_ID_PREFIX}:${e.data.requestId}`:`${TASK_AUTHORIZATION_REQUEST_ID_PREFIX}:${e.data.attemptId??e.data.name}`}const TASK_PROGRESS_STREAM_NAMESPACE=`eve.task.progress`,TASK_VIEW_STREAM_NAMESPACE=`eve.task`;function isTerminalTaskStatus(e){return e===`completed`||e===`failed`||e===`cancelled`}function isReadyTaskStatus(e){return e===`input_required`||isTerminalTaskStatus(e)}export{TASK_PROGRESS_STREAM_NAMESPACE,TASK_VIEW_STREAM_NAMESPACE,isReadyTaskStatus,isTerminalTaskStatus,readTaskInputRequestId,readTaskUsage,sameTaskMetadata,taskAuthorizationRequestId};
@@ -16,10 +16,15 @@ export type CompiledToolHandling = {
16
16
  readonly workflowId: string;
17
17
  };
18
18
  /** Closed, serializable behavior carried by one selected compiled tool. */
19
+ export interface ToolExecutionShape {
20
+ readonly lifetime: "step" | "task";
21
+ readonly suspend: "none" | "workflow";
22
+ }
19
23
  export interface CompiledToolBehavior {
20
24
  readonly availability: readonly ToolAvailabilityCondition[];
21
25
  readonly handling?: CompiledToolHandling;
22
26
  readonly presentation?: "load-skill";
27
+ readonly shape?: ToolExecutionShape;
23
28
  }
24
29
  /** Concrete dispatch identity prepared before a tool reaches the harness. */
25
30
  export type PreparedDispatchTarget = {
@@ -7,11 +7,11 @@ import type { TokenResult } from "#shared/connection-types.js";
7
7
  import type { ToolAuthOptions, ToolAuthProvider } from "#tools/auth.js";
8
8
  import type { InputOption } from "#shared/input.js";
9
9
  import type { ToolModelOutput } from "#tools/model-output.js";
10
- import type { TaskDelegated, TaskExec, TaskReceipt } from "#tools/task.js";
10
+ import type { TaskExec, TaskReceipt } from "#tools/task.js";
11
11
  type ApprovalContextInput<TInput> = unknown extends TInput ? Record<string, unknown> : TInput;
12
12
  export type { ToolAuthDefinition, ToolAuthOptions, ToolAuthProvider } from "#tools/auth.js";
13
13
  export type { ToolModelOutput, ToolModelOutputPart } from "#tools/model-output.js";
14
- export type { TaskBinding, TaskDelegated, TaskExec, TaskExecutorBinding, TaskReceipt, TaskSendCommand, } from "#tools/task.js";
14
+ export type { TaskExec, TaskExecutorBinding, TaskReceipt } from "#tools/task.js";
15
15
  export type ToolExecuteOptions = Omit<ToolExecutionOptions<unknown>, "context">;
16
16
  export type ToolExecuteFn<TInput = unknown, TOutput = unknown> = (input: TInput, options: ToolExecuteOptions, task?: TaskExec) => Promise<TOutput> | TOutput | AsyncIterable<TOutput>;
17
17
  export type ToolExecution = "background";
@@ -53,7 +53,7 @@ export interface PublicToolDefinitionWithExecuteFn<TInput = unknown, TOutput = u
53
53
  }
54
54
  /**
55
55
  * A question a workflow tool asks the human on the session's channel, sent
56
- * with `ask` from `eve/workflow`. Channels render it the way they render
56
+ * with `ctx.ask` from a `defineWorkflowTool` executor. Channels render it the way they render
57
57
  * `ask_question` and tool approvals.
58
58
  */
59
59
  export interface ToolInputRequest {
@@ -82,10 +82,8 @@ export interface ToolInputResponse {
82
82
  * Extends {@link SessionContext} with token accessors. Passing a provider
83
83
  * resolves that provider inline, which lets one tool use multiple credentials.
84
84
  *
85
- * A tool whose `execute` is a workflow (`"use workflow"`) receives the same
86
- * context inside its durable body, except that `getSandbox`, `getSkill`,
87
- * `getToken`, and `requireAuth` are unavailable there and throw when touched —
88
- * read credentials inside a `"use step"` function instead.
85
+ * Workflow tools use the separate `WorkflowToolContext` provided by
86
+ * `defineWorkflowTool`.
89
87
  */
90
88
  export type ToolContext = SessionContext & {
91
89
  /**
@@ -152,14 +150,14 @@ export interface ToolDefinition<TInput = unknown, TOutput = unknown> extends Pub
152
150
  toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
153
151
  }
154
152
  /** A tool whose executor can outlive the model tool-call phase as a durable task. */
155
- export interface BackgroundToolDefinition<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> {
153
+ export interface BackgroundToolDefinition<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TaskReceipt> {
156
154
  readonly execution: "background";
157
- execute(input: TInput, ctx: ToolContext, task: TaskExec): Promise<TaskDelegated | TOutput> | TaskDelegated | TOutput | AsyncIterable<TOutput>;
155
+ execute(input: TInput, ctx: ToolContext, task: TaskExec): Promise<TOutput> | TOutput | AsyncIterable<unknown>;
158
156
  approval?: Approval<ApprovalContextInput<TInput>>;
159
- toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
157
+ toModelOutput?: (output: TaskReceipt) => ToolModelOutput | Promise<ToolModelOutput>;
160
158
  }
161
159
  type ToolOutputFromExecuteReturn<TReturn> = TReturn extends Promise<infer TOutput> ? TOutput : TReturn extends AsyncIterable<infer TOutput> ? TOutput : TReturn;
162
- type BackgroundToolOutputFromExecuteReturn<TReturn> = ToolOutputFromExecuteReturn<TReturn> extends infer TOutput ? TOutput extends TaskDelegated<infer TData> ? TaskReceipt<TData> : TOutput : never;
160
+ type BackgroundToolOutputFromExecuteReturn<TReturn> = TReturn extends AsyncGenerator<unknown, infer TOutput> ? TOutput : TReturn extends AsyncIterable<unknown> ? null : Awaited<TReturn>;
163
161
  type ToolDefinitionWithExecuteReturn<TInput, TOutput, TReturn> = ToolDefinition<TInput, TOutput> & {
164
162
  execute(input: TInput, ctx: ToolContext): TReturn;
165
163
  };
@@ -178,7 +176,7 @@ export declare function defineTool<TSchema extends StandardSchemaV1<unknown, unk
178
176
  description: BackgroundToolDefinition<unknown, unknown>["description"];
179
177
  execution: "background";
180
178
  inputSchema: TSchema;
181
- outputSchema?: PublicToolDefinition<unknown, BackgroundToolOutputFromExecuteReturn<TReturn>>["outputSchema"];
179
+ outputSchema?: PublicToolDefinition<unknown, TaskReceipt>["outputSchema"];
182
180
  execute(input: StandardSchemaV1.InferOutput<TSchema>, ctx: ToolContext, task: TaskExec): TReturn;
183
181
  approval?: BackgroundToolDefinition<StandardSchemaV1.InferOutput<TSchema>, unknown>["approval"];
184
182
  toModelOutput?: BackgroundToolDefinition<unknown, BackgroundToolOutputFromExecuteReturn<TReturn>>["toModelOutput"];
@@ -216,6 +214,12 @@ export declare function defineTool<TReturn>(definition: {
216
214
  toModelOutput?: ToolDefinition<unknown, ToolOutputFromExecuteReturn<TReturn>>["toModelOutput"];
217
215
  }): ToolDefinitionWithExecuteReturn<Record<string, unknown>, ToolOutputFromExecuteReturn<TReturn>, TReturn>;
218
216
  export declare function defineTool<TInput = unknown, TOutput = unknown>(definition: ToolDefinition<TInput, TOutput>): ToolDefinition<TInput, TOutput>;
217
+ export declare function stampToolDefinition<T extends {
218
+ readonly description: string;
219
+ readonly execute: (...args: never[]) => unknown;
220
+ readonly approval?: Approval<never>;
221
+ readonly toModelOutput?: (...args: never[]) => unknown;
222
+ }>(definition: T, definer: "defineTool" | "defineWorkflowTool"): T;
219
223
  /**
220
224
  * Marker discriminator written into every {@link DisabledToolSentinel}.
221
225
  */
@@ -1 +1 @@
1
- import{collectDurableDynamicToolCallbacks,stampDurableDynamicToolCallbacks}from"#tools/durable-callbacks.js";import{TOOL_BRAND}from"#tools/dynamic.js";import{stampDefinitionKey}from"#internal/authored-definition/source-identity.js";function defineTool(t){if(t.auth!==void 0)throw Error(`defineTool: The "auth" field is no longer supported. Pass auth providers inline to ctx.getToken(provider) or ctx.requireAuth(provider).`);return Object.assign(t,{[TOOL_BRAND]:!0}),stampDurableDynamicToolCallbacks(t,collectDurableDynamicToolCallbacks({approval:t.approval,execute:t.execute,toModelOutput:t.toModelOutput})),stampDefinitionKey(t,`tool:${t.description}`),t}const DISABLED_TOOL_SENTINEL_KIND=`eve:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}export{defineTool,disableTool,isDisabledToolSentinel};
1
+ import{collectDurableDynamicToolCallbacks,stampDurableDynamicToolCallbacks}from"#tools/durable-callbacks.js";import{TOOL_BRAND}from"#tools/dynamic.js";import{stampDefinitionKey}from"#internal/authored-definition/source-identity.js";function defineTool(e){return stampToolDefinition(e,`defineTool`)}function stampToolDefinition(t,n){if(t.auth!==void 0)throw Error(`${n}: The "auth" field is no longer supported. Pass auth providers inline to ctx.getToken(provider) or ctx.requireAuth(provider).`);return Object.assign(t,{[TOOL_BRAND]:!0}),stampDurableDynamicToolCallbacks(t,collectDurableDynamicToolCallbacks({approval:t.approval,execute:t.execute,toModelOutput:t.toModelOutput})),stampDefinitionKey(t,`tool:${t.description}`),t}const DISABLED_TOOL_SENTINEL_KIND=`eve:disabled-tool`;function disableTool(){return{kind:DISABLED_TOOL_SENTINEL_KIND}}function isDisabledToolSentinel(e){return typeof e==`object`&&!!e&&e.kind===DISABLED_TOOL_SENTINEL_KIND}export{defineTool,disableTool,isDisabledToolSentinel,stampToolDefinition};
@@ -1,7 +1,7 @@
1
1
  import type { Approval } from "#approval/definition.js";
2
2
  import type { DynamicResolveContext, DynamicToolEventName } from "#dynamic/definition.js";
3
3
  import type { PublicToolInputSchema, PublicToolOutputSchema, ToolContext } from "#tools/definition.js";
4
- import type { TaskDelegated, TaskExec } from "#tools/task.js";
4
+ import type { TaskExec } from "#tools/task.js";
5
5
  import type { ToolModelOutput } from "#tools/model-output.js";
6
6
  /**
7
7
  * A single tool entry within a resolved dynamic tool set.
@@ -20,7 +20,7 @@ export interface DynamicToolEntry<TInput = Record<string, unknown>, TOutput = an
20
20
  readonly inputSchema: PublicToolInputSchema<TInput>;
21
21
  readonly outputSchema?: PublicToolOutputSchema<TOutput>;
22
22
  readonly execution?: "background";
23
- execute(input: TInput, ctx: ToolContext, task?: TaskExec): TOutput | TaskDelegated | Promise<TOutput | TaskDelegated>;
23
+ execute(input: TInput, ctx: ToolContext, task?: TaskExec): TOutput | Promise<TOutput>;
24
24
  readonly toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
25
25
  /**
26
26
  * Optional per-call approval gate, mirroring the authored-tool
@@ -1,4 +1,4 @@
1
- import { type ToolDefinition } from "#tools/definition.js";
1
+ import { type BlockingWorkflowToolDefinition } from "#tools/workflow-definition.js";
2
2
  import { type SleepToolInput, type SleepToolOutput } from "#execution/tools/sleep.js";
3
3
  export type { SleepToolInput, SleepToolOutput };
4
4
  /**
@@ -15,4 +15,4 @@ export type { SleepToolInput, SleepToolOutput };
15
15
  * Each call runs as a durable workflow, so the wait does not hold an
16
16
  * application runtime open.
17
17
  */
18
- export declare function sleep(): ToolDefinition<SleepToolInput, SleepToolOutput>;
18
+ export declare function sleep(): BlockingWorkflowToolDefinition<SleepToolInput, SleepToolOutput>;
@@ -1 +1 @@
1
- import{defineTool}from"#tools/definition.js";import{SLEEP_INPUT_SCHEMA,SLEEP_OUTPUT_SCHEMA,SLEEP_TOOL_DESCRIPTION,executeSleepTool}from"#execution/tools/sleep.js";function sleep(){return defineTool({description:SLEEP_TOOL_DESCRIPTION,execute:executeSleepTool,inputSchema:SLEEP_INPUT_SCHEMA,outputSchema:SLEEP_OUTPUT_SCHEMA})}export{sleep};
1
+ import{defineWorkflowTool}from"#tools/workflow-definition.js";import{SLEEP_INPUT_SCHEMA,SLEEP_OUTPUT_SCHEMA,SLEEP_TOOL_DESCRIPTION,executeSleepTool}from"#execution/tools/sleep.js";function sleep(){return defineWorkflowTool({description:SLEEP_TOOL_DESCRIPTION,execute:executeSleepTool,inputSchema:SLEEP_INPUT_SCHEMA,outputSchema:SLEEP_OUTPUT_SCHEMA})}export{sleep};
@@ -1,48 +1,25 @@
1
1
  import type { BackgroundTask } from "#execution/tasks/parent/delegate.js";
2
- import type { BackgroundToolCall } from "#harness/background-tools.js";
3
2
  import type { HarnessSession } from "#harness/types.js";
4
3
  import type { JsonObject, JsonValue } from "#shared/json.js";
5
- declare const TASK_DELEGATED_KIND = "eve:task-delegated";
6
- /** Private address an executor uses to report lifecycle changes to its owning task. */
7
- export interface TaskBinding {
8
- readonly taskId: string;
9
- readonly token: string;
10
- readonly url?: string;
11
- }
12
- /**
13
- * Opaque, task-private address used to control an external executor. `data`
14
- * means nothing to the task layer beyond deep equality (replay idempotency);
15
- * only the executor `kind` that wrote it may parse it (e.g. cancel routing).
16
- */
4
+ declare const TASK_MESSAGE_KIND: "eve:task-message";
5
+ export type TaskMessage = JsonObject & {
6
+ readonly kind: typeof TASK_MESSAGE_KIND;
7
+ readonly message: string;
8
+ };
9
+ export declare function createTaskMessage(message: string): TaskMessage;
10
+ export declare function isTaskMessage(value: unknown): value is TaskMessage;
11
+ /** Opaque, framework-private address used to control a task executor. */
17
12
  export interface TaskExecutorBinding {
18
13
  readonly kind: string;
19
14
  readonly data: JsonObject;
20
15
  }
21
- /**
22
- * What the model sees as this call's tool output when work is delegated: the
23
- * author-supplied data plus `status: "working"` and the `taskId` it can poll
24
- * or cancel. It acknowledges delegation — it is not the task's result, which
25
- * arrives later through task completion.
26
- */
27
- export type TaskReceipt<TData extends JsonObject = JsonObject> = TData & {
28
- readonly status: "working";
16
+ /** @deprecated Use workflow-backed background tools with yield descriptors. */
17
+ export interface TaskBinding {
29
18
  readonly taskId: string;
30
- };
31
- /**
32
- * Sentinel returned by a background tool after an external executor accepts
33
- * responsibility for the task. Returning it ends `execute`; it does not
34
- * complete the durable task.
35
- */
36
- export interface TaskDelegated<TData extends JsonObject = JsonObject> {
37
- readonly kind: typeof TASK_DELEGATED_KIND;
38
- readonly executor: TaskExecutorBinding;
39
- readonly receipt: TaskReceipt<TData>;
19
+ readonly token: string;
20
+ readonly url?: string;
40
21
  }
41
- /**
42
- * Commands an in-process executor may report to its task via
43
- * {@link TaskExec.send}. Deliberately narrower than the task run's full
44
- * command surface — bind, ready, and input routing stay runtime-owned.
45
- */
22
+ /** @deprecated Use workflow-backed background tools with yield descriptors. */
46
23
  export type TaskSendCommand = {
47
24
  readonly kind: "update";
48
25
  readonly message: string;
@@ -55,53 +32,24 @@ export type TaskSendCommand = {
55
32
  } | {
56
33
  readonly kind: "cancel";
57
34
  };
58
- /** Task capability passed only to tools declared with `execution: "background"`. */
35
+ /** Fixed acknowledgement returned when a background task is admitted. */
36
+ export interface TaskReceipt {
37
+ readonly status: "working";
38
+ readonly taskId: string;
39
+ }
40
+ /** Capability passed only to tools declared with `execution: "background"`. */
59
41
  export interface TaskExec {
60
- /**
61
- * The sibling background calls admitted in the same step. The only view a
62
- * tool has of what launched alongside it, for enforcing batch-wide
63
- * invariants before delegating.
64
- */
65
- readonly batch: readonly BackgroundToolCall[];
66
- /**
67
- * The task-private address for reporting lifecycle changes back to this
68
- * task. Hand it to the external executor so completion routes to the task
69
- * directly instead of through the (already finished) tool call.
70
- */
42
+ /** Model-facing durable task identity. */
43
+ readonly taskId: string;
44
+ /** Returns a descriptor which sends one message to the parent when yielded. */
45
+ postMessage(message: string): TaskMessage;
46
+ /** @deprecated Use yields from a workflow-backed background tool. */
71
47
  readonly binding: TaskBinding;
72
- /**
73
- * Snapshot of the harness session at step start, for reading context.
74
- * Mutating it changes nothing durable: session writes belong to the
75
- * runtime, keyed off the executor binding at step commit.
76
- */
77
- readonly session: HarnessSession;
78
- /**
79
- * Delivers progress or a terminal command to this task's inbox from the same
80
- * process, for executors that outlive `execute` in-memory (e.g. a callback firing
81
- * after delegation). Call it only after `execute` returned `delegated(...)`
82
- * — the runtime settles non-delegated returns itself, and a second terminal
83
- * command is refused. Not restart-safe: an in-process callback dies with
84
- * the process; the persisted executor binding remains the durable
85
- * cancellation path. Throws when the task no longer accepts commands
86
- * (already terminal).
87
- */
48
+ /** @deprecated Use yields from a workflow-backed background tool. */
88
49
  readonly send: (command: TaskSendCommand) => Promise<void>;
89
- /** The durable task backing this call; its identity outlives `execute`. */
50
+ /** @deprecated Use ctx.session. */
51
+ readonly session: HarnessSession;
52
+ /** @deprecated Framework-owned task internals are not part of the authoring API. */
90
53
  readonly task: BackgroundTask;
91
- /**
92
- * Builds the `TaskDelegated` sentinel to return from `execute`. Centralizes
93
- * receipt stamping so every receipt carries this task's `taskId` and
94
- * `status: "working"` — tools cannot mint receipts for tasks they don't own.
95
- */
96
- delegated<TData extends JsonObject>(input: {
97
- readonly executor: TaskExecutorBinding;
98
- readonly receipt: TData;
99
- }): TaskDelegated<TData>;
100
54
  }
101
- export declare function createTaskDelegated<TData extends JsonObject>(input: {
102
- readonly binding: TaskBinding;
103
- readonly executor: TaskExecutorBinding;
104
- readonly receipt: TData;
105
- }): TaskDelegated<TData>;
106
- export declare function isTaskDelegated(value: unknown): value is TaskDelegated;
107
55
  export {};
@@ -1 +1 @@
1
- const TASK_DELEGATED_KIND=`eve:task-delegated`;function createTaskDelegated(e){return{executor:e.executor,kind:TASK_DELEGATED_KIND,receipt:{...e.receipt,status:`working`,taskId:e.binding.taskId}}}function isTaskDelegated(e){return typeof e==`object`&&!!e&&`kind`in e&&e.kind===TASK_DELEGATED_KIND}export{createTaskDelegated,isTaskDelegated};
1
+ const TASK_MESSAGE_KIND=`eve:task-message`;function createTaskMessage(e){if(e.trim()===``)throw TypeError(`Task messages must not be empty.`);return{kind:TASK_MESSAGE_KIND,message:e}}function isTaskMessage(e){return typeof e==`object`&&!!e&&Reflect.get(e,`kind`)===TASK_MESSAGE_KIND}export{createTaskMessage,isTaskMessage};
@@ -0,0 +1,60 @@
1
+ import type { StandardJSONSchemaV1, StandardSchemaV1 } from "#compiled/@standard-schema/spec/index.js";
2
+ import type { Approval } from "#approval/definition.js";
3
+ import type { JsonObject, JsonValue } from "#shared/json.js";
4
+ import { type PublicToolDefinition, type BackgroundToolDefinition, type ToolContext, type ToolInputRequest, type ToolInputResponse } from "#tools/definition.js";
5
+ import type { TaskExec } from "#tools/task.js";
6
+ import type { ToolModelOutput } from "#tools/model-output.js";
7
+ export interface AgentInput {
8
+ readonly agentId?: string;
9
+ readonly key: string;
10
+ readonly message: string;
11
+ readonly outputSchema?: JsonObject;
12
+ readonly target: string;
13
+ }
14
+ /** Context supplied only to a defineWorkflowTool executor, inside its durable run. */
15
+ export type WorkflowToolContext = Pick<ToolContext, "abortSignal" | "callId" | "session" | "toolName"> & {
16
+ /** Invoke a visible subagent. The key must be unique within this workflow run. */
17
+ agent(input: AgentInput): Promise<JsonValue>;
18
+ /** Ask the human on the session's channel; awaiting the answer suspends the run. */
19
+ ask(request: ToolInputRequest): PromiseLike<ToolInputResponse>;
20
+ };
21
+ declare const WORKFLOW_TOOL_BRAND: unique symbol;
22
+ /** A static tool whose executor runs as a durable workflow. Its executor must start with "use workflow". */
23
+ export interface BlockingWorkflowToolDefinition<TInput = unknown, TOutput = unknown> extends PublicToolDefinition<TInput, TOutput> {
24
+ readonly [WORKFLOW_TOOL_BRAND]: true;
25
+ readonly execution?: never;
26
+ execute(input: TInput, ctx: WorkflowToolContext): Promise<TOutput> | AsyncIterable<TOutput>;
27
+ approval?: Approval<unknown extends TInput ? Record<string, unknown> : TInput>;
28
+ toModelOutput?: (output: TOutput) => ToolModelOutput | Promise<ToolModelOutput>;
29
+ }
30
+ type BackgroundWorkflowToolDefinition<TInput, TOutput> = Omit<BackgroundToolDefinition<TInput, TOutput>, "execute"> & {
31
+ readonly [WORKFLOW_TOOL_BRAND]: true;
32
+ execute(input: TInput, ctx: WorkflowToolContext, task: TaskExec): Promise<TOutput> | AsyncIterable<unknown>;
33
+ };
34
+ /** A static tool whose executor runs as a durable workflow. */
35
+ export type WorkflowToolDefinition<TInput = unknown, TOutput = unknown> = BlockingWorkflowToolDefinition<TInput, TOutput> | BackgroundWorkflowToolDefinition<TInput, TOutput>;
36
+ type Unbranded<T> = T extends unknown ? Omit<T, typeof WORKFLOW_TOOL_BRAND> : never;
37
+ type BackgroundReturn<T> = T extends AsyncGenerator<unknown, infer Output> ? Output : T extends AsyncIterable<unknown> ? null : Awaited<T>;
38
+ type BackgroundDefinition<TInput, TReturn> = Omit<BackgroundWorkflowToolDefinition<TInput, BackgroundReturn<TReturn>>, typeof WORKFLOW_TOOL_BRAND | "execute"> & {
39
+ execute(input: TInput, ctx: WorkflowToolContext, task: TaskExec): TReturn;
40
+ };
41
+ type WorkflowReturn<T> = T extends AsyncIterable<infer Output> ? Output : Awaited<T>;
42
+ type Schema = StandardSchemaV1<unknown, unknown> | StandardJSONSchemaV1<unknown, unknown>;
43
+ type Definition<TInput, TReturn> = Omit<BlockingWorkflowToolDefinition<TInput, WorkflowReturn<TReturn>>, typeof WORKFLOW_TOOL_BRAND | "execute"> & {
44
+ execute(input: TInput, ctx: WorkflowToolContext): TReturn;
45
+ };
46
+ export declare function defineWorkflowTool<TSchema extends Schema, TReturn extends Promise<unknown> | AsyncIterable<unknown>>(definition: Omit<BackgroundDefinition<StandardSchemaV1.InferOutput<TSchema>, TReturn>, "inputSchema"> & {
47
+ inputSchema: TSchema;
48
+ }): BackgroundWorkflowToolDefinition<StandardSchemaV1.InferOutput<TSchema>, BackgroundReturn<TReturn>>;
49
+ export declare function defineWorkflowTool<TReturn extends Promise<unknown> | AsyncIterable<unknown>>(definition: BackgroundDefinition<Record<string, unknown>, TReturn> & {
50
+ inputSchema: JsonObject;
51
+ }): BackgroundWorkflowToolDefinition<Record<string, unknown>, BackgroundReturn<TReturn>>;
52
+ export declare function defineWorkflowTool<TSchema extends Schema, TReturn extends Promise<unknown> | AsyncIterable<unknown>>(definition: Omit<Definition<StandardSchemaV1.InferOutput<TSchema>, TReturn>, "inputSchema"> & {
53
+ inputSchema: TSchema;
54
+ }): BlockingWorkflowToolDefinition<StandardSchemaV1.InferOutput<TSchema>, WorkflowReturn<TReturn>>;
55
+ export declare function defineWorkflowTool<TReturn extends Promise<unknown> | AsyncIterable<unknown>>(definition: Definition<Record<string, unknown>, TReturn> & {
56
+ inputSchema: JsonObject;
57
+ }): BlockingWorkflowToolDefinition<Record<string, unknown>, WorkflowReturn<TReturn>>;
58
+ export declare function defineWorkflowTool<TInput = unknown, TOutput = unknown>(definition: Unbranded<WorkflowToolDefinition<TInput, TOutput>>): WorkflowToolDefinition<TInput, TOutput>;
59
+ export declare function isWorkflowToolDefinition(value: unknown): boolean;
60
+ export {};
@@ -0,0 +1 @@
1
+ import{stampToolDefinition}from"#tools/definition.js";const WORKFLOW_TOOL_BRAND=Symbol.for(`eve:workflow-tool-brand`);function defineWorkflowTool(t){return stampToolDefinition(t,`defineWorkflowTool`),Object.assign(t,{[WORKFLOW_TOOL_BRAND]:!0})}function isWorkflowToolDefinition(e){return typeof e==`object`&&!!e&&Reflect.get(e,WORKFLOW_TOOL_BRAND)===!0}export{defineWorkflowTool,isWorkflowToolDefinition};
@@ -67,6 +67,8 @@ The authorization server identified by `issuer` must issue tokens accepted by th
67
67
 
68
68
  `oauthResource()` does not issue tokens or run an authorization server. It decorates an ordinary inbound `AuthFn` with OAuth protected-resource metadata so `mcpChannel()` can publish discovery and add `resource_metadata` to Bearer challenges. Client registration, consent, token issuance, and authorization-server metadata remain the identity provider's responsibility.
69
69
 
70
+ Most hosted MCP clients (Claude, ChatGPT, Grok, and similar) register themselves with the authorization server through Dynamic Client Registration ([RFC 7591](https://www.rfc-editor.org/rfc/rfc7591)) the first time a user connects. Choose an issuer that supports it, or pre-register each client with the issuer before the demo. If registration fails, the client stops before it ever reaches eve.
71
+
70
72
  ### Verify the bearer token yourself
71
73
 
72
74
  Use a custom `AuthFn` when token verification needs application-specific logic:
@@ -144,7 +146,7 @@ export default mcpChannel({
144
146
  });
145
147
  ```
146
148
 
147
- This allows anyone to invoke the agent. Every caller shares the anonymous principal, so invocation IDs become bearer capabilities until workflow retention expires. Use public access only when anonymous invocation is intentional.
149
+ This allows anyone to invoke the agent. Every caller shares the anonymous principal, so invocation IDs become bearer capabilities until workflow retention expires: anyone holding an ID can read, answer, or cancel that invocation. Use public access only when anonymous invocation is intentional. For a public demo, prefer [Interactive OAuth](#interactive-oauth) so each caller owns their own invocations.
148
150
 
149
151
  ## HTTP security
150
152
 
@@ -171,6 +173,10 @@ MCP clients receive four tools:
171
173
  | `agent_update` | `{ invocationId, responses }` | Answer the complete pending human-input batch. |
172
174
  | `agent_cancel` | `{ invocationId }` | Request cooperative cancellation of non-terminal work. |
173
175
 
176
+ The server also returns `instructions` from `initialize` and `server/discover` that summarize this
177
+ protocol for the connecting model, so a hosted client does not have to infer it from the tool
178
+ schemas alone.
179
+
174
180
  `agent_start` creates one task-mode eve session and returns after durable acceptance without
175
181
  waiting for the session continuation hook to become readable. Keep its `invocationId`, then call
176
182
  `agent_get` until the invocation reaches a terminal state. While the status is `working`, wait at
@@ -179,15 +185,31 @@ least `pollAfterMs` before polling again.
179
185
  The invocation response is discriminated by `status`:
180
186
 
181
187
  - `working`: work is active; continue polling according to `pollAfterMs`.
182
- - `input_required`: present `inputRequests`, then send the complete answer batch through `agent_update`. A successful update returns fresh `working` state.
188
+ - `input_required`: present `inputRequests`, then send the complete answer batch through `agent_update`. A successful update returns the current invocation state.
183
189
  - `authorization_required`: present the returned sign-in URL, user code, or instructions. The connection callback resumes the invocation automatically; continue polling.
184
190
  - `completed`: consume the optional `result`.
185
191
  - `failed`: inspect the structured `error`.
186
192
  - `cancelled`: cancellation reached a terminal state.
187
193
 
194
+ A tool result with `isError: true` means the call itself was rejected. A `failed` status means the call succeeded and the task itself failed. Handle them differently: correct the call in the first case, report the task failure in the second. Rejected calls carry `structuredContent.error` with a stable `code`, a short `message`, and `retryable`:
195
+
196
+ | `code` | Meaning | `retryable` |
197
+ | --------------- | ------------------------------------------------------------------------------ | ----------- |
198
+ | `invalid_input` | An argument was rejected, for example an oversized or external `outputSchema`. | `false` |
199
+ | `not_found` | The invocation does not exist, has expired, or belongs to another caller. | `false` |
200
+ | `conflict` | The invocation is not in the expected state; read it with `agent_get` first. | `true` |
201
+ | `internal` | eve failed; `errorId` correlates with server logs. No details are exposed. | `false` |
202
+
188
203
  Cancellation is cooperative, so call `agent_get` after `agent_cancel` until the state becomes terminal.
189
204
 
190
- Optional output schemas are limited to 64 KiB, 32 levels, and 2,048 nodes. External `$ref` values are rejected.
205
+ Requests are bounded: the whole MCP request body is limited to 1 MiB, `message` to 64 KiB, each input-response `text` to 16 KiB (both measured as UTF-8 bytes, not characters), and one `agent_update` to 64 responses. Optional output schemas are limited to 64 KiB, 32 levels, and 2,048 nodes, and external `$ref` values are rejected. Oversized bodies receive a JSON-RPC `413`; oversized fields fail input validation before any work starts.
206
+
207
+ ### Durability guarantees
208
+
209
+ - Once `agent_start` returns, the work is durable. A dropped HTTP connection, a client restart, or a closed MCP session does not cancel it. Only `agent_cancel` stops work.
210
+ - `agent_start` is not idempotent. If its response is lost, the client has no `invocationId` to check, and a second call starts a second task. Ask the user before starting again rather than retrying blindly.
211
+ - `agent_update` answers one pending batch. Re-sending the same answers after eve has accepted them returns the current invocation state; sending different answers for an already-answered batch is a conflict.
212
+ - `agent_cancel` is cooperative and can race with completion. Poll `agent_get` until the status is terminal (`cancelled`, `completed`, or `failed`), not specifically `cancelled`.
191
213
 
192
214
  ## Invocation ownership
193
215
 
@@ -60,11 +60,22 @@ Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up fro
60
60
 
61
61
  There's nothing to configure. eve owns the workflow lifecycle, and sessions are durable by default.
62
62
 
63
- You don't write workflow code directly. Workflow primitives (`start()`, `resumeHook()`, etc.) are an implementation detail of eve's runtime layer; channels, tools, and hooks never touch them. Two surfaces give your own code session data: tools read the current session's metadata (id, turn, auth, parent lineage) via `ctx.session`, and [`defineState`](./state) reads or writes session-scoped durable state. See [State](./state) for the read/write model.
63
+ For ordinary tools, eve manages the workflow around your executor. Use [`defineWorkflowTool`](../tools/workflows) when your own tool body needs durable waits, such as a timer, webhook, or human answer. Two surfaces give your own code session data: tools read the current session's metadata (id, turn, auth, parent lineage) via `ctx.session`, and [`defineState`](./state) reads or writes session-scoped durable state. See [State](./state) for the read/write model.
64
64
 
65
65
  ## Parked work
66
66
 
67
- Some work has to wait, including a human approving a [tool](../tools) or an interactive OAuth sign-in for a [connection](../connections). At those points the turn parks durably. The workflow suspends and holds no compute until the input it's waiting on arrives, even if that's much later. When it does, the conversation picks up exactly where it left off. Background tools and subagents return a task receipt instead, so the turn continues and later task notifications deliver progress or the outcome.
67
+ Some work has to wait, including a human approving a [tool](../tools) or an interactive OAuth sign-in for a [connection](../connections). At those points the turn parks durably. The workflow suspends and holds no compute until the input it's waiting on arrives, even if that's much later. When it does, the conversation picks up exactly where it left off.
68
+
69
+ Background execution is a separate choice about result delivery. A background workflow tool
70
+ returns a task receipt so the parent turn can continue; the tool's workflow may then run or
71
+ suspend independently. A default workflow tool can suspend too, with its original tool call
72
+ still pending. Ordinary background tools run their executor inside the initiating step and do
73
+ not gain durable waits by setting `execution: "background"`.
74
+
75
+ A generator's `yield` reports progress; an awaited workflow operation provides the durable wait.
76
+ For background tools, ordinary yields are stream-only, while `yield task.postMessage(...)`
77
+ requests a parent-agent turn. See [background execution](../tools#background-execution) and
78
+ [workflow suspension](../tools/workflows#how-suspension-works) for the execution and result rules.
68
79
 
69
80
  ## Message delivery and steering
70
81
 
@@ -59,7 +59,7 @@ const { session, response } = await client.sessions.create({
59
59
  await response.result();
60
60
  ```
61
61
 
62
- `clientContext` is one-turn context for the next model call. Strings become user-role context messages, arrays of strings become multiple context messages, and objects are JSON-serialized into one context message. It isn't persisted to durable session history and doesn't dispatch a turn by itself.
62
+ `clientContext` is ephemeral context for the current turn. Strings become user-role context messages, arrays of strings become multiple context messages, and objects are JSON-serialized into one context message. The context remains available to every model call in the turn, then disappears before the next turn. It isn't persisted to durable session history and doesn't dispatch a turn by itself.
63
63
 
64
64
  ## Send attachments
65
65
 
@@ -69,6 +69,8 @@ Create this layout with `eve init my-project --agents support,research`, or add
69
69
 
70
70
  With no authored `vercel.json#services`, `eve build` derives the complete Vercel Services graph on every build. If `vercel.json` declares `services`, that authored graph is authoritative instead; use `vercel build` to build and validate the complete project. This supports heterogeneous projects with frontends, private APIs, bindings, and other non-eve services without generated configuration files.
71
71
 
72
+ An authored eve service routed at `/eve/v1` already uses the protocol path; callbacks remain at `/eve/v1/callback/*`. A named mount such as `/support` adds that mount before the protocol path, giving `/support/eve/v1/callback/*`.
73
+
72
74
  Deploy the linked project to production:
73
75
 
74
76
  ```bash
@@ -201,7 +201,7 @@ For fully custom state machines, `authorization.required` and `authorization.com
201
201
 
202
202
  ## Attach page context per turn
203
203
 
204
- `clientContext` adds ephemeral context for the next model call only. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. It rides along with a message or HITL response, so it never dispatches a turn on its own and never lands in durable session history. Pass it in the second argument to `send()` or `respond()`:
204
+ `clientContext` adds ephemeral context for the current turn. Strings (or an array of strings) become user-role context messages; an object is JSON-serialized into one. The context remains available to every model call in the turn, then disappears before the next turn. It rides along with a message or HITL response, so it never dispatches a turn on its own and never lands in durable session history. Pass it in the second argument to `send()` or `respond()`:
205
205
 
206
206
  ```tsx
207
207
  await agent.send("What should I do on this screen?", {
@@ -25,8 +25,8 @@ export default defineMemory({
25
25
 
26
26
  That file declares a `profile` slot that remembers facts per authenticated
27
27
  caller using the built-in file provider. Swap `provider` for
28
- [Supermemory](#choose-a-provider) or your own implementation and the rest of the
29
- definition stays the same.
28
+ [Supermemory](#supermemory), [Upstash AgentKit](#upstash-agentkit), or your own
29
+ implementation and the rest of the definition stays the same.
30
30
 
31
31
  ## How a memory slot works
32
32
 
@@ -70,11 +70,12 @@ Every slot needs a provider. The provider decides how memory is stored, how
70
70
  relevant context is retrieved, and whether the agent captures conversation
71
71
  automatically or only through explicit tool calls.
72
72
 
73
- | Provider | Ships as | Recall | Capture |
74
- | ------------------------------------ | ------------------ | ------------------------------------ | -------------------------------------------- |
75
- | [Supermemory](#supermemory) | `@supermemory/eve` | Semantic search over stored memories | Automatic after each turn, plus tools |
76
- | [File memory](#file-memory) | Built into eve | One bounded document per scope | Model-driven `save_memory` / `remove_memory` |
77
- | [Your own provider](#build-your-own) | Your code | Whatever your store returns | Whatever rules you implement |
73
+ | Provider | Ships as | Recall | Capture |
74
+ | ------------------------------------- | ----------------------- | ------------------------------------------------------ | ---------------------------------------------------- |
75
+ | [Supermemory](#supermemory) | `@supermemory/eve` | Semantic search over stored memories | Automatic after each turn, plus tools |
76
+ | [Upstash AgentKit](#upstash-agentkit) | `@upstash/agentkit-eve` | Ranked Redis Search recall or a Redis document backend | Automatic user-message capture or model-driven tools |
77
+ | [File memory](#file-memory) | Built into eve | One bounded document per scope | Model-driven `save_memory` / `remove_memory` |
78
+ | [Your own provider](#build-your-own) | Your code | Whatever your store returns | Whatever rules you implement |
78
79
 
79
80
  ### Supermemory
80
81
 
@@ -103,10 +104,38 @@ export default defineMemory({
103
104
  });
104
105
  ```
105
106
 
106
- Set `SUPERMEMORY_API_KEY` in the agent's environment. The provider sends
107
- conversation content and extracted sources to Supermemory, so review its
108
- retention and data handling before enabling it for sensitive data. See the
109
- [Supermemory integration page](/integrations/supermemory) for provider options.
107
+ See the [Supermemory integration page](/integrations/supermemory) for provider
108
+ options.
109
+
110
+ ### Upstash AgentKit
111
+
112
+ [Upstash AgentKit](https://upstash.com/docs/redis/sdks/agentkit/eve) backs a
113
+ memory slot with your Upstash Redis database. `redisMemory()` recalls
114
+ relevance-ranked facts before each turn, captures user messages after completed
115
+ turns by default, and gives the model tools to save, search, read past
116
+ sessions, and forget.
117
+
118
+ ```bash
119
+ eve add memory/upstash-agentkit
120
+ ```
121
+
122
+ The command installs `@upstash/agentkit-eve` and writes an `upstash-agentkit`
123
+ slot:
124
+
125
+ ```ts title="agent/memory/upstash-agentkit.ts"
126
+ import { redisMemory } from "@upstash/agentkit-eve/memory";
127
+ import { defineMemory } from "eve/memory";
128
+ import { byPrincipal } from "eve/memory/scope";
129
+
130
+ export default defineMemory({
131
+ description: "Recall and manage durable context for the current user.",
132
+ provider: redisMemory({ topK: 5 }),
133
+ scope: byPrincipal,
134
+ });
135
+ ```
136
+
137
+ See the [Upstash AgentKit integration page](/integrations/upstash-agentkit) for
138
+ options.
110
139
 
111
140
  ### File memory
112
141