@vellumai/assistant 0.10.3-dev.202606252138.db46320 → 0.10.3-dev.202606252237.df0fc92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/openapi.yaml CHANGED
@@ -17426,6 +17426,30 @@ paths:
17426
17426
  webUrl:
17427
17427
  type: string
17428
17428
  additionalProperties: false
17429
+ eventKind:
17430
+ type: string
17431
+ enum:
17432
+ - message
17433
+ - reaction
17434
+ reaction:
17435
+ type: object
17436
+ properties:
17437
+ emoji:
17438
+ type: string
17439
+ op:
17440
+ type: string
17441
+ enum:
17442
+ - added
17443
+ - removed
17444
+ actorDisplayName:
17445
+ type: string
17446
+ targetChannelTs:
17447
+ type: string
17448
+ required:
17449
+ - emoji
17450
+ - op
17451
+ - targetChannelTs
17452
+ additionalProperties: false
17429
17453
  required:
17430
17454
  - channelId
17431
17455
  - channelTs
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.10.3-dev.202606252138.db46320",
3
+ "version": "0.10.3-dev.202606252237.df0fc92",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -109,6 +109,13 @@ interface MessagePayload {
109
109
  sender?: { displayName?: string; externalUserId?: string };
110
110
  messageLink?: { appUrl?: string; webUrl?: string };
111
111
  threadLink?: { appUrl?: string; webUrl?: string };
112
+ eventKind?: "message" | "reaction";
113
+ reaction?: {
114
+ emoji: string;
115
+ op: "added" | "removed";
116
+ actorDisplayName?: string;
117
+ targetChannelTs: string;
118
+ };
112
119
  };
113
120
  }
114
121
 
@@ -482,6 +489,7 @@ describe("handleListMessages page=latest", () => {
482
489
  webUrl:
483
490
  "https://example.slack.com/archives/C123ABCDEF/p1710000000000100",
484
491
  },
492
+ eventKind: "message",
485
493
  });
486
494
  });
487
495
 
@@ -527,6 +535,7 @@ describe("handleListMessages page=latest", () => {
527
535
  webUrl:
528
536
  "https://example.slack.com/archives/C123ABCDEF/p1710000000000200",
529
537
  },
538
+ eventKind: "message",
530
539
  });
531
540
  });
532
541
 
@@ -283,6 +283,13 @@ const SlackMessageLinkSchema = z.object({
283
283
  webUrl: z.string().optional(),
284
284
  });
285
285
 
286
+ const SlackReactionSchema = z.object({
287
+ emoji: z.string(),
288
+ op: z.enum(["added", "removed"]),
289
+ actorDisplayName: z.string().optional(),
290
+ targetChannelTs: z.string(),
291
+ });
292
+
286
293
  /** Slack provenance for a history row that originated from a Slack channel. */
