eve 0.10.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -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/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 +70 -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 +12 -12
- package/docs/legal.md +16 -0
- package/docs/meta.json +1 -0
- package/docs/reference/cli.md +101 -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/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
|
@@ -32,6 +32,7 @@ import { cn } from "@/lib/utils";
|
|
|
32
32
|
import { AgentMessage } from "./agent-message";
|
|
33
33
|
|
|
34
34
|
const AGENT_NAME = "__EVE_INIT_APP_NAME__";
|
|
35
|
+
const BETA_TERMS_HREF = "https://vercel.com/docs/release-phases/public-beta-agreement";
|
|
35
36
|
|
|
36
37
|
type AgentStatus = ReturnType<typeof useEveAgent>["status"];
|
|
37
38
|
|
|
@@ -57,9 +58,19 @@ export function AgentChat() {
|
|
|
57
58
|
return (
|
|
58
59
|
<main className="flex h-dvh flex-col overflow-hidden bg-background text-foreground">
|
|
59
60
|
{isEmpty ? null : (
|
|
60
|
-
<header className="flex h-14 shrink-0 items-center justify-center gap-
|
|
61
|
-
<span className="
|
|
62
|
-
|
|
61
|
+
<header className="flex h-14 shrink-0 items-center justify-center gap-3 pl-4 pr-2">
|
|
62
|
+
<span className="flex min-w-0 items-center gap-2">
|
|
63
|
+
<span className="truncate text-muted-foreground text-sm">{AGENT_NAME}</span>
|
|
64
|
+
<StatusDot status={agent.status} />
|
|
65
|
+
</span>
|
|
66
|
+
<a
|
|
67
|
+
className="rounded-full border border-amber-500/30 px-2 py-0.5 font-medium text-amber-700 text-xs transition-colors hover:bg-amber-500/10 dark:text-amber-300"
|
|
68
|
+
href={BETA_TERMS_HREF}
|
|
69
|
+
rel="noreferrer"
|
|
70
|
+
target="_blank"
|
|
71
|
+
>
|
|
72
|
+
Public preview
|
|
73
|
+
</a>
|
|
63
74
|
</header>
|
|
64
75
|
)}
|
|
65
76
|
|
|
@@ -102,7 +113,19 @@ export function AgentChat() {
|
|
|
102
113
|
: "max-w-3xl shrink-0 pb-6",
|
|
103
114
|
)}
|
|
104
115
|
>
|
|
105
|
-
{isEmpty ?
|
|
116
|
+
{isEmpty ? (
|
|
117
|
+
<div className="flex flex-col items-center gap-3 text-center">
|
|
118
|
+
<h1 className="font-medium text-5xl tracking-tighter">{AGENT_NAME}</h1>
|
|
119
|
+
<a
|
|
120
|
+
className="rounded-full border border-amber-500/30 px-2 py-0.5 font-medium text-amber-700 text-xs transition-colors hover:bg-amber-500/10 dark:text-amber-300"
|
|
121
|
+
href={BETA_TERMS_HREF}
|
|
122
|
+
rel="noreferrer"
|
|
123
|
+
target="_blank"
|
|
124
|
+
>
|
|
125
|
+
Public preview
|
|
126
|
+
</a>
|
|
127
|
+
</div>
|
|
128
|
+
) : null}
|
|
106
129
|
<div className="w-full">{composer}</div>
|
|
107
130
|
</div>
|
|
108
131
|
</main>
|
|
@@ -4,4 +4,4 @@ import { slackChannel } from "eve/channels/slack";
|
|
|
4
4
|
export default slackChannel({
|
|
5
5
|
credentials: connectSlackCredentials(${JSON.stringify(e)}),
|
|
6
6
|
});
|
|
7
|
-
`}function renderWebAppTemplate(e,t
|
|
7
|
+
`}function renderWebAppTemplate(e,t){return e.replaceAll(`__EVE_INIT_APP_NAME__`,t).replaceAll(`__EVE_INIT_WITH_EVE_OPTIONS__`,``)}function withWebVercelServices(e){let t=JSON.parse(e);if(!isJsonObject(t))throw Error(`${WEB_VERCEL_JSON_PATH} must contain a JSON object.`);let n=t.experimentalServices;if(n!==void 0&&!isJsonObject(n))throw Error(`${WEB_VERCEL_JSON_PATH} experimentalServices must contain a JSON object.`);let r={...t,$schema:typeof t.$schema==`string`?t.$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:{...n,web:n?.web??WEB_DEFAULT_VERCEL_SERVICES.web,eve:n?.eve??WEB_DEFAULT_VERCEL_SERVICES.eve}};return JSON.stringify(t)===JSON.stringify(r)?e:`${JSON.stringify(r,null,2)}\n`}async function ensureWebVercelServices(e){if(!await pathExists(e))return await writeTextFile(e,`${JSON.stringify({$schema:WEB_VERCEL_JSON_SCHEMA,experimentalServices:WEB_DEFAULT_VERCEL_SERVICES},null,2)}\n`,{force:!0}),`written`;let t=await readFile(e,`utf8`),i=withWebVercelServices(t);return i===t?`skipped`:(await writeFile(e,i,`utf8`),`written`)}async function findCompetingNextConfigFiles(e){let t=[];for(let r of WEB_COMPETING_NEXT_CONFIG_PATHS){let i=join(e,r);await pathExists(i)&&t.push(i)}return t}async function ensureChannel(e){switch(e.kind){case`slack`:return ensureSlackChannel({...e,kind:`slack`});case`web`:return ensureWebChannel({...e,kind:`web`})}}async function ensureWebChannel(t){let i=join(t.projectRoot,`package.json`),a=await pathExists(join(t.projectRoot,`app/page.tsx`));if(!t.force&&await isNextJsProject(t.projectRoot))return{kind:`web`,action:`skipped`,skipReason:`nextjs-project`,filesWritten:[],filesSkipped:[i],packageJsonUpdated:[]};let o=await patchWebPackageJson(i,resolveWebPackageVersions(t.webPackageVersions)),s=[],l=[],u=[],d=[],m=basename(resolve(t.projectRoot));if(t.configureVercelServices??!0){let e=join(t.projectRoot,WEB_VERCEL_JSON_PATH);await ensureWebVercelServices(e)===`written`?s.push(e):d.push(e)}let h=await getPackageManagerStrategy(t.packageManager??`pnpm`).applyProjectConfiguration(t.projectRoot);s.push(...h.filesWritten),d.push(...h.filesSkipped);for(let[e,i]of Object.entries(WEB_APP_TEMPLATE_FILES)){let a=join(t.projectRoot,e);if(e===`agent/channels/eve.ts`&&!t.force&&await pathExists(a)){d.push(a);continue}let o=await pathExists(a);await writeTextFile(a,renderWebAppTemplate(i,m),{force:!0}),s.push(a),o&&l.push(a)}u.push(...await findCompetingNextConfigFiles(t.projectRoot));let g={kind:`web`,action:a?`overwritten`:`created`,filesWritten:s,filesSkipped:d,packageJsonUpdated:o.mutations};return l.length>0&&(g.filesOverwritten=l),u.length>0&&(g.competingNextConfigFiles=u),o.nodeEngineOverride!==void 0&&(g.nodeEngineOverride=o.nodeEngineOverride),g}async function ensureSlackChannel(e){let t=join(e.projectRoot,`agent/channels/slack.ts`),i=await pathExists(t);if(!e.force&&i)return{kind:`slack`,action:`skipped`,filesWritten:[],filesSkipped:[t],packageJsonUpdated:[]};let o=resolveVersionToken(`connectPackageVersion`,e.connectPackageVersion??`0.2.2`),s=await ensurePackageDependency(join(e.projectRoot,`package.json`),`@vercel/connect`,o),c=e.slackConnectorSlug??await deriveSlackConnectorSlug(e.projectRoot);await writeTextFile(t,buildSlackTemplate(e.slackConnectorUid??`slack/${c}`),{force:e.force});let l={kind:`slack`,action:i?`overwritten`:`created`,filesWritten:[t],filesSkipped:[],packageJsonUpdated:s,slackConnectorSlug:c};return i&&(l.filesOverwritten=[t]),l}async function listAuthoredChannels(e){let t=join(e,`agent/channels`),n;try{n=await readdir(t,{withFileTypes:!0})}catch(e){if(e.code===`ENOENT`)return[];throw e}let r=[];for(let e of n){if(e.isFile()){let t=getSupportedModuleBaseName(e.name);t!==null&&r.push(t);continue}if(e.isDirectory())try{(await readdir(join(t,e.name))).some(e=>matchesSupportedModuleBaseName(e,`connection`))&&r.push(e.name)}catch{}}return r.sort()}export{DEFAULT_SLACK_CONNECTOR_SLUG,SLACK_CHANNEL_DEFAULT_ROUTE,deriveSlackConnectorSlug,ensureChannel,isNextJsProject,listAuthoredChannels,normalizeSlackConnectorSlug};
|
package/docs/README.md
CHANGED
|
@@ -10,6 +10,20 @@ Important naming note:
|
|
|
10
10
|
- The current published package name is `eve`.
|
|
11
11
|
- The CLI binary is `eve`.
|
|
12
12
|
|
|
13
|
+
## Legal and safeguards
|
|
14
|
+
|
|
15
|
+
Eve is currently a preview and subject to the Vercel beta terms; the framework, APIs, documentation, and behavior may change before general availability.
|
|
16
|
+
|
|
17
|
+
As the deployer, it is your responsibility to ensure your agent complies with applicable laws.
|
|
18
|
+
|
|
19
|
+
You are responsible for configuring approval policies, tool restrictions, connection scopes, route/session authorization, sandbox controls, telemetry exports, and other safeguards appropriate for your use case.
|
|
20
|
+
|
|
21
|
+
Before using Eve with non-public, sensitive, regulated, or production data, review which default tools, custom tools, MCP tools, shell/file/web tools, connected services, subagents, schedules, and external actions are available to the agent.
|
|
22
|
+
|
|
23
|
+
Require human approval or other safeguards for sensitive, irreversible, regulated, financial, healthcare, employment, housing, legal, safety-impacting, user-impacting, or external side-effecting actions.
|
|
24
|
+
|
|
25
|
+
Unless you configure stricter controls, Eve agents may operate with permissive settings, including tool execution without human approval where approval is omitted and sandbox network egress that is not deny-all. Do not rely on model behavior alone to prevent sensitive or irreversible actions.
|
|
26
|
+
|
|
13
27
|
Casing convention:
|
|
14
28
|
|
|
15
29
|
- Use Title Case for page `title` frontmatter and `meta.json` section titles (Fumadocs renders the page `title` as both the sidebar entry and the `<h1>`, so one casing covers both) — e.g. `Execution Model & Durability`, `Dynamic Capabilities`, `Build an Agent`.
|
|
@@ -30,14 +44,14 @@ Read in this order:
|
|
|
30
44
|
9. [Connections](./connections.mdx)
|
|
31
45
|
10. [Sandboxes](./sandbox.mdx)
|
|
32
46
|
11. [Channels](./channels/overview.mdx)
|
|
33
|
-
12. [Session Context](./
|
|
47
|
+
12. [Session Context](./reference/typescript-api.md)
|
|
34
48
|
13. [Sessions And Streaming](./concepts/sessions-runs-and-streaming.md)
|
|
35
|
-
14. [TypeScript SDK](./
|
|
49
|
+
14. [TypeScript SDK](./clients/typescript-sdk/overview.mdx)
|
|
36
50
|
15. [Subagents](./subagents.mdx)
|
|
37
51
|
16. [Schedules](./schedules.mdx)
|
|
38
52
|
17. [Evals](./evals/overview.mdx)
|
|
39
|
-
18. [Auth And Route Protection](./
|
|
40
|
-
19. [Vercel Deployment](./
|
|
53
|
+
18. [Auth And Route Protection](./develop/auth-and-route-protection.md)
|
|
54
|
+
19. [Vercel Deployment](./develop/deployment.md)
|
|
41
55
|
20. [CLI, Build, And Debugging](./reference/cli.md)
|
|
42
56
|
|
|
43
57
|
## The public mental model
|
|
@@ -90,5 +104,5 @@ That is why Eve exposes two identifiers:
|
|
|
90
104
|
|
|
91
105
|
## Good companions in this repo
|
|
92
106
|
|
|
93
|
-
- Weather-focused smoke/dev fixture: [`../../apps/fixtures/weather-
|
|
107
|
+
- Weather-focused smoke/dev fixture: [`../../apps/fixtures/weather-fixture`](../../apps/fixtures/weather-fixture)
|
|
94
108
|
- Public API source of truth: [`../../packages/eve/src/public/index.ts`](../../packages/eve/src/public/index.ts)
|
package/docs/agent-config.md
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "agent.ts"
|
|
3
|
-
description: "
|
|
3
|
+
description: "Set the agent's runtime config in agent.ts with defineAgent, including the model and compaction."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
An agent's `agent.ts` calls `defineAgent` (from `eve`) to set its runtime config.
|
|
7
7
|
|
|
8
|
-
##
|
|
8
|
+
## Set the model
|
|
9
9
|
|
|
10
10
|
A typical config selects a model:
|
|
11
11
|
|
|
@@ -20,7 +20,7 @@ export default defineAgent({
|
|
|
20
20
|
The root `agent.ts` can be omitted when no runtime config is needed. In that case, Eve defaults
|
|
21
21
|
to `anthropic/claude-sonnet-4.6`. When `agent.ts` is present, `model` is required.
|
|
22
22
|
|
|
23
|
-
`model`
|
|
23
|
+
`model` accepts a gateway model id string, which routes through the [Vercel AI Gateway](https://vercel.com/docs/ai-gateway). To call a provider directly and configure the model in code, pass a provider-authored `LanguageModel`:
|
|
24
24
|
|
|
25
25
|
```ts title="agent/agent.ts"
|
|
26
26
|
import { anthropic } from "@ai-sdk/anthropic";
|
|
@@ -31,9 +31,11 @@ export default defineAgent({
|
|
|
31
31
|
});
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
+
Model use is subject to the terms, data-processing commitments, retention behavior, and available controls of the selected provider and routing path. Review the [AI Gateway model catalog](https://vercel.com/ai-gateway/models) for gateway-routed models, and review the provider's terms when you configure a direct `LanguageModel`.
|
|
35
|
+
|
|
34
36
|
## Compaction
|
|
35
37
|
|
|
36
|
-
Compaction summarizes older turns as you approach the context window. It
|
|
38
|
+
Compaction summarizes older turns as you approach the context window. It's on by default, so you only tune when it kicks in. Lower `thresholdPercent` to compact sooner:
|
|
37
39
|
|
|
38
40
|
```ts title="agent/agent.ts"
|
|
39
41
|
export default defineAgent({
|
|
@@ -46,25 +48,20 @@ export default defineAgent({
|
|
|
46
48
|
|
|
47
49
|
See [Default harness](./concepts/default-harness#compaction) for how the loop applies it.
|
|
48
50
|
|
|
49
|
-
## Other fields
|
|
50
|
-
|
|
51
|
-
`defineAgent` takes a few more fields. For every field and its type, see the [TypeScript API](./reference/typescript-api).
|
|
52
|
-
|
|
53
|
-
### `modelOptions`
|
|
54
|
-
|
|
55
|
-
Provider option overrides forwarded to the model call.
|
|
56
|
-
|
|
57
|
-
### `experimental`
|
|
58
|
-
|
|
59
|
-
Opt-in flags that can change or disappear in any release, so treat them as unstable. The main one is `codeMode`, which routes executable tools through a sandboxed code-execution wrapper.
|
|
51
|
+
## Other defineAgent fields
|
|
60
52
|
|
|
61
|
-
|
|
53
|
+
`defineAgent` takes a few more fields, all optional. For the exported types, see the [TypeScript API](./reference/typescript-api).
|
|
62
54
|
|
|
63
|
-
|
|
55
|
+
| Field | Type | Default | Description |
|
|
56
|
+
| -------------- | --------------------------------------- | ----------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
57
|
+
| `modelOptions` | `AgentModelOptionsDefinition` | none | Provider option overrides forwarded to the model call. |
|
|
58
|
+
| `experimental` | `{ codeMode?: boolean }` | flags unset | Opt-in flags that can change or disappear in any release. Treat them as unstable. `codeMode` routes executable tools through a sandboxed code-execution wrapper, where the model writes JavaScript that calls the tools inside the [sandbox](./sandbox). |
|
|
59
|
+
| `outputSchema` | Standard Schema or a JSON Schema object | none | Structured return type for task-mode runs (a subagent, schedule, or remote job). Interactive conversation turns ignore it unless the client supplies a per-message schema. |
|
|
60
|
+
| `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. |
|
|
64
61
|
|
|
65
|
-
|
|
62
|
+
`codeMode` is experimental and may change or be removed.
|
|
66
63
|
|
|
67
|
-
|
|
64
|
+
`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.
|
|
68
65
|
|
|
69
66
|
## Where adjacent settings live
|
|
70
67
|
|
package/docs/channels/custom.mdx
CHANGED
|
@@ -3,13 +3,13 @@ title: "Custom Channels"
|
|
|
3
3
|
description: "Author custom HTTP and WebSocket channels with routes, events, metadata, continuation tokens, and file uploads."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
When Eve doesn't ship a channel for your surface, you build one. Custom channels
|
|
6
|
+
When Eve doesn't ship a channel for your surface, you build one. Custom channels expose HTTP or WebSocket endpoints, parse incoming requests, start or resume sessions, observe runtime events, and own delivery back to your platform.
|
|
7
7
|
|
|
8
8
|
## File location and identity
|
|
9
9
|
|
|
10
10
|
Custom channels live in `agent/channels/` at the root agent. Local subagents do not declare channels today.
|
|
11
11
|
|
|
12
|
-
The channel file stem becomes the channel id, so `agent/channels/internal-webhook.ts` is addressed as `internal-webhook`.
|
|
12
|
+
The channel file stem becomes the channel id, so `agent/channels/internal-webhook.ts` is addressed as `internal-webhook`. Export the channel definition as the module's default export.
|
|
13
13
|
|
|
14
14
|
## Define a channel
|
|
15
15
|
|
|
@@ -32,7 +32,7 @@ export default defineChannel({
|
|
|
32
32
|
const stream = await session.getEventStream();
|
|
33
33
|
|
|
34
34
|
return new Response(stream, {
|
|
35
|
-
headers: { "content-type": "
|
|
35
|
+
headers: { "content-type": "application/x-ndjson; charset=utf-8" },
|
|
36
36
|
});
|
|
37
37
|
}),
|
|
38
38
|
],
|
|
@@ -44,14 +44,16 @@ export default defineChannel({
|
|
|
44
44
|
});
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Declare routes with the `POST()` and `GET()` helpers. Each route handler receives the raw `Request` and a helpers object:
|
|
48
48
|
|
|
49
|
-
- `send(message, { auth, continuationToken, state? })
|
|
50
|
-
- `getSession(sessionId)
|
|
51
|
-
- `
|
|
52
|
-
- `
|
|
49
|
+
- `send(message, { auth, continuationToken, state? })` starts or resumes a session. Returns a `Session`.
|
|
50
|
+
- `getSession(sessionId)` looks up an existing session. The returned `Session` exposes `getEventStream({ startIndex? })` for streaming.
|
|
51
|
+
- `receive(channel, ...)` hands inbound work to a different channel for cross-channel hand-off.
|
|
52
|
+
- `params` holds route parameters extracted from the path pattern.
|
|
53
|
+
- `waitUntil(promise)` extends the request lifetime for background work.
|
|
54
|
+
- `requestIp` is the client IP, or `null` when the host cannot provide it.
|
|
53
55
|
|
|
54
|
-
Event handlers like `"message.completed"` are declared under the `events` key. They receive `(eventData, channel, ctx)`, where `channel` carries platform handles and session continuation operations, and `ctx` is the Eve `SessionContext`.
|
|
56
|
+
Event handlers like `"message.completed"` are declared under the `events` key. They receive `(eventData, channel, ctx)`, where `eventData` is the event payload, `channel` carries platform handles and session continuation operations, and `ctx` is the Eve `SessionContext`. Every channel kind shares this signature. The one exception is `session.failed`, which receives only `(eventData, channel)` with no `ctx`.
|
|
55
57
|
|
|
56
58
|
## WebSocket routes
|
|
57
59
|
|
|
@@ -92,7 +94,7 @@ export default defineChannel({
|
|
|
92
94
|
});
|
|
93
95
|
```
|
|
94
96
|
|
|
95
|
-
The bridge server does not listen on its own port. It receives only upgrade events that matched the Eve route, and only on hosts where Nitro exposes the raw Node upgrade request, socket, and head. Treat it as a compatibility adapter for libraries with server-binding APIs, not
|
|
97
|
+
The bridge server does not listen on its own port. It receives only upgrade events that matched the Eve route, and only on hosts where Nitro exposes the raw Node upgrade request, socket, and head. Treat it as a compatibility adapter for libraries with server-binding APIs, not the primary way to build websocket channels in Eve.
|
|
96
98
|
|
|
97
99
|
## Cross-channel hand-off
|
|
98
100
|
|
|
@@ -135,7 +137,7 @@ Semantics:
|
|
|
135
137
|
|
|
136
138
|
## Channel metadata
|
|
137
139
|
|
|
138
|
-
|
|
140
|
+
A channel can project a subset of its adapter state as metadata, available to instrumentation resolvers, dynamic tool resolvers, and dynamic skill or instruction resolvers. Define a `metadata(state)` function on the channel config:
|
|
139
141
|
|
|
140
142
|
```ts
|
|
141
143
|
import { defineChannel, POST } from "eve/channels";
|
|
@@ -167,8 +169,8 @@ export default defineChannel({
|
|
|
167
169
|
}),
|
|
168
170
|
],
|
|
169
171
|
events: {
|
|
170
|
-
"turn.started"(
|
|
171
|
-
|
|
172
|
+
"turn.started"(eventData, channel) {
|
|
173
|
+
channel.state.internalCounter += 1;
|
|
172
174
|
},
|
|
173
175
|
},
|
|
174
176
|
});
|
|
@@ -190,13 +192,17 @@ slackContinuationToken("C0123ABC", "1800000000.001234"); // "C0123ABC:1800000000
|
|
|
190
192
|
twilioContinuationToken("+15551234567", "+15557654321"); // "+15551234567:+15557654321"
|
|
191
193
|
```
|
|
192
194
|
|
|
193
|
-
Custom channels write their own function that joins the identity fields. The framework
|
|
195
|
+
Custom channels write their own function that joins the identity fields. The framework derives nothing for you; the channel owns its token format.
|
|
194
196
|
|
|
195
|
-
When the identity that should address a session is not known until later, the channel can re-key the parked session by calling `
|
|
197
|
+
When the identity that should address a session is not known until later, the channel can re-key the parked session by calling `session.setContinuationToken(...)`. Pass the channel-local raw token; the runtime preserves the current channel namespace.
|
|
198
|
+
|
|
199
|
+
The `context(state, session)` config option builds the per-step `channel` argument handed to every event handler. It receives the channel's live adapter `state` and a `SessionHandle`, and returns the channel-owned context (thread handles, API clients, late-bound callbacks). The framework injects [`ChannelSessionOps`](#define-a-channel) and passes the result as the second positional argument to each handler. Closing over `session` lets the factory register callbacks that re-key the session later. State mutations made through the returned context are written back to adapter state.
|
|
196
200
|
|
|
197
201
|
```ts
|
|
198
202
|
import { defineChannel } from "eve/channels";
|
|
199
203
|
|
|
204
|
+
import { mintRef } from "./refs.js";
|
|
205
|
+
|
|
200
206
|
defineChannel<{ ref: string | null }>({
|
|
201
207
|
state: { ref: null },
|
|
202
208
|
context(state, session) {
|
|
@@ -209,8 +215,8 @@ defineChannel<{ ref: string | null }>({
|
|
|
209
215
|
};
|
|
210
216
|
},
|
|
211
217
|
events: {
|
|
212
|
-
"message.completed"(
|
|
213
|
-
if (!
|
|
218
|
+
"message.completed"(eventData, channel) {
|
|
219
|
+
if (!channel.state.ref) channel.registerAnchor(mintRef());
|
|
214
220
|
},
|
|
215
221
|
},
|
|
216
222
|
routes: [
|
|
@@ -264,7 +270,7 @@ defineChannel({
|
|
|
264
270
|
});
|
|
265
271
|
```
|
|
266
272
|
|
|
267
|
-
The `URL` object survives the queue boundary as a string and is reconstituted inside the workflow step. The staging pipeline calls `fetchFile(url)
|
|
273
|
+
The `URL` object survives the queue boundary as a string and is reconstituted inside the workflow step. The staging pipeline calls `fetchFile` with the URL serialized as a string (the URL's `href`), which is why the example matches on `url.startsWith(...)`. Return bytes to stage the file to the sandbox, or `null` to let the URL pass through to the model provider.
|
|
268
274
|
|
|
269
275
|
The framework handles staging bytes to the sandbox, enforcing upload policy, hydrating files for the model call, and reconstituting `URL` objects after queue serialization.
|
|
270
276
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Discord"
|
|
3
|
-
description: "Reach your agent from Discord HTTP Interactions
|
|
3
|
+
description: "Reach your agent from Discord HTTP Interactions, including slash commands, components, and modals."
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Discord channel wires your agent into Discord's HTTP Interactions
|
|
7
|
+
The Discord channel wires your agent into Discord's HTTP Interactions, including slash and application commands, message components, and modal submissions. Discord enforces a three-second ACK deadline, so the channel verifies the Ed25519 signature headers, acknowledges the command right away, and runs the Eve work in the background. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Add the channel
|
|
10
10
|
|
|
@@ -20,11 +20,11 @@ DISCORD_APPLICATION_ID=... # edits the deferred response and sends followups
|
|
|
20
20
|
DISCORD_BOT_TOKEN=... # proactive messages + fallback + typing indicators
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
|
|
23
|
+
To skip env vars, pass the same values through `credentials: { applicationId, botToken, publicKey }`. The route is `POST /eve/v1/discord` by default. Paste that public URL into your Discord application's Interactions Endpoint URL.
|
|
24
24
|
|
|
25
25
|
## Register a command
|
|
26
26
|
|
|
27
|
-
Registering commands is on you, not the channel. Use Discord's API or the Developer Portal.
|
|
27
|
+
Registering commands is on you, not the channel. Use Discord's API or the Developer Portal. A string option named `message` lines up with Eve's default prompt extraction:
|
|
28
28
|
|
|
29
29
|
```bash
|
|
30
30
|
curl -X PUT "https://discord.com/api/v10/applications/$DISCORD_APPLICATION_ID/commands" \
|
|
@@ -35,9 +35,11 @@ curl -X PUT "https://discord.com/api/v10/applications/$DISCORD_APPLICATION_ID/co
|
|
|
35
35
|
|
|
36
36
|
Use guild commands during development for faster propagation.
|
|
37
37
|
|
|
38
|
-
##
|
|
38
|
+
## How the channel handles messages
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
### Dispatch
|
|
41
|
+
|
|
42
|
+
`onCommand(ctx, interaction)` decides whether to dispatch and under what `auth`. Return `{ auth }` to proceed or `null` to drop the interaction. By default, auth comes from the invoking user. Event handlers receive `(eventData, channel, ctx)`, with Discord platform handles on `channel.discord`:
|
|
41
43
|
|
|
42
44
|
```ts
|
|
43
45
|
import { discordChannel } from "eve/channels/discord";
|
|
@@ -52,21 +54,31 @@ export default discordChannel({
|
|
|
52
54
|
},
|
|
53
55
|
}),
|
|
54
56
|
events: {
|
|
55
|
-
"message.completed"(
|
|
56
|
-
if (
|
|
57
|
-
if (
|
|
57
|
+
"message.completed"(eventData, channel, ctx) {
|
|
58
|
+
if (eventData.finishReason === "tool-calls") return;
|
|
59
|
+
if (eventData.message) channel.discord.post(eventData.message);
|
|
58
60
|
},
|
|
59
61
|
},
|
|
60
62
|
});
|
|
61
63
|
```
|
|
62
64
|
|
|
63
|
-
|
|
65
|
+
### Delivery
|
|
66
|
+
|
|
67
|
+
The default `message.completed` handler edits the deferred response for the first reply and sends followups after that. If the interaction token is rejected, it falls back to a bot-authenticated channel message. Long text is split to Discord's 2000-char limit, and generated messages default to `allowed_mentions: { parse: [] }`.
|
|
68
|
+
|
|
69
|
+
Typing fires on `turn.started` and `actions.requested`, but only when a bot token is present. In custom hooks, call `channel.discord.startTyping()` yourself.
|
|
70
|
+
|
|
71
|
+
### Human-in-the-loop (HITL)
|
|
72
|
+
|
|
73
|
+
HITL renders as Discord components. Confirmations and options become buttons, `display: "select"` becomes a string select, and freeform input becomes a button that opens a modal. When the user responds, the parked session (paused awaiting input) resumes.
|
|
74
|
+
|
|
75
|
+
### Proactive sessions
|
|
64
76
|
|
|
65
|
-
|
|
77
|
+
Start a session without an inbound interaction through `receive(discord, { message, target, auth })` from a schedule `run` handler, or `args.receive(discord, ...)` from another channel. The proactive target shape is `{ channelId, conversationId?, initialMessage? }`. Either path needs `DISCORD_BOT_TOKEN`.
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
### Attachments
|
|
68
80
|
|
|
69
|
-
|
|
81
|
+
Inbound file attachments are not supported on this channel today.
|
|
70
82
|
|
|
71
83
|
## What to read next
|
|
72
84
|
|
package/docs/channels/eve.mdx
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Eve"
|
|
3
|
-
description: "The default HTTP API for an agent
|
|
3
|
+
description: "The default HTTP API for an agent, covering session routes, auth, and customization."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
The Eve channel is the framework's default HTTP API. It's what the terminal UI, [`useEveAgent`](../guides/frontend/overview), `curl`, and any SDK client talk to when they start sessions, send messages, and stream events. `eveChannel()` mounts the canonical session routes under `/eve/v1/session*`, and they are enabled by default even when `agent/channels/eve.ts` does not exist.
|
|
7
7
|
|
|
8
|
-
Reach for it when something needs HTTP access to your agent
|
|
8
|
+
Reach for it when something needs HTTP access to your agent, including local tooling, a browser frontend, the terminal UI, or another API client. Most apps never write this file. Add `agent/channels/eve.ts` only to override the defaults, usually the route auth policy.
|
|
9
9
|
|
|
10
10
|
```ts title="agent/channels/eve.ts"
|
|
11
11
|
import { eveChannel } from "eve/channels/eve";
|
|
@@ -18,18 +18,36 @@ export default eveChannel({
|
|
|
18
18
|
|
|
19
19
|
## Routes
|
|
20
20
|
|
|
21
|
-
The channel exposes
|
|
21
|
+
The channel exposes routes that create sessions, send follow-ups, and stream events:
|
|
22
22
|
|
|
23
23
|
- `GET /eve/v1/health`
|
|
24
24
|
- `POST /eve/v1/session` (start a session)
|
|
25
25
|
- `POST /eve/v1/session/:sessionId` (send a follow-up)
|
|
26
26
|
- `GET /eve/v1/session/:sessionId/stream` (stream events, NDJSON)
|
|
27
27
|
|
|
28
|
-
|
|
28
|
+
Start a session with a minimal body. The response returns `sessionId` and the `continuationToken` you reuse for follow-ups:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
curl -X POST https://<deployment>/eve/v1/session \
|
|
32
|
+
-H "Content-Type: application/json" \
|
|
33
|
+
-d '{"message":"What is the weather in Paris?"}'
|
|
34
|
+
# {"continuationToken":"eve:7f3c...","ok":true,"sessionId":"ses_01h..."}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Stream that session's events as newline-delimited JSON (`application/x-ndjson; charset=utf-8`), one event object per line:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
curl -N https://<deployment>/eve/v1/session/ses_01h.../stream
|
|
41
|
+
# {"type":"turn.started",...}
|
|
42
|
+
# {"type":"text.delta","delta":"It is "}
|
|
43
|
+
# {"type":"message.completed",...}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
See [Sessions, runs & streaming](../concepts/sessions-runs-and-streaming) for the full request and stream flow, including the complete event set.
|
|
29
47
|
|
|
30
48
|
## Authentication
|
|
31
49
|
|
|
32
|
-
The `auth` option decides who can call these routes. The built-in helpers
|
|
50
|
+
The `auth` option decides who can call these routes. The built-in helpers cover development and trusted infrastructure:
|
|
33
51
|
|
|
34
52
|
- `localDev()` accepts requests during local development.
|
|
35
53
|
- `vercelOidc()` lets the local CLI reach a deployed agent, and lets other internal deployments from your team call it.
|
|
@@ -58,7 +76,7 @@ export default eveChannel({
|
|
|
58
76
|
};
|
|
59
77
|
},
|
|
60
78
|
events: {
|
|
61
|
-
"message.completed"(
|
|
79
|
+
"message.completed"(eventData, channel, ctx) {
|
|
62
80
|
console.log("Eve response completed", {
|
|
63
81
|
continuationToken: channel.continuationToken,
|
|
64
82
|
sessionId: ctx.session.id,
|
package/docs/channels/github.mdx
CHANGED
|
@@ -4,7 +4,7 @@ description: "Reach your agent from GitHub App webhooks, with @mention dispatch,
|
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The GitHub channel lets the agent work directly on a repository. Someone `@mentions` it in an issue, PR, or review comment, and the agent answers right there in the thread, with the PR diff already in context and the repo checked out into the sandbox.
|
|
7
|
+
The GitHub channel lets the agent work directly on a repository. Someone `@mentions` it in an issue, PR, or review comment, and the agent answers right there in the thread, with the PR diff already in context and the repo checked out into the sandbox. It takes GitHub App webhooks at `/eve/v1/github`, checks the signature, derives auth from whoever triggered the event, and replies on the native surface. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Add the channel
|
|
10
10
|
|
|
@@ -21,26 +21,31 @@ export default githubChannel({
|
|
|
21
21
|
});
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
-
Every field falls back to an env var
|
|
24
|
+
Every field falls back to an env var, so you can drop the `credentials` block entirely once these are set:
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
```bash
|
|
27
|
+
GITHUB_APP_ID=... # GitHub App id
|
|
28
|
+
GITHUB_APP_PRIVATE_KEY=... # GitHub App private key (PEM)
|
|
29
|
+
GITHUB_WEBHOOK_SECRET=... # verifies the webhook signature
|
|
30
|
+
GITHUB_APP_SLUG=... # supplies botName when it is not set in config
|
|
31
|
+
```
|
|
27
32
|
|
|
28
|
-
|
|
33
|
+
`appId`/`privateKey`/`webhookSecret` also take a lazy resolver function if you'd rather fetch them on demand.
|
|
29
34
|
|
|
30
|
-
|
|
35
|
+
Point the GitHub App webhook URL at `https://<deployment>/eve/v1/github`. For mention-driven turns, subscribe to `issue_comment` and `pull_request_review_comment`; add `issues` / `pull_request` if you wire up their opt-in hooks. A comment that `@mention`s `botName` starts a turn.
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
## How the channel handles messages
|
|
33
38
|
|
|
34
|
-
|
|
39
|
+
### Dispatch
|
|
35
40
|
|
|
36
|
-
|
|
41
|
+
Inbound hooks return `{ auth }` to dispatch, or `null` to ignore. Use `defaultGitHubAuth(ctx)` to derive auth from the actor.
|
|
37
42
|
|
|
38
43
|
```ts
|
|
39
44
|
import { defaultGitHubAuth, githubChannel } from "eve/channels/github";
|
|
40
45
|
|
|
41
46
|
export default githubChannel({
|
|
42
47
|
botName: "my-agent",
|
|
43
|
-
// Replaces the @mention gate. ctx.conversation.kind
|
|
48
|
+
// Replaces the @mention gate. ctx.conversation.kind is "issue", "pull_request", or "review_thread".
|
|
44
49
|
onComment: (ctx, comment) => ({ auth: defaultGitHubAuth(ctx) }),
|
|
45
50
|
// Opt in; no default dispatch on these events.
|
|
46
51
|
onIssue: (ctx, issue) => (issue.action === "opened" ? { auth: defaultGitHubAuth(ctx) } : null),
|
|
@@ -48,7 +53,33 @@ export default githubChannel({
|
|
|
48
53
|
});
|
|
49
54
|
```
|
|
50
55
|
|
|
51
|
-
|
|
56
|
+
### Delivery
|
|
57
|
+
|
|
58
|
+
When a turn starts, the channel adds an `eyes` reaction to the triggering comment (turn this off with `progress: { reactions: false }`). The reply comes back as a comment, on the timeline or in the review thread, and splits across multiple comments when it runs long. If the turn fails, you get a short error comment carrying an error id.
|
|
59
|
+
|
|
60
|
+
### Human-in-the-loop (HITL)
|
|
61
|
+
|
|
62
|
+
GitHub comments have no interactive button or card affordance. A human-in-the-loop (HITL) `input.requested` event is posted as a comment prompt, and the user's reply comment maps back to the pending input request. Declare an `events["input.requested"]` handler to customize the prompt.
|
|
63
|
+
|
|
64
|
+
### Proactive sessions
|
|
65
|
+
|
|
66
|
+
Start a session without an inbound mention through `receive(github, { message, target, auth })` from a schedule `run` handler, or `args.receive(github, ...)` from another channel. The target requires `owner`, `repo`, and exactly one of `issueNumber` or `pullRequestNumber`.
|
|
67
|
+
|
|
68
|
+
### Attachments
|
|
69
|
+
|
|
70
|
+
Inbound file attachments are not supported on this channel today. Repository contents reach the agent through the sandbox checkout below, not as message attachments.
|
|
71
|
+
|
|
72
|
+
### PR context
|
|
73
|
+
|
|
74
|
+
Summon the agent on a PR and it always sees the diff. PR metadata and the changed-file patch land in `context`. Large generated files still appear in the list, but their patch body is dropped; add more paths to the skip list with `pullRequestContext.excludedFiles`.
|
|
75
|
+
|
|
76
|
+
### Sandbox checkout
|
|
77
|
+
|
|
78
|
+
Before the first model call, every triggered turn checks out the relevant ref into the sandbox, so `read_file`/`glob`/`grep`/`bash` all run against the real tree. The installation token never enters the sandbox. `git` fetches a token-free URL, and the platform injects auth on egress at the firewall. That requires a firewall-capable backend (Vercel); the local backend skips checkout. Within a session, checkout is incremental across turns.
|
|
79
|
+
|
|
80
|
+
### Arbitrary API calls
|
|
81
|
+
|
|
82
|
+
For anything the channel doesn't wrap, call `ctx.github.request({ method, path, body })`. It carries installation-token auth.
|
|
52
83
|
|
|
53
84
|
## What to read next
|
|
54
85
|
|