@vellumai/assistant 0.10.9-dev.202607161831.8c8f521 → 0.10.9-dev.202607161931.aae7e04

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
@@ -29081,13 +29081,13 @@ paths:
29081
29081
  /v1/telemetry/ingest:
29082
29082
  post:
29083
29083
  operationId: telemetry_ingest_post
29084
- summary: Record a client-reportable telemetry event
29084
+ summary: Record an outbox-backed telemetry event
29085
29085
  description:
29086
- "Record any client-reportable outbox-backed telemetry event by its wire `type` + `fields`.
29087
- Client-orchestrated: for events the daemon can't observe on its own (e.g. onboarding_research). The type must be
29088
- on the daemon's client-reportable allowlist and the payload must pass the platform wire schema. Gated on
29089
- share_analytics consent like every other outbox-backed event; the platform re-checks the owner's consent
29090
- server-side at ingest."
29086
+ Record any outbox-backed telemetry event by its wire `type` + `fields`. For events a client observes and
29087
+ the daemon can't detect on its own (e.g. onboarding_research). The type must be an outbox-backed event — the
29088
+ watermark types (turn, llm_usage, tool_executed) have no variant — and the payload must pass the platform wire
29089
+ schema. Gated on share_analytics consent like every other outbox-backed event; the platform re-checks the
29090
+ owner's consent server-side at ingest.
29091
29091
  tags:
29092
29092
  - telemetry
29093
29093
  requestBody:
@@ -29095,29 +29095,403 @@ paths:
29095
29095
  content:
29096
29096
  application/json:
29097
29097
  schema:
