eve 0.27.1 → 0.27.2

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 (33) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/dist/src/chunks/{use-eve-agent-PMY2WkAt.js → use-eve-agent-CbF0l_Fp.js} +66 -27
  3. package/dist/src/chunks/{use-eve-agent-AeQLLhu9.js → use-eve-agent-CgxB9WQv.js} +66 -27
  4. package/dist/src/client/index.d.ts +1 -1
  5. package/dist/src/client/open-stream.d.ts +15 -2
  6. package/dist/src/client/open-stream.js +1 -1
  7. package/dist/src/client/session.d.ts +3 -2
  8. package/dist/src/client/session.js +1 -1
  9. package/dist/src/client/types.d.ts +32 -0
  10. package/dist/src/internal/application/package.js +1 -1
  11. package/dist/src/internal/authored-module-evaluation-error.d.ts +2 -0
  12. package/dist/src/internal/authored-module-evaluation-error.js +4 -0
  13. package/dist/src/internal/authored-module-loader.js +2 -2
  14. package/dist/src/packages/eve-catalog/src/index.js +1 -1
  15. package/dist/src/public/channels/eve.js +2 -1
  16. package/dist/src/public/channels/slack/api.d.ts +26 -2
  17. package/dist/src/public/channels/slack/api.js +1 -1
  18. package/dist/src/public/channels/slack/attachments.d.ts +6 -5
  19. package/dist/src/public/channels/slack/index.d.ts +1 -1
  20. package/dist/src/public/channels/slack/interactions.d.ts +2 -1
  21. package/dist/src/public/channels/slack/interactions.js +1 -1
  22. package/dist/src/public/channels/slack/slackChannel.d.ts +51 -14
  23. package/dist/src/public/channels/slack/slackChannel.js +1 -1
  24. package/dist/src/public/channels/slack/thread.d.ts +4 -3
  25. package/dist/src/public/channels/slack/thread.js +1 -1
  26. package/dist/src/setup/scaffold/create/project.js +1 -1
  27. package/dist/src/svelte/index.js +1 -1
  28. package/dist/src/svelte/use-eve-agent.js +1 -1
  29. package/dist/src/vue/index.js +1 -1
  30. package/dist/src/vue/use-eve-agent.js +1 -1
  31. package/docs/channels/slack.mdx +40 -3
  32. package/docs/guides/client/streaming.mdx +15 -0
  33. package/package.json +1 -1
@@ -54,7 +54,7 @@ VERCEL_USE_EXPERIMENTAL_FRAMEWORKS=1 vercel deploy --prod
54
54
 
55
55
  Message hooks return `{ auth }` to dispatch, `null` to drop, or `{ auth, context }` to inject background into history.
56
56
 
57
- - `onMessage(ctx, message)` handles Slack `message` events. `ctx.isBotMentioned()` and `ctx.isSubscribed()` support mention and active-thread policies; check `message.author?.isBot` when bot messages should be ignored.
57
+ - `onMessage(ctx, message)` handles Slack `message` events. eve drops messages authored by the installed app before this hook runs, preventing self-reply loops. Messages from other bots remain visible; check `message.author?.isBot` when those should also be ignored. `ctx.isBotMentioned()` and `ctx.isSubscribed()` support mention and active-thread policies.
58
58
  - `onAppMention(ctx, message)` handles only `app_mention` and takes precedence over `onMessage`. Its default derives workspace-scoped auth and posts `Thinking…`.
59
59
  - `onDirectMessage(ctx, message)` handles only DMs and takes precedence over `onMessage`. Bot-authored messages and edits are filtered first; Slack requires `message.im` and `im:history`.
60
60
 
