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
package/docs/channels/linear.mdx
CHANGED
|
@@ -4,7 +4,7 @@ description: "Reach your agent through Linear Agent Sessions, with native Agent
|
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Linear channel uses Linear's Agent Session surface rather than ordinary comments. Users delegate work to the agent from Linear, Eve receives `AgentSessionEvent` webhooks at `/eve/v1/linear`, and the channel replies with native Agent Activities
|
|
7
|
+
The Linear channel uses Linear's Agent Session surface rather than ordinary comments. Users delegate work to the agent from Linear, Eve receives `AgentSessionEvent` webhooks at `/eve/v1/linear`, and the channel replies with native Agent Activities, including `thought`, `action`, `elicitation`, `response`, and `error`. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Add the channel
|
|
10
10
|
|
|
@@ -24,7 +24,7 @@ LINEAR_AGENT_ACCESS_TOKEN=lin_api_... # posts Agent Activities and creates proac
|
|
|
24
24
|
LINEAR_WEBHOOK_SECRET=... # verifies Linear-Signature
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
The sample passes credentials explicitly. To rely on env vars instead, drop the `credentials` block: the access token falls back to `LINEAR_AGENT_ACCESS_TOKEN`, `LINEAR_ACCESS_TOKEN`, `LINEAR_API_KEY`, or `LINEAR_API_TOKEN`, and the webhook secret falls back to `LINEAR_WEBHOOK_SECRET`. Both fields also accept lazy resolver functions.
|
|
28
28
|
|
|
29
29
|
## Configure Linear
|
|
30
30
|
|
|
@@ -38,25 +38,31 @@ For Linear's agent surface, configure the OAuth authorize URL with `actor=app` a
|
|
|
38
38
|
|
|
39
39
|
Linear sends webhook signatures in `Linear-Signature`; Eve verifies the HMAC over the raw body and rejects stale `webhookTimestamp` values. If a trusted gateway verifies Linear before the request reaches Eve, pass `credentials.webhookVerifier` instead of a webhook secret.
|
|
40
40
|
|
|
41
|
-
##
|
|
41
|
+
## How the channel handles messages
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
### Dispatch
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
The default hook dispatches `created` and `prompted` Agent Session events. Eve adds a Linear context block with the agent session, issue, comment, and organization identifiers, then continues the same session with `agent-session:<id>`.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
### Delivery
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
Turn start posts an ephemeral `thought`, tool calls post ephemeral `action` activities, final assistant text posts a durable `response`, and failures post `error` activities. When the model emits text before a tool call, Eve buffers the first non-empty line and uses it as the next ephemeral Linear `thought`, mirroring Slack's typing-status behavior.
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
### Human-in-the-loop (HITL)
|
|
52
52
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
Human-in-the-loop (HITL) input requests render as Linear `elicitation` activities. When the user replies to the Agent Session, the channel resolves that prompt back to the pending Eve input request and resumes with `inputResponses`.
|
|
54
|
+
|
|
55
|
+
### Proactive sessions
|
|
56
|
+
|
|
57
|
+
Start a session without an inbound webhook with `receive(linear, { target })`. See [Proactive sessions](#proactive-sessions) below for the target shape and examples.
|
|
58
|
+
|
|
59
|
+
### Attachments
|
|
60
|
+
|
|
61
|
+
Inbound file attachments are not supported on this channel today.
|
|
62
|
+
|
|
63
|
+
### API handle
|
|
64
|
+
|
|
65
|
+
Event handlers receive `channel.linear`, which exposes `createActivity`, `listActivities`, and `updateSession` for custom Agent Activity delivery and Agent Session metadata.
|
|
60
66
|
|
|
61
67
|
## Custom hooks
|
|
62
68
|
|
|
@@ -73,7 +79,7 @@ export default linearChannel({
|
|
|
73
79
|
});
|
|
74
80
|
```
|
|
75
81
|
|
|
76
|
-
Restrict dispatch to a subset of Linear teams or projects by inspecting `event.agentSession.issue` in `onAgentSession`. Add extra context by returning `context` alongside auth
|
|
82
|
+
Restrict dispatch to a subset of Linear teams or projects by inspecting `event.agentSession.issue` in `onAgentSession`. Add extra context by returning `context` alongside `auth`.
|
|
77
83
|
|
|
78
84
|
```ts
|
|
79
85
|
import { defaultLinearAuth, linearChannel } from "eve/channels/linear";
|
|
@@ -96,16 +102,16 @@ import { linearChannel } from "eve/channels/linear";
|
|
|
96
102
|
|
|
97
103
|
export default linearChannel({
|
|
98
104
|
events: {
|
|
99
|
-
async "message.completed"(
|
|
100
|
-
if (
|
|
105
|
+
async "message.completed"(eventData, channel) {
|
|
106
|
+
if (eventData.finishReason === "tool-calls" || !eventData.message) return;
|
|
101
107
|
await channel.linear.createActivity({
|
|
102
|
-
body: `Done.\n\n${
|
|
108
|
+
body: `Done.\n\n${eventData.message}`,
|
|
103
109
|
type: "response",
|
|
104
110
|
});
|
|
105
111
|
},
|
|
106
|
-
async "input.requested"(
|
|
112
|
+
async "input.requested"(eventData, channel) {
|
|
107
113
|
await channel.linear.createActivity({
|
|
108
|
-
body:
|
|
114
|
+
body: eventData.requests.map((request) => request.prompt).join("\n\n"),
|
|
109
115
|
type: "elicitation",
|
|
110
116
|
});
|
|
111
117
|
},
|
|
@@ -123,7 +129,7 @@ await channel.linear.updateSession({
|
|
|
123
129
|
|
|
124
130
|
## Proactive sessions
|
|
125
131
|
|
|
126
|
-
Use the channel's `receive` target to continue an existing Agent Session or create one from a Linear issue or root comment.
|
|
132
|
+
Use the channel's `receive` target to continue an existing Agent Session or create one from a Linear issue or root comment. The target accepts an existing `agentSessionId`, or an `issueId` or root `commentId` to create a new session before sending the message. The example below runs from a schedule; a route handler uses the same target shape through its own `receive` helper.
|
|
127
133
|
|
|
128
134
|
```ts
|
|
129
135
|
import { defineSchedule } from "eve/schedules";
|
|
@@ -147,20 +153,7 @@ export default defineSchedule({
|
|
|
147
153
|
});
|
|
148
154
|
```
|
|
149
155
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
await receive(linear, {
|
|
154
|
-
auth: null,
|
|
155
|
-
message: "Post a concise status update with blockers and next actions.",
|
|
156
|
-
target: {
|
|
157
|
-
issueId: "EVE-123",
|
|
158
|
-
initialActivity: "Preparing the status update.",
|
|
159
|
-
},
|
|
160
|
-
});
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
For issue/comment targets, the channel calls Linear's proactive Agent Session mutations before starting the Eve turn. For an existing `agentSessionId`, it skips session creation and only seeds the continuation token.
|
|
156
|
+
For issue or comment targets, the channel calls Linear's proactive Agent Session mutations before starting the Eve turn. For an existing `agentSessionId`, it skips session creation and only seeds the continuation token.
|
|
164
157
|
|
|
165
158
|
## What to read next
|
|
166
159
|
|
|
@@ -3,10 +3,16 @@ title: "Overview"
|
|
|
3
3
|
description: "How users reach your agent: the channel contract, the base Eve HTTP channel, and authoring custom channels."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
A channel is the edge adapter between a platform and your agent
|
|
6
|
+
A channel is the edge adapter between a platform and your agent. It does three things:
|
|
7
|
+
|
|
8
|
+
- Normalizes platform input into a user message.
|
|
9
|
+
- Owns the `continuationToken`, the resume handle for a conversation on that surface.
|
|
10
|
+
- Decides delivery, meaning how, where, and whether a response goes back.
|
|
7
11
|
|
|
8
12
|
Eve ships a base HTTP channel plus first-class platform channels, and you can author your own. Browse the full set in the [Integrations](/integrations) gallery.
|
|
9
13
|
|
|
14
|
+
Each channel has its own provider terms, data flow, auth model, and user-consent expectations. Before sending non-public, sensitive, regulated, or production data through a channel, confirm that the channel provider and your configured scopes, signature checks, route auth, and delivery behavior are appropriate for your use case.
|
|
15
|
+
|
|
10
16
|
## Where channels live
|
|
11
17
|
|
|
12
18
|
Channel files live under `agent/channels/` in the root agent. The file stem is the channel id: `agent/channels/intake.ts` is addressed as `intake`. Export the channel as the module's default export. Local subagents do not declare channels.
|
|
@@ -24,17 +30,17 @@ Scaffold a channel file with `eve channels add` (interactive), or pass a kind: `
|
|
|
24
30
|
|
|
25
31
|
## The Eve HTTP channel (default)
|
|
26
32
|
|
|
27
|
-
Eve's
|
|
33
|
+
The Eve channel is the framework's default HTTP session API, the routes the terminal UI, [`useEveAgent`](../guides/frontend/overview), and `curl` all talk to. It is enabled by default, even with no `agent/channels/eve.ts` file. Add that file only to override the defaults, most often the route auth policy. See [HTTP channel](./eve) for routes, auth, and customization.
|
|
28
34
|
|
|
29
35
|
## Custom channels
|
|
30
36
|
|
|
31
|
-
When Eve doesn't ship a channel for your surface, build one with `defineChannel` from `eve/channels
|
|
37
|
+
When Eve doesn't ship a channel for your surface, build one with `defineChannel` from `eve/channels`. A custom channel declares route handlers (`GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `WS`), an `events` map, and a `send` call inside a handler to start or resume a session. See [Custom channels](./custom) for the full walkthrough, including WebSocket routes, cross-channel hand-off, channel metadata, continuation tokens, and file uploads.
|
|
32
38
|
|
|
33
39
|
## Relationship to the Chat SDK
|
|
34
40
|
|
|
35
41
|
Eve uses the Chat SDK's **card-builder components** (Cards, Buttons, Actions, etc.) for composing rich Slack messages. When you build a card with the [Slack channel](./slack), the underlying primitives come from the Chat SDK and get converted to Slack Block Kit at post time.
|
|
36
42
|
|
|
37
|
-
Eve does **not** use the Chat SDK's runtime. The `Chat`, `Adapter`, and `Thread` primitives are never imported or reachable through Eve's public API. Eve
|
|
43
|
+
Eve does **not** use the Chat SDK's runtime. The `Chat`, `Adapter`, and `Thread` primitives are never imported or reachable through Eve's public API. Eve implements its own channel layer (webhook handling, signature verification, event parsing, and thread management). Building Slack messages works like Chat SDK cards, but wiring a channel means authoring against Eve's `defineChannel(...)` API, not a Chat SDK adapter.
|
|
38
44
|
|
|
39
45
|
## Which channel?
|
|
40
46
|
|
|
@@ -51,6 +57,12 @@ Eve does **not** use the Chat SDK's runtime. The `Chat`, `Adapter`, and `Thread`
|
|
|
51
57
|
| Linear issue delegation and Agent Sessions | [Linear](./linear) |
|
|
52
58
|
| Anything else (internal webhook, WebSocket) | Custom channel (`defineChannel`, above) |
|
|
53
59
|
|
|
60
|
+
## Disclaimer
|
|
61
|
+
|
|
62
|
+
As the deployer, it is your responsibility to ensure your agent complies with applicable laws.
|
|
63
|
+
|
|
64
|
+
Where an Eve agent communicates with people, you may be required to disclose that they are interacting with an automated AI system where law requires it. Eve does not add this disclosure automatically; configure it in your instructions and/or channel responses.
|
|
65
|
+
|
|
54
66
|
## What to read next
|
|
55
67
|
|
|
56
68
|
- [Slack](./slack): the most common platform channel, end to end
|
package/docs/channels/slack.mdx
CHANGED
|
@@ -4,7 +4,7 @@ description: "Reach your agent from Slack app mentions and DMs, with thread anch
|
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Slack channel puts your agent inside a workspace
|
|
7
|
+
The Slack channel puts your agent inside a workspace. It answers `@mentions` and DMs, replies in threads, shows typing indicators, and turns human-in-the-loop (HITL) prompts into buttons. Use it when the conversation should happen where your team already works. Credentials run through [Vercel Connect](../guides/auth-and-route-protection), which handles both the outbound bot token and inbound webhook verification, so there's no `SLACK_BOT_TOKEN` or `SLACK_SIGNING_SECRET` for you to manage. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Set up Connect
|
|
10
10
|
|
|
@@ -17,9 +17,9 @@ vercel connect detach <uid> --yes
|
|
|
17
17
|
vercel connect attach <uid> --triggers --trigger-path /eve/v1/slack --yes
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
`FF_CONNECT_ENABLED=1` turns on the Connect commands, which are feature-flagged in the Vercel CLI today. The `create` step provisions a destination at the default Connect path. `detach` then `attach --trigger-path /eve/v1/slack` re-points the trigger at the Eve Slack route, since Eve does not serve the default Connect path. `--triggers` turns on Slack Event Subscriptions; without it, Slack never delivers `app_mention` or `message.im`. You can also create the client from the [Connect dashboard](https://vercel.com/d?to=/%5Bteam%5D/~/connect&title=Go+to+Connect).
|
|
21
21
|
|
|
22
|
-
## Add the channel
|
|
22
|
+
## Add the channel
|
|
23
23
|
|
|
24
24
|
Scaffold the channel and its dependency with `eve channels add slack`, or set it up by hand:
|
|
25
25
|
|
|
@@ -36,67 +36,94 @@ export default slackChannel({
|
|
|
36
36
|
});
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
`connectSlackCredentials` returns `{ botToken, webhookVerifier }
|
|
39
|
+
`connectSlackCredentials` returns `{ botToken, webhookVerifier }`, keeping token rotation, multi-workspace tenancy, and request verification inside Connect rather than your code. Deploy once the trigger destination and channel file are ready:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
42
|
VERCEL_USE_EXPERIMENTAL_FRAMEWORKS=1 vercel deploy --prod
|
|
43
43
|
```
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
`VERCEL_USE_EXPERIMENTAL_FRAMEWORKS=1` lets the Vercel CLI recognize Eve as a framework during the build. Eve's own setup commands set the same flag.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
## How the channel handles messages
|
|
48
|
+
|
|
49
|
+
### Dispatch
|
|
50
|
+
|
|
51
|
+
Inbound hooks decide whether to dispatch a turn and with what `auth`. Return `{ auth }` to dispatch, `null` to drop, or `{ auth, context }` to inject background into history.
|
|
48
52
|
|
|
49
53
|
- `onAppMention(ctx, message)` handles `app_mention` events. The default derives workspace-scoped auth and posts a `Thinking…` indicator.
|
|
50
54
|
- `onDirectMessage(ctx, message)` handles `message.im` events (needs `im:history` scope). Bot-authored messages and edits are filtered out first.
|
|
51
55
|
- `onInteraction(action, ctx)` handles `block_actions` callbacks not consumed by HITL.
|
|
52
56
|
|
|
53
|
-
|
|
57
|
+
You get the triggering mention by default, but not the earlier replies in the thread. Pull them in with `loadThreadContextMessages` and return them as `context`, which Eve appends to history as user messages the model sees on every later turn. Use `since: "last-agent-reply"` so repeated mentions in one thread inject only what is new:
|
|
54
58
|
|
|
55
59
|
```ts
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const prior = await loadThreadContextMessages(ctx.thread, message, { since: "last-agent-reply" });
|
|
59
|
-
if (prior.length === 0) return { auth };
|
|
60
|
-
const transcript = prior.map((m) => `${m.isMe ? "you" : (m.user ?? "user")}: ${m.markdown}`).join("\n");
|
|
61
|
-
return { auth, context: [`Recent thread messages since your last reply:\n\n${transcript}`] };
|
|
62
|
-
}
|
|
63
|
-
```
|
|
60
|
+
import { defaultSlackAuth, loadThreadContextMessages, slackChannel } from "eve/channels/slack";
|
|
61
|
+
import { connectSlackCredentials } from "@vercel/connect/eve";
|
|
64
62
|
|
|
65
|
-
|
|
63
|
+
export default slackChannel({
|
|
64
|
+
credentials: connectSlackCredentials("slack/my-agent"),
|
|
65
|
+
async onAppMention(ctx, message) {
|
|
66
|
+
const auth = defaultSlackAuth(message, ctx);
|
|
67
|
+
const prior = await loadThreadContextMessages(ctx.thread, message, {
|
|
68
|
+
since: "last-agent-reply",
|
|
69
|
+
});
|
|
70
|
+
if (prior.length === 0) return { auth };
|
|
71
|
+
const transcript = prior
|
|
72
|
+
.map((m) => `${m.isMe ? "you" : (m.user ?? "user")}: ${m.markdown}`)
|
|
73
|
+
.join("\n");
|
|
74
|
+
return { auth, context: [`Recent thread messages since your last reply:\n\n${transcript}`] };
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
```
|
|
66
78
|
|
|
67
|
-
|
|
79
|
+
### Delivery
|
|
68
80
|
|
|
69
|
-
|
|
81
|
+
The default handlers reply in-thread and show progress. Typing indicators post automatically: `Thinking…` on inbound, `Working…` on `turn.started`, tool status on `actions.requested`. Override `onAppMention` or the `events` handlers to customize.
|
|
70
82
|
|
|
71
|
-
|
|
83
|
+
When a session starts without a `threadTs` (say, from a schedule or `receive(slack, ...)`), it anchors on the first agent post, and later posts and mentions resume that same session. Pass `initialMessage` with a `Card` to land a structured anchor first instead. `threadTs` and `initialMessage` are mutually exclusive.
|
|
72
84
|
|
|
73
|
-
|
|
74
|
-
events: {
|
|
75
|
-
"authorization.required"(event, ctx) {
|
|
76
|
-
const userId = ctx.state.triggeringUserId;
|
|
77
|
-
if (!userId || !event.authorization?.url) return;
|
|
78
|
-
return ctx.postDirectMessage(userId, `Sign in to continue: ${event.authorization.url}`);
|
|
79
|
-
},
|
|
80
|
-
},
|
|
81
|
-
```
|
|
85
|
+
The example below overrides `onAppMention` to gate on an authored message and posts the completed reply to the thread. Event handlers receive `(eventData, channel, ctx)`, with Slack platform handles on `channel.thread` and `channel.slack`:
|
|
82
86
|
|
|
83
87
|
```ts
|
|
84
88
|
import { defaultSlackAuth, slackChannel } from "eve/channels/slack";
|
|
89
|
+
import { connectSlackCredentials } from "@vercel/connect/eve";
|
|
85
90
|
|
|
86
91
|
export default slackChannel({
|
|
87
92
|
credentials: connectSlackCredentials("slack/my-agent"),
|
|
88
93
|
onAppMention: (ctx, message) =>
|
|
89
94
|
message.author ? { auth: defaultSlackAuth(message, ctx) } : null,
|
|
90
95
|
events: {
|
|
91
|
-
"message.completed"(
|
|
92
|
-
if (
|
|
93
|
-
if (
|
|
96
|
+
"message.completed"(eventData, channel, ctx) {
|
|
97
|
+
if (eventData.finishReason === "tool-calls") return;
|
|
98
|
+
if (eventData.message) channel.thread.post(eventData.message);
|
|
94
99
|
},
|
|
95
100
|
},
|
|
96
101
|
});
|
|
97
102
|
```
|
|
98
103
|
|
|
99
|
-
|
|
104
|
+
### Human-in-the-loop (HITL)
|
|
105
|
+
|
|
106
|
+
HITL renders as Slack buttons and selects. When the user responds, the parked session (paused awaiting input) resumes.
|
|
107
|
+
|
|
108
|
+
Authorization prompts are private. A sign-in challenge (OAuth URL, device code) is a credential. Anyone who completes it binds their identity to the session's connection. The default `authorization.required` handler delivers the challenge ephemerally to the triggering user, device code included, and posts a public link-free status only when it has no user to target. The handler receives a private-delivery context with `postEphemeral`, `postDirectMessage` (needs the `im:write` scope), and `state`. There is, intentionally, no public `post` and no raw API access.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
events: {
|
|
112
|
+
"authorization.required"(eventData, channel) {
|
|
113
|
+
const userId = channel.state.triggeringUserId;
|
|
114
|
+
if (!userId || !eventData.authorization?.url) return;
|
|
115
|
+
return channel.postDirectMessage(userId, `Sign in to continue: ${eventData.authorization.url}`);
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### Proactive sessions
|
|
121
|
+
|
|
122
|
+
Start a session without an inbound message through `receive(slack, { message, target, auth })` from a schedule `run` handler, or `args.receive(slack, ...)` from another channel. The proactive target shape is `{ channelId }`.
|
|
123
|
+
|
|
124
|
+
### Attachments
|
|
125
|
+
|
|
126
|
+
Inbound files behind authenticated Slack URLs are staged with `fetchFile`. See [File uploads](./custom#file-uploads) for the `fetchFile` contract.
|
|
100
127
|
|
|
101
128
|
## What to read next
|
|
102
129
|
|
package/docs/channels/teams.mdx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Microsoft Teams"
|
|
3
|
-
description: "Reach your agent from Microsoft Teams via the Bot Framework Activity protocol, with Adaptive Card
|
|
3
|
+
description: "Reach your agent from Microsoft Teams via the Bot Framework Activity protocol, with Adaptive Card human-in-the-loop prompts."
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Teams channel
|
|
7
|
+
The Teams channel runs your agent inside Microsoft Teams as a bot. It takes Bot Framework Activity POSTs, checks the Bot Connector bearer JWT on each one, and routes message activities to your agent. Human-in-the-loop (HITL) prompts come back as Adaptive Cards, and replies go out over the Bot Framework Connector REST API. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Add the channel
|
|
10
10
|
|
|
@@ -22,9 +22,11 @@ MICROSOFT_TENANT_ID=... # optional, single-tenant bots
|
|
|
22
22
|
|
|
23
23
|
By default the channel mounts at `POST /eve/v1/teams`. Point your Azure Bot or Teams app messaging endpoint at that public URL. To mount somewhere else, pass `route: "/api/teams/activity"`.
|
|
24
24
|
|
|
25
|
-
##
|
|
25
|
+
## How the channel handles messages
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
### Dispatch
|
|
28
|
+
|
|
29
|
+
The default `onMessage` handles two cases: personal-chat messages, and channel or group-chat messages that mention the bot directly. Ambient resource-specific-consent messages are dropped unless you override it. Before dispatch, Eve strips the mention, adds a `<teams_context>` block, and scopes channel and group threads by root activity id (`replyToId ?? id`).
|
|
28
30
|
|
|
29
31
|
```ts
|
|
30
32
|
import { defaultTeamsAuth, teamsChannel } from "eve/channels/teams";
|
|
@@ -37,11 +39,21 @@ export default teamsChannel({
|
|
|
37
39
|
});
|
|
38
40
|
```
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
### Delivery
|
|
43
|
+
|
|
44
|
+
Replies post as Markdown (`textFormat: "markdown"`), with oversized text split across messages and a typing indicator sent on turn start and action requests.
|
|
45
|
+
|
|
46
|
+
### Human-in-the-loop (HITL)
|
|
47
|
+
|
|
48
|
+
A human-in-the-loop (HITL) `input.requested` event renders as an Adaptive Card. Buttons and options map to `Action.Submit`, selects to `Input.ChoiceSet`, and freeform to `Input.Text`. When the user submits, the activity converts to Eve `inputResponses` for you. For invokes that aren't HITL, handle them in `onInvoke(ctx, activity)`.
|
|
49
|
+
|
|
50
|
+
### Proactive sessions
|
|
51
|
+
|
|
52
|
+
Proactive sessions need an existing conversation reference, because the Bot Framework v1 surface cannot create new chats by Azure Active Directory (AAD) user id. Pass `serviceUrl`, `conversationId`, and the other reference fields to `receive(teams, { target })`.
|
|
41
53
|
|
|
42
|
-
|
|
54
|
+
### Attachments
|
|
43
55
|
|
|
44
|
-
|
|
56
|
+
Inbound files are off by default. Opt in to allow personal-scope downloads and public media URLs:
|
|
45
57
|
|
|
46
58
|
```ts
|
|
47
59
|
export default teamsChannel({
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: "Telegram"
|
|
3
|
-
description: "Reach your agent from Telegram bot webhooks, with inline-keyboard
|
|
3
|
+
description: "Reach your agent from Telegram bot webhooks, with inline-keyboard human-in-the-loop prompts and attachments."
|
|
4
4
|
type: integration
|
|
5
5
|
---
|
|
6
6
|
|
|
7
|
-
The Telegram channel puts your agent behind a Telegram bot. It takes Bot API webhooks, checks the `X-Telegram-Bot-Api-Secret-Token` header before
|
|
7
|
+
The Telegram channel puts your agent behind a Telegram bot. It takes Bot API webhooks, checks the `X-Telegram-Bot-Api-Secret-Token` header before trusting anything, and routes the messages it cares about (private chats plus group messages that address the bot) to a reply over `sendMessage`. See [Channels](./overview) for the contract this builds on.
|
|
8
8
|
|
|
9
9
|
## Add the channel
|
|
10
10
|
|
|
@@ -31,15 +31,31 @@ curl -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook" \
|
|
|
31
31
|
"allowed_updates":["message","callback_query"]}'
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
##
|
|
34
|
+
## How the channel handles messages
|
|
35
35
|
|
|
36
|
-
|
|
36
|
+
### Dispatch
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
In a private chat, text, captions, photos, and documents all go through. Groups are stricter. Only three things wake the bot: a command (`/ask`, `/ask@my_bot`), an `@my_bot` mention (when `botUsername` is set), or a reply to one of the bot's own messages. Everything else is ignored.
|
|
39
39
|
|
|
40
|
-
|
|
40
|
+
Forum topics carry `message_thread_id` in the continuation token, so each topic stays on its own thread.
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
To customize auth or filtering, override `onMessage`. Group privacy mode itself lives in BotFather, not here.
|
|
43
|
+
|
|
44
|
+
### Delivery
|
|
45
|
+
|
|
46
|
+
The default `message.completed` handler sends plain text via `sendMessage`. It passes no `parse_mode`, so any Markdown shows up literally. Replies longer than Telegram's 4096-char limit are split across messages. Custom handlers use `channel.telegram`.
|
|
47
|
+
|
|
48
|
+
### Human-in-the-loop (HITL)
|
|
49
|
+
|
|
50
|
+
Human-in-the-loop (HITL) turns option requests into inline-keyboard buttons and freeform requests into `ForceReply`. Telegram caps `callback_data` at 64 bytes, so Eve keeps compact callback ids in channel state instead. It acknowledges its own callbacks with `answerCallbackQuery`; anything it doesn't recognize goes to `onCallbackQuery`.
|
|
51
|
+
|
|
52
|
+
### Proactive sessions
|
|
53
|
+
|
|
54
|
+
Start a session without an inbound message through `receive(telegram, { message, target, auth })` from a schedule `run` handler, or `args.receive(telegram, ...)` from another channel. `target.chatId` is required. Add `messageThreadId` to land in a specific forum topic.
|
|
55
|
+
|
|
56
|
+
### Attachments
|
|
57
|
+
|
|
58
|
+
Inbound photos and documents are supported. Eve fetches them on demand via `getFile`, only when an upload policy allows the type:
|
|
43
59
|
|
|
44
60
|
```ts
|
|
45
61
|
export default telegramChannel({
|
|
@@ -48,8 +64,6 @@ export default telegramChannel({
|
|
|
48
64
|
});
|
|
49
65
|
```
|
|
50
66
|
|
|
51
|
-
**Proactive sessions** start with `receive(telegram, { message, target, auth })` from a schedule `run` handler, or `args.receive(telegram, ...)` when you're kicking off from another channel. `target.chatId` is required. Add `messageThreadId` to land in a specific forum topic.
|
|
52
|
-
|
|
53
67
|
## What to read next
|
|
54
68
|
|
|
55
69
|
- [Channels overview](./overview): the channel contract and every built-in channel
|
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
|
|