29098
+ oneOf:
29099
+ - type: object
29100
+ properties:
29101
+ type:
29102
+ type: string
29103
+ const: lifecycle
29104
+ fields:
29105
+ type: object
29106
+ properties:
29107
+ event_name:
29108
+ type: string
29109
+ minLength: 1
29110
+ maxLength: 64
29111
+ required:
29112
+ - event_name
29113
+ description:
29114
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29115
+ assistant_version).
29116
+ daemon_event_id:
29117
+ description:
29118
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29119
+ per-row id."
29120
+ type: string
29121
+ minLength: 1
29122
+ maxLength: 128
29123
+ required:
29124
+ - type
29125
+ - fields
29126
+ - type: object
29127
+ properties:
29128
+ type:
29129
+ type: string
29130
+ const: onboarding
29131
+ fields:
29132
+ type: object
29133
+ properties:
29134
+ screen:
29135
+ type: string
29136
+ minLength: 1
29137
+ maxLength: 64
29138
+ tools:
29139
+ type: array
29140
+ items:
29141
+ type: string
29142
+ minLength: 1
29143
+ maxLength: 128
29144
+ tasks:
29145
+ type: array
29146
+ items:
29147
+ type: string
29148
+ minLength: 1
29149
+ maxLength: 128
29150
+ tone:
29151
+ type: string
29152
+ minLength: 1
29153
+ maxLength: 64
29154
+ google_connected:
29155
+ type: boolean
29156
+ google_scopes:
29157
+ type: array
29158
+ items:
29159
+ type: string
29160
+ minLength: 1
29161
+ maxLength: 256
29162
+ ab_variant:
29163
+ type: string
29164
+ minLength: 1
29165
+ maxLength: 64
29166
+ session_id:
29167
+ type: string
29168
+ minLength: 1
29169
+ maxLength: 128
29170
+ step_name:
29171
+ type: string
29172
+ minLength: 1
29173
+ maxLength: 128
29174
+ step_index:
29175
+ type: integer
29176
+ minimum: 0
29177
+ maximum: 9007199254740991
29178
+ completed_at:
29179
+ type: string
29180
+ minLength: 1
29181
+ maxLength: 64
29182
+ funnel_version:
29183
+ type: string
29184
+ minLength: 1
29185
+ maxLength: 128
29186
+ user_id:
29187
+ anyOf:
29188
+ - type: string
29189
+ minLength: 1
29190
+ maxLength: 64
29191
+ - type: "null"
29192
+ outcome:
29193
+ type: string
29194
+ minLength: 1
29195
+ maxLength: 32
29196
+ description:
29197
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29198
+ assistant_version).
29199
+ daemon_event_id:
29200
+ description:
29201
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29202
+ per-row id."
29203
+ type: string
29204
+ minLength: 1
29205
+ maxLength: 128
29206
+ required:
29207
+ - type
29208
+ - fields
29209
+ - type: object
29210
+ properties:
29211
+ type:
29212
+ type: string
29213
+ const: auth_fallback
29214
+ fields:
29215
+ type: object
29216
+ properties:
29217
+ guard:
29218
+ type: string
29219
+ minLength: 1
29220
+ maxLength: 64
29221
+ failure_kind:
29222
+ type: string
29223
+ minLength: 1
29224
+ maxLength: 64
29225
+ path:
29226
+ type: string
29227
+ minLength: 1
29228
+ maxLength: 2048
29229
+ count:
29230
+ type: integer
29231
+ minimum: 0
29232
+ maximum: 9007199254740991
29233
+ window_start:
29234
+ type: integer
29235
+ minimum: 0
29236
+ maximum: 9007199254740991
29237
+ window_end:
29238
+ type: integer
29239
+ minimum: 0
29240
+ maximum: 9007199254740991
29241
+ required:
29242
+ - guard
29243
+ - failure_kind
29244
+ - path
29245
+ - count
29246
+ - window_start
29247
+ - window_end
29248
+ description:
29249
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29250
+ assistant_version).
29251
+ daemon_event_id:
29252
+ description:
29253
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29254
+ per-row id."
29255
+ type: string
29256
+ minLength: 1
29257
+ maxLength: 128
29258
+ required:
29259
+ - type
29260
+ - fields
29261
+ - type: object
29262
+ properties:
29263
+ type:
29264
+ type: string
29265
+ const: skill_loaded
29266
+ fields:
29267
+ type: object
29268
+ properties:
29269
+ provider:
29270
+ anyOf:
29271
+ - type: string
29272
+ minLength: 1
29273
+ maxLength: 64
29274
+ - type: "null"
29275
+ model:
29276
+ anyOf:
29277
+ - type: string
29278
+ minLength: 1
29279
+ maxLength: 128
29280
+ - type: "null"
29281
+ inference_profile:
29282
+ anyOf:
29283
+ - type: string
29284
+ minLength: 1
29285
+ maxLength: 255
29286
+ - type: "null"
29287
+ inference_profile_source:
29288
+ anyOf:
29289
+ - type: string
29290
+ minLength: 1
29291
+ maxLength: 255
29292
+ - type: "null"
29293
+ skill_name:
29294
+ type: string
29295
+ minLength: 1
29296
+ maxLength: 255
29297
+ skill_updated_at:
29298
+ anyOf:
29299
+ - type: string
29300
+ minLength: 1
29301
+ maxLength: 64
29302
+ - type: "null"
29303
+ conversation_id:
29304
+ anyOf:
29305
+ - type: string
29306
+ minLength: 1
29307
+ maxLength: 128
29308
+ - type: "null"
29309
+ required:
29310
+ - skill_name
29311
+ description:
29312
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29313
+ assistant_version).
29314
+ daemon_event_id:
29315
+ description:
29316
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29317
+ per-row id."
29318
+ type: string
29319
+ minLength: 1
29320
+ maxLength: 128
29321
+ required:
29322
+ - type
29323
+ - fields
29324
+ - type: object
29325
+ properties:
29326
+ type:
29327
+ type: string
29328
+ const: watchdog
29329
+ fields:
29330
+ type: object
29331
+ properties:
29332
+ check_name:
29333
+ type: string
29334
+ minLength: 1
29335
+ maxLength: 128
29336
+ value:
29337
+ anyOf:
29338
+ - type: number
29339
+ - type: "null"
29340
+ detail:
29341
+ anyOf:
29342
+ - $ref: "#/components/schemas/TelemetryJsonValue"
29343
+ - type: "null"
29344
+ required:
29345
+ - check_name
29346
+ description:
29347
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29348
+ assistant_version).
29349
+ daemon_event_id:
29350
+ description:
29351
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29352
+ per-row id."
29353
+ type: string
29354
+ minLength: 1
29355
+ maxLength: 128
29356
+ required:
29357
+ - type
29358
+ - fields
29359
+ - type: object
29360
+ properties:
29361
+ type:
29362
+ type: string
29363
+ const: config_setting
29364
+ fields:
29365
+ type: object
29366
+ properties:
29367
+ config_key:
29368
+ type: string
29369
+ minLength: 1
29370
+ maxLength: 128
29371
+ config_value:
29372
+ type: string
29373
+ minLength: 1
29374
+ maxLength: 256
29375
+ required:
29376
+ - config_key
29377
+ - config_value
29378
+ description:
29379
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29380
+ assistant_version).
29381
+ daemon_event_id:
29382
+ description:
29383
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29384
+ per-row id."
29385
+ type: string
29386
+ minLength: 1
29387
+ maxLength: 128
29388
+ required:
29389
+ - type
29390
+ - fields
29391
+ - type: object
29392
+ properties:
29393
+ type:
29394
+ type: string
29395
+ const: onboarding_research
29396
+ fields:
29397
+ type: object
29398
+ properties:
29399
+ conversation_id:
29400
+ anyOf:
29401
+ - type: string
29402
+ minLength: 1
29403
+ maxLength: 64
29404
+ - type: "null"
29405
+ status:
29406
+ type: string
29407
+ minLength: 1
29408
+ maxLength: 32
29409
+ self_reported_occupation:
29410
+ anyOf:
29411
+ - type: string
29412
+ maxLength: 256
29413
+ - type: "null"
29414
+ self_reported_hobbies:
29415
+ maxItems: 32
29416
+ type: array
29417
+ items:
29418
+ type: string
29419
+ minLength: 1
29420
+ maxLength: 128
29421
+ self_reported_timezone:
29422
+ anyOf:
29423
+ - type: string
29424
+ maxLength: 64
29425
+ - type: "null"
29426
+ claims:
29427
+ maxItems: 20
29428
+ type: array
29429
+ items:
29430
+ $ref: "#/components/schemas/TelemetryJsonValue"
29431
+ claim_count:
29432
+ type: integer
29433
+ minimum: 0
29434
+ maximum: 9007199254740991
29435
+ claims_confident:
29436
+ type: integer
29437
+ minimum: 0
29438
+ maximum: 9007199254740991
29439
+ claims_maybe:
29440
+ type: integer
29441
+ minimum: 0
29442
+ maximum: 9007199254740991
29443
+ claims_guessing:
29444
+ type: integer
29445
+ minimum: 0
29446
+ maximum: 9007199254740991
29447
+ suggestions:
29448
+ maxItems: 20
29449
+ type: array
29450
+ items:
29451
+ $ref: "#/components/schemas/TelemetryJsonValue"
29452
+ suggestion_count:
29453
+ type: integer
29454
+ minimum: 0
29455
+ maximum: 9007199254740991
29456
+ plugins:
29457
+ maxItems: 20
29458
+ type: array
29459
+ items:
29460
+ type: string
29461
+ minLength: 1
29462
+ maxLength: 128
29463
+ installed_plugins:
29464
+ maxItems: 20
29465
+ type: array
29466
+ items:
29467
+ type: string
29468
+ minLength: 1
29469
+ maxLength: 128
29470
+ required:
29471
+ - status
29472
+ - claims
29473
+ - claim_count
29474
+ - claims_confident
29475
+ - claims_maybe
29476
+ - claims_guessing
29477
+ - suggestions
29478
+ - suggestion_count
29479
+ - plugins
29480
+ - installed_plugins
29481
+ description:
29482
+ Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29483
+ assistant_version).
29484
+ daemon_event_id:
29485
+ description:
29486
+ "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29487
+ per-row id."
29488
+ type: string
29489
+ minLength: 1
29490
+ maxLength: 128
29491
+ required:
29492
+ - type
29493
+ - fields
29098
29494
  type: object
