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.
Files changed (98) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +14 -0
  3. package/dist/src/cli/banner.d.ts +6 -3
  4. package/dist/src/cli/banner.js +1 -1
  5. package/dist/src/cli/commands/init.js +1 -1
  6. package/dist/src/cli/dev/tui/agent-header.js +1 -1
  7. package/dist/src/cli/run.js +1 -1
  8. package/dist/src/evals/runner/run-evals.d.ts +1 -1
  9. package/dist/src/execution/sandbox/bindings/docker.js +1 -1
  10. package/dist/src/execution/sandbox/bindings/microsandbox-lifecycle.js +1 -1
  11. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.d.ts +2 -1
  12. package/dist/src/execution/sandbox/bindings/microsandbox-runtime.js +1 -1
  13. package/dist/src/execution/sandbox/bindings/vercel-errors.d.ts +1 -0
  14. package/dist/src/execution/sandbox/bindings/vercel-errors.js +1 -2
  15. package/dist/src/execution/sandbox/bindings/vercel.d.ts +0 -5
  16. package/dist/src/execution/sandbox/bindings/vercel.js +1 -1
  17. package/dist/src/harness/input-requests.d.ts +20 -1
  18. package/dist/src/harness/input-requests.js +1 -1
  19. package/dist/src/harness/tool-loop.js +1 -1
  20. package/dist/src/internal/application/package.js +1 -1
  21. package/dist/src/protocol/message.d.ts +11 -2
  22. package/dist/src/protocol/message.js +2 -2
  23. package/dist/src/public/next/index.d.ts +1 -7
  24. package/dist/src/public/next/index.js +1 -1
  25. package/dist/src/public/next/vercel-output-config.js +1 -1
  26. package/dist/src/setup/scaffold/create/project.js +1 -1
  27. package/dist/src/setup/scaffold/create/web-template.d.ts +1 -1
  28. package/dist/src/setup/scaffold/create/web-template.js +27 -4
  29. package/dist/src/setup/scaffold/update/channels.js +1 -1
  30. package/docs/README.md +19 -5
  31. package/docs/agent-config.md +16 -19
  32. package/docs/channels/custom.mdx +24 -18
  33. package/docs/channels/discord.mdx +25 -13
  34. package/docs/channels/eve.mdx +24 -6
  35. package/docs/channels/github.mdx +41 -10
  36. package/docs/channels/linear.mdx +29 -36
  37. package/docs/channels/overview.mdx +16 -4
  38. package/docs/channels/slack.mdx +59 -32
  39. package/docs/channels/teams.mdx +19 -7
  40. package/docs/channels/telegram.mdx +23 -9
  41. package/docs/channels/twilio.mdx +28 -6
  42. package/docs/concepts/context-control.md +24 -41
  43. package/docs/concepts/default-harness.md +19 -9
  44. package/docs/concepts/execution-model-and-durability.md +14 -14
  45. package/docs/concepts/security-model.md +32 -8
  46. package/docs/concepts/sessions-runs-and-streaming.md +11 -9
  47. package/docs/connections.mdx +49 -29
  48. package/docs/evals/assertions.mdx +30 -29
  49. package/docs/evals/cases.mdx +10 -10
  50. package/docs/evals/judge.mdx +14 -14
  51. package/docs/evals/overview.mdx +15 -17
  52. package/docs/evals/reporters.mdx +19 -7
  53. package/docs/evals/running.mdx +2 -2
  54. package/docs/evals/targets.mdx +15 -4
  55. package/docs/getting-started.mdx +72 -31
  56. package/docs/guides/auth-and-route-protection.md +18 -12
  57. package/docs/guides/client/continuations.mdx +5 -13
  58. package/docs/guides/client/messages.mdx +2 -2
  59. package/docs/guides/client/output-schema.mdx +2 -2
  60. package/docs/guides/client/overview.mdx +4 -4
  61. package/docs/guides/client/streaming.mdx +6 -5
  62. package/docs/guides/deployment.md +22 -20
  63. package/docs/guides/dev-tui.md +85 -13
  64. package/docs/guides/dynamic-capabilities.md +24 -8
  65. package/docs/guides/dynamic-workflows.md +33 -12
  66. package/docs/guides/frontend/nextjs.mdx +28 -14
  67. package/docs/guides/frontend/nuxt.mdx +21 -4
  68. package/docs/guides/frontend/overview.mdx +11 -11
  69. package/docs/guides/frontend/sveltekit.mdx +20 -3
  70. package/docs/guides/frontend/use-eve-agent-svelte.mdx +106 -14
  71. package/docs/guides/frontend/use-eve-agent-vue.mdx +108 -15
  72. package/docs/guides/hooks.md +14 -60
  73. package/docs/guides/instrumentation.md +24 -18
  74. package/docs/guides/remote-agents.md +19 -15
  75. package/docs/guides/session-context.md +12 -12
  76. package/docs/guides/state.md +25 -9
  77. package/docs/instructions.mdx +18 -10
  78. package/docs/{introduction.md → introduction.mdx} +14 -12
  79. package/docs/reference/cli.md +99 -53
  80. package/docs/reference/meta.json +1 -1
  81. package/docs/reference/project-layout.md +39 -32
  82. package/docs/reference/typescript-api.md +1 -1
  83. package/docs/responsible-use.md +14 -0
  84. package/docs/sandbox.mdx +25 -19
  85. package/docs/schedules.mdx +16 -14
  86. package/docs/skills.mdx +8 -6
  87. package/docs/subagents.mdx +39 -13
  88. package/docs/tools.mdx +13 -9
  89. package/docs/tutorial/connect-a-warehouse.mdx +16 -7
  90. package/docs/tutorial/first-agent.mdx +21 -11
  91. package/docs/tutorial/guard-the-spend.mdx +11 -9
  92. package/docs/tutorial/how-it-runs.mdx +10 -8
  93. package/docs/tutorial/query-sample-data.mdx +8 -8
  94. package/docs/tutorial/remember-definitions.mdx +5 -5
  95. package/docs/tutorial/run-analysis.mdx +13 -11
  96. package/docs/tutorial/ship-it.mdx +70 -14
  97. package/docs/tutorial/team-playbooks.mdx +33 -10
  98. package/package.json +1 -1
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  title: "Eve"
3
- description: "The default HTTP API for an agent: session routes, auth, and customization."
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: 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:
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 the routes that create sessions, send follow-ups, and stream events:
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
- See [Sessions, runs & streaming](../concepts/sessions-runs-and-streaming) for the request and stream flow.
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 are meant for development and trusted infrastructure:
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"(event, channel, ctx) {
79
+ "message.completed"(eventData, channel, ctx) {
62
80
  console.log("Eve response completed", {
63
81
  continuationToken: channel.continuationToken,
64
82
  sessionId: ctx.session.id,
@@ -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. Under the hood it takes GitHub App webhooks at `/eve/v1/github`, checks the signature, figures out auth from whoever triggered the event, and replies on the native surface. See [Channels](./overview) for the contract this builds on.
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 (`GITHUB_APP_ID`, `GITHUB_APP_PRIVATE_KEY`, `GITHUB_WEBHOOK_SECRET`; `botName` reads `GITHUB_APP_SLUG`), so you can drop the `credentials` block entirely once those are set. `appId`/`privateKey`/`webhookSecret` will also take a lazy resolver function if you'd rather fetch them on demand.
24
+ Every field falls back to an env var, so you can drop the `credentials` block entirely once these are set:
25
25
 
26
- 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.
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
- ## Affordances
33
+ `appId`/`privateKey`/`webhookSecret` also take a lazy resolver function if you'd rather fetch them on demand.
29
34
 
30
- **Acknowledgement & replies.** When a turn starts, the channel drops an `eyes` reaction on 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.
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
- **PR context.** 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 show up in the list, but their patch body is dropped; add more paths to the skip list with `pullRequestContext.excludedFiles`.
37
+ ## How the channel handles messages
33
38
 
34
- **Sandbox checkout.** 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 trick with the installation token is that it 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.
39
+ ### Dispatch
35
40
 
36
- **Inbound hooks** return `{ auth }` to dispatch, or `null` to ignore. Reach for `defaultGitHubAuth(ctx)` to derive auth from the actor.
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: "issue" | "pull_request" | "review_thread".
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
- **Arbitrary API calls.** For anything the channel doesn't wrap, call `ctx.github.request({ method, path, body })`; it carries installation-token auth.
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
 
@@ -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: `thought`, `action`, `elicitation`, `response`, and `error`.
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
- If you'd rather not use env vars, pass the same values through `credentials: { accessToken, webhookSecret }`. Both fields also accept lazy resolver functions. The access token falls back to `LINEAR_AGENT_ACCESS_TOKEN`, `LINEAR_ACCESS_TOKEN`, `LINEAR_API_KEY`, or `LINEAR_API_TOKEN`; the webhook secret falls back to `LINEAR_WEBHOOK_SECRET`.
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
- ## Affordances
41
+ ## How the channel handles messages
42
42
 
43
- **Agent Session dispatch.** 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>`.
43
+ ### Dispatch
44
44
 
45
- **Native progress and replies.** 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.
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
- **Human input.** Eve input requests are rendered 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`.
47
+ ### Delivery
48
48
 
49
- **API handle.** Event handlers receive `channel.linear`, which exposes `createActivity`, `listActivities`, and `updateSession` for custom Agent Activity delivery and Agent Session metadata.
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
- **Proactive sessions.** `receive(linear, { target })` accepts an existing `agentSessionId`, or can create a new Agent Session on an `issueId` or root `commentId` before sending the message.
51
+ ### Human-in-the-loop (HITL)
52
52
 
53
- ```ts
54
- await receive(linear, {
55
- auth: null,
56
- message: "Summarize the current status and risks.",
57
- target: { issueId: "issue-id" },
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"(event, channel) {
100
- if (event.finishReason === "tool-calls" || !event.message) return;
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${event.message}`,
108
+ body: `Done.\n\n${eventData.message}`,
103
109
  type: "response",
104
110
  });
105
111
  },
