@vellumai/assistant 0.10.4-dev.202607011847.0734ff2 → 0.10.4-dev.202607012136.5ef7865

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 (67) hide show
  1. package/eslint.config.mjs +7 -1
  2. package/openapi.yaml +305 -138
  3. package/package.json +1 -1
  4. package/src/__tests__/conversation-agent-loop.test.ts +38 -0
  5. package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
  6. package/src/__tests__/plugin-import-boundary-guard.test.ts +24 -9
  7. package/src/__tests__/resolve-trust-class.test.ts +28 -10
  8. package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
  9. package/src/__tests__/schedule-routes.test.ts +4 -4
  10. package/src/__tests__/slack-app-setup-skill-regression.test.ts +13 -14
  11. package/src/__tests__/system-prompt.test.ts +6 -92
  12. package/src/__tests__/workspace-git-service.test.ts +1 -1
  13. package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
  14. package/src/api/events/open-panel.ts +26 -0
  15. package/src/api/index.ts +6 -0
  16. package/src/avatar/identity-avatar.ts +3 -7
  17. package/src/cli/commands/__tests__/schedules.test.ts +30 -34
  18. package/src/cli/commands/monitoring.ts +191 -0
  19. package/src/cli/commands/schedules.ts +2 -3
  20. package/src/cli/program.ts +2 -0
  21. package/src/config/schema.ts +7 -1
  22. package/src/config/schemas/monitoring.ts +61 -0
  23. package/src/daemon/conversation-agent-loop-handlers.ts +31 -89
  24. package/src/daemon/conversation-agent-loop.ts +20 -47
  25. package/src/daemon/conversation-surfaces.ts +17 -0
  26. package/src/daemon/conversation-turn-finalize.ts +211 -0
  27. package/src/daemon/lifecycle.ts +5 -0
  28. package/src/daemon/message-types/integrations.ts +2 -0
  29. package/src/daemon/message-types/surfaces.ts +1 -0
  30. package/src/daemon/shutdown-handlers.ts +4 -0
  31. package/src/daemon/trust-context.ts +14 -6
  32. package/src/export/__tests__/transcript-formatter.test.ts +11 -0
  33. package/src/export/transcript-formatter.ts +49 -67
  34. package/src/monitoring/__tests__/control.test.ts +235 -0
  35. package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
  36. package/src/monitoring/control.ts +248 -0
  37. package/src/monitoring/resource-sampler.ts +258 -0
  38. package/src/monitoring/sample-ring-buffer.ts +108 -0
  39. package/src/monitoring/worker.ts +94 -0
  40. package/src/persistence/__tests__/slow-query-log.test.ts +190 -0
  41. package/src/persistence/conversation-crud.ts +106 -36
  42. package/src/persistence/db-connection.ts +3 -0
  43. package/src/persistence/raw-query.ts +21 -42
  44. package/src/persistence/slow-query-log.ts +261 -0
  45. package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
  46. package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -3
  47. package/src/prompts/__tests__/system-prompt.test.ts +8 -35
  48. package/src/prompts/system-prompt.ts +6 -8
  49. package/src/prompts/templates/system-sections.ts +0 -12
  50. package/src/runtime/actor-trust-resolver.ts +7 -21
  51. package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
  52. package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +13 -15
  53. package/src/runtime/routes/avatar-routes.ts +0 -4
  54. package/src/runtime/routes/identity-routes.ts +4 -87
  55. package/src/runtime/routes/index.ts +2 -0
  56. package/src/runtime/routes/monitoring-routes.ts +237 -0
  57. package/src/runtime/routes/schedule-routes.ts +4 -4
  58. package/src/runtime/slack-reply-session.test.ts +1 -17
  59. package/src/runtime/slack-reply-session.ts +0 -4
  60. package/src/runtime/trust-class.ts +33 -0
  61. package/src/tools/terminal/safe-env.ts +1 -1
  62. package/src/tools/ui-surface/definitions.ts +3 -1
  63. package/src/util/cgroup-memory.ts +142 -0
  64. package/src/util/platform.ts +17 -0
  65. package/src/workspace/git-service.ts +1 -0
  66. package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
  67. package/src/workspace/migrations/registry.ts +2 -0