29099
- properties:
29100
- type:
29101
- type: string
29102
- description: Wire event type; must be a client-reportable telemetry event.
29103
- fields:
29104
- type: object
29105
- propertyNames:
29106
- type: string
29107
- additionalProperties: {}
29108
- description:
29109
- Wire event fields, excluding the daemon-stamped base fields (type, daemon_event_id, recorded_at,
29110
- assistant_version).
29111
- daemon_event_id:
29112
- description:
29113
- "Optional collapse key: rows sharing an id collapse downstream (e.g. a retried report). Defaults to a fresh
29114
- per-row id."
29115
- type: string
29116
- minLength: 1
29117
- maxLength: 128
29118
- required:
29119
- - type
29120
- - fields
29121
29495
  responses:
29122
29496
  "200":
29123
29497
  description: Successful response
@@ -32039,6 +32413,20 @@ components:
32039
32413
  minLength: 1
32040
32414
  required:
32041
32415
  - id
32416
+ TelemetryJsonValue:
32417
+ anyOf:
32418
+ - type: string
32419
+ - type: number
32420
+ - type: boolean
32421
+ - type: "null"
32422
+ - type: array
32423
+ items:
32424
+ $ref: "#/components/schemas/TelemetryJsonValue"
32425
+ - type: object
32426
+ propertyNames:
32427
+ type: string
32428
+ additionalProperties:
32429
+ $ref: "#/components/schemas/TelemetryJsonValue"
32042
32430
  ConfigGetResponse:
