eve 0.32.0 → 0.33.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.
Files changed (178) hide show
  1. package/CHANGELOG.md +13 -1
  2. package/README.md +8 -4
  3. package/dist/src/channel/channel-address.d.ts +4 -1
  4. package/dist/src/channel/channel-address.js +1 -1
  5. package/dist/src/channel/channel-operations.d.ts +3 -1
  6. package/dist/src/channel/compiled-channel.d.ts +2 -1
  7. package/dist/src/channel/cross-channel-receive.d.ts +5 -2
  8. package/dist/src/channel/cross-channel-receive.js +1 -1
  9. package/dist/src/channel/session.d.ts +6 -2
  10. package/dist/src/channel/session.js +1 -1
  11. package/dist/src/channel/types.d.ts +6 -0
  12. package/dist/src/channel/types.js +1 -1
  13. package/dist/src/chunks/{use-eve-agent-CX87G1vU.js → use-eve-agent-3oBnxzhV.js} +27 -17
  14. package/dist/src/chunks/{use-eve-agent-DwyRde1N.js → use-eve-agent-B-Hky2f4.js} +27 -17
  15. package/dist/src/cli/commands/agent-prompt/collect-intent.md +3 -0
  16. package/dist/src/cli/commands/agent-prompt/scaffold.md +4 -2
  17. package/dist/src/cli/commands/info.js +1 -1
  18. package/dist/src/cli/commands/init-repl.d.ts +1 -1
  19. package/dist/src/cli/commands/init-repl.js +1 -1
  20. package/dist/src/cli/commands/init.d.ts +7 -0
  21. package/dist/src/cli/commands/init.js +1 -1
  22. package/dist/src/cli/commands/integration-connect.d.ts +3 -3
  23. package/dist/src/cli/commands/integration-connect.js +1 -1
  24. package/dist/src/cli/commands/integration-setup.js +1 -1
  25. package/dist/src/cli/commands/set.d.ts +20 -0
  26. package/dist/src/cli/commands/set.js +1 -0
  27. package/dist/src/cli/dev/tui/runner.js +1 -1
  28. package/dist/src/cli/dev/tui/setup-issues.js +1 -1
  29. package/dist/src/cli/option-parsers.d.ts +3 -0
  30. package/dist/src/cli/option-parsers.js +1 -1
  31. package/dist/src/cli/run.js +1 -1
  32. package/dist/src/client/agent-info-schema.d.ts +28 -5
  33. package/dist/src/client/agent-info-schema.js +1 -1
  34. package/dist/src/client/session.js +1 -1
  35. package/dist/src/client/types.d.ts +3 -0
  36. package/dist/src/compiler/extension-compatibility.d.ts +19 -9
  37. package/dist/src/compiler/extension-compatibility.js +1 -1
  38. package/dist/src/compiler/manifest.d.ts +119 -19
  39. package/dist/src/compiler/manifest.js +1 -1
  40. package/dist/src/compiler/model-catalog.d.ts +2 -30
  41. package/dist/src/compiler/model-catalog.js +1 -1
  42. package/dist/src/compiler/module-map.d.ts +2 -2
  43. package/dist/src/compiler/module-map.js +2 -2
  44. package/dist/src/compiler/normalize-agent-config.js +1 -1
  45. package/dist/src/compiler/normalize-instructions.js +1 -1
  46. package/dist/src/compiler/normalize-manifest.js +2 -2
  47. package/dist/src/compiler/normalize-skill.js +1 -1
  48. package/dist/src/compiler/normalize-subagent.d.ts +5 -1
  49. package/dist/src/compiler/normalize-subagent.js +1 -1
  50. package/dist/src/compiler/remote-agent-node.d.ts +4 -1
  51. package/dist/src/compiler/workspace-resources.js +1 -1
  52. package/dist/src/context/dynamic-model-lifecycle.d.ts +7 -2
  53. package/dist/src/context/dynamic-model-lifecycle.js +1 -1
  54. package/dist/src/context/dynamic-subagent-lifecycle.js +1 -1
  55. package/dist/src/context/hook-lifecycle.js +1 -1
  56. package/dist/src/context/keys.d.ts +8 -0
  57. package/dist/src/context/keys.js +1 -1
  58. package/dist/src/evals/session.js +1 -1
  59. package/dist/src/execution/dispatch-runtime-actions-step.js +1 -1
  60. package/dist/src/execution/effective-agent-config.js +1 -1
  61. package/dist/src/execution/node-step.js +1 -1
  62. package/dist/src/execution/session-command-wire.js +1 -1
  63. package/dist/src/execution/session.d.ts +2 -0
  64. package/dist/src/execution/session.js +2 -2
  65. package/dist/src/execution/settle-cancelled-turn-step.js +1 -1
  66. package/dist/src/execution/turn-control-receiver.d.ts +2 -0
  67. package/dist/src/execution/turn-control-receiver.js +1 -1
  68. package/dist/src/execution/workflow-steps.js +1 -1
  69. package/dist/src/harness/emission.d.ts +1 -1
  70. package/dist/src/harness/emission.js +1 -1
  71. package/dist/src/harness/step-hooks.d.ts +1 -1
  72. package/dist/src/harness/step-hooks.js +1 -1
  73. package/dist/src/harness/tool-loop.d.ts +1 -1
  74. package/dist/src/harness/tool-loop.js +2 -2
  75. package/dist/src/harness/types.d.ts +11 -5
  76. package/dist/src/harness/types.js +1 -1
  77. package/dist/src/internal/application/package.js +1 -1
  78. package/dist/src/internal/authored-definition/core.js +1 -1
  79. package/dist/src/internal/authored-definition/schema-backed.js +1 -1
  80. package/dist/src/internal/authored-module-loader.js +1 -1
  81. package/dist/src/internal/authored-module-map-loader.js +1 -1
  82. package/dist/src/internal/model-catalog.d.ts +46 -0
  83. package/dist/src/internal/model-catalog.js +1 -0
  84. package/dist/src/internal/nitro/host/build-vercel-agent-summary.js +1 -1
  85. package/dist/src/internal/nitro/host/create-application-nitro.js +1 -1
  86. package/dist/src/internal/nitro/host/dev-host-fingerprint.js +1 -1
  87. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response-from-manifest.js +1 -1
  88. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.d.ts +20 -10
  89. package/dist/src/internal/nitro/routes/agent-info/build-agent-info-response.js +1 -1
  90. package/dist/src/internal/nitro/routes/channel-dispatch.js +1 -1
  91. package/dist/src/internal/nitro/routes/info.js +1 -1
  92. package/dist/src/internal/vercel-agent-summary.d.ts +12 -3
  93. package/dist/src/internal/vercel-agent-summary.js +1 -1
  94. package/dist/src/protocol/message.d.ts +2 -2
  95. package/dist/src/protocol/message.js +1 -1
  96. package/dist/src/public/channels/chat-sdk/chatSdkChannel.d.ts +5 -5
  97. package/dist/src/public/channels/chat-sdk/chatSdkChannel.js +2 -2
  98. package/dist/src/public/channels/discord/discordChannel.d.ts +3 -1
  99. package/dist/src/public/channels/discord/discordChannel.js +1 -1
  100. package/dist/src/public/channels/eve.d.ts +3 -1
  101. package/dist/src/public/channels/eve.js +1 -1
  102. package/dist/src/public/channels/github/githubChannel.d.ts +3 -1
  103. package/dist/src/public/channels/github/githubChannel.js +1 -1
  104. package/dist/src/public/channels/index.d.ts +1 -1
  105. package/dist/src/public/channels/linear/linearChannel.d.ts +3 -1
  106. package/dist/src/public/channels/linear/linearChannel.js +1 -1
  107. package/dist/src/public/channels/photon/photonIMessageChannel.d.ts +3 -1
  108. package/dist/src/public/channels/photon/photonIMessageChannel.js +1 -1
  109. package/dist/src/public/channels/slack/slackChannel.d.ts +3 -1
  110. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  111. package/dist/src/public/channels/teams/teamsChannel.d.ts +3 -1
  112. package/dist/src/public/channels/teams/teamsChannel.js +1 -1
  113. package/dist/src/public/channels/telegram/telegramChannel.d.ts +3 -1
  114. package/dist/src/public/channels/telegram/telegramChannel.js +1 -1
  115. package/dist/src/public/channels/twilio/twilioChannel.d.ts +3 -1
  116. package/dist/src/public/channels/twilio/twilioChannel.js +1 -1
  117. package/dist/src/public/definitions/agent.d.ts +5 -7
  118. package/dist/src/public/definitions/agent.js +1 -1
  119. package/dist/src/public/definitions/channel.d.ts +3 -1
  120. package/dist/src/public/definitions/channel.js +1 -1
  121. package/dist/src/public/definitions/tool.d.ts +1 -5
  122. package/dist/src/public/definitions/tool.js +1 -1
  123. package/dist/src/public/index.d.ts +1 -1
  124. package/dist/src/runtime/agent/bootstrap.d.ts +19 -6
  125. package/dist/src/runtime/agent/bootstrap.js +1 -1
  126. package/dist/src/runtime/agent/model-catalog.d.ts +10 -0
  127. package/dist/src/runtime/agent/model-catalog.js +1 -0
  128. package/dist/src/runtime/agent/resolve-model.d.ts +8 -4
  129. package/dist/src/runtime/agent/resolve-model.js +1 -1
  130. package/dist/src/runtime/framework-channels/index.js +1 -1
  131. package/dist/src/runtime/resolve-agent-graph.js +1 -1
  132. package/dist/src/runtime/resolve-agent.d.ts +2 -2
  133. package/dist/src/runtime/resolve-agent.js +1 -1
  134. package/dist/src/runtime/resolve-channel.js +1 -1
  135. package/dist/src/runtime/resolve-dynamic-subagent.d.ts +2 -5
  136. package/dist/src/runtime/subagents/dynamic-agent-config.d.ts +8 -7
  137. package/dist/src/runtime/subagents/dynamic-agent-config.js +1 -1
  138. package/dist/src/runtime/types.d.ts +11 -4
  139. package/dist/src/setup/flows/deploy.d.ts +5 -3
  140. package/dist/src/setup/flows/deploy.js +1 -1
  141. package/dist/src/setup/flows/ensure-vercel-project.d.ts +5 -1
  142. package/dist/src/setup/flows/ensure-vercel-project.js +1 -1
  143. package/dist/src/setup/flows/model-source-change.d.ts +1 -0
  144. package/dist/src/setup/flows/model-source-change.js +1 -1
  145. package/dist/src/setup/integrations/discord/setup.js +1 -1
  146. package/dist/src/setup/integrations/github/setup.js +1 -1
  147. package/dist/src/setup/integrations/linear/setup.js +1 -1
  148. package/dist/src/setup/integrations/photon/setup-flow.js +1 -1
  149. package/dist/src/setup/integrations/slack/setup.js +1 -1
  150. package/dist/src/setup/scaffold/create/add-to-project.d.ts +2 -0
  151. package/dist/src/setup/scaffold/create/add-to-project.js +1 -1
  152. package/dist/src/setup/scaffold/create/project.d.ts +3 -1
  153. package/dist/src/setup/scaffold/create/project.js +4 -4
  154. package/dist/src/shared/agent-definition.d.ts +23 -23
  155. package/dist/src/shared/agent-definition.js +1 -1
  156. package/dist/src/shared/channel-definition.d.ts +3 -1
  157. package/dist/src/shared/dynamic-tool-definition.d.ts +4 -10
  158. package/dist/src/shared/dynamic-tool-definition.js +1 -1
  159. package/dist/src/svelte/index.js +1 -1
  160. package/dist/src/svelte/use-eve-agent.js +1 -1
  161. package/dist/src/vue/index.js +1 -1
  162. package/dist/src/vue/use-eve-agent.js +1 -1
  163. package/docs/agent-config.md +30 -19
  164. package/docs/channels/chat-sdk.mdx +5 -5
  165. package/docs/channels/custom.mdx +20 -0
  166. package/docs/channels/discord.mdx +1 -0
  167. package/docs/channels/eve.mdx +2 -0
  168. package/docs/channels/github.mdx +1 -1
  169. package/docs/channels/linear.mdx +1 -1
  170. package/docs/channels/overview.mdx +19 -0
  171. package/docs/channels/photon.mdx +5 -2
  172. package/docs/channels/slack.mdx +5 -11
  173. package/docs/concepts/execution-model-and-durability.mdx +5 -8
  174. package/docs/concepts/sessions-runs-and-streaming.md +2 -2
  175. package/docs/guides/dynamic-capabilities.md +24 -20
  176. package/docs/installation.mdx +7 -1
  177. package/docs/reference/cli.md +33 -8
  178. package/package.json +1 -1