package/eslint.config.mjs CHANGED
@@ -12,6 +12,10 @@ const eslintConfig = defineConfig([
12
12
  "simple-import-sort": simpleImportSort,
13
13
  },
14
14
  rules: {
15
+ // Require braces on every control-statement body (if/else/for/
16
+ // while/do). A braceless body is a maintenance hazard: a second
17
+ // line added under the condition reads as guarded but always runs.
18
+ curly: ["warn", "all"],
15
19
  "simple-import-sort/imports": [
16
20
  "error",
17
21
  {
@@ -52,7 +56,9 @@ const eslintConfig = defineConfig([
52
56
  {
53
57
  files: ["src/cli/commands/**/*.ts"],
54
58
  ignores: ["src/cli/commands/**/__tests__/**"],
55
- plugins: { cli: { rules: { "no-daemon-internals": cliNoDaemonInternals } } },
59
+ plugins: {
60
+ cli: { rules: { "no-daemon-internals": cliNoDaemonInternals } },
61
+ },
56
62
  rules: { "cli/no-daemon-internals": "error" },
57
63
  },
58
64
  ]);
package/openapi.yaml CHANGED
@@ -19360,6 +19360,175 @@ paths:
19360
19360
  responses:
19361
19361
  "200":
19362
19362
  description: Successful response
19363
+ /v1/monitoring/start:
19364
+ post:
19365
+ operationId: monitoring_start_post
19366
+ summary: Start the resource monitor
19367
+ description: Spawns (or reuses) the resource monitor process as a child of the daemon and enables monitoring.enabled.
19368
+ tags:
19369
+ - system
19370
+ responses:
19371
+ "200":
19372
+ description: Successful response
19373
+ content:
19374
+ application/json:
19375
+ schema:
19376
+ type: object
19377
+ properties:
19378
+ pid:
19379
+ type: number
19380
+ alreadyRunning:
19381
+ type: boolean
19382
+ monitoringEnabled:
19383
+ type: boolean
19384
+ const: true
19385
+ pidPath:
19386
+ type: string
19387
+ required:
19388
+ - pid
19389
+ - alreadyRunning
19390
+ - monitoringEnabled
19391
+ - pidPath
19392
+ additionalProperties: false
19393
+ /v1/monitoring/status:
19394
+ get:
19395
+ operationId: monitoring_status_get
19396
+ summary: Resource monitor status
19397
+ description:
19398
+ Reports the resource monitor process state, monitoring.enabled, the forensics data directory, and the most
19399
+ recent persisted memory/disk sample.
19400
+ tags:
19401
+ - system
19402
+ responses:
19403
+ "200":
19404
+ description: Successful response
19405
+ content:
19406
+ application/json:
19407
+ schema:
19408
+ type: object
19409
+ properties:
19410
+ status:
19411
+ type: string
19412
+ enum:
19413
+ - running
19414
+ - not_running
19415
+ pid:
19416
+ type: number
19417
+ monitoringEnabled:
19418
+ type: boolean
19419
+ dataDir:
19420
+ type: string
19421
+ latestSample:
19422
+ anyOf:
19423
+ - type: object
19424
+ properties:
19425
+ ts:
19426
+ type: number
19427
+ memory:
19428
+ anyOf:
19429
+ - type: object
19430
+ properties:
19431
+ currentBytes:
19432
+ type: number
19433
+ limitBytes:
19434
+ anyOf:
19435
+ - type: number
19436
+ - type: "null"
19437
+ peakBytes:
19438
+ anyOf:
19439
+ - type: number
19440
+ - type: "null"
19441
+ ratio:
19442
+ anyOf:
19443
+ - type: number
19444
+ - type: "null"
19445
+ required:
19446
+ - currentBytes
19447
+ - limitBytes
19448
+ - peakBytes
19449
+ - ratio
19450
+ additionalProperties: false
19451
+ - type: "null"
19452
+ events:
19453
+ anyOf:
19454
+ - type: object
19455
+ properties:
19456
+ low:
19457
+ type: number
19458
+ high:
19459
+ type: number
19460
+ max:
19461
+ type: number
19462
+ oom:
19463
+ type: number
19464
+ oomKill:
19465
+ type: number
19466
+ required:
19467
+ - low
19468
+ - high
19469
+ - max
19470
+ - oom
19471
+ - oomKill
19472
+ additionalProperties: false
19473
+ - type: "null"
19474
+ disk:
19475
+ anyOf:
19476
+ - type: object
19477
+ properties:
19478
+ path:
19479
+ type: string
19480
+ usedMb:
19481
+ type: number
19482
+ totalMb:
19483
+ type: number
19484
+ freeMb:
19485
+ type: number
19486
+ required:
19487
+ - path
19488
+ - usedMb
19489
+ - totalMb
19490
+ - freeMb
19491
+ additionalProperties: false
19492
+ - type: "null"
19493
+ required:
19494
+ - ts
19495
+ - memory
19496
+ - events
19497
+ - disk
19498
+ additionalProperties: false
19499
+ - type: "null"
19500
+ required:
19501
+ - status
19502
+ - monitoringEnabled
19503
+ - dataDir
19504
+ - latestSample
19505
+ additionalProperties: false
19506
+ /v1/monitoring/stop:
19507
+ post:
19508
+ operationId: monitoring_stop_post
19509
+ summary: Stop the resource monitor
19510
+ description: Disables monitoring.enabled and SIGTERMs the resource monitor process if it is running.
19511
+ tags:
19512
+ - system
19513
+ responses:
19514
+ "200":
19515
+ description: Successful response
19516
+ content:
19517
+ application/json:
19518
+ schema:
19519
+ type: object
19520
+ properties:
19521
+ monitoringWasRunning:
19522
+ type: boolean
19523
+ pid:
19524
+ type: number
19525
+ monitoringEnabled:
19526
+ type: boolean
19527
+ const: false
19528
+ required:
19529
+ - monitoringWasRunning
19530
+ - monitoringEnabled
19531
+ additionalProperties: false
19363
19532
  /v1/notification-intent-result:
19364
19533
  post:
19365
19534
  operationId: notificationintentresult_post
@@ -22860,145 +23029,143 @@ paths:
22860
23029
  schema:
22861
23030
  type: object
22862
23031
  properties:
22863
- schedules:
22864
- type: array
22865
- items:
22866
- type: object
22867
- properties:
22868
- id:
22869
- type: string
22870
- name:
22871
- type: string
22872
- enabled:
22873
- type: boolean
22874
- syntax:
22875
- type: string
22876
- enum:
22877
- - cron
22878
- - rrule
22879
- expression:
22880
- anyOf:
22881
- - type: string
22882
- - type: "null"
22883
- cronExpression:
22884
- anyOf:
22885
- - type: string
22886
- - type: "null"
22887
- timezone:
22888
- anyOf:
22889
- - type: string
22890
- - type: "null"
22891
- message:
22892
- type: string
22893
- script:
22894
- anyOf:
22895
- - type: string
22896
- - type: "null"
22897
- nextRunAt:
22898
- type: number
22899
- lastRunAt:
22900
- anyOf:
22901
- - type: number
22902
- - type: "null"
22903
- lastStatus:
22904
- anyOf:
22905
- - type: string
22906
- - type: "null"
22907
- retryCount:
22908
- type: number
22909
- maxRetries:
22910
- type: number
22911
- retryBackoffMs:
22912
- type: number
22913
- timeoutMs:
22914
- anyOf:
22915
- - type: number
22916
- - type: "null"
22917
- inferenceProfile:
22918
- anyOf:
22919
- - type: string
22920
- - type: "null"
22921
- createdFromConversationId:
22922
- anyOf:
22923
- - type: string
22924
- - type: "null"
22925
- createdFromConversationExists:
22926
- type: boolean
22927
- createdFromConversationArchivedAt:
22928
- anyOf:
22929
- - type: number
22930
- - type: "null"
22931
- description:
22932
- type: string
22933
- cadenceDescription:
22934
- type: string
22935
- mode:
22936
- type: string
22937
- enum:
22938
- - notify
22939
- - execute
22940
- - script
22941
- - wake
22942
- - workflow
22943
- status:
22944
- type: string
22945
- enum:
22946
- - active
22947
- - firing
22948
- - fired
22949
- - cancelled
22950
- routingIntent:
22951
- type: string
22952
- enum:
22953
- - single_channel
22954
- - multi_channel
22955
- - all_channels
22956
- reuseConversation:
22957
- type: boolean
22958
- wakeConversationId:
22959
- anyOf:
22960
- - type: string
22961
- - type: "null"
22962
- workflowName:
22963
- anyOf:
22964
- - type: string
22965
- - type: "null"
22966
- isOneShot:
22967
- type: boolean
22968
- required:
22969
- - id
22970
- - name
22971
- - enabled
22972
- - syntax
22973
- - expression
22974
- - cronExpression
22975
- - timezone
22976
- - message
22977
- - script
22978
- - nextRunAt
22979
- - lastRunAt
22980
- - lastStatus
22981
- - retryCount
22982
- - maxRetries
22983
- - retryBackoffMs
22984
- - timeoutMs
22985
- - inferenceProfile
22986
- - createdFromConversationId
22987
- - createdFromConversationExists
22988
- - createdFromConversationArchivedAt
22989
- - description
22990
- - cadenceDescription
22991
- - mode
22992
- - status
22993
- - routingIntent
22994
- - reuseConversation
22995
- - wakeConversationId
22996
- - workflowName
22997
- - isOneShot
22998
- additionalProperties: false
22999
- description: Updated schedule list
23032
+ schedule:
23033
+ type: object
23034
+ properties:
23035
+ id:
23036
+ type: string
23037
+ name:
23038
+ type: string
23039
+ enabled:
23040
+ type: boolean
23041
+ syntax:
23042
+ type: string
23043
+ enum:
23044
+ - cron
23045
+ - rrule
23046
+ expression:
23047
+ anyOf:
23048
+ - type: string
23049
+ - type: "null"
23050
+ cronExpression:
23051
+ anyOf:
23052
+ - type: string
23053
+ - type: "null"
23054
+ timezone:
23055
+ anyOf:
23056
+ - type: string
23057
+ - type: "null"
23058
+ message:
23059
+ type: string
23060
+ script:
23061
+ anyOf:
23062
+ - type: string
23063
+ - type: "null"
23064
+ nextRunAt:
23065
+ type: number
23066
+ lastRunAt:
23067
+ anyOf:
23068
+ - type: number
23069
+ - type: "null"
23070
+ lastStatus:
23071
+ anyOf:
23072
+ - type: string
23073
+ - type: "null"
23074
+ retryCount:
23075
+ type: number
23076
+ maxRetries:
23077
+ type: number
23078
+ retryBackoffMs:
23079
+ type: number
23080
+ timeoutMs:
23081
+ anyOf:
23082
+ - type: number
23083
+ - type: "null"
23084
+ inferenceProfile:
23085
+ anyOf:
23086
+ - type: string
23087
+ - type: "null"
23088
+ createdFromConversationId:
23089
+ anyOf:
23090
+ - type: string
23091
+ - type: "null"
23092
+ createdFromConversationExists:
23093
+ type: boolean
23094
+ createdFromConversationArchivedAt:
23095
+ anyOf:
23096
+ - type: number
23097
+ - type: "null"
23098
+ description:
23099
+ type: string
23100
+ cadenceDescription:
23101
+ type: string
23102
+ mode:
23103
+ type: string
23104
+ enum:
23105
+ - notify
23106
+ - execute
23107
+ - script
23108
+ - wake
23109
+ - workflow
23110
+ status:
23111
+ type: string
23112
+ enum:
23113
+ - active
23114
+ - firing
23115
+ - fired
23116
+ - cancelled
23117
+ routingIntent:
23118
+ type: string
23119
+ enum:
23120
+ - single_channel
23121
+ - multi_channel
23122
+ - all_channels
23123
+ reuseConversation:
23124
+ type: boolean
23125
+ wakeConversationId:
23126
+ anyOf:
23127
+ - type: string
23128
+ - type: "null"
23129
+ workflowName:
23130
+ anyOf:
23131
+ - type: string
23132
+ - type: "null"
23133
+ isOneShot:
23134
+ type: boolean
23135
+ required:
23136
+ - id
23137
+ - name
23138
+ - enabled
23139
+ - syntax
23140
+ - expression
23141
+ - cronExpression
23142
+ - timezone
23143
+ - message
23144
+ - script
23145
+ - nextRunAt
23146
+ - lastRunAt
23147
+ - lastStatus
23148
+ - retryCount
23149
+ - maxRetries
23150
+ - retryBackoffMs
23151
+ - timeoutMs
23152
+ - inferenceProfile
23153
+ - createdFromConversationId
23154
+ - createdFromConversationExists
23155
+ - createdFromConversationArchivedAt
23156
+ - description
23157
+ - cadenceDescription
23158
+ - mode
23159
+ - status
23160
+ - routingIntent
23161
+ - reuseConversation
23162
+ - wakeConversationId
23163
+ - workflowName
23164
+ - isOneShot
23165
+ additionalProperties: false
23166
+ description: The created schedule
23000
23167
  required:
23001
- - schedules
23168
+ - schedule
23002
23169
  additionalProperties: false
23003
23170
  /v1/schedules/{id}:
23004
23171
  delete:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vellumai/assistant",
3
- "version": "0.10.4-dev.202607011847.0734ff2",
3
+ "version": "0.10.4-dev.202607012136.5ef7865",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -2409,6 +2409,44 @@ describe("session-agent-loop", () => {
2409
2409
  expect(metadataPublishes).toHaveLength(1);
2410
2410
  });
2411
2411
 
2412
+ test("terminal message_complete is emitted before the deferred indexer runs (LUM-2654)", async () => {
2413
+ // Regression guard for LUM-2654 ("long delay between last streaming token
2414
+ // and send-button becoming available"). The terminal `message_complete`
2415
+ // SSE — which the client uses to flip stop→send — is emitted before the
2416
+ // non-critical finalize side-effects (memory segment indexing, lexical
2417
+ // indexing, attention projection), which the orchestrator drains from its
2418
+ // end-of-turn tail. The tail runs within the turn, so the indexer still
2419
+ // fires exactly once; this test pins the ordering by asserting
2420
+ // `message_complete` is already in the client stream when it does.
2421
+ mockMessageById = {
2422
+ id: "msg-reserve",
2423
+ conversationId: "test-conv",
2424
+ createdAt: 1234567,
2425
+ role: "assistant",
2426
+ content: "[]",
2427
+ metadata: null,
2428
+ };
2429
+
2430
+ const events: ServerMessage[] = [];
2431
+ let messageCompleteSeenWhenIndexed: boolean | undefined;
2432
+ indexMessageNowMock.mockImplementationOnce(async () => {
2433
+ messageCompleteSeenWhenIndexed = events.some(
2434
+ (event) => event.type === "message_complete",
2435
+ );
2436
+ return { indexedSegments: 0, enqueuedJobs: 0 };
2437
+ });
2438
+
2439
+ const ctx = makeCtx({
2440
+ providerResponses: [textResponse("indexed reply")],
2441
+ });
2442
+ await runAgentLoopImpl(ctx, "hi", "msg-1", (msg) => events.push(msg));
2443
+
2444
+ // The deferred indexer runs exactly once, within the turn…
2445
+ expect(indexMessageNowMock).toHaveBeenCalledTimes(1);
2446
+ // …and only after the terminal SSE that re-enables the composer.
2447
+ expect(messageCompleteSeenWhenIndexed).toBe(true);
2448
+ });
2449
+
2412
2450
  test("handleMessageComplete skips sync invalidation when attention state unchanged", async () => {
2413
2451
  // Mirror of the previous test but with the default projector return
2414
2452
  // (`false`). The projection still runs every turn, but the sync
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Security regression test for the personal-memory trust gate under
3
+ * DISABLE_HTTP_AUTH.
4
+ *
5
+ * `isPersonalMemoryAllowed` derives trust from `resolveTrustClass`, which only
6
+ * elevates an *unresolved* actor to guardian under DISABLE_HTTP_AUTH (the
7
+ * standing config in platform-managed deployments). A resolved non-guardian
8
+ * channel actor must therefore be denied personal memory even with auth
9
+ * disabled — otherwise the guardian's memory leaks to Slack/phone contacts in
10
+ * the cloud. See LUM-2669. These cases fail on the pre-fix behavior.
11
+ *
12
+ * Uses process.env directly (not a module mock) since isHttpAuthDisabled()
13
+ * reads DISABLE_HTTP_AUTH live.
14
+ */
15
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
16
+
17
+ import {
18
+ isPersonalMemoryAllowed,
19
+ type TrustContext,
20
+ } from "../daemon/trust-context.js";
21
+ import type { TrustClass } from "../runtime/actor-trust-resolver.js";
22
+
23
+ function slack(trustClass: TrustClass): TrustContext {
24
+ return { sourceChannel: "slack", trustClass };
25
+ }
26
+
27
+ let prior: string | undefined;
28
+
29
+ beforeEach(() => {
30
+ // Platform-managed / dev-bypass posture: the flag is on process-wide.
31
+ prior = process.env.DISABLE_HTTP_AUTH;
32
+ process.env.DISABLE_HTTP_AUTH = "true";
33
+ });
34
+
35
+ afterEach(() => {
36
+ if (prior === undefined) {
37
+ delete process.env.DISABLE_HTTP_AUTH;
38
+ } else {
39
+ process.env.DISABLE_HTTP_AUTH = prior;
40
+ }
41
+ });
42
+
43
+ describe("isPersonalMemoryAllowed — no exposure to non-guardian channel actors under DISABLE_HTTP_AUTH", () => {
44
+ test("blocks personal memory for a non-guardian Slack actor even with auth disabled", () => {
45
+ expect(isPersonalMemoryAllowed(slack("trusted_contact"))).toBe(false);
46
+ expect(isPersonalMemoryAllowed(slack("unknown"))).toBe(false);
47
+ expect(isPersonalMemoryAllowed(slack("unverified_contact"))).toBe(false);
48
+ });
49
+
50
+ test("allows personal memory for the guardian and for local / internal turns", () => {
51
+ expect(isPersonalMemoryAllowed(slack("guardian"))).toBe(true);
52
+ // Local/native turn — no resolved actor.
53
+ expect(isPersonalMemoryAllowed(undefined)).toBe(true);
54
+ // Internal vellum-channel flow.
55
+ expect(
56
+ isPersonalMemoryAllowed({
57
+ sourceChannel: "vellum",
58
+ trustClass: "unknown",
59
+ }),
60
+ ).toBe(true);
61
+ });
62
+ });