32043
32431
  type: object
32044
32432
  properties:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.10.9-dev.202607161831.8c8f521",
3
+ "version": "0.10.9-dev.202607161931.aae7e04",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -30,6 +30,14 @@ import type {
30
30
  } from "zod-openapi";
31
31
  import { createDocument } from "zod-openapi";
32
32
 
33
+ import { jsonValueSchema } from "../src/telemetry/telemetry-wire.generated.js";
34
+
35
+ // The recursive wire JSON-value schema (`claims`/`suggestions` item type) must
36
+ // be hoisted into a named component so it can `$ref` itself; without a
37
+ // registered id zod-openapi falls back to an anonymous `__schema0`. Name it
38
+ // explicitly so the spec + generated SDK read as `TelemetryJsonValue`.
39
+ z.globalRegistry.add(jsonValueSchema, { id: "TelemetryJsonValue" });
40
+
33
41
  const ROOT = resolve(import.meta.dir, "..");
34
42
  const ROUTES_DIR = join(ROOT, "src/runtime/routes");
35
43
  const PLUGIN_DEFAULTS_DIR = join(ROOT, "src/plugins/defaults");
@@ -113,16 +113,34 @@ describe("telemetry-routes: ingest", () => {
113
113
  expect(pendingPayloads().length).toBe(1);
114
114
  });
115
115
 
