eve 0.59.0 → 0.59.1
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 +7 -0
- package/dist/src/approval/definition.d.ts +2 -0
- package/dist/src/compiled/.vendor-stamp.json +1 -1
- package/dist/src/compiler/default-tool-policy.d.ts +3 -1
- package/dist/src/compiler/default-tool-policy.js +1 -1
- package/dist/src/compiler/extension-compatibility.d.ts +8 -8
- package/dist/src/compiler/extension-compatibility.js +1 -1
- package/dist/src/compiler/manifest.d.ts +8 -2
- package/dist/src/compiler/manifest.js +1 -1
- package/dist/src/compiler/normalize-agent-config.js +1 -1
- package/dist/src/compiler/normalize-manifest-helpers.js +1 -1
- package/dist/src/compiler/normalize-manifest.js +1 -1
- package/dist/src/compiler/normalize-subagent.d.ts +1 -0
- package/dist/src/compiler/normalize-subagent.js +1 -1
- package/dist/src/compiler/remote-agent-node.d.ts +1 -0
- package/dist/src/compiler/remote-agent-node.js +1 -1
- package/dist/src/compiler/source-graph.d.ts +1 -0
- package/dist/src/compiler/source-graph.js +1 -1
- package/dist/src/context/dynamic-subagent-lifecycle.js +1 -1
- package/dist/src/execution/dynamic-workflow/tool.js +1 -1
- package/dist/src/execution/tools/sleep-workflow.js +1 -1
- package/dist/src/framework/sources/registry.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/harness/tools.d.ts +1 -1
- package/dist/src/harness/tools.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/internal/authored-definition/core.js +1 -1
- package/dist/src/public/definitions/connections/mcp.d.ts +1 -0
- package/dist/src/public/definitions/connections/openapi.d.ts +1 -0
- package/dist/src/public/definitions/remote-agent.d.ts +5 -0
- package/dist/src/public/definitions/workspace-agent.d.ts +5 -0
- package/dist/src/public/definitions/workspace-agent.js +1 -1
- package/dist/src/public/tools/approval/index.d.ts +2 -1
- package/dist/src/public/tools/approval/index.js +1 -1
- package/dist/src/runtime/resolve-agent-graph.js +1 -1
- package/dist/src/runtime/resolve-agent.js +1 -1
- package/dist/src/runtime/subagents/dynamic-agent-config.d.ts +1 -0
- package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -1
- package/dist/src/runtime/subagents/dynamic-remote-agent-config.d.ts +1 -0
- package/dist/src/runtime/subagents/dynamic-remote-agent-config.js +1 -1
- package/dist/src/runtime/subagents/registry.d.ts +5 -2
- package/dist/src/runtime/subagents/registry.js +1 -1
- package/dist/src/runtime/types.d.ts +2 -0
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/shared/agent-definition.d.ts +9 -0
- package/dist/src/tools/approval/policies.d.ts +18 -0
- package/dist/src/tools/approval/policies.js +1 -1
- package/dist/src/tools/definition.d.ts +4 -3
- package/docs/agent-config.md +1 -0
- package/docs/connections/mcp.mdx +2 -2
- package/docs/connections/overview.mdx +1 -1
- package/docs/guides/evaluate.md +25 -0
- package/docs/guides/remote-agents.md +2 -1
- package/docs/reference/typescript-api.md +1 -1
- package/docs/subagents/index.mdx +25 -8
- package/docs/tools/human-in-the-loop.md +27 -5
- package/docs/tools/overview.mdx +2 -2
- package/docs/tools/workflows.mdx +2 -3
- package/package.json +1 -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{DEFAULT_CONNECT_PACKAGE_VERSION,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.105`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.59.
|
|
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{DEFAULT_CONNECT_PACKAGE_VERSION,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.105`,DEFAULT_ZOD_PACKAGE_VERSION=`4.5.4`,DEFAULT_EVE_PACKAGE_CONTRACT={version:`0.59.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,t){let n=parseChatGptModelSelection(e);return n===void 0?BASE_AGENT_TEMPLATE.replaceAll(`__EVE_INIT_MODEL__`,e).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t)):`import { defineAgent } from "eve";\nimport { chatgpt } from "eve/models/openai";\n\nexport default defineAgent({\n model: chatgpt(${JSON.stringify(n)}),\n${reasoningTemplateLine(t)}});\n`}function reasoningTemplateLine(e){return e===void 0||e===`provider-default`?``:` reasoning: "${e}",\n`}function renderTemplate(e,t){return e===BASE_AGENT_TEMPLATE&&parseChatGptModelSelection(t.model)!==void 0?renderAgentTemplate(t.model,t.reasoning):e.replaceAll(`__EVE_INIT_APP_NAME__`,t.appName).replaceAll(`__EVE_INIT_MODEL__`,t.model).replaceAll(`__EVE_INIT_REASONING__`,reasoningTemplateLine(t.reasoning)).replaceAll(`__EVE_INIT_BYOK_PROVIDER__`,modelProviderSlug(t.model)).replaceAll(`__EVE_INIT_BYOK_ENV_VAR__`,byokProviderEnvVar(t.model)).replaceAll(`__EVE_INIT_PACKAGE_VERSION__`,formatEveDependencySpecifier(t.eveVersion)).replaceAll(`__EVE_INIT_AI_SDK_VERSION__`,t.aiPackageVersion).replaceAll(`__EVE_INIT_CONNECT_VERSION__`,t.connectPackageVersion).replaceAll(`__EVE_INIT_ZOD_VERSION__`,t.zodPackageVersion).replaceAll(`__EVE_INIT_TYPESCRIPT_VERSION__`,t.typescriptPackageVersion).replaceAll(`__EVE_INIT_TYPES_NODE_VERSION__`,t.nodeTypesVersion).replaceAll(`__EVE_INIT_NODE_ENGINE__`,t.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__",
|
|
@@ -298,6 +298,7 @@ export type InternalAgentDefinition = {
|
|
|
298
298
|
outputSchema?: JsonObject;
|
|
299
299
|
reasoning?: AgentReasoningDefinition;
|
|
300
300
|
source?: ModuleSourceRef;
|
|
301
|
+
tool?: boolean;
|
|
301
302
|
limits?: AgentLimitsDefinition;
|
|
302
303
|
};
|
|
303
304
|
/**
|
|
@@ -336,6 +337,14 @@ type PublicAgentDefinitionBase = {
|
|
|
336
337
|
* Framework-owned runtime limits for this agent's runs.
|
|
337
338
|
*/
|
|
338
339
|
readonly limits?: AgentLimitsDefinition;
|
|
340
|
+
/**
|
|
341
|
+
* Whether eve exposes this agent to its parent model as a tool. On the root
|
|
342
|
+
* agent, this controls the built-in `agent` tool. Defaults to `true`.
|
|
343
|
+
*
|
|
344
|
+
* A subagent with this set to `false` remains callable through `ctx.agent()`
|
|
345
|
+
* in workflow tools.
|
|
346
|
+
*/
|
|
347
|
+
readonly tool?: boolean;
|
|
339
348
|
/**
|
|
340
349
|
* Optional structured return type used when this agent runs in task mode
|
|
341
350
|
* (for example as a subagent, schedule, or remote job). Interactive
|
|
@@ -1,4 +1,22 @@
|
|
|
1
|
+
import type { Experimental_EvaluationModel as EvaluationModel } from "ai";
|
|
1
2
|
import type { ApprovalPolicy } from "#approval/definition.js";
|
|
3
|
+
export interface AutoApprovalOptions {
|
|
4
|
+
/** Evaluation model instance or ID. Defaults to TypeSafe Jev. */
|
|
5
|
+
readonly model?: EvaluationModel;
|
|
6
|
+
/** Instructions used to classify the exact tool call. */
|
|
7
|
+
readonly instructions?: string;
|
|
8
|
+
/** Descriptions of the fixed approval outcomes. */
|
|
9
|
+
readonly criteria?: {
|
|
10
|
+
readonly clear?: string;
|
|
11
|
+
readonly caution?: string;
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Returns an `approval` callback that asks an AI SDK evaluation model whether
|
|
16
|
+
* the exact tool call presents concrete security danger. Defaults to TypeSafe Jev.
|
|
17
|
+
* Unavailable or invalid evaluations require user approval.
|
|
18
|
+
*/
|
|
19
|
+
export declare function auto<TInput = unknown>(options?: AutoApprovalOptions): ApprovalPolicy<TInput>;
|
|
2
20
|
/**
|
|
3
21
|
* Returns an `approval` callback that always requires user approval before
|
|
4
22
|
* the tool executes.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{stampDurableDynamicCallback}from"#tools/durable-callbacks.js";function alwaysApproval(e){return`user-approval`}function neverApproval(e){return`not-applicable`}function onceApproval(e,t){return t.approvedTools.has(t.toolName)?`not-applicable`:`user-approval`}function always(){return stampDurableDynamicCallback(()=>`user-approval`,{callback:alwaysApproval,closure:{}})}function never(){return stampDurableDynamicCallback(()=>`not-applicable`,{callback:neverApproval,closure:{}})}function once(){return stampDurableDynamicCallback(({approvedTools:e,toolName:t})=>e.has(t)?`not-applicable`:`user-approval`,{callback:onceApproval,closure:{}})}export{always,never,once};
|
|
1
|
+
import{parseJsonValue}from"#shared/json.js";import{stampDurableDynamicCallback}from"#tools/durable-callbacks.js";import{evaluate}from"#experimental/evaluate/evaluate.js";async function autoApproval(e,t,n){try{let r=parseJsonValue(n.toolInput??null),i=JSON.stringify(r);if(new TextEncoder().encode(i).byteLength>65536)return`user-approval`;let a=AbortSignal.any([n.abortSignal,AbortSignal.timeout(3e4)]);return(await evaluate({model:e,state:{action:{input:r,tool:n.toolName}},questions:{permission:{type:`choice`,instructions:t.instructions??`Review the exact tool action for dangerous effects. Return caution when it could cause meaningful harm, including destructive data loss, credential exposure, financial transactions, deployments or public changes, external communication, privilege or system changes, or concealed execution. Return clear for routine, low-impact actions. Judge the action's actual effects from its name and input. If important effects are unclear, return caution.`,criteria:{clear:t.criteria?.clear??`The action is routine and low impact.`,caution:t.criteria?.caution??`The action is dangerous or its important effects are unclear.`}}},abortSignal:a,maxRetries:0})).answers.permission.choice===`clear`?`approved`:`user-approval`}catch{return n.abortSignal.throwIfAborted(),`user-approval`}}function alwaysApproval(e){return`user-approval`}function neverApproval(e){return`not-applicable`}function onceApproval(e,t){return t.approvedTools.has(t.toolName)?`not-applicable`:`user-approval`}function auto(e={}){let t=e.model??`typesafe-ai/jev`;return stampDurableDynamicCallback(n=>autoApproval(t,e,n),{callback:(n,r)=>autoApproval(t,e,r),closure:{}})}function always(){return stampDurableDynamicCallback(()=>`user-approval`,{callback:alwaysApproval,closure:{}})}function never(){return stampDurableDynamicCallback(()=>`not-applicable`,{callback:neverApproval,closure:{}})}function once(){return stampDurableDynamicCallback(({approvedTools:e,toolName:t})=>e.has(t)?`not-applicable`:`user-approval`,{callback:onceApproval,closure:{}})}export{always,auto,never,once};
|
|
@@ -257,14 +257,15 @@ export declare function stampToolDefinition<T extends {
|
|
|
257
257
|
declare const DISABLED_TOOL_SENTINEL_KIND = "eve:disabled-tool";
|
|
258
258
|
/**
|
|
259
259
|
* Marker value returned from {@link disableTool}. Export this as the default
|
|
260
|
-
* export of a file in `agent/tools/` to remove the
|
|
261
|
-
*
|
|
260
|
+
* export of a file in `agent/tools/` to remove the model tool whose name
|
|
261
|
+
* matches the file's slug, including framework defaults and derived subagent
|
|
262
|
+
* tools.
|
|
262
263
|
*/
|
|
263
264
|
export interface DisabledToolSentinel {
|
|
264
265
|
readonly kind: typeof DISABLED_TOOL_SENTINEL_KIND;
|
|
265
266
|
}
|
|
266
267
|
/**
|
|
267
|
-
* Returns a sentinel that disables the
|
|
268
|
+
* Returns a sentinel that disables the model tool whose name matches the
|
|
268
269
|
* containing file's slug.
|
|
269
270
|
*/
|
|
270
271
|
export declare function disableTool(): DisabledToolSentinel;
|
package/docs/agent-config.md
CHANGED
|
@@ -336,6 +336,7 @@ it falls back to the World's default retention period.
|
|
|
336
336
|
| `experimental` | `AgentExperimentalDefinition` | unset | Unstable opt-ins. `workflow.world` selects the Workflow world package on the root agent; `workflow.modelCallsPerStep` batches sequential model calls into a wider replay unit; `workflow.retention` controls how long the durable runtime keeps run data. |
|
|
337
337
|
| `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for function-like invocations such as a subagent turn, schedule, or remote job. Ordinary interactive turns ignore it unless the client supplies a per-message schema. |
|
|
338
338
|
| `build` | `{ externalDependencies?: string[] }` | none | Hosted-build packaging controls. `externalDependencies` keeps listed packages external while eve compiles authored modules such as tools and channels, and traces those packages into the hosted output. |
|
|
339
|
+
| `tool` | `boolean` | `true` | Exposes this agent to its parent model as a tool. On the root agent, controls the built-in `agent` tool. A subagent with `tool: false` remains callable from authored workflow tools through `ctx.agent()`. |
|
|
339
340
|
|
|
340
341
|
`externalDependencies` is a packaging control only. It keeps selected packages as runtime dependencies in the hosted output; it does not authorize, configure, or review any third-party service those packages may call.
|
|
341
342
|
|
package/docs/connections/mcp.mdx
CHANGED
|
@@ -100,11 +100,11 @@ Prefer `allow` for the smallest safe surface, especially when the server exposes
|
|
|
100
100
|
|
|
101
101
|
## Approval gates
|
|
102
102
|
|
|
103
|
-
Use the shared `approval` option to gate every tool served by an MCP connection. The [connections overview](../connections#per-connection-approval) defines the `never()`, `once()`, and `
|
|
103
|
+
Use the shared `approval` option to gate every tool served by an MCP connection. The [connections overview](../connections#per-connection-approval) defines the `never()`, `once()`, `always()`, and `auto()` helpers; [Human-in-the-loop](../human-in-the-loop#approvals) defines the pause-and-resume contract.
|
|
104
104
|
|
|
105
105
|
### Gate specific tools by name or input
|
|
106
106
|
|
|
107
|
-
A remote MCP server usually mixes read tools with destructive or publishing ones, so a blanket `always()` would prompt on every harmless call. Pass a custom policy instead — the same [`Approval`](/docs/human-in-the-loop#approvals) shape authored tools use — to gate only the calls that matter. The policy receives `{ session, toolName, toolInput, approvedTools }` and returns an approval status, synchronously or as a promise.
|
|
107
|
+
A remote MCP server usually mixes read tools with destructive or publishing ones, so a blanket `always()` would prompt on every harmless call. Pass a custom policy instead — the same [`Approval`](/docs/human-in-the-loop#approvals) shape authored tools use — to gate only the calls that matter. The policy receives `{ session, toolName, toolInput, approvedTools, callId, abortSignal }` and returns an approval status, synchronously or as a promise.
|
|
108
108
|
|
|
109
109
|
This connection always gates deletes, gates a publish only when the call actually schedules a post, and lets everything else through:
|
|
110
110
|
|
|
@@ -172,7 +172,7 @@ export default defineMcpClientConnection({
|
|
|
172
172
|
});
|
|
173
173
|
```
|
|
174
174
|
|
|
175
|
-
`never()` lets every call through, `once()` asks for approval the first time in a session,
|
|
175
|
+
`never()` lets every call through, `once()` asks for approval the first time in a session, `always()` asks every time, and `auto()` uses an evaluation model to allow routine calls and ask about dangerous or unclear effects. The pause and resume is the same human-in-the-loop flow covered in [Tools](/docs/tools).
|
|
176
176
|
|
|
177
177
|
For connection tools that can create, modify, delete, transmit, purchase, message, or access sensitive data, use approval, allow-lists, or other safeguards appropriate to the action.
|
|
178
178
|
|
package/docs/guides/evaluate.md
CHANGED
|
@@ -152,6 +152,31 @@ You can also call `evaluate` outside a tool; it does not require an active eve
|
|
|
152
152
|
session. Each call performs its own evaluation. `autoModel` uses this function
|
|
153
153
|
and adds the per-turn routing behavior described below.
|
|
154
154
|
|
|
155
|
+
## Evaluate tool approvals
|
|
156
|
+
|
|
157
|
+
Use `auto({ model? })` when an evaluation model should decide whether a
|
|
158
|
+
tool call can run automatically or needs human approval. It accepts the same
|
|
159
|
+
AI SDK evaluation model strings and provider instances described above and
|
|
160
|
+
defaults to `typesafe-ai/jev`:
|
|
161
|
+
|
|
162
|
+
```ts title="agent/tools/deploy.ts"
|
|
163
|
+
import { defineTool } from "eve/tools";
|
|
164
|
+
import { auto } from "eve/tools/approval";
|
|
165
|
+
import { z } from "zod";
|
|
166
|
+
|
|
167
|
+
export default defineTool({
|
|
168
|
+
description: "Deploy an application.",
|
|
169
|
+
inputSchema: z.object({ environment: z.string() }),
|
|
170
|
+
approval: auto({ model: "typesafe-ai/jev" }), // Uses AI SDK string-model resolution
|
|
171
|
+
execute: ({ environment }) => deploy(environment),
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
The evaluation model reviews the tool name and input for dangerous effects. A
|
|
176
|
+
caution, failed review, or incomplete input requires human approval. See
|
|
177
|
+
[Human-in-the-loop approvals](/docs/human-in-the-loop#approvals) for classifier
|
|
178
|
+
options and data handling.
|
|
179
|
+
|
|
155
180
|
## Runtime behavior
|
|
156
181
|
|
|
157
182
|
`autoModel` evaluates at the first `step.started` event, after the incoming prompt
|
|
@@ -29,6 +29,7 @@ export default defineRemoteAgent({
|
|
|
29
29
|
| `headers` | `HeadersValue` | No | none | Static or lazily resolved request headers. |
|
|
30
30
|
| `path` | `string` | No | `/eve/v1/session` | Route appended to `url` for the create-session request. |
|
|
31
31
|
| `outputSchema` | `StandardSchema \| JSON Schema` | No | none | Structured return type for the first turn of each fresh remote session. A continuation may provide its own per-call schema. |
|
|
32
|
+
| `tool` | `boolean` | No | `true` | Expose the remote agent as a tool to the parent model. Set `false` to allow only `ctx.agent()` calls from authored workflow tools. |
|
|
32
33
|
|
|
33
34
|
## Dynamic remote agents
|
|
34
35
|
|
|
@@ -80,7 +81,7 @@ The function may be async and must return a non-empty string. `auth` and `header
|
|
|
80
81
|
|
|
81
82
|
## Calling a remote agent
|
|
82
83
|
|
|
83
|
-
|
|
84
|
+
By default, a remote agent is another subagent tool to the model. The model calls it the same way it calls a local subagent, with a `message` and an optional `outputSchema`. Set `tool: false` when an authored workflow tool should be the only model-facing routing surface; the workflow can still call the remote agent by its path-derived name through `ctx.agent()`. The message must carry the full task, including any context the remote agent needs, because it never receives the parent's conversation history.
|
|
84
85
|
|
|
85
86
|
To require structured output, set an `outputSchema` on the agent definition for fresh delegations or on an individual call for that turn. The structured value arrives in the task's completion notification, and the remote child remains available for follow-up messages. See [Subagents](../subagents) for continuation behavior.
|
|
86
87
|
|
|
@@ -115,7 +115,7 @@ import template from "../../prompts/template.txt?raw";
|
|
|
115
115
|
| `eve` | `defineAgent`, `defineRemoteAgent`, `defineDynamic`, agent config types |
|
|
116
116
|
| `eve/tools` | `defineTool`, `defineWorkflowTool`, `defineDurableCallback`, `defineDurableSchema`, `defineDynamic`, `disableTool`, tool types |
|
|
117
117
|
| `eve/tools/{bash,read_file,write_file,todo,web_fetch,load_skill,glob,grep}` | Individual reusable tool definitions |
|
|
118
|
-
| `eve/tools/approval` | Approval types and `always`, `once`, `never`
|
|
118
|
+
| `eve/tools/approval` | Approval types and `auto`, `always`, `once`, `never` |
|
|
119
119
|
| `eve/tools/web_search` | Provider-managed `webSearch` configuration |
|
|
120
120
|
| `eve/tools/workflow` | Runtime-generated `workflow` tool factory |
|
|
121
121
|
| `eve/tools/sleep` | Opt-in durable `sleep` tool |
|
package/docs/subagents/index.mdx
CHANGED
|
@@ -38,15 +38,18 @@ The copy uses the root's instructions, connections, auth, and sandbox. It receiv
|
|
|
38
38
|
|
|
39
39
|
The parent transfers data to the child through the `message` input it gives the subagent. Do not include sensitive data in a subagent request unless that child and its inherited tools, connections, sandbox, and telemetry path are appropriate for that data.
|
|
40
40
|
|
|
41
|
-
To prevent the root session from delegating to a fresh copy of itself,
|
|
41
|
+
To prevent the root session from delegating to a fresh copy of itself, set `tool: false` on the root agent:
|
|
42
42
|
|
|
43
|
-
```ts title="agent/
|
|
44
|
-
import {
|
|
43
|
+
```ts title="agent/agent.ts"
|
|
44
|
+
import { defineAgent } from "eve";
|
|
45
45
|
|
|
46
|
-
export default
|
|
46
|
+
export default defineAgent({
|
|
47
|
+
model: "anthropic/claude-opus-4.8",
|
|
48
|
+
tool: false,
|
|
49
|
+
});
|
|
47
50
|
```
|
|
48
51
|
|
|
49
|
-
|
|
52
|
+
You can also export `disableTool()` from `agent/tools/agent.ts`. An authored root tool at that path takes priority over `tool: false` and the built-in.
|
|
50
53
|
|
|
51
54
|
## Declared subagents
|
|
52
55
|
|
|
@@ -61,7 +64,21 @@ export default defineAgent({
|
|
|
61
64
|
});
|
|
62
65
|
```
|
|
63
66
|
|
|
64
|
-
`description` is required. The parent reads it to decide whether to delegate, so the compiler rejects any subagent whose `agent.ts` leaves it out.
|
|
67
|
+
`description` is required. The parent reads it to decide whether to delegate, so the compiler rejects any subagent whose `agent.ts` leaves it out. Set `tool: false` to keep the subagent out of the parent model's tools while allowing an authored [workflow tool](/docs/tools/workflows) to call it by name through `ctx.agent()`:
|
|
68
|
+
|
|
69
|
+
```ts title="agent/subagents/researcher/agent.ts"
|
|
70
|
+
import { defineAgent } from "eve";
|
|
71
|
+
|
|
72
|
+
export default defineAgent({
|
|
73
|
+
description: "Investigate ambiguous questions for the routing workflow.",
|
|
74
|
+
model: "anthropic/claude-opus-4.8",
|
|
75
|
+
tool: false,
|
|
76
|
+
});
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
The parent can alternatively export `disableTool()` from a same-named tool path, such as `agent/tools/researcher.ts`. This suppresses the derived model tool without removing `researcher` from the workflow invocation registry. A same-named authored tool replaces the model-facing surface while the workflow can still call the underlying subagent with `ctx.agent("researcher", ...)`.
|
|
80
|
+
|
|
81
|
+
Every declared local or remote subagent runs as a durable background task: the call returns `{ status: "working", taskId, agentId }` immediately, then task notifications wake the parent with completion, failure, or cancellation. Human input requests surface separately on the parent session.
|
|
65
82
|
|
|
66
83
|
`task_cancel` is available to sessions that own background tasks, including a child that starts nested background work.
|
|
67
84
|
|
|
@@ -195,7 +212,7 @@ The root built-in `agent` tool is the exception. Its children share the root's s
|
|
|
195
212
|
|
|
196
213
|
## What the parent sees
|
|
197
214
|
|
|
198
|
-
eve lowers every subagent visible to the current agent (the root built-in copy, declared, or [remote](./guides/remote-agents)) into a model-visible tool with the same `{ message, agentId?, outputSchema? }` shape. The parent packs `message` with everything the child needs, since the child never sees the parent's history. Set `outputSchema` to require structured output for that turn; the child remains available for follow-up messages afterward.
|
|
215
|
+
eve lowers every tool-enabled subagent visible to the current agent (the root built-in copy, declared, or [remote](./guides/remote-agents)) into a model-visible tool with the same `{ message, agentId?, outputSchema? }` shape. The parent packs `message` with everything the child needs, since the child never sees the parent's history. Set `outputSchema` to require structured output for that turn; the child remains available for follow-up messages afterward.
|
|
199
216
|
|
|
200
217
|
Declared subagents can call nested subagents defined under their own directories. eve does not apply a separate depth limit; nesting ends where the authored directory tree ends. The built-in `agent` follows the stricter root-only rule above, so `limits.maxSubagentDepth` no longer exists.
|
|
201
218
|
|
|
@@ -211,7 +228,7 @@ A directly declared subagent's tool name is the bare path-derived name, with no
|
|
|
211
228
|
}
|
|
212
229
|
```
|
|
213
230
|
|
|
214
|
-
|
|
231
|
+
By default, a subagent named `researcher` collides with an authored tool named `researcher`. Set the subagent's `tool` to `false` when the authored tool intentionally wraps that subagent; the authored tool becomes the model-facing capability while `ctx.agent("researcher", ...)` continues to address the child. A same-named `disableTool()` removes the model-facing capability entirely. Other static and active dynamic collisions remain errors.
|
|
215
232
|
|
|
216
233
|
Do not rely on subagent delegation by itself as an approval boundary. Put sensitive tools behind `approval`, connection approval, route/session authorization, or other controls wherever those tools can be called.
|
|
217
234
|
|
|
@@ -6,24 +6,24 @@ url: /human-in-the-loop
|
|
|
6
6
|
|
|
7
7
|
Human-in-the-loop (HITL) is any point where the agent durably pauses and waits for a person. Two things trigger it, and both ride the same pause-and-resume protocol:
|
|
8
8
|
|
|
9
|
-
- **Approvals** — a tool
|
|
9
|
+
- **Approvals** — a tool policy allows, denies, or pauses a call for a person to review. The agent decides to call the tool; the policy decides whether it runs automatically or needs a human decision.
|
|
10
10
|
- **Questions** — the agent itself asks the user a clarifying question or a choice mid-turn, and parks until they answer.
|
|
11
11
|
|
|
12
12
|
Either way the run parks at `session.waiting`, durably, for as long as it takes — seconds or days — and picks back up exactly where it left off once the answer arrives. Channels render the request for you.
|
|
13
13
|
|
|
14
14
|
## Approvals
|
|
15
15
|
|
|
16
|
-
Approval is a property of a [tool](/docs/tools) that
|
|
16
|
+
Approval is a property of a [tool](/docs/tools) that gates it before it runs. The policy can decide automatically or pause for a person. Set `approval` with the helpers from `eve/tools/approval`:
|
|
17
17
|
|
|
18
18
|
```ts title="agent/tools/refund_charge.ts"
|
|
19
19
|
import { defineTool } from "eve/tools";
|
|
20
|
-
import {
|
|
20
|
+
import { auto } from "eve/tools/approval";
|
|
21
21
|
import { z } from "zod";
|
|
22
22
|
|
|
23
23
|
export default defineTool({
|
|
24
24
|
description: "Refund a charge.",
|
|
25
25
|
inputSchema: z.object({ tenantId: z.string(), chargeId: z.string(), amount: z.number() }),
|
|
26
|
-
approval:
|
|
26
|
+
approval: auto(), // or always() / once() / never() / a policy
|
|
27
27
|
async execute(input) {
|
|
28
28
|
return refund(input);
|
|
29
29
|
},
|
|
@@ -35,12 +35,34 @@ export default defineTool({
|
|
|
35
35
|
| `never()` | Never require approval (the default when omitted). |
|
|
36
36
|
| `once()` | Require approval only the first time the tool runs in a session; auto-allow after. |
|
|
37
37
|
| `always()` | Require approval before every call. |
|
|
38
|
+
| `auto()` | Ask an evaluation model whether to run the exact call or require user approval. |
|
|
38
39
|
|
|
39
40
|
By default, omitted `approval` behaves like `never()`, so tool calls may execute without human approval. Require human approval or other safeguards for sensitive, irreversible, regulated, financial, healthcare, employment, housing, legal, safety-impacting, user-impacting, or external side-effecting actions.
|
|
40
41
|
|
|
42
|
+
`auto()` uses an [AI SDK evaluation model](/docs/guides/evaluate) to classify each call as `clear` or `caution`. It defaults to `typesafe-ai/jev`. Like `evaluate`, a model string uses Vercel AI Gateway unless the application configures a global AI SDK default provider:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
approval: auto({ model: "typesafe-ai/jev" });
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The evaluation model reviews the tool name and input for dangerous effects. A caution, failed review, or incomplete input requires user approval. The tool input is sent to the evaluation model's provider.
|
|
49
|
+
|
|
50
|
+
Override the classifier text for application-specific policy:
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
approval: auto({
|
|
54
|
+
model: "typesafe-ai/jev",
|
|
55
|
+
instructions: "Review whether this refund needs finance approval.",
|
|
56
|
+
criteria: {
|
|
57
|
+
clear: "The refund can proceed automatically.",
|
|
58
|
+
caution: "A person must review the refund.",
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
41
63
|
A reusable approval grant applies only after every matching request that is already pending has been resolved. If several calls to a `once()`-gated tool have each produced an approval prompt, approving one does not authorize the others; each visible prompt remains an independent decision. After those pending requests are resolved, later calls in the session are allowed automatically.
|
|
42
64
|
|
|
43
|
-
When the decision depends on the input, pass your own policy instead of a helper. It receives the same session context as tool execution, plus `{ toolName, toolInput, approvedTools, callId }`, and returns an AI SDK 7 approval status synchronously or as a promise. Use `ctx.session.auth.current` to guard by the caller of the current turn and `ctx.session.auth.initiator` to guard by the caller that created the session. Return `"user-approval"` to pause for a person or `"not-applicable"` to continue without a prompt. `toolInput` can be undefined, so guard the access. This policy denies cross-tenant calls, then requires approval only when an amount crosses a threshold:
|
|
65
|
+
When the decision depends on the input, pass your own policy instead of a helper. It receives the same session context as tool execution, plus `{ toolName, toolInput, approvedTools, callId, abortSignal }`, and returns an AI SDK 7 approval status synchronously or as a promise. Use `abortSignal` for asynchronous policy work so cancellation stops it with the turn. Use `ctx.session.auth.current` to guard by the caller of the current turn and `ctx.session.auth.initiator` to guard by the caller that created the session. Return `"user-approval"` to pause for a person or `"not-applicable"` to continue without a prompt. `toolInput` can be undefined, so guard the access. This policy denies cross-tenant calls, then requires approval only when an amount crosses a threshold:
|
|
44
66
|
|
|
45
67
|
```ts
|
|
46
68
|
approval: ({ session, toolInput }) => {
|
package/docs/tools/overview.mdx
CHANGED
|
@@ -212,14 +212,14 @@ import { z } from "zod";
|
|
|
212
212
|
export default defineTool({
|
|
213
213
|
description: "Refund a charge.",
|
|
214
214
|
inputSchema: z.object({ chargeId: z.string(), amount: z.number() }),
|
|
215
|
-
approval: always(), // or once() / never() / a policy
|
|
215
|
+
approval: always(), // or auto() / once() / never() / a policy
|
|
216
216
|
async execute(input) {
|
|
217
217
|
return refund(input);
|
|
218
218
|
},
|
|
219
219
|
});
|
|
220
220
|
```
|
|
221
221
|
|
|
222
|
-
Approval is one half of eve's [human-in-the-loop](./human-in-the-loop) model — the page covers the `always
|
|
222
|
+
Approval is one half of eve's [human-in-the-loop](./human-in-the-loop) model — the page covers the `auto`/`always`/`once`/`never` helpers, input-dependent policies, and how a gated call pauses and resumes durably.
|
|
223
223
|
|
|
224
224
|
## Shape what the model sees with `toModelOutput`
|
|
225
225
|
|
package/docs/tools/workflows.mdx
CHANGED
|
@@ -111,7 +111,7 @@ export default workflow({ maxSubagents: 20 });
|
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
The model supplies an async function body through the tool's `js` input. Its only host capability is
|
|
114
|
-
`ctx.agent(name, { message, agentId?, outputSchema? })`. For example:
|
|
114
|
+
`ctx.agent(name, { message, agentId?, outputSchema? })`. This can invoke subagents configured with `tool: false` or hidden by a same-named `disableTool()` file. Include those path-derived names in the workflow tool description or agent instructions when the model writes the program. For example:
|
|
115
115
|
|
|
116
116
|
```js
|
|
117
117
|
const [triage, review] = await Promise.all([
|
|
@@ -317,8 +317,7 @@ const result = await ctx.agent("reviewer", {
|
|
|
317
317
|
});
|
|
318
318
|
```
|
|
319
319
|
|
|
320
|
-
The first argument is the model-visible subagent
|
|
321
|
-
invocation identity, including repeated and parallel calls to the same subagent. Pass `agentId` to
|
|
320
|
+
The first argument is the subagent's path-derived name. It can identify a model-visible subagent or one hidden with `tool: false` or `disableTool()`. eve assigns each call a replay-stable invocation identity, including repeated and parallel calls to the same subagent. Pass `agentId` to
|
|
322
321
|
continue an existing child. An inline `outputSchema` requires structured output and determines the
|
|
323
322
|
return type, so `result` in the example is typed as `{ findings: string[] }`.
|
|
324
323
|
|