106
- async "input.requested"(event, channel) {
112
+ async "input.requested"(eventData, channel) {
107
113
  await channel.linear.createActivity({
108
- body: event.requests.map((request) => request.prompt).join("\n\n"),
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
- Route handlers can use the same target shape through their `receive` helper:
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, and its job is deliberately small. It does exactly three things: normalizes platform input into a user message, owns the `continuationToken` (the resume handle for a conversation on that surface), and decides delivery (how, where, and whether a response goes back).
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 canonical 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 [Eve channel](./eve) for the routes, auth, and customization.
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`: 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.
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's channel layer (webhook handling, signature verification, event parsing, and thread management) is implemented inside Eve itself. In short: building Slack messages feels just like Chat SDK cards, but wiring a channel means authoring against Eve's `defineChannel(...)` API, not a Chat SDK adapter.
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
@@ -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: it answers `@mentions` and DMs, replies in threads, shows typing indicators, and turns 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.
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
- `--triggers` turns on Slack Event Subscriptions; without it, Slack never delivers `app_mention` or `message.im`. `--trigger-path /eve/v1/slack` must match the channel route, since Eve doesn't serve the default Connect path. You can also create the client from the [Connect dashboard](https://vercel.com/d?to=/%5Bteam%5D/~/connect&title=Go+to+Connect).
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 file
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 }`. That keeps token rotation, multi-workspace tenancy, and request verification inside Connect rather than your code. Deploy once the trigger destination and channel file are ready:
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
- ## Affordances
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
- **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.
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
- **Thread context.** 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 only inject what is new:
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
- async onAppMention(ctx, message) {
57
- const auth = defaultSlackAuth(message, ctx);
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
- **Thread anchoring.** When a session starts without a `threadTs` (say, from a schedule or `args.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.
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
- **Typing indicators** post out of the box: `Thinking…` on inbound, `Working…` on `turn.started`, tool status on `actions.requested`. Override any handler to customize.
79
+ ### Delivery
68
80
 
69
- **HITL** renders as Slack buttons/selects; submissions resume the parked session.
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
- **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.
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
- ```ts
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"(event, ctx) {
92
- if (event.finishReason === "tool-calls") return;
93
- if (event.message) ctx.thread.post(event.message);
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
- Event handlers receive `(eventData, ctx)` with platform handles on `ctx.thread` and `ctx.slack`.
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
 
@@ -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 HITL."
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 lets your agent live 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. 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.
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
- ## Affordances
25
+ ## How the channel handles messages
26
26
 
27
- **Message dispatch.** 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`).
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
- **Delivery & HITL.** Replies post as Markdown (`textFormat: "markdown"`), with oversized text split across messages and a typing indicator sent on turn start and action requests. An `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)`.
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
- **Proactive sessions** need an existing conversation reference, because Teams v1 cannot create new chats by AAD user id. Pass `serviceUrl`, `conversationId`, etc. to `receive(teams, { target })`.
54
+ ### Attachments
43
55
 
44
- **Files** are off by default. Opt in to enable personal-scope downloads and public media URLs:
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 HITL and attachments."
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 it trusts 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.
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
- ## Affordances
34
+ ## How the channel handles messages
35
35
 
36
- **Dispatch.** 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 gets ignored. Forum topics carry `message_thread_id` in the continuation token, so each topic stays on its own thread. Need custom auth or filtering? Override `onMessage`. Group privacy mode itself lives in BotFather, not here.
36
+ ### Dispatch
37
37
 
38
- **Delivery.** 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 get split across messages. Custom handlers reach for `ctx.telegram`.
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
- **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`.
40
+ Forum topics carry `message_thread_id` in the continuation token, so each topic stays on its own thread.
41
41
 
42
- **Attachments** are inbound photos and documents. Eve fetches them on demand via `getFile`, only when an upload policy allows the type:
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