116
- test("rejects a type not on the client-reportable allowlist", () => {
117
- // `turn` is a real wire type but daemon-authoritative a client must never
118
- // be able to inject it.
116
+ test("rejects a non-outbox (watermark) or unknown type", () => {
117
+ // `turn` is a real wire type but watermark-flushed, not outbox-backed, so it
118
+ // has no ingest variant and a client can't inject it.
119
119
  expect(() => call({ type: "turn", fields: {} })).toThrow(RouteError);
120
120
  // An unknown type is rejected the same way.
121
121
  expect(() => call({ type: "not_a_type", fields: {} })).toThrow(RouteError);
122
122
  expect(pendingPayloads().length).toBe(0);
123
123
  });
124
124
 
125
- test("rejects a payload that fails the wire schema without persisting", () => {
125
+ test("accepts any outbox-backed type, e.g. config_setting", () => {
126
+ const result = call({
127
+ type: "config_setting",
128
+ fields: { config_key: "voice.provider", config_value: "elevenlabs" },
129
+ });
130
+ expect(result).toEqual({ id: expect.any(String) });
131
+
132
+ const payloads = pendingOutboxPayloads<{ config_key: string }>(
133
+ "config_setting",
134
+ );
135
+ expect(payloads.length).toBe(1);
136
+ expect(payloads[0]).toMatchObject({
137
+ type: "config_setting",
138
+ config_key: "voice.provider",
139
+ config_value: "elevenlabs",
140
+ });
141
+ });
142
+
143
+ test("rejects malformed fields (missing or mistyped) without persisting", () => {
126
144
  // Missing the required derived counts.
127
145
  const { claim_count: _c, suggestion_count: _s, ...missingCounts } =
128
146
  VALID_FIELDS;
@@ -146,4 +164,14 @@ describe("telemetry-routes: ingest", () => {
146
164
  expect(() => call({ fields: VALID_FIELDS })).toThrow(RouteError);
147
165
  expect(pendingPayloads().length).toBe(0);
148
166
  });
167
+
168
+ test("strips unknown fields keys (typed schema, not a passthrough record)", () => {
169
+ call({
170
+ type: "onboarding_research",
171
+ fields: { ...VALID_FIELDS, bogus_extra: "nope" },
172
+ });
173
+ const payloads = pendingPayloads();
174
+ expect(payloads.length).toBe(1);
175
+ expect(payloads[0]).not.toHaveProperty("bogus_extra");
176
+ });
149
177
  });
@@ -94,7 +94,7 @@ const pendingTurnTeardowns = new Map<string, Promise<void>>();
94
94
  * when the signal aborts mid-wait. Timer and abort listener are removed on
95
95
  * every exit path.
96
96
  */
97
- async function waitForPriorTurnTeardown(
97
+ export async function waitForPriorTurnTeardown(
98
98
  teardown: Promise<void>,
99
99
  timeoutMs: number,
100
100
  signal?: AbortSignal,
@@ -127,6 +127,24 @@ async function waitForPriorTurnTeardown(
127
127
  });
128
128
  }
129
129
 
130
+ /**
131
+ * The pending teardown promise for a conversation's most recent turn, or
132
+ * `undefined` when no turn is currently tearing down. The live-voice barge-in
133
+ * path reads this synchronously at interrupt time — before the next utterance's
134
+ * `startVoiceTurn` overwrites the per-conversation entry — to capture the
135
+ * interrupted turn's teardown, then awaits it before forking a background
136
+ * continuation. That guarantees the fork snapshots history only after the
137
+ * interrupted turn's completed tool calls have settled into it, so a
138
+ * side-effecting continuation cannot repeat a call the interrupted turn already
139
+ * ran. It is turn-scoped: it resolves once THIS turn's teardown finishes, and
140
+ * does not block on any later turn's work.
141
+ */
142
+ export function getConversationTurnTeardown(
143
+ conversationId: string,
144
+ ): Promise<void> | undefined {
145
+ return pendingTurnTeardowns.get(conversationId);
146
+ }
147
+
130
148
  // ---------------------------------------------------------------------------
131
149
  // Types
132
150
  // ---------------------------------------------------------------------------
@@ -29,9 +29,15 @@ let ipcResponse: {
29
29
  };
30
30
 
31
31
  const exitCodeFromIpcResult = (r: { statusCode?: number }): number => {
32
- if (r.statusCode === undefined) return 10;
33
- if (r.statusCode >= 500) return 3;
34
- if (r.statusCode >= 400) return 2;
32
+ if (r.statusCode === undefined) {
33
+ return 10;
34
+ }
35
+ if (r.statusCode >= 500) {
36
+ return 3;
37
+ }
38
+ if (r.statusCode >= 400) {
39
+ return 2;
40
+ }
35
41
  return 1;
36
42
  };
37
43
 
@@ -518,6 +524,21 @@ describe("notifications list", () => {
518
524
  expect(ipcCalls[0].method).toBe("list_home_feed");
519
525
  });
520
526
 
527
+ test("list help disambiguates Vellum notifications from email inboxes", async () => {
528
+ const { stdout, exitCode } = await runRawCommand([
529
+ "notifications",
530
+ "list",
531
+ "--help",
532
+ ]);
533
+
534
+ expect(exitCode).toBe(0);
535
+ const normalizedHelp = stdout.replace(/\s+/g, " ");
536
+ expect(normalizedHelp).toContain("Vellum Home feed");
537
+ expect(normalizedHelp).toContain("does not read email inboxes");
538
+ expect(normalizedHelp).toContain("Gmail");
539
+ expect(normalizedHelp).toContain("Outlook");
540
+ });
541
+
521
542
  test("list returns items from IPC", async () => {
522
543
  ipcResponse = {
523
544
  ok: true,
@@ -48,9 +48,9 @@ source channel, event name, and attention hints. The decision engine evaluates
48
48
  whether and where to deliver the notification based on connected channels,
49
49
  urgency, and user preferences.
50
50
 
51
- Minimal usage: only --message is required. Add --urgent for a push + visual
52
- flag in the inbox. Source channel/event name fall back to assistant_tool /
53
- assistant.share when omitted.
51
+ Minimal usage: only --message is required. Add --urgent for a push +
52
+ visual flag in the Vellum Home feed. Source channel/event name fall back
53
+ to assistant_tool / assistant.share when omitted.
54
54
 
55
55
  Examples:
56
56
  $ assistant notifications send --message "Build finished"
@@ -71,7 +71,7 @@ Examples:
71
71
  {
72
72
  flags: "--urgent",
73
73
  description:
74
- "Mark this notification as urgent (fires push + visual flag in inbox)",
74
+ "Mark this notification as urgent (fires push + visual flag in Vellum Home)",
75
75
  defaultValue: false,
76
76
  },
77
77
  {
@@ -176,7 +176,7 @@ Examples:
176
176
  {
177
177
  name: "list",
178
178
  description:
179
- "List notifications surfaced to the user via the home feed. Excludes dismissed items by default.",
179
+ "List Vellum Home feed notifications surfaced by the assistant. Excludes dismissed items by default.",
180
180
  options: [
181
181
  {
182
182
  flags: "--all",
@@ -231,11 +231,11 @@ Examples:
231
231
  },
232
232
  ],
233
233
  helpText: `
234
- Reads the home feed at $VELLUM_WORKSPACE_DIR/data/home-feed.json — the
235
- user's notification inbox. Items are ordered by priority then recency,
236
- matching what the user sees in the macOS Home page. The home feed covers
237
- background/async notifications mirrored from the unified pipeline;
238
- real-time chat pushes that did not mirror to the feed will not appear.
234
+ Reads Vellum's Home feed at $VELLUM_WORKSPACE_DIR/data/home-feed.json.
235
+ Items are ordered by priority then recency, matching what the user sees
236
+ in the macOS Home page. This is only the assistant's Vellum notification
237
+ feed; it does not read email inboxes, Gmail, Outlook, or other external
238
+ message providers. Use OAuth/provider-specific commands for external mail.
239
239
 
240
240
  Examples:
241
241
  $ assistant notifications list