@@ -17,6 +17,10 @@ export default defineAgent({
17
17
  });
18
18
  ```
19
19
 
20
+ For a static AI Gateway model ID, you can make the same source change from the
21
+ project root with `eve set --model anthropic/claude-opus-4.8` or from the local
22
+ dev TUI with `/model anthropic/claude-opus-4.8`.
23
+
20
24
  The root `agent.ts` can be omitted when no runtime config is needed. In that case, eve defaults
21
25
  to `anthropic/claude-sonnet-5`. When `agent.ts` is present, `model` is required.
22
26
 
@@ -45,21 +49,23 @@ Model use is subject to the terms, data-processing commitments, retention behavi
45
49
 
46
50
  ### Choose the model dynamically
47
51
 
48
- `model` also accepts `defineDynamic({ fallback, events })`. `fallback` is the
49
- compiled static model: it anchors build-time metadata (routing, credentials,
50
- context window) and serves whenever no dynamic selection is set.
52
+ `model` also accepts `defineDynamic({ events })`. Each matching handler must
53
+ return the concrete model for its scope; a dynamic model has no compiled
54
+ default.
51
55
 
52
56
  ```ts title="agent/agent.ts"
53
57
  import { defineAgent, defineDynamic } from "eve";
54
58
 
55
59
  export default defineAgent({
56
60
  model: defineDynamic({
57
- fallback: "anthropic/claude-sonnet-5",
58
61
  events: {
59
- "session.started": (_event, ctx) =>
60
- ctx.session.auth.initiator?.attributes.plan === "enterprise"
61
- ? "anthropic/claude-opus-4.8"
62
- : null,
62
+ "session.started": (_event, ctx) => {
63
+ if (ctx.session.auth.initiator?.attributes.plan === "enterprise") {
64
+ return "anthropic/claude-opus-4.8";
65
+ }
66
+
67
+ return "anthropic/claude-sonnet-5";
68
+ },
63
69
  },
64
70
  }),
65
71
  });