287
294
  export const ConversationSlackMessageSchema = z.object({
288
295
  channelId: z.string(),
@@ -297,6 +304,8 @@ export const ConversationSlackMessageSchema = z.object({
297
304
  .optional(),
298
305
  messageLink: SlackMessageLinkSchema.optional(),
299
306
  threadLink: SlackMessageLinkSchema.optional(),
307
+ eventKind: z.enum(["message", "reaction"]).optional(),
308
+ reaction: SlackReactionSchema.optional(),
300
309
  });
301
310
  export type ConversationSlackMessage = z.infer<
302
311
  typeof ConversationSlackMessageSchema
@@ -1,5 +1,5 @@
1
1
  import type { ExternalConversationBinding } from "../memory/external-conversation-store.js";
2
- import type { ChannelBindingMetadata } from "./provider-types.js";
2
+ import type { ChannelBindingMetadata } from "./channel-binding-schema.js";
3
3
  import { buildSlackBindingMetadata } from "./providers/slack/binding-metadata.js";
4
4
 
5
5
  type BindingMetadataBuilder = (
@@ -0,0 +1,51 @@
1
+ import { z } from "zod";
2
+
3
+ const slackThreadSchema = z.object({
4
+ channelId: z.string(),
5
+ threadTs: z.string(),
6
+ link: z
7
+ .object({
8
+ appUrl: z.string().optional(),
9
+ webUrl: z.string().optional(),
10
+ })
11
+ .optional(),
12
+ });
13
+
14
+ const slackChannelSchema = z.object({
15
+ channelId: z.string(),
16
+ name: z.string().optional(),
17
+ link: z.object({ webUrl: z.string() }).optional(),
18
+ });
19
+
20
+ /**
21
+ * Wire shape of a serialized conversation channel binding — the single source
22
+ * of truth for this contract.
23
+ *
24
+ * Consumed as a route `responseBody` (which drives `openapi.yaml` generation
25
+ * and, in turn, the web client's generated daemon types), and the server-side
26
+ * builders derive their TypeScript types from it via `z.infer`. The shape is
27
+ * therefore declared exactly once.
28
+ */
29
+ export const channelBindingSchema = z.object({
30
+ sourceChannel: z.string(),
31
+ externalChatId: z.string(),
32
+ externalChatName: z.string().optional(),
33
+ externalThreadId: z.string().optional(),
34
+ externalUserId: z.string().nullable(),
35
+ displayName: z.string().nullable(),
36
+ username: z.string().nullable(),
37
+ slackThread: slackThreadSchema.optional(),
38
+ slackChannel: slackChannelSchema.optional(),
39
+ });
40
+
41
+ type ChannelBinding = z.infer<typeof channelBindingSchema>;
42
+
43
+ /**
44
+ * The channel-specific fields a per-channel builder contributes to a binding
45
+ * (everything beyond the channel-neutral base). Picked from the schema above
46
+ * so a builder's output can never drift from the wire contract.
47
+ */
48
+ export type ChannelBindingMetadata = Pick<
49
+ ChannelBinding,
50
+ "externalChatName" | "slackThread" | "slackChannel"
51
+ >;
@@ -1,13 +1,5 @@
1
1
  /** Platform-agnostic types for the messaging provider abstraction. */
2
2
 
3
- /**
4
- * Extra, channel-specific fields a channel contributes to a serialized
5
- * conversation channel binding (e.g. deep links back to the source message).
6
- * Additive by design: each channel returns its own fields, so this is an open
7
- * record rather than a committed cross-channel schema.
8
- */
9
- export type ChannelBindingMetadata = Record<string, unknown>;
10
-
11
3
  export interface Conversation {
12
4
  id: string;
13
5
  name: string;
@@ -1,6 +1,6 @@
1
1
  import { getConfig } from "../../../config/loader.js";
2
2
  import type { ExternalConversationBinding } from "../../../memory/external-conversation-store.js";
3
- import type { ChannelBindingMetadata } from "../../provider-types.js";
3
+ import type { ChannelBindingMetadata } from "../../channel-binding-schema.js";
4
4
  import {
5
5
  buildSlackMessageDeepLinks,
6
6
  buildSlackWebChannelUrl,
@@ -12,10 +12,12 @@ import {
12
12
  * links that jump back to the source thread and channel in the Slack app or
13
13
  * web client.
14
14
  *
15
- * The returned fields are spread onto the channel-neutral binding by the
16
- * serializerSlack is the only channel that can currently produce
17
- * message-level deep links, because the link inputs (workspace team id/url +
18
- * a stable per-message timestamp) only exist for Slack.
15
+ * The return type is derived from the channel-binding Zod schema
16
+ * (`ChannelBindingMetadata`)the single source of truth that also drives
17
+ * `openapi.yaml` and the web client's generated types so this builder cannot
18
+ * drift from the wire contract. Slack is the only channel that can currently
19
+ * produce message-level deep links, because the link inputs (workspace team
20
+ * id/url + a stable per-message timestamp) only exist for Slack.
19
21
  */
20
22
  export function buildSlackBindingMetadata(
21
23
  binding: ExternalConversationBinding,
@@ -31,6 +31,7 @@ import {
31
31
  import type { ConversationType } from "../../memory/conversation-types.js";
32
32
  import { getBindingsForConversations } from "../../memory/external-conversation-store.js";
33
33
  import { listGroups } from "../../memory/group-crud.js";
34
+ import { channelBindingSchema } from "../../messaging/channel-binding-schema.js";
34
35
  import { UserError } from "../../util/errors.js";
35
36
  import { getLogger } from "../../util/logger.js";
36
37
  import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
@@ -86,35 +87,6 @@ const assistantAttentionSchema = z.object({
86
87
  .optional(),
87
88
  });
88
89
 
89
- const slackThreadSchema = z.object({
90
- channelId: z.string(),
91
- threadTs: z.string(),
92
- link: z
93
- .object({
94
- appUrl: z.string().optional(),
95
- webUrl: z.string().optional(),
96
- })
97
- .optional(),
98
- });
99
-
100
- const slackChannelSchema = z.object({
101
- channelId: z.string(),
102
- name: z.string().optional(),
103
- link: z.object({ webUrl: z.string() }).optional(),
104
- });
105
-
106
- const channelBindingSchema = z.object({
107
- sourceChannel: z.string(),
108
- externalChatId: z.string(),
109
- externalChatName: z.string().optional(),
110
- externalThreadId: z.string().optional(),
111
- externalUserId: z.string().nullable(),
112
- displayName: z.string().nullable(),
113
- username: z.string().nullable(),
114
- slackThread: slackThreadSchema.optional(),
115
- slackChannel: slackChannelSchema.optional(),
116
- });
117
-
118
90
  const forkParentSchema = z.object({
119
91
  conversationId: z.string(),
120
92
  messageId: z.string(),
@@ -394,6 +394,8 @@ function buildSlackHistoryMessage(
394
394
  : {}),
395
395
  ...(messageLink ? { messageLink } : {}),
396
396
  ...(threadLink ? { threadLink } : {}),
397
+ ...(slackMeta.eventKind ? { eventKind: slackMeta.eventKind } : {}),
398
+ ...(slackMeta.reaction ? { reaction: slackMeta.reaction } : {}),
397
399
  };
398
400
  }
399
401