eve 0.10.0 → 0.11.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 +17 -0
- package/README.md +14 -0
- package/dist/src/cli/banner.d.ts +6 -3
- package/dist/src/cli/banner.js +1 -1
- package/dist/src/cli/commands/init.js +1 -1
- package/dist/src/cli/dev/tui/agent-header.js +1 -1
- package/dist/src/cli/run.js +1 -1
- package/dist/src/evals/runner/run-evals.d.ts +1 -1
- package/dist/src/execution/sandbox/bindings/docker.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.d.ts +2 -1
- package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
- package/dist/src/execution/sandbox/bindings/vercel-errors.d.ts +1 -0
- package/dist/src/execution/sandbox/bindings/vercel-errors.js +1 -2
- package/dist/src/execution/sandbox/bindings/vercel.d.ts +0 -5
- package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
- package/dist/src/harness/input-requests.d.ts +20 -1
- package/dist/src/harness/input-requests.js +1 -1
- package/dist/src/harness/tool-loop.js +1 -1
- package/dist/src/internal/application/package.js +1 -1
- package/dist/src/protocol/message.d.ts +11 -2
- package/dist/src/protocol/message.js +2 -2
- package/dist/src/public/next/index.d.ts +1 -7
- package/dist/src/public/next/index.js +1 -1
- package/dist/src/public/next/vercel-output-config.js +1 -1
- package/dist/src/setup/scaffold/create/project.js +1 -1
- package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
- package/dist/src/setup/scaffold/create/web-template.js +27 -4
- package/dist/src/setup/scaffold/update/channels.js +1 -1
- package/docs/README.md +19 -5
- package/docs/agent-config.md +16 -19
- package/docs/channels/custom.mdx +24 -18
- package/docs/channels/discord.mdx +25 -13
- package/docs/channels/eve.mdx +24 -6
- package/docs/channels/github.mdx +41 -10
- package/docs/channels/linear.mdx +29 -36
- package/docs/channels/overview.mdx +16 -4
- package/docs/channels/slack.mdx +59 -32
- package/docs/channels/teams.mdx +19 -7
- package/docs/channels/telegram.mdx +23 -9
- package/docs/channels/twilio.mdx +28 -6
- package/docs/concepts/context-control.md +24 -41
- package/docs/concepts/default-harness.md +19 -9
- package/docs/concepts/execution-model-and-durability.md +14 -14
- package/docs/concepts/security-model.md +32 -8
- package/docs/concepts/sessions-runs-and-streaming.md +11 -9
- package/docs/connections.mdx +49 -29
- package/docs/evals/assertions.mdx +30 -29
- package/docs/evals/cases.mdx +10 -10
- package/docs/evals/judge.mdx +14 -14
- package/docs/evals/overview.mdx +15 -17
- package/docs/evals/reporters.mdx +19 -7
- package/docs/evals/running.mdx +2 -2
- package/docs/evals/targets.mdx +15 -4
- package/docs/getting-started.mdx +72 -31
- package/docs/guides/auth-and-route-protection.md +18 -12
- package/docs/guides/client/continuations.mdx +5 -13
- package/docs/guides/client/messages.mdx +2 -2
- package/docs/guides/client/output-schema.mdx +2 -2
- package/docs/guides/client/overview.mdx +4 -4
- package/docs/guides/client/streaming.mdx +6 -5
- package/docs/guides/deployment.md +22 -20
- package/docs/guides/dev-tui.md +85 -13
- package/docs/guides/dynamic-capabilities.md +24 -8
- package/docs/guides/dynamic-workflows.md +33 -12
- package/docs/guides/frontend/nextjs.mdx +28 -14
- package/docs/guides/frontend/nuxt.mdx +21 -4
- package/docs/guides/frontend/overview.mdx +11 -11
- package/docs/guides/frontend/sveltekit.mdx +20 -3
- package/docs/guides/frontend/use-eve-agent-svelte.mdx +106 -14
- package/docs/guides/frontend/use-eve-agent-vue.mdx +108 -15
- package/docs/guides/hooks.md +14 -60
- package/docs/guides/instrumentation.md +24 -18
- package/docs/guides/remote-agents.md +19 -15
- package/docs/guides/session-context.md +12 -12
- package/docs/guides/state.md +25 -9
- package/docs/instructions.mdx +18 -10
- package/docs/{introduction.md → introduction.mdx} +14 -12
- package/docs/reference/cli.md +99 -53
- package/docs/reference/meta.json +1 -1
- package/docs/reference/project-layout.md +39 -32
- package/docs/reference/typescript-api.md +1 -1
- package/docs/responsible-use.md +14 -0
- package/docs/sandbox.mdx +25 -19
- package/docs/schedules.mdx +16 -14
- package/docs/skills.mdx +8 -6
- package/docs/subagents.mdx +39 -13
- package/docs/tools.mdx +13 -9
- package/docs/tutorial/connect-a-warehouse.mdx +16 -7
- package/docs/tutorial/first-agent.mdx +21 -11
- package/docs/tutorial/guard-the-spend.mdx +11 -9
- package/docs/tutorial/how-it-runs.mdx +10 -8
- package/docs/tutorial/query-sample-data.mdx +8 -8
- package/docs/tutorial/remember-definitions.mdx +5 -5
- package/docs/tutorial/run-analysis.mdx +13 -11
- package/docs/tutorial/ship-it.mdx +70 -14
- package/docs/tutorial/team-playbooks.mdx +33 -10
- package/package.json +1 -1
package/docs/channels/twilio.mdx
CHANGED
|
@@ -4,7 +4,7 @@ description: "Reach your agent over SMS and speech-transcribed phone calls with
|
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Twilio channel puts your agent on a phone number, so people can text it or call it. Inbound SMS arrives as a webhook. Inbound calls
|
|
7
|
+
The Twilio channel puts your agent on a phone number, so people can text it or call it. Inbound SMS arrives as a webhook. Inbound calls are answered with TwiML `<Gather input="speech">`, and the resulting transcript feeds the same Eve session that SMS uses, so a caller and a texter look identical downstream. Every request is checked against `X-Twilio-Signature` before anything else runs. The raw continuation token is `From:To`. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Add the channel
|
|
10
10
|
|
|
@@ -22,7 +22,7 @@ TWILIO_ACCOUNT_SID=AC... # required for default outbound SMS
|
|
|
22
22
|
TWILIO_AUTH_TOKEN=... # required for inbound signature verification
|
|
23
23
|
```
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
To skip env vars, pass the same values via `credentials: { accountSid, authToken }`. The channel mounts three routes:
|
|
26
26
|
|
|
27
27
|
- `POST /eve/v1/twilio/messages`: Messaging webhook
|
|
28
28
|
- `POST /eve/v1/twilio/voice`: inbound call webhook
|
|
@@ -30,15 +30,17 @@ If you'd rather not use env vars, pass the same values via `credentials: { accou
|
|
|
30
30
|
|
|
31
31
|
Point your Twilio number's Messaging webhook at `/messages` and Voice webhook at `/voice`, using the exact public URL Twilio will call.
|
|
32
32
|
|
|
33
|
-
##
|
|
33
|
+
## How the channel handles messages
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
### Dispatch
|
|
36
|
+
|
|
37
|
+
`allowFrom` is required. It gates who can reach the inbound hooks. Pass a single number, a list, an async resolver, or `"*"`. The wildcard is dangerous; only use it with an explicit check inside `onText`/`onVoice`.
|
|
36
38
|
|
|
37
39
|
```ts
|
|
38
40
|
export default twilioChannel({ allowFrom: ["+15551234567", "+15557654321"] });
|
|
39
41
|
```
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
`onText` and `onVoiceTranscription` decide dispatch and `auth`. Return `{ auth }` to proceed, or `null` to drop the message. `onVoice` fires the moment a call comes in. Return `null` to reject it, or return an object to override the spoken prompt, language, `<Say voice>`, and speech-recognition options.
|
|
42
44
|
|
|
43
45
|
```ts
|
|
44
46
|
export default twilioChannel({
|
|
@@ -54,7 +56,27 @@ export default twilioChannel({
|
|
|
54
56
|
});
|
|
55
57
|
```
|
|
56
58
|
|
|
57
|
-
|
|
59
|
+
### Delivery
|
|
60
|
+
|
|
61
|
+
The default `message.completed` handler sends the reply as SMS through Twilio's Messages API. A reply to an inbound message can reuse the webhook's `To` as the sender, but a proactive send has nothing to reuse, so it needs `messaging.from` or `messaging.messagingServiceSid`. Behind a proxy, set `webhookUrl` so signature verification matches the exact configured URL, and `publicBaseUrl` so voice TwiML can build absolute callback URLs.
|
|
62
|
+
|
|
63
|
+
### Human-in-the-loop (HITL)
|
|
64
|
+
|
|
65
|
+
SMS and voice have no native button or card affordance, so HITL prompts do not render as interactive controls. The agent's `input.requested` event reaches your `events["input.requested"]` handler if you declare one. Handle it by sending the prompt as text and mapping the caller's reply back to the input request yourself.
|
|
66
|
+
|
|
67
|
+
### Proactive sessions
|
|
68
|
+
|
|
69
|
+
Start a session without an inbound message through `receive(twilio, { message, target, auth })` from a schedule `run` handler, or `args.receive(twilio, ...)` from another channel. `target.phoneNumber` is required, and the channel needs `messaging.from` or `messaging.messagingServiceSid` for the outbound sender.
|
|
70
|
+
|
|
71
|
+
### Attachments
|
|
72
|
+
|
|
73
|
+
Inbound media attachments are not supported on this channel today.
|
|
74
|
+
|
|
75
|
+
## Disclaimer
|
|
76
|
+
|
|
77
|
+
As the deployer, it is your responsibility to ensure your agent complies with applicable laws.
|
|
78
|
+
|
|
79
|
+
For example, you may be required to inform callers and texters that calls are recorded/transcribed and processed by an automated AI system, and obtain consent where required (including two-party-consent jurisdictions). For outbound SMS or calls you initiate, you may be required to get prior express consent, honor STOP/opt-out and quiet-hour rules, and complete required carrier registration.
|
|
58
80
|
|
|
59
81
|
## What to read next
|
|
60
82
|
|
|
@@ -1,17 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Context Control"
|
|
3
|
-
description: "Control what
|
|
3
|
+
description: "Control what an Eve agent's model sees and when, across instructions, skills, the workspace, and subagents."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Eve gives you a few levers for controlling what the model sees and when
|
|
6
|
+
Eve gives you a few levers for controlling what the model sees and when. `instructions.md` (or `instructions.ts`) is always on, `skills/` are available but loaded on demand, and the workspace and sandbox are visible through tools rather than pasted into the prompt.
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
- `instructions.md` (or `instructions.ts`) is always on.
|
|
11
|
-
- `skills/` are available but loaded on demand.
|
|
12
|
-
- The workspace and sandbox are visible through tools, not pasted into the prompt.
|
|
13
|
-
|
|
14
|
-
## 1. Base identity with `instructions.md`
|
|
8
|
+
## Base identity with `instructions.md`
|
|
15
9
|
|
|
16
10
|
Use `instructions.md` for the core contract of the agent.
|
|
17
11
|
|
|
@@ -22,9 +16,9 @@ used a tool.
|
|
|
22
16
|
|
|
23
17
|
Keep this file focused on stable behavior that should apply on every turn.
|
|
24
18
|
|
|
25
|
-
##
|
|
19
|
+
## Compose instructions in TypeScript with `instructions.ts`
|
|
26
20
|
|
|
27
|
-
|
|
21
|
+
To build the instructions prompt from typed helpers, lib code, or environment-derived values, author it as a module instead of markdown.
|
|
28
22
|
|
|
29
23
|
```ts title="agent/instructions.ts"
|
|
30
24
|
import { defineInstructions } from "eve/instructions";
|
|
@@ -37,13 +31,9 @@ export default defineInstructions({
|
|
|
37
31
|
|
|
38
32
|
Module-backed instructions run once at build time. Eve captures the resulting markdown into the compiled manifest, so the runtime serves the same prompt every session without re-running the module.
|
|
39
33
|
|
|
40
|
-
##
|
|
41
|
-
|
|
42
|
-
Skills are not part of the always-on prompt by default.
|
|
43
|
-
|
|
44
|
-
Instead, Eve advertises the available skills and adds a framework-owned `load_skill` tool. When the request clearly matches a skill description, or the user names a skill explicitly, the model activates that skill, and Eve appends the skill's markdown to the active instructions for later turn work.
|
|
34
|
+
## Load procedures on demand with `skills/`
|
|
45
35
|
|
|
46
|
-
|
|
36
|
+
Skills stay out of the always-on prompt by default, which keeps rich procedures available without bloating every turn. Eve advertises the available skills and adds a framework-owned `load_skill` tool. When the request clearly matches a skill description, or the user names a skill explicitly, the model activates that skill, and Eve appends the skill's markdown to the active instructions for later turn work.
|
|
47
37
|
|
|
48
38
|
### Flat skill
|
|
49
39
|
|
|
@@ -62,48 +52,41 @@ When the task is novel or ambiguous, gather evidence first, then answer with the
|
|
|
62
52
|
remaining uncertainty.
|
|
63
53
|
```
|
|
64
54
|
|
|
65
|
-
Packaged skills are useful when you also want sibling files such as `references/`, `assets/`, or `scripts/` under the same skill directory. Those
|
|
55
|
+
Packaged skills are useful when you also want sibling files such as `references/`, `assets/`, or `scripts/` under the same skill directory. Those paths show up under the runtime workspace root, so the model can inspect them with the normal file or shell tools instead of pasting their content into the prompt.
|
|
66
56
|
|
|
67
57
|
See [Skills](../skills) for the full authoring model and install notes.
|
|
68
58
|
|
|
69
|
-
##
|
|
59
|
+
## Put runtime files in the workspace, not the prompt
|
|
70
60
|
|
|
71
|
-
Eve does not inline the entire authored surface into the prompt. Instead, it gives the model a shallow workspace hint and runtime tools to inspect deeper when needed.
|
|
61
|
+
Eve does not inline the entire authored surface into the prompt. Instead, it gives the model a shallow workspace hint and runtime tools to inspect deeper when needed. Skill files are available under the active workspace root, and the model inspects them with the shared `bash` tool, which keeps prompts smaller and makes file and command work explicit.
|
|
72
62
|
|
|
73
63
|
See [Sandbox](../sandbox) for the workspace and sandbox model.
|
|
74
64
|
|
|
75
|
-
##
|
|
65
|
+
## Delegate to a specialist with a subagent
|
|
76
66
|
|
|
77
|
-
If a task deserves its own prompt and tool surface, use a local subagent instead of overloading the root agent. Subagents are a context-control
|
|
67
|
+
If a task deserves its own prompt and tool surface, use a local subagent instead of overloading the root agent. Subagents are a context-control lever too. They get their own `instructions.md`, tools, and sandbox, and they run inside their own delegated context instead of extending the root agent inline.
|
|
78
68
|
|
|
79
69
|
See [Subagents](../subagents).
|
|
80
70
|
|
|
81
71
|
## Dynamic context with `defineDynamic`
|
|
82
72
|
|
|
83
|
-
The levers above are static
|
|
73
|
+
The levers above are static, authored once and the same on every session. When the right context depends on who is calling (their team, tenant, plan, or feature flags), resolve it at runtime instead. `defineDynamic` in `agent/instructions/` returns the per-session system prompt, and `defineDynamic` in `agent/skills/` returns the set of skills a caller can load. Both read `ctx.session.auth` or channel metadata, so a caller on the billing team gets the billing instructions and playbook while no one else sees them. See [Dynamic capabilities](../guides/dynamic-capabilities) for the resolver API and when each event fires.
|
|
84
74
|
|
|
85
|
-
##
|
|
75
|
+
## Recommended context layout
|
|
86
76
|
|
|
87
|
-
|
|
77
|
+
Pick the lever by what the context is for:
|
|
88
78
|
|
|
89
|
-
- `instructions.md` for the agent's permanent identity.
|
|
79
|
+
- `instructions.md` for the agent's permanent identity. Keep it short and stable.
|
|
90
80
|
- `instructions.ts` when you need to compose the prompt from typed helpers at build time.
|
|
91
|
-
- `skills/` for optional procedures that should load only when needed.
|
|
92
|
-
-
|
|
81
|
+
- `skills/` for optional procedures that should load only when needed. Move long procedures here instead of into the always-on prompt.
|
|
82
|
+
- `tools/` to expose typed integrations.
|
|
83
|
+
- a subagent when the task needs a different specialist surface; use one only for real specialization boundaries.
|
|
93
84
|
- the workspace or sandbox when the model should inspect files or run commands instead of relying on pasted instructions.
|
|
94
85
|
|
|
95
|
-
## A good pattern
|
|
96
|
-
|
|
97
|
-
For most agents:
|
|
98
|
-
|
|
99
|
-
1. Keep `instructions.md` short and stable.
|
|
100
|
-
2. Move long procedures into `skills/`.
|
|
101
|
-
3. Expose typed integrations through `tools/`.
|
|
102
|
-
4. Use subagents only for real specialization boundaries.
|
|
103
|
-
|
|
104
86
|
## What to read next
|
|
105
87
|
|
|
106
|
-
- [Tools](../tools)
|
|
107
|
-
- [Skills](../skills)
|
|
108
|
-
- [Subagents](../subagents)
|
|
109
|
-
- [
|
|
88
|
+
- [Tools](../tools): expose typed integrations the model can call.
|
|
89
|
+
- [Skills](../skills): the full authoring model for on-demand procedures.
|
|
90
|
+
- [Subagents](../subagents): delegate to a specialist with its own prompt and tools.
|
|
91
|
+
- [Dynamic capabilities](../guides/dynamic-capabilities): resolve per-session instructions and skills with `defineDynamic`.
|
|
92
|
+
- [Hooks](../guides/hooks): run code on session events to update the channel state that dynamic resolvers read.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "The Harness"
|
|
3
|
-
description: "The out-of-the-box agent loop and the built-in tools every
|
|
3
|
+
description: "The out-of-the-box Eve agent loop and the built-in tools every agent ships with, plus how to override or disable them."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
The default harness is what every Eve agent ships with
|
|
6
|
+
The default harness is what every Eve agent ships with. It includes the framework-owned agent loop plus a set of built-in tools the model can call without you writing a line. You extend it with capabilities specific to your agent. The loop itself, how a turn runs and checkpoints and resumes, lives in [Execution model and durability](./execution-model-and-durability).
|
|
7
7
|
|
|
8
8
|
## Compaction
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
The harness keeps a long session from overflowing the model's context window. Once the conversation crosses a fraction of the window (`thresholdPercent`, `0.9` by default), it summarizes the older turns into a compact form and keeps going. The summary uses the active turn model unless you override it. Tune when and how it kicks in under [`compaction`](../agent-config#compaction) in `agent.ts`:
|
|
11
11
|
|
|
12
12
|
```ts title="agent/agent.ts"
|
|
13
13
|
export default defineAgent({
|
|
@@ -18,11 +18,11 @@ export default defineAgent({
|
|
|
18
18
|
});
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
-
Compaction also preserves the framework's own tool state automatically.
|
|
21
|
+
Compaction also preserves the framework's own tool state automatically. It resets read-before-write tracking (so a write afterward re-reads the file whose read evidence was summarized away) and re-injects the active todo list, so the model keeps its task list across the summary. There is no per-tool hook to configure.
|
|
22
22
|
|
|
23
23
|
## Built-in tools
|
|
24
24
|
|
|
25
|
-
These ship with every agent, no imports.
|
|
25
|
+
These ship with every agent, no imports. The harness shows the model the tool descriptors first, then executes only what the model actually calls; discovery never runs them. The shell and file tools (`bash`, `read_file`, `write_file`, `glob`, `grep`) live in the app runtime and proxy their work into the agent's single [sandbox](../sandbox); the rest run in the app runtime. The "Where it runs" column below names where each tool's effect lands.
|
|
26
26
|
|
|
27
27
|
| Tool | Does | Where it runs |
|
|
28
28
|
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
|
|
@@ -46,9 +46,11 @@ Notes:
|
|
|
46
46
|
- **`connection_search`** is the model-facing `connection__search` tool. A search surfaces a connection's tools by their qualified name (e.g. `connection__linear__list_issues`), and the model can then call them directly. It's registered only when the agent has connections.
|
|
47
47
|
- **`web_search`** has no local executor; the provider runs it. To supply your own implementation, override it with `defineTool()`.
|
|
48
48
|
|
|
49
|
+
Review these built-in tools before production use. Disable, wrap, restrict, or require approval for any tool that can access the filesystem, network, shell, or sensitive data.
|
|
50
|
+
|
|
49
51
|
## Override a default
|
|
50
52
|
|
|
51
|
-
Author a tool at the same slug and it takes over the built-in of that name. The file `agent/tools/write_file.ts` replaces the built-in `write_file`
|
|
53
|
+
Author a tool at the same slug and it takes over the built-in of that name. The file `agent/tools/write_file.ts` replaces the built-in `write_file` by existing:
|
|
52
54
|
|
|
53
55
|
```ts title="agent/tools/write_file.ts"
|
|
54
56
|
import { defineTool } from "eve/tools";
|
|
@@ -63,7 +65,7 @@ export default defineTool({
|
|
|
63
65
|
});
|
|
64
66
|
```
|
|
65
67
|
|
|
66
|
-
The framework defaults are importable from `eve/tools/defaults` (`bash`, `readFile`, `writeFile`, `glob`, `grep`, `webFetch`, `webSearch`, `todo`, `loadSkill`), so you can spread, wrap, or patch them. Skip the spread and your replacement owns its own context
|
|
68
|
+
The framework defaults are importable from `eve/tools/defaults` (`bash`, `readFile`, `writeFile`, `glob`, `grep`, `webFetch`, `webSearch`, `todo`, `loadSkill`), so you can spread, wrap, or patch them. Skip the spread and your replacement owns its own context. A fresh `defineTool` for `todo` won't inherit the framework's durable state key.
|
|
67
69
|
|
|
68
70
|
## Disable a default
|
|
69
71
|
|
|
@@ -75,11 +77,19 @@ import { disableTool } from "eve/tools";
|
|
|
75
77
|
export default disableTool();
|
|
76
78
|
```
|
|
77
79
|
|
|
78
|
-
|
|
80
|
+
If the filename matches no known framework tool, resolution fails instead of silently doing nothing, so a typo surfaces at build time rather than removing the wrong tool.
|
|
81
|
+
|
|
82
|
+
## When to override, disable, or author a new tool
|
|
83
|
+
|
|
84
|
+
Three moves shape the harness. The right one depends on whether the model should keep the built-in capability.
|
|
85
|
+
|
|
86
|
+
- **Override** when you want the same capability with different behavior. Spread the default from `eve/tools/defaults` and wrap it (logging, an extra guard, a different backend), and the model still sees a tool by that name. Spreading keeps the default's description, schema, and any framework state, such as the `todo` tool's durable state key. Drop the spread and your replacement owns its own context, losing that wiring.
|
|
87
|
+
- **Disable** when the model should not have the capability at all. A `disableTool()` sentinel removes the built-in, and the model never sees it. Reach for this to lock down `bash` or `web_fetch` in an agent that should not run shell commands or fetch arbitrary URLs.
|
|
88
|
+
- **Author a new tool** when you want a capability the harness does not ship. Give it a fresh slug under `agent/tools/` and it joins the built-ins instead of replacing one. See [Tools](../tools) for the authoring model.
|
|
79
89
|
|
|
80
90
|
## The opt-in `Workflow` tool
|
|
81
91
|
|
|
82
|
-
|
|
92
|
+
An experimental `Workflow` tool ships but stays off by default. To turn it on, re-export the opt-in marker from `agent/tools/workflow.ts`:
|
|
83
93
|
|
|
84
94
|
```ts
|
|
85
95
|
export { ExperimentalWorkflow as default } from "eve/tools";
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: "Execution Model
|
|
3
|
-
description: "How
|
|
2
|
+
title: "Execution Model and Durability"
|
|
3
|
+
description: "How an Eve session runs. Durable conversations, turns that checkpoint at steps, and parked work that resumes later."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
An Eve session is a durable conversation. It can run for days and survives process restarts and redeploys without any work on your part. You write the capabilities (tools, instructions, channels) and Eve runs the loop.
|
|
7
7
|
|
|
8
8
|
## Sessions, turns, and steps
|
|
9
9
|
|
|
@@ -13,38 +13,38 @@ Work nests in three levels:
|
|
|
13
13
|
- **turn**: one user message and all the work it triggers (model calls, tool calls, reasoning) until the agent produces its response.
|
|
14
14
|
- **step**: a durable checkpoint inside a turn (one model call and the tool calls it makes).
|
|
15
15
|
|
|
16
|
-
Every turn runs as a durable workflow, built on the open-source [Workflow SDK](https://workflow-sdk.dev/) (Vercel Workflow when you deploy on Vercel). Eve checkpoints progress
|
|
16
|
+
Every turn runs as a durable workflow, built on the open-source [Workflow SDK](https://workflow-sdk.dev/) (Vercel Workflow when you deploy on Vercel). Eve checkpoints progress and serializes durable state at each step boundary. Your code runs inside a managed step, so tools, the sandbox, and subagents feel synchronous even though the session underneath them is durable.
|
|
17
17
|
|
|
18
18
|
## Resuming after a crash
|
|
19
19
|
|
|
20
|
-
Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn.
|
|
20
|
+
Crash the process, hit a timeout, or redeploy mid-turn, and the run picks up from the last completed step rather than replaying the whole turn. Completed steps never re-run; Eve replays the recorded result. A step interrupted mid-execution re-runs, so make non-idempotent side effects like charges or emails idempotent, or gate them with approval.
|
|
21
21
|
|
|
22
|
-
There's nothing to configure
|
|
22
|
+
There's nothing to configure. Eve owns the workflow lifecycle, and sessions are durable by default.
|
|
23
23
|
|
|
24
|
-
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.
|
|
24
|
+
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`](../guides/state) reads or writes session-scoped durable state. See [State](../guides/state) for the read/write model.
|
|
25
25
|
|
|
26
26
|
## Parked work
|
|
27
27
|
|
|
28
|
-
Some work has to wait
|
|
28
|
+
Some work has to wait, including a human approving a [tool](../tools), an interactive OAuth sign-in for a [connection](../connections), or a long-running [subagent](../subagents). At those points the turn parks durably. The workflow suspends and holds no compute until the input it's waiting on arrives (a click, a callback, a child completing), even if that's much later. When it does, the conversation picks up exactly where it left off.
|
|
29
29
|
|
|
30
30
|
## Message delivery and queueing
|
|
31
31
|
|
|
32
|
-
Eve does not maintain a durable FIFO queue of user messages for a session
|
|
32
|
+
Eve does not maintain a durable FIFO queue of user messages for a session. The `continuationToken` is a resume handle for the session's current workflow hook, not a general message-queue address.
|
|
33
33
|
|
|
34
|
-
When a session is waiting, a delivery to the current continuation token wakes the session and starts the next turn. When a turn is already active,
|
|
34
|
+
When a session is waiting, a delivery to the current continuation token wakes the session and starts the next turn. When a turn is already active, the hook may accept additional deliveries, but the runtime only drains them at specific workflow boundaries. If more than one delivery is ready when the driver checks, Eve may fold them into the next turn; that drain is best-effort and depends on workflow and transport timing.
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
So don't rely on concurrent sends to the same session behaving like a typical ordered chat queue. For deterministic behavior, send one user turn at a time and wait for `session.waiting` before sending the next message to the same session. If your channel can receive bursts while the agent is working, keep your own per-session queue in the channel or app layer, then deliver the next message after the session parks again. Separate sessions still run independently.
|
|
37
37
|
|
|
38
38
|
## Subagents
|
|
39
39
|
|
|
40
40
|
A turn can hand work off to a [subagent](../subagents). Each subagent gets its own context and its own durable session; a declared subagent also gets its own sandbox, skills, and state. Nothing crosses the boundary implicitly.
|
|
41
41
|
|
|
42
|
-
##
|
|
42
|
+
## How Eve orders session history
|
|
43
43
|
|
|
44
|
-
Conversation history within a session is append-only. Turns land in order, and the tool calls inside a turn (plus their results) keep their order too. Read a session back and you see
|
|
44
|
+
Conversation history within a session is append-only. Turns land in order, and the tool calls inside a turn (plus their results) keep their order too. Read a session back and you see events in the order they happened.
|
|
45
45
|
|
|
46
46
|
## What to read next
|
|
47
47
|
|
|
48
|
-
- [Sessions
|
|
48
|
+
- [Sessions and streaming](./sessions-runs-and-streaming): the handles you hold and the event stream you watch.
|
|
49
49
|
- [Security model](./security-model): the trust boundaries the runtime enforces.
|
|
50
50
|
- [State](../guides/state): durable per-session memory that persists across step boundaries.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Security Model"
|
|
3
|
-
description: "
|
|
3
|
+
description: "Eve's trust boundaries, where secrets live, how credentials reach hosts, and what fails closed by default."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
Your agent runs across two contexts, with a trust boundary
|
|
6
|
+
Your Eve agent runs across two contexts, with a trust boundary between them and every secret kept on the trusted side. Use this mental model when deciding what an agent (and the model driving it) is allowed to reach.
|
|
7
7
|
|
|
8
8
|
## Trust boundaries
|
|
9
9
|
|
|
@@ -16,13 +16,37 @@ Your agent runs across two contexts, with a trust boundary drawn between them an
|
|
|
16
16
|
|
|
17
17
|
The app runtime is the trusted side. Your tool implementations, model calls, connections, state, and durable execution all run here, with `process.env` and full Node.js available. (On Vercel, this is a Vercel Function.)
|
|
18
18
|
|
|
19
|
-
The sandbox is the isolated side. The model runs shell commands there through the built-in `bash`, `read_file`, `write_file`, `glob`, and `grep` tools. It gets its own `/workspace` filesystem, but no `process.env`, no secrets, and no path back into the app runtime. (On Vercel, each sandbox is a [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM with hardware-level isolation.)
|
|
19
|
+
The sandbox is the isolated side. The model runs shell commands there through the built-in `bash`, `read_file`, `write_file`, `glob`, and `grep` tools. It gets its own `/workspace` filesystem, but no `process.env`, no secrets, and no path back into the app runtime. (On Vercel, each sandbox is a [Vercel Sandbox](https://vercel.com/docs/sandbox) microVM with hardware-level isolation.) Only shell commands execute in the sandbox. Even the built-in `bash`/`read_file`/`write_file` tools live in the app runtime and _proxy_ into the sandbox. The model sees tool definitions and results, never your secrets.
|
|
20
20
|
|
|
21
21
|
A concrete trace makes the boundary clear. When the model calls a custom `charge_card` tool, its `execute` runs in the app runtime, reads `process.env.STRIPE_KEY`, calls Stripe, and returns `{ ok: true }`. The model sees only `{ ok: true }`: the key never leaves the app runtime, and nothing about the call touches the sandbox. The built-in `write_file` is the mirror image, running in the app runtime and proxying the write into the sandbox `/workspace`. Either way the model drives the work through tool calls and their results, never by holding a credential or reaching the runtime directly.
|
|
22
22
|
|
|
23
|
+
## Data flow at a glance
|
|
24
|
+
|
|
25
|
+
```mermaid
|
|
26
|
+
flowchart LR
|
|
27
|
+
User["User or channel provider"] --> Channel["Channel route and route auth"]
|
|
28
|
+
Channel --> Runtime["Eve app runtime and durable session"]
|
|
29
|
+
Runtime --> Model["Configured model provider or Vercel AI Gateway"]
|
|
30
|
+
Runtime --> Tools["Authored tools and connections"]
|
|
31
|
+
Tools --> Services["Customer-selected external services"]
|
|
32
|
+
Runtime --> Sandbox["Per-session sandbox"]
|
|
33
|
+
Sandbox --> Egress["Allowed sandbox network egress"]
|
|
34
|
+
Runtime --> Telemetry["Configured telemetry or eval provider"]
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Eve sends data where your agent configuration and runtime choices send it:
|
|
38
|
+
|
|
39
|
+
- Inbound channel data flows through the channel provider you configure, then into the Eve app runtime.
|
|
40
|
+
- Model inputs and outputs flow to the model or routing path selected in `agent.ts`, such as a Vercel AI Gateway model id or a provider-authored `LanguageModel`.
|
|
41
|
+
- Tool and connection calls flow to the external services, MCP servers, OpenAPI endpoints, and channels you configure.
|
|
42
|
+
- Sandbox commands can reach network destinations allowed by the sandbox network policy.
|
|
43
|
+
- Telemetry and eval data flows to the exporters and providers you configure in `instrumentation.ts` or eval settings.
|
|
44
|
+
|
|
45
|
+
Eve stores durable session and workflow state needed to resume conversations, stream events, replay completed steps, and show run observability. You are responsible for deciding whether the selected channels, model providers, connected services, sandbox egress destinations, telemetry exporters, retention settings, and deletion controls are appropriate for your data and use case.
|
|
46
|
+
|
|
23
47
|
## Credential brokering
|
|
24
48
|
|
|
25
|
-
|
|
49
|
+
Credential brokering gives the model _authenticated_ network access from inside the sandbox, like a `git clone` of a private repo or an authenticated `curl`, when there's no [tool](../tools) or [connection](../connections) to route it through. On the Vercel Sandbox backend, auth headers get injected at the sandbox's network firewall for matching domains. The secret stays in the app runtime; the sandbox process only ever sees the response. See [Vercel Sandbox Credential Brokering](https://vercel.com/docs/sandbox/concepts/firewall#credentials-brokering) for the platform mechanism, and [Sandbox](../sandbox) for the Eve policy API.
|
|
26
50
|
|
|
27
51
|
## Connection credentials
|
|
28
52
|
|
|
@@ -30,7 +54,7 @@ Sometimes the model needs _authenticated_ network access from inside the sandbox
|
|
|
30
54
|
|
|
31
55
|
## Channel verification
|
|
32
56
|
|
|
33
|
-
A [channel](../channels/overview) is your agent's front door,
|
|
57
|
+
A [channel](../channels/overview) is your agent's front door, so authenticating inbound traffic is its job. The built-in platform channels follow two rules, and so must any channel you write yourself:
|
|
34
58
|
|
|
35
59
|
- **Verify signatures in constant time.** Platform channels (Slack, GitHub,
|
|
36
60
|
Telegram, Twilio) verify the platform's HMAC signature over the raw request body
|
|
@@ -46,11 +70,11 @@ A custom channel that accepts dashboard-style webhooks should follow the same sh
|
|
|
46
70
|
|
|
47
71
|
## Authored markdown is data
|
|
48
72
|
|
|
49
|
-
[Skill](../skills) and [schedule](../schedules) files are markdown with YAML frontmatter, and Eve treats that frontmatter strictly as data. The code-capable engines (`---js` / `---javascript`, which would `eval()` the frontmatter body the moment the file is parsed) are disabled
|
|
73
|
+
[Skill](../skills) and [schedule](../schedules) files are markdown with YAML frontmatter, and Eve treats that frontmatter strictly as data. The code-capable engines (`---js` / `---javascript`, which would `eval()` the frontmatter body the moment the file is parsed) are disabled, so such a fence throws rather than running. Frontmatter has to parse to a plain YAML object.
|
|
50
74
|
|
|
51
75
|
## Auth fails closed
|
|
52
76
|
|
|
53
|
-
Routes reject unauthenticated traffic by default
|
|
77
|
+
Routes reject unauthenticated traffic by default. If no `AuthFn` in the walk accepts the request, it gets a `401`, and admitting anonymous callers takes an explicit `none()`. The scaffold's `placeholderAuth()` keeps a half-configured app closed in production until you replace it. See [Auth & route protection](../guides/auth-and-route-protection) for the full walk and verifiers.
|
|
54
78
|
|
|
55
79
|
## Pre-production checklist
|
|
56
80
|
|
|
@@ -75,5 +99,5 @@ Before exposing an agent to real traffic:
|
|
|
75
99
|
|
|
76
100
|
- [Auth & route protection](../guides/auth-and-route-protection): the full auth walk and verifier helpers
|
|
77
101
|
- [Sandbox](../sandbox): backends, network policy, and brokering config
|
|
78
|
-
- [Execution model
|
|
102
|
+
- [Execution model and durability](./execution-model-and-durability): how durable sessions run
|
|
79
103
|
- [Connections](../connections): static-token and OAuth connections
|
|
@@ -7,7 +7,7 @@ Every Eve app speaks the same stable HTTP API to a [durable session](./execution
|
|
|
7
7
|
|
|
8
8
|
## The two handles
|
|
9
9
|
|
|
10
|
-
Two handles do two jobs
|
|
10
|
+
Two handles do two jobs, and mixing them up is the most common mistake. One handle creates and resumes a session; a different one streams and inspects it.
|
|
11
11
|
|
|
12
12
|
- **`continuationToken`**: the resume handle. Use it to send a follow-up message to the same conversation. Owned by the channel.
|
|
13
13
|
- **`sessionId` / `runId`**: the stream-and-inspect handle. Use it to attach to the event stream and watch a run. Owned by the runtime.
|
|
@@ -19,17 +19,17 @@ React, Vue, and Svelte apps reach for [`useEveAgent()`](../guides/frontend/overv
|
|
|
19
19
|
## Start a session
|
|
20
20
|
|
|
21
21
|
```bash
|
|
22
|
-
curl -X POST http://127.0.0.1:
|
|
22
|
+
curl -X POST http://127.0.0.1:3000/eve/v1/session \
|
|
23
23
|
-H 'content-type: application/json' \
|
|
24
24
|
-d '{"message":"Summarize the latest forecast."}'
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
Eve responds right away. The JSON body carries a `sessionId` and a `continuationToken`, and the `x-eve-session-id` header
|
|
27
|
+
Eve responds right away. The JSON body carries a `sessionId` and a `continuationToken`, and the `x-eve-session-id` header names the durable session to stream.
|
|
28
28
|
|
|
29
29
|
## Stream a session
|
|
30
30
|
|
|
31
31
|
```bash
|
|
32
|
-
curl http://127.0.0.1:
|
|
32
|
+
curl http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
The stream is newline-delimited JSON (NDJSON), one event per line:
|
|
@@ -64,6 +64,8 @@ The stream is newline-delimited JSON (NDJSON), one event per line:
|
|
|
64
64
|
|
|
65
65
|
`reasoning.appended` and `message.appended` stream deltas as they arrive, and each one carries both the new delta and the cumulative text for the current block. The finalized block shows up on `message.completed` and `reasoning.completed`, which is the compatibility path for clients that don't render incremental streaming.
|
|
66
66
|
|
|
67
|
+
Note: consider the privacy, confidentiality, and user-experience implications for displaying, storing, or transmitting reasoning events in your application.
|
|
68
|
+
|
|
67
69
|
`message.completed` can fire more than once in a turn: the agent often emits interim assistant text before a tool call. To tell tool-call narration from a terminal reply, check `message.completed.data.finishReason`. `step.completed.data.finishReason` mirrors the step outcome, and usage lives on `step.completed`.
|
|
68
70
|
|
|
69
71
|
A delegated subagent publishes progress on its own child-session stream. The parent only emits `subagent.called` with a `childSessionId`, which a client uses to attach.
|
|
@@ -75,7 +77,7 @@ A delegated subagent publishes progress on its own child-session stream. The par
|
|
|
75
77
|
Once the session is waiting (you'll see `session.waiting`), POST your follow-up to the session endpoint with the stored continuation token:
|
|
76
78
|
|
|
77
79
|
```bash
|
|
78
|
-
curl -X POST http://127.0.0.1:
|
|
80
|
+
curl -X POST http://127.0.0.1:3000/eve/v1/session/<sessionId> \
|
|
79
81
|
-H 'content-type: application/json' \
|
|
80
82
|
-d '{"continuationToken":"<token>","message":"Now send the short version."}'
|
|
81
83
|
```
|
|
@@ -86,10 +88,10 @@ For deterministic ordering, send one follow-up at a time and wait for the next `
|
|
|
86
88
|
|
|
87
89
|
## Reconnect and rewind
|
|
88
90
|
|
|
89
|
-
The stream is durable. Every event is recorded before a step completes, so
|
|
91
|
+
The stream is durable. Every event is recorded before a step completes, so the whole stream is replayable. Pass `startIndex` to reconnect by event count and pick up where you dropped off, or rewind to the start:
|
|
90
92
|
|
|
91
93
|
```bash
|
|
92
|
-
curl "http://127.0.0.1:
|
|
94
|
+
curl "http://127.0.0.1:3000/eve/v1/session/<sessionId>/stream?startIndex=<count>"
|
|
93
95
|
```
|
|
94
96
|
|
|
95
97
|
## Use the client from TypeScript
|
|
@@ -103,7 +105,7 @@ Start with the [TypeScript SDK](../guides/client/overview) guide. It covers basi
|
|
|
103
105
|
`GET /eve/v1/info` returns a JSON inspection snapshot for the running agent: model, instructions, authored and framework tools, skills, channels, schedules, subagents, sandbox, connections, hooks, workflow, and workspace metadata. Local development accepts loopback requests; deployed Vercel targets require the route's OIDC auth.
|
|
104
106
|
|
|
105
107
|
```bash
|
|
106
|
-
curl http://127.0.0.1:
|
|
108
|
+
curl http://127.0.0.1:3000/eve/v1/info
|
|
107
109
|
```
|
|
108
110
|
|
|
109
111
|
The route uses the same default auth chain as the eve channel (`[localDev(), vercelOidc()]`). Locally it answers anonymously; a deployed Vercel target requires a valid OIDC bearer, with a same-project bypass for in-deployment callers. See [auth & route protection](../guides/auth-and-route-protection).
|
|
@@ -117,7 +119,7 @@ Every stream event runs four steps, in this order:
|
|
|
117
119
|
3. **Hooks**: authored [hooks](../guides/hooks) subscribed to the event fire.
|
|
118
120
|
4. **Dynamic resolvers**: [dynamic](../guides/dynamic-capabilities) tool, skill, and instruction resolvers fire, and `ctx.channel.metadata` already holds the freshly projected metadata from step 2.
|
|
119
121
|
|
|
120
|
-
The order
|
|
122
|
+
The order is structural, not incidental. By the time a resolver or hook reads channel metadata, the channel has already updated its state and the projection is current.
|
|
121
123
|
|
|
122
124
|
## What to read next
|
|
123
125
|
|