@@ -68,24 +74,28 @@ export default defineAgent({
68
74
  Handlers receive the shared [dynamic resolver
69
75
  context](./guides/dynamic-capabilities) (`ctx.session`, `ctx.channel`,
70
76
  `ctx.messages`) and return a gateway model id, an AI SDK `LanguageModel`, a
71
- selection object, or `null` to leave the scope unset.
77
+ selection object. Returning `null` or `undefined` fails the turn.
72
78
 
73
79
  - **Scopes.** `session.started` (once per session), `turn.started` (once per
74
80
  turn), `step.started` (every model step). Precedence: step > turn >
75
- session > `fallback`. Prefer `session.started`: prompt caches are per
76
- model, so every switch re-ingests the conversation at uncached prices.
77
- - **Failures degrade, never fail the turn.** A resolver that throws or
78
- returns an invalid selection logs an error and leaves its scope unset.
79
- Build-time validation covers only `fallback`; a selected model without
80
- credentials fails at request time.
81
+ session. Prefer `session.started`: prompt caches are per model, so every
82
+ switch re-ingests the conversation at uncached prices. If no active
83
+ selection exists before model-dependent work begins, the turn fails.
84
+ - **Failures stop the turn.** A resolver that throws, returns no model, or
85
+ returns an invalid selection fails before the provider call. A selected
86
+ model without valid credentials fails at request time.
81
87
  - **Serialization.** Session/turn selections must be model id strings; return
82
88
  live `LanguageModel` objects only from `step.started`.
83
89
  - **Selection object.** `{ model, modelContextWindowTokens?, modelOptions? }`.
84
- Set `modelContextWindowTokens` when the selected model's window differs
85
- from the fallback's — it is never inherited. Omitted `modelOptions` reuses
86
- the agent-level `modelOptions`.
90
+ When `modelContextWindowTokens` is omitted, eve resolves it from the AI
91
+ Gateway catalog and caches successful metadata in durable session state for
92
+ 24 hours. Set it explicitly for an unlisted or custom model. Dynamic agents
93
+ cannot set sibling `modelContextWindowTokens` or `modelOptions` fields;
94
+ return per-model values from the handler.
87
95
 
88
- Runtime identity reports a dynamic agent's model as `dynamic:<fallback id>`.
96
+ The `session.started` runtime identity does not include a model id for a
97
+ dynamic agent. Each public `step.started` event reports the concrete `modelId`
98
+ selected for that model call.
89
99
 
90
100
  ## Reasoning effort
91
101
 
@@ -103,6 +113,7 @@ Supported values are `"provider-default"`, `"none"`, `"minimal"`, `"low"`,
103
113
  `"medium"`, `"high"`, and `"xhigh"`. The selected model and provider determine
104
114
  which levels are available and how they map to provider-native settings. Use
105
115
  `modelOptions.providerOptions` when you need provider-specific reasoning controls.
116
+ Run `eve set --reasoning high` to update this field from the command line.
106
117
 
107
118
  ## Compaction
108
119
 
@@ -99,22 +99,22 @@ bot.onNewMention(async (thread, message) => {
99
99
 
100
100
  `options` accepts `{ thread, auth?, title?, mode?, callback?, adapterName?, turnPolicy? }`. `title` sets the eve session's display title without changing the model message; `auth` attaches an authenticated principal to the turn.
101
101
 
102
- ### Experimental steering
102
+ ### Steering
103
103
 
104
- By default, a message sent while an eve turn is active waits for the next turn. Pass `turnPolicy: "experimental-steer"` to cancel the active turn before sending the new message:
104
+ Messages default to `turnPolicy: "steer"`: a message sent while an eve turn is active is durably buffered, then cancels that turn and starts as its replacement. Set `turnPolicy: "queue"` when the active turn should finish first:
105
105
 
106
106
  ```ts
107
107
  bot.onSubscribedMessage(async (thread, message) => {
108
108
  await send(message.text, {
109
109
  thread,
110
- turnPolicy: "experimental-steer",
110
+ turnPolicy: "queue",
111
111
  });
112
112
  });
113
113
  ```
114
114
 
115
- This is cancellation-backed steering: the interrupted turn emits `turn.cancelled`, and the replacement message starts a new turn with a new turn ID. Partial output and completed side effects from the interrupted turn are not rolled back. If no turn is active, the message is sent normally. Use the default `turnPolicy: "queue"` when every turn should finish in order.
115
+ Cancellation-backed steering emits `turn.cancelled`, and the replacement message starts a new turn with a new turn ID. Partial output and completed side effects from the interrupted turn are not rolled back. If no turn is active, the message is sent normally. You can set the policy once on `chatSdkChannel({ turnPolicy })` or override it per `send(...)`.
116
116
 
117
- This policy controls overlapping eve turns. Chat SDK's separate `concurrency` option controls overlapping webhook handlers; use `concurrency: "concurrent"` when each inbound message should reach the experimental steering path immediately.
117
+ This policy controls overlapping eve turns. Chat SDK's separate `concurrency` option controls overlapping webhook handlers; use `concurrency: "concurrent"` when each inbound message should reach the steering path immediately.
118
118
 
119
119
  ### Delivery
120
120
 
@@ -109,6 +109,26 @@ await session.reset({ reason: "Retire this session" });
109
109
  await session.getEventStream({ startIndex: 12 });
110
110
  ```
111
111
 
112
+ Message sends use the channel's `turnPolicy`, which defaults to `"steer"`. An accepted message arriving during an active turn is durably buffered before eve cancels that turn and starts the message as a replacement turn. Configure `turnPolicy: "queue"` on `defineChannel(...)` when active turns should finish in order, or override one send:
113
+
114
+ ```ts
115
+ export default defineChannel({
116
+ turnPolicy: "queue",
117
+ routes: [
118
+ POST("/messages", async (request, { from }) => {
119
+ const body = await request.json();
120
+ await from(body.threadId).send(body.message, {
121
+ auth: null,
122
+ turnPolicy: "steer",
123
+ });
124
+ return new Response(null, { status: 202 });
125
+ }),
126
+ ],
127
+ });
128
+ ```
129
+
130
+ The same override is available on fixed `Session.send(...)` and cross-channel `to(...).send(...)`. `respond(...)` never steers: it delivers only addressed input responses. Use `cancel()` when you need to stop work without a replacement message.
131
+
112
132
  Attaching does no lookup. The first operation reports whether the ID is active.
113
133
  Call `resolveSession(address)` only when you explicitly need to snapshot an
114
134
  address's current owner as a fixed handle.
@@ -16,6 +16,7 @@ pnpm eve add channel/discord
16
16
 
17
17
  The setup guides you through creating a Discord application and bot, then:
18
18
 
19
+ - signs you in to Vercel and creates or links a project when needed;
19
20
  - validates the bot token;
20
21
  - creates a Vercel Connect client and attaches `/eve/v1/discord` as its trigger destination;
21
22
  - registers an application command with a required `message` option;
@@ -56,6 +56,8 @@ curl -X POST https://<deployment>/eve/v1/session/wrun_A \
56
56
  -d '{"inputResponses":[{"requestId":"req_A","optionId":"approve"}]}'
57
57
  ```
58
58
 
59
+ Follow-up messages use `turnPolicy: "steer"` by default. If a turn is active, eve buffers the message before cooperatively cancelling that turn, then starts the follow-up as a replacement turn with a new turn ID. Set `turnPolicy: "queue"` on `eveChannel(...)` when follow-ups should wait for active turns to finish. `inputResponses` never steer.
60
+
59
61
  Sending a message to an unknown or terminal session ID returns `409` with
60
62
  `{"code":"session_not_active","error":"The session is no longer active.","ok":false}`.
61
63
  TypeScript clients expose the stable code as `ClientError.code`. The route never
@@ -14,7 +14,7 @@ Run the registry setup from the agent directory:
14
14
  eve add channel/github
15
15
  ```
16
16
 
17
- The flow checks that the Vercel CLI is authenticated, creates or links a Vercel project when needed, provisions an app-scoped GitHub Connect client, and registers `/eve/v1/github` as a trigger destination. It then installs `@vercel/connect` and writes `agent/channels/github.ts` with the connector UID.
17
+ The flow signs you in to Vercel when needed, creates or links a Vercel project, provisions an app-scoped GitHub Connect client, and registers `/eve/v1/github` as a trigger destination. It then installs `@vercel/connect` and writes `agent/channels/github.ts` with the connector UID.
18
18
 
19
19
  Vercel Connect creates the GitHub App, receives and verifies its webhooks, and forwards them to the deployed agent. After deploying, open the GitHub App in the Connect dashboard and install it in the organization or account where you want to use it. Add the generated invocation token (for example, `@my-agent`) to a new issue, pull request, or review comment to start a conversation. GitHub may not autocomplete the token or render it as a linked mention.
20
20
 
@@ -16,7 +16,7 @@ eve add linear
16
16
 
17
17
  Select **Linear Channel** in the component checklist. **Linear MCP** is also selected by default if you want the agent to search and update Linear through MCP. Run `eve add channel/linear-agent` instead to install only the channel directly.
18
18
 
19
- The flow checks that the Vercel CLI is authenticated, creates or links a Vercel project when needed, reuses a compatible existing connector when available or provisions an app-scoped Linear Connect client, and registers `/eve/v1/linear` as a trigger destination. It then installs `@vercel/connect` and writes `agent/channels/linear.ts` with the connector UID.
19
+ The flow signs you in to Vercel when needed, creates or links a Vercel project, reuses a compatible existing connector when available or provisions an app-scoped Linear Connect client, and registers `/eve/v1/linear` as a trigger destination. It then installs `@vercel/connect` and writes `agent/channels/linear.ts` with the connector UID.
20
20
 
21
21
  Vercel Connect creates the Linear app with the `app:assignable` and `app:mentionable` scopes required for Agent Sessions, receives and verifies `AgentSessionEvent` webhooks, and forwards them to the deployed agent. After deploying, open the Linear app in the Connect dashboard and install it in the workspace where you want to delegate work. Then delegate an issue or mention the agent in a Linear Agent Session.
22
22
 
@@ -13,6 +13,25 @@ eve ships a base HTTP channel plus first-class platform channels, and you can au
13
13
 
14
14
  After a channel normalizes input, eve runs the same agent runtime regardless of where the message came from. Tools and instructions do not need channel-specific logic.
15
15
 
16
+ ## Overlapping messages
17
+
18
+ Channels default to `turnPolicy: "steer"`. When an accepted message arrives while a turn is active, eve first durably buffers the message, then cooperatively cancels the active turn and starts a replacement turn. The cancelled turn emits `turn.cancelled` followed by `session.waiting`; the replacement starts with a new turn ID. Output already streamed and completed side effects are not rolled back.
19
+
20
+ Set `turnPolicy: "queue"` on any built-in or custom channel when each turn must finish before the next message starts:
21
+
22
+ ```ts
23
+ export default defineChannel({
24
+ turnPolicy: "queue",
25
+ routes: [
26
+ // ...
27
+ ],
28
+ });
29
+ ```
30
+
31
+ `from(address).send(...)`, fixed `Session.send(...)`, cross-channel sends, and Chat SDK bridge sends also accept a per-send `turnPolicy` override. Pure `inputResponses` deliveries answer their pending request without steering. Explicit `cancel()` remains the stop-without-replacement operation.
32
+
33
+ Channel admission still runs first. Ignored mentions, rejected signatures, duplicates, and any other dropped platform events never affect the active turn.
34
+
16
35
  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.
17
36
 
18
37
  ## Where channels live
@@ -7,8 +7,9 @@ Use `photonIMessageChannel` to receive and reply to iMessages through a Photon p
7
7
 
8
8
  Run `eve add channel/photon-imessage` to create or use a Photon project and register
9
9
  your phone number. It then asks whether to configure Vercel Connect or portable
10
- credentials. With Vercel Connect, eve creates the connector and configures
11
- Photon’s webhook through Connect. The channel resolves credentials lazily when
10
+ credentials. With Vercel Connect, eve signs you in and creates or links a Vercel
11
+ project when needed, then creates the connector and configures Photon’s webhook
12
+ through Connect. The channel resolves credentials lazily when
12
13
  the adapter first initializes:
13
14
 
14
15
  ```ts title="agent/channels/photon.ts"
@@ -26,6 +27,8 @@ read, and continues the same eve session for every message in an iMessage
26
27
  conversation. A new accepted message cooperatively cancels an active turn and
27
28
  steers its replacement turn.
28
29
 
30
+ Set `turnPolicy: "queue"` when every response should finish before Photon starts the next message.
31
+
29
32
  Customize inbound dispatch with `onMessage`. Return `null` to ignore a message:
30
33
 
31
34
  ```ts
@@ -18,7 +18,7 @@ The command recommends Vercel Connect, then scaffolds `agent/channels/slack.ts`
18
18
 
19
19
  ### Recommended: use Vercel Connect
20
20
 
21
- Vercel Connect setup requires an authenticated Vercel CLI and a linked Vercel project. The guided flow creates or reuses a Slack connector, waits for you to install it in a workspace, and registers `/eve/v1/slack` as a trigger destination before writing the channel file.
21
+ Vercel Connect setup requires the Vercel CLI. The guided flow signs you in when needed, creates or links a Vercel project, creates or reuses a Slack connector, waits for you to install it in a workspace, and registers `/eve/v1/slack` as a trigger destination before writing the channel file.
22
22
 
23
23
  The generated channel resolves credentials at runtime:
24
24
 
@@ -236,24 +236,18 @@ export default slackChannel({
236
236
 
237
237
  `threadContext` requires the matching Slack history scope. Thread helpers reuse messages already loaded within the same inbound handler, and overlapping refreshes share one `conversations.replies` request. Omit it when the agent should see only direct mentions. `loadThreadContextMessages` remains available when you need custom filtering or non-model processing of the raw thread messages.
238
238
 
239
- #### Cancel an active turn
239
+ #### Control overlapping turns
240
240
 
241
- Message hooks (`onMessage`, `onAppMention`, and `onDirectMessage`) receive thread-bound session operations directly on `ctx`. Call `ctx.cancel({ turnId? })` before returning `{ auth }` to stop the current turn and queue the new Slack message as replacement input, producing a debounce-like experience:
241
+ Accepted Slack messages use cancellation-backed steering by default: eve buffers the new message, cancels the active turn, and starts a replacement turn. Admission happens first, so ignored mentions and messages rejected by your hooks never cancel work. Set `turnPolicy: "queue"` when every active turn should finish:
242
242
 
243
243
  ```ts title="agent/channels/slack.ts"
244
244
  export default slackChannel({
245
245
  credentials: connectSlackCredentials("slack/my-agent"),
246
- async onMessage(ctx, message) {
247
- const shouldHandle = ctx.isBotMentioned() || (await ctx.isSubscribed());
248
- if (!shouldHandle || message.author?.isBot) return null;
249
-
250
- await ctx.cancel();
251
- return { auth: null };
252
- },
246
+ turnPolicy: "queue",
253
247
  });
254
248
  ```
255
249
 
256
- `"accepted"` means the live thread session durably queued the cancellation request. A parked session consumes it as a no-op; `"no_active_turn"` means the thread has no active session owner. Both are successful outcomes, so the hook can still return `{ auth }` to deliver the replacement message. Cancellation never sends input itself. A custom `onInteraction` handler receives the same flat operations, which is useful for a Stop button that should cancel without replacement input.
250
+ Message hooks (`onMessage`, `onAppMention`, and `onDirectMessage`) also receive thread-bound session operations directly on `ctx`. `ctx.cancel({ turnId? })` remains useful for a Stop button: it cancels without sending replacement input. `"accepted"` means the live thread session durably queued that request; a parked session consumes it as a no-op, and `"no_active_turn"` means the thread has no active session owner.
257
251
 
258
252
  Message and interaction hooks expose every current-owner operation directly on `ctx`:
259
253
 
@@ -66,7 +66,7 @@ You don't write workflow code directly. Workflow primitives (`start()`, `resumeH
66
66
 
67
67
  Some work has to wait, including a human approving a [tool](../tools), an interactive OAuth sign-in for a [connection](../connections), or a long-running [subagent](../subagents). At those points the turn parks durably. The workflow suspends and holds no compute until the input it's waiting on arrives (a click, a callback, a child completing), even if that's much later. When it does, the conversation picks up exactly where it left off.
68
68
 
69
- ## Message delivery and queueing
69
+ ## Message delivery and steering
70
70
 
71
71
  eve does not maintain a durable FIFO queue of user messages for a session. An
72
72
  ID-addressed HTTP delivery and a channel-address delivery both target the
@@ -79,14 +79,11 @@ channel alias. Rekeying replaces only that channel alias. An HTTP-created
79
79
  session has the stable ID alias and no channel continuation token. Competing
80
80
  channel input is not forwarded to the owner.
81
81
 
82
- When a session is waiting, a delivery through its ID or current channel address
83
- wakes the session and starts the next turn. When a turn is already active, the
84
- inbox may accept additional deliveries, but the runtime only drains them at
85
- specific workflow boundaries. If more than one delivery is ready when the driver
86
- checks, eve may fold them into the next turn; that drain is best-effort and
87
- depends on workflow and transport timing.
82
+ When a session is waiting, a delivery through its ID or current channel address wakes it and starts the next turn. Message sends default to `turnPolicy: "steer"`: while a turn is active, the session driver durably buffers the replacement before requesting cooperative cancellation. The interrupted turn emits `turn.cancelled` followed by `session.waiting`, then the replacement starts with a new turn ID. Partial output and completed side effects are not rolled back.
88
83
 
89
- So don't rely on concurrent sends to the same session behaving like a typical ordered chat queue. For deterministic behavior, send one user turn at a time and wait for `session.waiting` before sending the next message to the same session. If your channel can receive bursts while the agent is working, keep your own per-session queue in the channel or app layer, then deliver the next message after the session parks again. Separate sessions still run independently.
84
+ `turnPolicy: "queue"` preserves the message until the active turn settles. If several deliveries are ready when the driver checks, eve may fold adjacent messages into the next turn while preserving their arrival order. Pure `inputResponses` deliveries do not steer; they remain available to the pending request they address.
85
+
86
+ Every built-in and custom channel accepts a default `turnPolicy`, and imperative message sends can override it. The policy is part of the same durable delivery command as the message, so concurrent senders cannot separate replacement ownership from cancellation intent. Separate sessions still run independently.
90
87
 
91
88
  ## Subagents
92
89
 
@@ -148,7 +148,7 @@ curl -X POST http://127.0.0.1:2000/eve/v1/session/<sessionId> \
148
148
  -d '{"message":"Now send the short version."}'
149
149
  ```
150
150
 
151
- The follow-up reuses the same durable session: same history, same state.
151
+ The follow-up reuses the same durable session: same history, same state. Message sends default to cancellation-backed `"steer"`; if a turn is active, eve buffers the follow-up, cancels that turn, and starts the message under a new turn ID. Channels and TypeScript `Session.send(...)` calls can select `turnPolicy: "queue"` when active work should finish first. Structured `inputResponses` never steer.
152
152
 
153
153
  If the session is waiting on a human-in-the-loop approval, a matching text reply such as `approve` or `cancel` answers the approval. Other follow-up text is held until the approval is answered, so an unrelated message does not implicitly deny the pending tool call.
154
154
 
@@ -158,7 +158,7 @@ A response is stale when its request is no longer pending: the question or appro
158
158
 
159
159
  Responses match pending requests by request ID, so a response to an older request stays a plain user message even while a different question or approval is pending. Like any follow-up message, a stale response clears a pending question and is held while an approval is pending.
160
160
 
161
- For deterministic ordering, send one follow-up at a time and wait for the next `session.waiting` event before sending another message to the same session. See [message delivery and queueing](./execution-model-and-durability#message-delivery-and-queueing) for the current runtime contract.
161
+ Multiple replacement messages retain their durable arrival order and may be folded into the same replacement turn when they arrive before cancellation settles. See [message delivery and steering](./execution-model-and-durability#message-delivery-and-steering) for the current runtime contract.
162
162
 
163
163
  ## Cancel the in-flight turn
164
164
 
@@ -7,26 +7,26 @@ description: "Resolve models, subagents, tools, skills, and instructions at runt
7
7
 
8
8
  ## Dynamic models
9
9
 
10
- The `model` field in `agent.ts` accepts `defineDynamic({ fallback, events })`.
11
- Resolvers run at `session.started`, `turn.started`, or `step.started`
12
- (precedence: step > turn > session > `fallback`); `null` leaves a scope unset
13
- and failures degrade to the next scope. Prefer `session.started` — prompt
14
- caches are per model, so switching mid-session re-ingests the conversation at
15
- uncached prices. See
10
+ The `model` field in `agent.ts` accepts `defineDynamic({ events })`. Resolvers
11
+ run at `session.started`, `turn.started`, or `step.started` (precedence: step >
12
+ turn > session). Every matching handler must return a concrete model. A
13
+ missing, invalid, or throwing selection fails the turn before model-dependent
14
+ work begins. Prefer `session.started` — prompt caches are per model, so
15
+ switching mid-session re-ingests the conversation at uncached prices. See
16
16
  [agent configuration](../agent-config#choose-the-model-dynamically) for the
17
17
  full contract.
18
18
 
19
- The agent always needs exactly one model, so the compiled fallback anchors
20
- build-time metadata. Tools, skills, instructions, and subagents default by
21
- authoring a static entry (or returning `null`), so `fallback` on their
22
- `defineDynamic` export is a build error.
19
+ Dynamic models do not compile a default model or model metadata. When a
20
+ resolver first selects a model, eve normalizes the selection and resolves any
21
+ omitted context-window metadata from the AI Gateway catalog. Dynamic tools,
22
+ skills, instructions, and subagents may return `null` to omit a capability.
23
23
 
24
24
  ## Dynamic subagents
25
25
 
26
26
  Wrap a declared subagent's own `agent.ts` in `defineDynamic` when its
27
27
  availability depends on the caller, tenant, environment, or a feature flag.
28
- Return the child definition to configure and expose it. Return `null` or
29
- `undefined` to omit it from the parent's model-visible tools.
28
+ Return the child definition to configure and expose it. Return `null` to omit
29
+ it from the parent's model-visible tools.
30
30
 
31
31
  ```ts title="agent/subagents/finance/agent.ts"
32
32
  import { defineAgent, defineDynamic } from "eve";
@@ -44,15 +44,19 @@ export default defineDynamic({
44
44
  });
45
45
  ```
46
46
 
47
- eve always compiles the subagent's filesystem manifest, including its
48
- instructions, tools, skills, connections, sandbox, and nested subagents. When
49
- the resolver selects it, eve injects the returned agent configuration into that
50
- compiled manifest. Each resolution can return a different model or other
51
- runtime agent settings. Runtime-selected models must use string model IDs;
52
- build and Workflow-world configuration cannot be selected at runtime.
47
+ eve always compiles the subagent's filesystem resources, including its
48
+ instructions, tools, skills, connections, sandbox, and nested subagents. It
49
+ does not compile an agent config or placeholder model for a dynamic subagent.
50
+ When the resolver selects the subagent, eve combines the returned config with
51
+ those resources before starting the child session. Each resolution can return
52
+ a different model or other runtime agent settings. A returned local config
53
+ must use a static model; it cannot contain another `defineDynamic` model.
54
+ Runtime-selected models must use string model IDs. Put build configuration on
55
+ the outer `defineDynamic` definition; build and Workflow-world configuration
56
+ cannot be selected in a handler result.
53
57
 
54
58
  A single-file remote subagent uses the same lifecycle. Return
55
- `defineRemoteAgent(...)` to expose the selected deployment, or nil to omit it:
59
+ `defineRemoteAgent(...)` to expose the selected deployment, or `null` to omit it:
56
60
 
57
61
  ```ts title="agent/subagents/finance.ts"
58
62
  import { defineDynamic, defineRemoteAgent } from "eve";
@@ -77,7 +81,7 @@ outbound request without entering durable workflow state.
77
81
 
78
82
  Dynamic subagents support `session.started` and `turn.started`. A turn selection
79
83
  shadows the session selection for that turn, including when the turn handler
80
- returns nil. If a resolver throws or returns an invalid definition, eve logs the
84
+ returns `null`. If a resolver throws or returns an invalid definition, eve logs the
81
85
  failure and omits the subagent.
82
86
 
83
87
  The resolved set applies to local and remote direct delegation and the
@@ -22,7 +22,13 @@ Run `eve init` with a project name:
22
22
  npx eve@latest init my-agent
23
23
  ```
24
24
 
25
- The command creates `my-agent/`, installs dependencies, initializes Git, and starts eve's development server. If a supported coding-agent REPL is available, eve offers to open it instead.
25
+ The command creates `my-agent/`, installs dependencies, and initializes Git. If a supported coding-agent REPL is available, eve offers to start the development server, open the REPL, or exit after scaffolding.
26
+
27
+ Pass an AI Gateway model ID or reasoning effort when you do not want the defaults:
28
+
29
+ ```bash
30
+ npx eve@latest init my-agent --model openai/gpt-5.5 --reasoning high
31
+ ```
26
32
 
27
33
  ## Run the agent
28
34
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  title: "CLI"
3
- description: "Reference for every eve CLI command: init, info, build, start, dev, logs, trace, link, deploy, eval, channels, and extension."
3
+ description: "Reference for every eve CLI command: init, set, info, build, start, dev, logs, trace, link, deploy, eval, channels, and extension."
4
4
  ---
5
5
 
6
6
  The `eve` binary (`bin: eve`) runs from your app root, and every command first loads `.env`/`.env.local` from that root. Running `eve` with no command runs `eve dev`.
@@ -26,6 +26,7 @@ The `eve` binary (`bin: eve`) runs from your app root, and every command first l
26
26
  | `eve channels list` | List user-authored channels |
27
27
  | `eve extension init [target]` | Create a new extension package |
28
28
  | `eve extension build` | Build the current package as an extension |
29
+ | `eve set` | Change the root agent's model and reasoning effort |
29
30
  | `eve add <item>` | Install an item from the official or a configured shadcn registry |
30
31
  | `eve registry <command>` | Add sources and list, search, or view registry catalog items |
31
32
 
@@ -34,7 +35,7 @@ When `eve build` fails on discovery errors, it prints the full diagnostics repor
34
35
  ## `eve init`
35
36
 
36
37
  ```bash
37
- eve init [target] [--channel-web-nextjs]
38
+ eve init [target] [--model <provider/model-id>] [--reasoning <effort>] [--channel-web-nextjs]
38
39
  ```
39
40
 
40
41
  Creates a new agent app or adds an agent to an existing app. Always installs dependencies. New directories also initialize Git.
@@ -45,11 +46,13 @@ Creates a new agent app or adds an agent to an existing app. Always installs dep
45
46
  | `eve init .` (or an existing project dir) | Adds `agent/` plus missing `eve`, `ai`, and `zod` deps. Needs a `package.json` and no `agent/` files yet |
46
47
  | `eve init` with no target | Same as `eve init .`, except coding agents (Claude Code, Cursor, and similar) get a setup guide instead of scaffolding — they have not chosen a name yet |
47
48
 
48
- After scaffolding, a human terminal usually continues into `eve dev` (or a coding-agent REPL if one is on `PATH` and you pick it). Coding-agent launches print the next steps instead of opening the TUI, so the session does not get stuck. Fresh projects use the parent workspace's package manager when there is one; otherwise they use the manager that launched `eve init`.
49
+ After scaffolding, a human terminal usually continues into `eve dev`. If a coding-agent REPL is on `PATH`, the handoff menu can open it instead or exit without starting either process. Coding-agent launches print the next steps instead of opening the TUI, so the session does not get stuck. Fresh projects use the parent workspace's package manager when there is one; otherwise they use the manager that launched `eve init`.
49
50
 
50
- | Flag | Type | Default | Description |
51
- | ---------------------- | ---- | ------- | ---------------------------------------------------------------------------------------------------- |
52
- | `--channel-web-nextjs` | flag | off | Add the Web Chat app (Next.js). Not for existing projects — run `eve add channel/web` there instead. |
51
+ | Flag | Type | Default | Description |
52
+ | ---------------------- | ------ | --------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
53
+ | `--model <model>` | string | `anthropic/claude-sonnet-5` | Set the root agent's AI Gateway model ID. |
54
+ | `--reasoning <effort>` | enum | provider default | Set reasoning to `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`. `provider-default` leaves the field unauthored. |
55
+ | `--channel-web-nextjs` | flag | off | Add the Web Chat app (Next.js). Not for existing projects — run `eve add channel/web` there instead. |
53
56
 
54
57
  ## `eve extension`
55
58
 
@@ -81,6 +84,28 @@ eve extension build
81
84
 
82
85
  Builds the complete agent-shaped extension tree into its configured dist root, emits declarations and compatibility metadata, and fills the package `exports` map. The original TypeScript source is not required in the published package.
83
86
 
87
+ ## Set model settings
88
+
89
+ Change the root agent's AI Gateway model and reasoning effort without opening the dev TUI:
90
+
91
+ ```bash
92
+ eve set \
93
+ --model openai/gpt-5.6-sol \
94
+ --reasoning high
95
+ ```
96
+
97
+ Pass either flag by itself to change one setting. When you pass both, eve writes
98
+ them to `agent/agent.ts` in one source edit. `--reasoning` accepts
99
+ `provider-default`, `none`, `minimal`, `low`, `medium`, `high`, or `xhigh`;
100
+ `provider-default` removes the authored `reasoning` field.
101
+
102
+ The command uses the same model ID validation and source editor as `/model` in
103
+ the local dev TUI. It does not configure model credentials. The `--model` flag
104
+ cannot rewrite models defined with `defineDynamic`, an environment expression,
105
+ or a provider-authored SDK model; change those models in `agent.ts`.
106
+ `--reasoning` can still update an editable root config when its model comes from
107
+ an SDK call.
108
+
84
109
  ## Registry items
85
110
 
86
111
  Commands for installing and discovering [shadcn registry](https://ui.shadcn.com/docs/registry) items. Official registry items use a kind and slug (for example, `extension/agent-browser`); URLs and configured registry addresses are also supported.
@@ -98,7 +123,7 @@ eve registry view @acme/my-extension
98
123
  eve add @acme/my-extension
99
124
  ```
100
125
 
101
- `eve add` asks before running setup declared by an official item and runs multiple declared flows in declaration order. Product-level packages can offer independently installable components: `eve add linear` lets you select the Linear Channel, Linear MCP, or both, with both selected by default. `--yes` installs a package's default components and accepts detected or recommended setup answers.
126
+ `eve add` asks before running setup declared by an official item and runs multiple declared flows in declaration order. Product-level packages can offer independently installable components: `eve add linear` lets you select the Linear Channel, Linear MCP, or both, with both selected by default. Interactive Vercel-backed setup signs in and creates or links a project when needed instead of stopping with a prerequisite. `--yes` installs a package's default components and accepts detected or recommended setup answers.
102
127
 
103
128
  Coding agents should use `eve add <item> --non-interactive`, adding `--yes` to accept recommended setup values and reduce setup round trips. Explicit `--answer` values take precedence. This mode never opens an eve prompt. When a component or setup decision is missing, the NDJSON terminal event includes a stable question key and a safe continuation command; add the requested answer to that command. Supply answers with repeatable `--answer 'key=<JSON value>'` options. Follow a reported `eve link` prerequisite before retrying Vercel Connect setup. Do not put secrets in command-line answers; use the integration's documented environment variable or secret store.
104
129
 
@@ -305,7 +330,7 @@ Links the current directory to a Vercel project. After selecting a team, you can
305
330
  eve deploy
306
331
  ```
307
332
 
308
- Deploys the agent to Vercel production (`vercel deploy --prod`), installing dependencies first and pulling environment variables after. An already-linked project deploys with or without a TTY (non-interactive runs pass the non-interactive `vercel` flags). An unlinked directory walks the `eve link` pickers when a terminal is present, and exits with guidance otherwise.
333
+ Deploys the agent to Vercel production (`vercel deploy --prod`), installing dependencies first and pulling environment variables after. An already-linked project deploys with or without a TTY (non-interactive runs pass the non-interactive `vercel` flags). When a terminal is present, an unlinked deployment signs in to Vercel if needed and then walks the `eve link` pickers; otherwise, it exits with guidance.
309
334
 
310
335
  ## `eve eval`
311
336
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.32.0",
3
+ "version": "0.33.0",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [