vessels-sdk 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -38,14 +38,20 @@ const { messageId, vesselId } = await vessels.push({
38
38
  });
39
39
  ```
40
40
 
41
- Get your API key from Settings API Keys in the [Vessels app](https://vessels.app), or via the CLI:
41
+ Get your API key via the CLI (Claude Code / AI assistants fully non-interactive):
42
42
 
43
43
  ```bash
44
44
  npm install -g vessels
45
- vessels login
46
- vessels keys create
45
+
46
+ # Step 1: send OTP to your email
47
+ vessels init --email me@example.com
48
+
49
+ # Step 2: verify with the code from your inbox — prints VESSELS_API_KEY=vsl_xxx
50
+ vessels init --email me@example.com --otp 847293
47
51
  ```
48
52
 
53
+ Or sign in at [vessels.app](https://vessels.app) → Settings → API Keys.
54
+
49
55
  ---
50
56
 
51
57
  ## API reference
package/dist/index.cjs CHANGED
@@ -1,5 +1,212 @@
1
1
  'use strict';
2
2
 
3
+ var zod = require('zod');
4
+
5
+ // ../types/src/index.ts
6
+ var SourceSchema = zod.z.enum(["agent", "user", "system"]);
7
+ var InteractionTypeSchema = zod.z.enum([
8
+ "approval",
9
+ "choice",
10
+ "checklist",
11
+ "text_input",
12
+ "confirm_preview"
13
+ ]);
14
+ var ApprovalInteractionSchema = zod.z.object({
15
+ type: zod.z.literal("approval"),
16
+ prompt: zod.z.string().min(1),
17
+ approveLabel: zod.z.string().optional(),
18
+ rejectLabel: zod.z.string().optional(),
19
+ reasonRequired: zod.z.boolean().optional(),
20
+ metadata: zod.z.record(zod.z.unknown()).optional()
21
+ });
22
+ var ChoiceOptionSchema = zod.z.object({
23
+ id: zod.z.string().min(1),
24
+ label: zod.z.string().min(1)
25
+ });
26
+ var ChoiceInteractionSchema = zod.z.object({
27
+ type: zod.z.literal("choice"),
28
+ prompt: zod.z.string().min(1),
29
+ options: zod.z.array(ChoiceOptionSchema).min(1),
30
+ allowCustom: zod.z.boolean().optional(),
31
+ customPlaceholder: zod.z.string().optional(),
32
+ metadata: zod.z.record(zod.z.unknown()).optional()
33
+ });
34
+ var ChecklistOptionSchema = zod.z.object({
35
+ id: zod.z.string().min(1),
36
+ label: zod.z.string().min(1),
37
+ checked: zod.z.boolean().optional()
38
+ });
39
+ var ChecklistInteractionSchema = zod.z.object({
40
+ type: zod.z.literal("checklist"),
41
+ prompt: zod.z.string().min(1),
42
+ options: zod.z.array(ChecklistOptionSchema).min(1),
43
+ minSelections: zod.z.number().int().min(0).optional(),
44
+ submitLabel: zod.z.string().optional(),
45
+ metadata: zod.z.record(zod.z.unknown()).optional()
46
+ });
47
+ var TextInputInteractionSchema = zod.z.object({
48
+ type: zod.z.literal("text_input"),
49
+ prompt: zod.z.string().min(1),
50
+ placeholder: zod.z.string().optional(),
51
+ multiline: zod.z.boolean().optional(),
52
+ submitLabel: zod.z.string().optional(),
53
+ metadata: zod.z.record(zod.z.unknown()).optional()
54
+ });
55
+ var ConfirmPreviewInteractionSchema = zod.z.object({
56
+ type: zod.z.literal("confirm_preview"),
57
+ prompt: zod.z.string().min(1),
58
+ previewUrl: zod.z.string().url(),
59
+ previewLabel: zod.z.string().optional(),
60
+ approveLabel: zod.z.string().optional(),
61
+ rejectLabel: zod.z.string().optional(),
62
+ reasonRequiredOnReject: zod.z.boolean().optional(),
63
+ metadata: zod.z.record(zod.z.unknown()).optional()
64
+ });
65
+ var InteractionSchema = zod.z.discriminatedUnion("type", [
66
+ ApprovalInteractionSchema,
67
+ ChoiceInteractionSchema,
68
+ ChecklistInteractionSchema,
69
+ TextInputInteractionSchema,
70
+ ConfirmPreviewInteractionSchema
71
+ ]);
72
+ var AgentActivityTypeSchema = zod.z.enum(["thinking", "searching", "tool_use", "browsing", "processing"]);
73
+ var AgentActivitySchema = zod.z.object({
74
+ type: AgentActivityTypeSchema,
75
+ label: zod.z.string().max(200).optional()
76
+ });
77
+ var CardFieldSchema = zod.z.object({
78
+ label: zod.z.string().min(1),
79
+ value: zod.z.string()
80
+ });
81
+ var CardSchema = zod.z.object({
82
+ title: zod.z.string().min(1),
83
+ fields: zod.z.array(CardFieldSchema)
84
+ });
85
+ var AttachmentSchema = zod.z.discriminatedUnion("type", [
86
+ zod.z.object({ type: zod.z.literal("image"), url: zod.z.string().url() }),
87
+ zod.z.object({ type: zod.z.literal("file"), url: zod.z.string().url(), filename: zod.z.string().optional() })
88
+ ]);
89
+ var VesselStatusSchema = zod.z.enum(["active", "waiting", "resolved"]);
90
+ zod.z.object({
91
+ message: zod.z.string().min(1).max(1e4).optional(),
92
+ vessel: zod.z.string().optional(),
93
+ vesselTitle: zod.z.string().optional(),
94
+ card: CardSchema.optional(),
95
+ interaction: InteractionSchema.optional(),
96
+ previewUrl: zod.z.string().url().optional(),
97
+ metadata: zod.z.record(zod.z.unknown()).refine(
98
+ (v) => JSON.stringify(v).length < 16e3,
99
+ "metadata exceeds 16KB limit"
100
+ ).optional(),
101
+ pinCard: CardSchema.nullable().optional(),
102
+ vesselStatus: VesselStatusSchema.optional(),
103
+ labels: zod.z.array(zod.z.string().min(1).max(50)).max(10).optional(),
104
+ attachments: zod.z.array(AttachmentSchema).max(10).optional(),
105
+ suggestions: zod.z.array(zod.z.string().min(1).max(500)).max(5).optional(),
106
+ agentActivity: AgentActivitySchema.optional()
107
+ }).refine((d) => d.message || d.agentActivity, {
108
+ message: "Either message or agentActivity is required"
109
+ });
110
+ zod.z.object({
111
+ vessels: zod.z.array(zod.z.string().min(1)).min(1).max(100),
112
+ message: zod.z.string().min(1).max(1e4),
113
+ vesselTitle: zod.z.string().optional(),
114
+ card: CardSchema.optional(),
115
+ interaction: InteractionSchema.optional(),
116
+ pinCard: CardSchema.nullable().optional(),
117
+ vesselStatus: VesselStatusSchema.optional(),
118
+ attachments: zod.z.array(AttachmentSchema).max(10).optional(),
119
+ suggestions: zod.z.array(zod.z.string().min(1).max(500)).max(5).optional(),
120
+ metadata: zod.z.record(zod.z.unknown()).refine(
121
+ (v) => JSON.stringify(v).length < 16e3,
122
+ "metadata exceeds 16KB limit"
123
+ ).optional()
124
+ });
125
+ zod.z.object({
126
+ content: zod.z.string().min(1).max(1e4).optional(),
127
+ card: CardSchema.nullable().optional(),
128
+ attachments: zod.z.array(AttachmentSchema).max(10).nullable().optional(),
129
+ suggestions: zod.z.array(zod.z.string().min(1).max(500)).max(5).nullable().optional(),
130
+ agentActivity: AgentActivitySchema.nullable().optional()
131
+ }).refine((d) => Object.values(d).some((v) => v !== void 0), {
132
+ message: "At least one field required"
133
+ });
134
+ var ApprovalResponseSchema = zod.z.object({
135
+ action: zod.z.enum(["approved", "rejected"]),
136
+ reason: zod.z.string().optional()
137
+ });
138
+ var ChoiceResponseSchema = zod.z.object({
139
+ selected: zod.z.string(),
140
+ customValue: zod.z.string().nullable().optional()
141
+ });
142
+ var ChecklistResponseSchema = zod.z.object({
143
+ selected: zod.z.array(zod.z.string())
144
+ });
145
+ var TextInputResponseSchema = zod.z.object({
146
+ text: zod.z.string()
147
+ });
148
+ var ConfirmPreviewResponseSchema = zod.z.object({
149
+ action: zod.z.enum(["approved", "rejected"]),
150
+ reason: zod.z.string().optional()
151
+ });
152
+ zod.z.discriminatedUnion("interactionType", [
153
+ zod.z.object({ interactionType: zod.z.literal("approval"), response: ApprovalResponseSchema }),
154
+ zod.z.object({ interactionType: zod.z.literal("choice"), response: ChoiceResponseSchema }),
155
+ zod.z.object({ interactionType: zod.z.literal("checklist"), response: ChecklistResponseSchema }),
156
+ zod.z.object({ interactionType: zod.z.literal("text_input"), response: TextInputResponseSchema }),
157
+ zod.z.object({ interactionType: zod.z.literal("confirm_preview"), response: ConfirmPreviewResponseSchema })
158
+ ]);
159
+ var WebhookVesselSchema = zod.z.object({
160
+ id: zod.z.string(),
161
+ external_id: zod.z.string().nullable(),
162
+ title: zod.z.string().nullable(),
163
+ metadata: zod.z.record(zod.z.unknown())
164
+ });
165
+ var WebhookContextMessageSchema = zod.z.object({
166
+ source: SourceSchema,
167
+ content: zod.z.string().nullable(),
168
+ created_at: zod.z.string()
169
+ });
170
+ var WebhookOriginMessageSchema = zod.z.object({
171
+ id: zod.z.string(),
172
+ content: zod.z.string().nullable(),
173
+ interaction: zod.z.record(zod.z.unknown()).nullable(),
174
+ metadata: zod.z.record(zod.z.unknown()),
175
+ created_at: zod.z.string()
176
+ });
177
+ var WebhookInteractionResponsePayloadSchema = zod.z.object({
178
+ event: zod.z.literal("interaction.response"),
179
+ vessel_id: zod.z.string(),
180
+ workspace_id: zod.z.string(),
181
+ timestamp: zod.z.string(),
182
+ data: zod.z.object({
183
+ message_id: zod.z.string(),
184
+ interaction_type: InteractionTypeSchema,
185
+ response: zod.z.record(zod.z.unknown()),
186
+ response_id: zod.z.string(),
187
+ metadata: zod.z.record(zod.z.unknown()).optional(),
188
+ /** The agent message that carried the interaction (prompt, content, metadata). */
189
+ message: WebhookOriginMessageSchema,
190
+ vessel: WebhookVesselSchema
191
+ })
192
+ });
193
+ var WebhookUserMessagePayloadSchema = zod.z.object({
194
+ event: zod.z.literal("message.user"),
195
+ vessel_id: zod.z.string(),
196
+ workspace_id: zod.z.string(),
197
+ timestamp: zod.z.string(),
198
+ data: zod.z.object({
199
+ message_id: zod.z.string(),
200
+ content: zod.z.string(),
201
+ vessel: WebhookVesselSchema,
202
+ context: zod.z.array(WebhookContextMessageSchema)
203
+ })
204
+ });
205
+ var WebhookPayloadSchema = zod.z.discriminatedUnion("event", [
206
+ WebhookInteractionResponsePayloadSchema,
207
+ WebhookUserMessagePayloadSchema
208
+ ]);
209
+
3
210
  // src/index.ts
4
211
  var AgentActivityTypes = {
5
212
  thinking: "thinking",
@@ -124,6 +331,38 @@ var Vessels = class {
124
331
  if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
125
332
  return { ok: true };
126
333
  }
334
+ /**
335
+ * Read a vessel's message history — the human-facing record, for re-reading
336
+ * the channel (e.g. a stateless or just-restarted worker reconciling state).
337
+ * This is NOT your agent's memory; keep your canonical history in your own
338
+ * system. `vessel` is your own external_id string by default; pass
339
+ * { byUuid: true } if you hold a Vessels UUID. Newest-last, paginate with `before`.
340
+ */
341
+ async getMessages(opts) {
342
+ const params = new URLSearchParams();
343
+ if (opts.limit != null) params.set("limit", String(opts.limit));
344
+ if (opts.before) params.set("before", opts.before);
345
+ const path = opts.byUuid ? `/api/v1/vessels/${encodeURIComponent(opts.vessel)}/messages` : `/api/v1/vessels/by-external/${encodeURIComponent(opts.vessel)}/messages`;
346
+ const res = await this._fetch(`${this.baseUrl}${path}?${params}`, {
347
+ headers: { "Authorization": `Bearer ${this.apiKey}` }
348
+ });
349
+ const data = await res.json();
350
+ if (res.status === 401) throw new VesselsAuthError(data.error ?? "Unauthorized");
351
+ if (res.status === 404) throw new Error(data.error ?? "Vessel not found");
352
+ if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
353
+ const messages = (data.messages ?? []).map((m) => ({
354
+ id: m.id,
355
+ source: m.source,
356
+ content: m.content ?? null,
357
+ card: m.card ?? null,
358
+ interaction: m.interaction ?? null,
359
+ attachments: m.attachments ?? [],
360
+ suggestions: m.suggestions ?? [],
361
+ metadata: m.metadata ?? {},
362
+ createdAt: m.created_at
363
+ }));
364
+ return { messages, hasMore: data.has_more ?? false };
365
+ }
127
366
  // Interaction helpers
128
367
  approval(opts) {
129
368
  return { type: "approval", ...opts };
@@ -170,6 +409,13 @@ var Vessels = class {
170
409
  interactionType: e.interaction_type,
171
410
  response: e.response,
172
411
  interactionMetadata: e.interaction_metadata ?? null,
412
+ originMessage: e.message ? {
413
+ id: e.message.id,
414
+ content: e.message.content ?? null,
415
+ interaction: e.message.interaction ?? null,
416
+ metadata: e.message.metadata ?? {},
417
+ createdAt: e.message.created_at
418
+ } : null,
173
419
  user: e.user ?? null
174
420
  };
175
421
  }
@@ -237,6 +483,13 @@ var Vessels = class {
237
483
  interactionType: raw.data.interaction_type,
238
484
  response: raw.data.response,
239
485
  interactionMetadata: raw.data.metadata ?? null,
486
+ originMessage: raw.data.message ? {
487
+ id: raw.data.message.id,
488
+ content: raw.data.message.content ?? null,
489
+ interaction: raw.data.message.interaction ?? null,
490
+ metadata: raw.data.message.metadata ?? {},
491
+ createdAt: raw.data.message.created_at
492
+ } : null,
240
493
  user: raw.data.user ?? null
241
494
  };
242
495
  }
@@ -266,3 +519,6 @@ exports.Vessels = Vessels;
266
519
  exports.VesselsAuthError = VesselsAuthError;
267
520
  exports.VesselsRateLimitError = VesselsRateLimitError;
268
521
  exports.VesselsValidationError = VesselsValidationError;
522
+ exports.WebhookInteractionResponsePayloadSchema = WebhookInteractionResponsePayloadSchema;
523
+ exports.WebhookPayloadSchema = WebhookPayloadSchema;
524
+ exports.WebhookUserMessagePayloadSchema = WebhookUserMessagePayloadSchema;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _vessels_types from '@vessels/types';
2
- export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyPayload, PushPayload, TextInputInteraction } from '@vessels/types';
2
+ export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyPayload, PushPayload, TextInputInteraction, WebhookInteractionResponsePayload, WebhookInteractionResponsePayloadSchema, WebhookPayload, WebhookPayloadSchema, WebhookUserMessagePayload, WebhookUserMessagePayloadSchema } from '@vessels/types';
3
3
 
4
4
  declare const AgentActivityTypes: {
5
5
  readonly thinking: "thinking";
@@ -51,15 +51,26 @@ interface VesselContext {
51
51
  metadata: Record<string, unknown>;
52
52
  labels: string[];
53
53
  }
54
+ /** The agent message an interaction was attached to. */
55
+ interface OriginMessage {
56
+ id: string;
57
+ content: string | null;
58
+ /** The interaction object you originally pushed (type, prompt, options, labels…). */
59
+ interaction: Record<string, unknown> | null;
60
+ metadata: Record<string, unknown>;
61
+ createdAt: string;
62
+ }
54
63
  interface InteractionResponseEvent {
55
64
  id: string;
56
65
  type: 'interaction.response';
57
66
  timestamp: string;
58
67
  vessel: VesselContext;
59
68
  messageId: string;
60
- interactionType: string;
69
+ interactionType: _vessels_types.InteractionType;
61
70
  response: Record<string, unknown>;
62
71
  interactionMetadata: Record<string, unknown> | null;
72
+ /** The message that carried the interaction — so you know WHAT was responded to. */
73
+ originMessage: OriginMessage | null;
63
74
  user: {
64
75
  id: string;
65
76
  email: string;
@@ -75,11 +86,23 @@ interface UserMessageEvent {
75
86
  content: string | null;
76
87
  };
77
88
  context: Array<{
78
- source: string;
89
+ source: _vessels_types.Source;
79
90
  content: string | null;
80
91
  createdAt: string;
81
92
  }>;
82
93
  }
94
+ /** A message in a vessel, as returned by getMessages — the human-facing record. */
95
+ interface Message {
96
+ id: string;
97
+ source: _vessels_types.Source;
98
+ content: string | null;
99
+ card: Record<string, unknown> | null;
100
+ interaction: Record<string, unknown> | null;
101
+ attachments: Array<Record<string, unknown>>;
102
+ suggestions: string[];
103
+ metadata: Record<string, unknown>;
104
+ createdAt: string;
105
+ }
83
106
  type PollEvent = InteractionResponseEvent | UserMessageEvent;
84
107
  interface PollResponse {
85
108
  ok: true;
@@ -97,6 +120,22 @@ declare class Vessels {
97
120
  editMessage(messageId: string, patch: _vessels_types.MessagePatch): Promise<{
98
121
  ok: true;
99
122
  }>;
123
+ /**
124
+ * Read a vessel's message history — the human-facing record, for re-reading
125
+ * the channel (e.g. a stateless or just-restarted worker reconciling state).
126
+ * This is NOT your agent's memory; keep your canonical history in your own
127
+ * system. `vessel` is your own external_id string by default; pass
128
+ * { byUuid: true } if you hold a Vessels UUID. Newest-last, paginate with `before`.
129
+ */
130
+ getMessages(opts: {
131
+ vessel: string;
132
+ byUuid?: boolean;
133
+ limit?: number;
134
+ before?: string;
135
+ }): Promise<{
136
+ messages: Message[];
137
+ hasMore: boolean;
138
+ }>;
100
139
  approval(opts: {
101
140
  prompt: string;
102
141
  approveLabel?: string;
@@ -146,4 +185,4 @@ declare class Vessels {
146
185
  parseWebhookEvent(body: string, signature: string, webhookSecret: string): Promise<InteractionResponseEvent | UserMessageEvent | null>;
147
186
  }
148
187
 
149
- export { AgentActivityTypes, type InteractionResponseEvent, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, Vessels, VesselsAuthError, type VesselsConfig, VesselsRateLimitError, VesselsValidationError };
188
+ export { AgentActivityTypes, type InteractionResponseEvent, type Message, type OriginMessage, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, Vessels, VesselsAuthError, type VesselsConfig, VesselsRateLimitError, VesselsValidationError };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _vessels_types from '@vessels/types';
2
- export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyPayload, PushPayload, TextInputInteraction } from '@vessels/types';
2
+ export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyPayload, PushPayload, TextInputInteraction, WebhookInteractionResponsePayload, WebhookInteractionResponsePayloadSchema, WebhookPayload, WebhookPayloadSchema, WebhookUserMessagePayload, WebhookUserMessagePayloadSchema } from '@vessels/types';
3
3
 
4
4
  declare const AgentActivityTypes: {
5
5
  readonly thinking: "thinking";
@@ -51,15 +51,26 @@ interface VesselContext {
51
51
  metadata: Record<string, unknown>;
52
52
  labels: string[];
53
53
  }
54
+ /** The agent message an interaction was attached to. */
55
+ interface OriginMessage {
56
+ id: string;
57
+ content: string | null;
58
+ /** The interaction object you originally pushed (type, prompt, options, labels…). */
59
+ interaction: Record<string, unknown> | null;
60
+ metadata: Record<string, unknown>;
61
+ createdAt: string;
62
+ }
54
63
  interface InteractionResponseEvent {
55
64
  id: string;
56
65
  type: 'interaction.response';
57
66
  timestamp: string;
58
67
  vessel: VesselContext;
59
68
  messageId: string;
60
- interactionType: string;
69
+ interactionType: _vessels_types.InteractionType;
61
70
  response: Record<string, unknown>;
62
71
  interactionMetadata: Record<string, unknown> | null;
72
+ /** The message that carried the interaction — so you know WHAT was responded to. */
73
+ originMessage: OriginMessage | null;
63
74
  user: {
64
75
  id: string;
65
76
  email: string;
@@ -75,11 +86,23 @@ interface UserMessageEvent {
75
86
  content: string | null;
76
87
  };
77
88
  context: Array<{
78
- source: string;
89
+ source: _vessels_types.Source;
79
90
  content: string | null;
80
91
  createdAt: string;
81
92
  }>;
82
93
  }
94
+ /** A message in a vessel, as returned by getMessages — the human-facing record. */
95
+ interface Message {
96
+ id: string;
97
+ source: _vessels_types.Source;
98
+ content: string | null;
99
+ card: Record<string, unknown> | null;
100
+ interaction: Record<string, unknown> | null;
101
+ attachments: Array<Record<string, unknown>>;
102
+ suggestions: string[];
103
+ metadata: Record<string, unknown>;
104
+ createdAt: string;
105
+ }
83
106
  type PollEvent = InteractionResponseEvent | UserMessageEvent;
84
107
  interface PollResponse {
85
108
  ok: true;
@@ -97,6 +120,22 @@ declare class Vessels {
97
120
  editMessage(messageId: string, patch: _vessels_types.MessagePatch): Promise<{
98
121
  ok: true;
99
122
  }>;
123
+ /**
124
+ * Read a vessel's message history — the human-facing record, for re-reading
125
+ * the channel (e.g. a stateless or just-restarted worker reconciling state).
126
+ * This is NOT your agent's memory; keep your canonical history in your own
127
+ * system. `vessel` is your own external_id string by default; pass
128
+ * { byUuid: true } if you hold a Vessels UUID. Newest-last, paginate with `before`.
129
+ */
130
+ getMessages(opts: {
131
+ vessel: string;
132
+ byUuid?: boolean;
133
+ limit?: number;
134
+ before?: string;
135
+ }): Promise<{
136
+ messages: Message[];
137
+ hasMore: boolean;
138
+ }>;
100
139
  approval(opts: {
101
140
  prompt: string;
102
141
  approveLabel?: string;
@@ -146,4 +185,4 @@ declare class Vessels {
146
185
  parseWebhookEvent(body: string, signature: string, webhookSecret: string): Promise<InteractionResponseEvent | UserMessageEvent | null>;
147
186
  }
148
187
 
149
- export { AgentActivityTypes, type InteractionResponseEvent, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, Vessels, VesselsAuthError, type VesselsConfig, VesselsRateLimitError, VesselsValidationError };
188
+ export { AgentActivityTypes, type InteractionResponseEvent, type Message, type OriginMessage, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, Vessels, VesselsAuthError, type VesselsConfig, VesselsRateLimitError, VesselsValidationError };
package/dist/index.js CHANGED
@@ -1,3 +1,210 @@
1
+ import { z } from 'zod';
2
+
3
+ // ../types/src/index.ts
4
+ var SourceSchema = z.enum(["agent", "user", "system"]);
5
+ var InteractionTypeSchema = z.enum([
6
+ "approval",
7
+ "choice",
8
+ "checklist",
9
+ "text_input",
10
+ "confirm_preview"
11
+ ]);
12
+ var ApprovalInteractionSchema = z.object({
13
+ type: z.literal("approval"),
14
+ prompt: z.string().min(1),
15
+ approveLabel: z.string().optional(),
16
+ rejectLabel: z.string().optional(),
17
+ reasonRequired: z.boolean().optional(),
18
+ metadata: z.record(z.unknown()).optional()
19
+ });
20
+ var ChoiceOptionSchema = z.object({
21
+ id: z.string().min(1),
22
+ label: z.string().min(1)
23
+ });
24
+ var ChoiceInteractionSchema = z.object({
25
+ type: z.literal("choice"),
26
+ prompt: z.string().min(1),
27
+ options: z.array(ChoiceOptionSchema).min(1),
28
+ allowCustom: z.boolean().optional(),
29
+ customPlaceholder: z.string().optional(),
30
+ metadata: z.record(z.unknown()).optional()
31
+ });
32
+ var ChecklistOptionSchema = z.object({
33
+ id: z.string().min(1),
34
+ label: z.string().min(1),
35
+ checked: z.boolean().optional()
36
+ });
37
+ var ChecklistInteractionSchema = z.object({
38
+ type: z.literal("checklist"),
39
+ prompt: z.string().min(1),
40
+ options: z.array(ChecklistOptionSchema).min(1),
41
+ minSelections: z.number().int().min(0).optional(),
42
+ submitLabel: z.string().optional(),
43
+ metadata: z.record(z.unknown()).optional()
44
+ });
45
+ var TextInputInteractionSchema = z.object({
46
+ type: z.literal("text_input"),
47
+ prompt: z.string().min(1),
48
+ placeholder: z.string().optional(),
49
+ multiline: z.boolean().optional(),
50
+ submitLabel: z.string().optional(),
51
+ metadata: z.record(z.unknown()).optional()
52
+ });
53
+ var ConfirmPreviewInteractionSchema = z.object({
54
+ type: z.literal("confirm_preview"),
55
+ prompt: z.string().min(1),
56
+ previewUrl: z.string().url(),
57
+ previewLabel: z.string().optional(),
58
+ approveLabel: z.string().optional(),
59
+ rejectLabel: z.string().optional(),
60
+ reasonRequiredOnReject: z.boolean().optional(),
61
+ metadata: z.record(z.unknown()).optional()
62
+ });
63
+ var InteractionSchema = z.discriminatedUnion("type", [
64
+ ApprovalInteractionSchema,
65
+ ChoiceInteractionSchema,
66
+ ChecklistInteractionSchema,
67
+ TextInputInteractionSchema,
68
+ ConfirmPreviewInteractionSchema
69
+ ]);
70
+ var AgentActivityTypeSchema = z.enum(["thinking", "searching", "tool_use", "browsing", "processing"]);
71
+ var AgentActivitySchema = z.object({
72
+ type: AgentActivityTypeSchema,
73
+ label: z.string().max(200).optional()
74
+ });
75
+ var CardFieldSchema = z.object({
76
+ label: z.string().min(1),
77
+ value: z.string()
78
+ });
79
+ var CardSchema = z.object({
80
+ title: z.string().min(1),
81
+ fields: z.array(CardFieldSchema)
82
+ });
83
+ var AttachmentSchema = z.discriminatedUnion("type", [
84
+ z.object({ type: z.literal("image"), url: z.string().url() }),
85
+ z.object({ type: z.literal("file"), url: z.string().url(), filename: z.string().optional() })
86
+ ]);
87
+ var VesselStatusSchema = z.enum(["active", "waiting", "resolved"]);
88
+ z.object({
89
+ message: z.string().min(1).max(1e4).optional(),
90
+ vessel: z.string().optional(),
91
+ vesselTitle: z.string().optional(),
92
+ card: CardSchema.optional(),
93
+ interaction: InteractionSchema.optional(),
94
+ previewUrl: z.string().url().optional(),
95
+ metadata: z.record(z.unknown()).refine(
96
+ (v) => JSON.stringify(v).length < 16e3,
97
+ "metadata exceeds 16KB limit"
98
+ ).optional(),
99
+ pinCard: CardSchema.nullable().optional(),
100
+ vesselStatus: VesselStatusSchema.optional(),
101
+ labels: z.array(z.string().min(1).max(50)).max(10).optional(),
102
+ attachments: z.array(AttachmentSchema).max(10).optional(),
103
+ suggestions: z.array(z.string().min(1).max(500)).max(5).optional(),
104
+ agentActivity: AgentActivitySchema.optional()
105
+ }).refine((d) => d.message || d.agentActivity, {
106
+ message: "Either message or agentActivity is required"
107
+ });
108
+ z.object({
109
+ vessels: z.array(z.string().min(1)).min(1).max(100),
110
+ message: z.string().min(1).max(1e4),
111
+ vesselTitle: z.string().optional(),
112
+ card: CardSchema.optional(),
113
+ interaction: InteractionSchema.optional(),
114
+ pinCard: CardSchema.nullable().optional(),
115
+ vesselStatus: VesselStatusSchema.optional(),
116
+ attachments: z.array(AttachmentSchema).max(10).optional(),
117
+ suggestions: z.array(z.string().min(1).max(500)).max(5).optional(),
118
+ metadata: z.record(z.unknown()).refine(
119
+ (v) => JSON.stringify(v).length < 16e3,
120
+ "metadata exceeds 16KB limit"
121
+ ).optional()
122
+ });
123
+ z.object({
124
+ content: z.string().min(1).max(1e4).optional(),
125
+ card: CardSchema.nullable().optional(),
126
+ attachments: z.array(AttachmentSchema).max(10).nullable().optional(),
127
+ suggestions: z.array(z.string().min(1).max(500)).max(5).nullable().optional(),
128
+ agentActivity: AgentActivitySchema.nullable().optional()
129
+ }).refine((d) => Object.values(d).some((v) => v !== void 0), {
130
+ message: "At least one field required"
131
+ });
132
+ var ApprovalResponseSchema = z.object({
133
+ action: z.enum(["approved", "rejected"]),
134
+ reason: z.string().optional()
135
+ });
136
+ var ChoiceResponseSchema = z.object({
137
+ selected: z.string(),
138
+ customValue: z.string().nullable().optional()
139
+ });
140
+ var ChecklistResponseSchema = z.object({
141
+ selected: z.array(z.string())
142
+ });
143
+ var TextInputResponseSchema = z.object({
144
+ text: z.string()
145
+ });
146
+ var ConfirmPreviewResponseSchema = z.object({
147
+ action: z.enum(["approved", "rejected"]),
148
+ reason: z.string().optional()
149
+ });
150
+ z.discriminatedUnion("interactionType", [
151
+ z.object({ interactionType: z.literal("approval"), response: ApprovalResponseSchema }),
152
+ z.object({ interactionType: z.literal("choice"), response: ChoiceResponseSchema }),
153
+ z.object({ interactionType: z.literal("checklist"), response: ChecklistResponseSchema }),
154
+ z.object({ interactionType: z.literal("text_input"), response: TextInputResponseSchema }),
155
+ z.object({ interactionType: z.literal("confirm_preview"), response: ConfirmPreviewResponseSchema })
156
+ ]);
157
+ var WebhookVesselSchema = z.object({
158
+ id: z.string(),
159
+ external_id: z.string().nullable(),
160
+ title: z.string().nullable(),
161
+ metadata: z.record(z.unknown())
162
+ });
163
+ var WebhookContextMessageSchema = z.object({
164
+ source: SourceSchema,
165
+ content: z.string().nullable(),
166
+ created_at: z.string()
167
+ });
168
+ var WebhookOriginMessageSchema = z.object({
169
+ id: z.string(),
170
+ content: z.string().nullable(),
171
+ interaction: z.record(z.unknown()).nullable(),
172
+ metadata: z.record(z.unknown()),
173
+ created_at: z.string()
174
+ });
175
+ var WebhookInteractionResponsePayloadSchema = z.object({
176
+ event: z.literal("interaction.response"),
177
+ vessel_id: z.string(),
178
+ workspace_id: z.string(),
179
+ timestamp: z.string(),
180
+ data: z.object({
181
+ message_id: z.string(),
182
+ interaction_type: InteractionTypeSchema,
183
+ response: z.record(z.unknown()),
184
+ response_id: z.string(),
185
+ metadata: z.record(z.unknown()).optional(),
186
+ /** The agent message that carried the interaction (prompt, content, metadata). */
187
+ message: WebhookOriginMessageSchema,
188
+ vessel: WebhookVesselSchema
189
+ })
190
+ });
191
+ var WebhookUserMessagePayloadSchema = z.object({
192
+ event: z.literal("message.user"),
193
+ vessel_id: z.string(),
194
+ workspace_id: z.string(),
195
+ timestamp: z.string(),
196
+ data: z.object({
197
+ message_id: z.string(),
198
+ content: z.string(),
199
+ vessel: WebhookVesselSchema,
200
+ context: z.array(WebhookContextMessageSchema)
201
+ })
202
+ });
203
+ var WebhookPayloadSchema = z.discriminatedUnion("event", [
204
+ WebhookInteractionResponsePayloadSchema,
205
+ WebhookUserMessagePayloadSchema
206
+ ]);
207
+
1
208
  // src/index.ts
2
209
  var AgentActivityTypes = {
3
210
  thinking: "thinking",
@@ -122,6 +329,38 @@ var Vessels = class {
122
329
  if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
123
330
  return { ok: true };
124
331
  }
332
+ /**
333
+ * Read a vessel's message history — the human-facing record, for re-reading
334
+ * the channel (e.g. a stateless or just-restarted worker reconciling state).
335
+ * This is NOT your agent's memory; keep your canonical history in your own
336
+ * system. `vessel` is your own external_id string by default; pass
337
+ * { byUuid: true } if you hold a Vessels UUID. Newest-last, paginate with `before`.
338
+ */
339
+ async getMessages(opts) {
340
+ const params = new URLSearchParams();
341
+ if (opts.limit != null) params.set("limit", String(opts.limit));
342
+ if (opts.before) params.set("before", opts.before);
343
+ const path = opts.byUuid ? `/api/v1/vessels/${encodeURIComponent(opts.vessel)}/messages` : `/api/v1/vessels/by-external/${encodeURIComponent(opts.vessel)}/messages`;
344
+ const res = await this._fetch(`${this.baseUrl}${path}?${params}`, {
345
+ headers: { "Authorization": `Bearer ${this.apiKey}` }
346
+ });
347
+ const data = await res.json();
348
+ if (res.status === 401) throw new VesselsAuthError(data.error ?? "Unauthorized");
349
+ if (res.status === 404) throw new Error(data.error ?? "Vessel not found");
350
+ if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
351
+ const messages = (data.messages ?? []).map((m) => ({
352
+ id: m.id,
353
+ source: m.source,
354
+ content: m.content ?? null,
355
+ card: m.card ?? null,
356
+ interaction: m.interaction ?? null,
357
+ attachments: m.attachments ?? [],
358
+ suggestions: m.suggestions ?? [],
359
+ metadata: m.metadata ?? {},
360
+ createdAt: m.created_at
361
+ }));
362
+ return { messages, hasMore: data.has_more ?? false };
363
+ }
125
364
  // Interaction helpers
126
365
  approval(opts) {
127
366
  return { type: "approval", ...opts };
@@ -168,6 +407,13 @@ var Vessels = class {
168
407
  interactionType: e.interaction_type,
169
408
  response: e.response,
170
409
  interactionMetadata: e.interaction_metadata ?? null,
410
+ originMessage: e.message ? {
411
+ id: e.message.id,
412
+ content: e.message.content ?? null,
413
+ interaction: e.message.interaction ?? null,
414
+ metadata: e.message.metadata ?? {},
415
+ createdAt: e.message.created_at
416
+ } : null,
171
417
  user: e.user ?? null
172
418
  };
173
419
  }
@@ -235,6 +481,13 @@ var Vessels = class {
235
481
  interactionType: raw.data.interaction_type,
236
482
  response: raw.data.response,
237
483
  interactionMetadata: raw.data.metadata ?? null,
484
+ originMessage: raw.data.message ? {
485
+ id: raw.data.message.id,
486
+ content: raw.data.message.content ?? null,
487
+ interaction: raw.data.message.interaction ?? null,
488
+ metadata: raw.data.message.metadata ?? {},
489
+ createdAt: raw.data.message.created_at
490
+ } : null,
238
491
  user: raw.data.user ?? null
239
492
  };
240
493
  }
@@ -259,4 +512,4 @@ var Vessels = class {
259
512
  }
260
513
  };
261
514
 
262
- export { AgentActivityTypes, Vessels, VesselsAuthError, VesselsRateLimitError, VesselsValidationError };
515
+ export { AgentActivityTypes, Vessels, VesselsAuthError, VesselsRateLimitError, VesselsValidationError, WebhookInteractionResponsePayloadSchema, WebhookPayloadSchema, WebhookUserMessagePayloadSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vessels-sdk",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Let your agent reach you. Official Vessels SDK.",
5
5
  "type": "module",
6
6
  "exports": {