@@ -88,6 +88,41 @@ export default slackChannel({
88
88
 
89
89
  `isBotMentioned()` identifies an explicit mention. `isSubscribed()` checks whether the message belongs to a thread with an active eve session. For Vercel Connect, open **Advanced** when creating the connector and add `message.channels` under **Trigger Event Types** and `channels:history` under **Bot Scopes**. Private channels additionally need `message.groups` and `groups:history`.
90
90
 
91
+ Use `ctx.thread.listParticipants()` when routing depends on who has joined the thread. It fetches the current thread and returns unique human Slack user ids in first-appearance order, so the first id is the starting author for a human-started thread. Bot and system messages are excluded:
92
+
93
+ ```ts
94
+ async onMessage(ctx, message) {
95
+ if (!message.author || message.author.isBot) return null;
96
+
97
+ const participants = await ctx.thread.listParticipants();
98
+ const isGroupFollowUpFromStarter =
99
+ participants.length > 1 && participants[0] === message.author.userId;
100
+
101
+ return isGroupFollowUpFromStarter ? { auth: null } : null;
102
+ }
103
+ ```
104
+
105
+ Like `threadContext`, this helper calls `conversations.replies` and requires the matching Slack history scope. It observes at most the first 50 messages of the thread, and a failed fetch is logged and swallowed, so the returned list may be empty or stale — treat an unexpected empty list as "don't route" rather than "no participants".
106
+
107
+ #### Cancel and replace in-flight work
108
+
109
+ Message hooks (`onMessage`, `onAppMention`, and `onDirectMessage`) receive a thread-bound `ctx.cancel({ turnId? })` helper. Call it before returning `{ auth }` to stop the current turn and queue the new Slack message as replacement input, producing a debounce-like experience:
110
+
111
+ ```ts title="agent/channels/slack.ts"
112
+ export default slackChannel({
113
+ credentials: connectSlackCredentials("slack/my-agent"),
114
+ async onMessage(ctx, message) {
115
+ const shouldHandle = ctx.isBotMentioned() || (await ctx.isSubscribed());
116
+ if (!shouldHandle || message.author?.isBot) return null;
117
+
118
+ await ctx.cancel();
119
+ return { auth: null };
120
+ },
121
+ });
122
+ ```
123
+
124
+ `"accepted"` means the cancellation request was consumed; `"no_active_turn"` means the thread had no cancellable turn. 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 bound helper, which is useful for a Stop button that should cancel without replacement input.
125
+
91
126
  ### Other Events API callbacks
92
127
 
93
128
  Use `onEvent` for subscribed events such as `reaction_added`, `team_join`, or `channel_created`. It receives the raw, open-ended Slack event and owns control flow. `ctx.receive(options)` is the current Slack channel's pre-bound form of the schedule API's `receive(slack, options)`: call it zero, one, or many times to start turns. Each call accepts `message`, `target`, and `auth`, and returns the resulting session.
@@ -118,6 +153,8 @@ export default slackChannel({
118
153
 
119
154
  The webhook invocation already keeps an awaited `onEvent` handler alive. Use `ctx.waitUntil(promise)` for deliberately detached work, matching a handler-form schedule. `ctx.slack.request(operation, body)` provides workspace-scoped Slack Web API access, while `ctx.envelope` carries delivery metadata such as `team_id`, `event_id`, and `event_time`. Calls to `ctx.receive` automatically seed the callback's team id into Slack session state.
120
155
 
156
+ Because a generic event is not necessarily tied to one thread, its cancellation helper takes the target explicitly: `ctx.cancel({ channelId, threadTs, turnId? })`. Pair it with `ctx.receive(...)` when an event should replace in-flight work, or call it alone to stop the turn.
157
+
121
158
  `onEvent` is the raw fallback after the message hooks. If an event is not claimed by `onAppMention`, `onDirectMessage`, or `onMessage`, an authored `onEvent` receives it; otherwise eve applies the built-in mention/DM default or ignores it.
122
159
 
123
160
  `onEvent` covers JSON `event_callback` deliveries only. URL verification, slash commands, and interactive payloads do not reach it. Add every desired event and required OAuth scope to the Slack app's Event Subscriptions configuration; eve can only handle events Slack sends.
@@ -137,10 +174,10 @@ export default slackChannel({
137
174
  `since` sets the boundary for what each mention injects and accepts three values:
138
175
 
139
176
  - `"thread-root"` (the default): every prior message in the thread, on every mention. `threadContext: {}` behaves the same.
140
- - `"last-agent-reply"`: only messages after the agent's last reply, keeping repeated mentions incremental.
177
+ - `"last-agent-reply"`: only messages after this installed agent's last reply, keeping repeated mentions incremental. Replies from other Slack bots do not move the boundary.
141
178
  - A predicate `(message: SlackThreadMessage) => boolean`: only messages after the last one it matches, such as "since the last message that mentioned a particular user".
142
179
 
143
- `threadContext` performs one `conversations.replies` request for each triggering thread reply and requires the matching Slack history scope. 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.
180
+ `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.
144
181
 
145
182
  ### Slack API calls outside a handler
146
183
 
@@ -105,6 +105,21 @@ If you support refresh while an authorization prompt is pending, keep the sessio
105
105
 
106
106
  HTTP connections can end before a run does. The client reconnects from the number of events already consumed, so long turns continue without replaying events. It stops at a turn boundary, when aborted, or when the stream can no longer make progress.
107
107
 
108
+ Set `streamReconnectPolicy: { reconnect: false }` when a relay or proxy owns the cursor and reconnection policy. This makes a single stream GET attempt and returns when that connection ends; it does not stop the server-side turn:
109
+
110
+ ```ts
111
+ const response = await session.send({
112
+ message: "Run the long operation.",
113
+ streamReconnectPolicy: { reconnect: false },
114
+ });
115
+
116
+ for await (const event of response) {
117
+ console.log(event.type);
118
+ }
119
+ ```
120
+
121
+ The same option is available on manual attachments as `session.stream({ streamReconnectPolicy: { reconnect: false } })`.
122
+
108
123
  ## Open a stream manually
109
124
 
110
125
  Use `session.stream()` when you already have a session cursor and only need to attach to the existing stream:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve",
3
- "version": "0.27.1",
3
+ "version": "0.27.2",
4
4
  "private": false,
5
5
  "description": "Filesystem-first framework for durable backend AI agents that run anywhere.",
6
6
  "keywords": [