@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 +416 -28
- package/package.json +1 -1
- package/scripts/generate-openapi.ts +8 -0
- package/src/__tests__/telemetry-routes.test.ts +32 -4
- package/src/calls/voice-session-bridge.ts +19 -1
- package/src/cli/commands/__tests__/notifications.test.ts +24 -3
- package/src/cli/commands/notifications.help.ts +10 -10
- package/src/cli/commands/oauth/connect-surface-guidance.test.ts +40 -0
- package/src/cli/commands/oauth/connect-surface-guidance.ts +54 -0
- package/src/cli/commands/oauth/connect.test.ts +126 -0
- package/src/cli/commands/oauth/connect.ts +29 -6
- package/src/cli/commands/oauth/index.help.ts +7 -1
- package/src/cli/commands/oauth/status.test.ts +69 -3
- package/src/cli/commands/oauth/status.ts +50 -12
- package/src/cli/lib/bundled-marketplace.json +14 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +145 -0
- package/src/live-voice/live-voice-session.ts +109 -18
- package/src/runtime/routes/telemetry-routes.ts +75 -55
- package/src/telemetry/telemetry-wire-validation.ts +30 -3
- package/src/telemetry/types.ts +0 -31
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
|
|
29084
|
+
summary: Record an outbox-backed telemetry event
|
|
29085
29085
|
description:
|
|
29086
|
-
|
|
29087
|
-
|
|
29088
|
-
|
|
29089
|
-
share_analytics consent like every other outbox-backed event; the platform re-checks the
|
|
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
|
@@ -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
|
|
117
|
-
// `turn` is a real wire type but
|
|
118
|
-
//
|
|
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("
|
|
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)
|
|
33
|
-
|
|
34
|
-
|
|
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 +
|
|
52
|
-
flag in the
|
|
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
|
|
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
|
|
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
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
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
|