@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.
- package/eslint.config.mjs +7 -1
- package/openapi.yaml +305 -138
- package/package.json +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +38 -0
- package/src/__tests__/personal-memory-auth-bypass.test.ts +62 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +24 -9
- package/src/__tests__/resolve-trust-class.test.ts +28 -10
- package/src/__tests__/schedule-routes-workflow-validation.test.ts +3 -3
- package/src/__tests__/schedule-routes.test.ts +4 -4
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +13 -14
- package/src/__tests__/system-prompt.test.ts +6 -92
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-migration-120-revise-onboarding-threads.test.ts +175 -0
- package/src/api/events/open-panel.ts +26 -0
- package/src/api/index.ts +6 -0
- package/src/avatar/identity-avatar.ts +3 -7
- package/src/cli/commands/__tests__/schedules.test.ts +30 -34
- package/src/cli/commands/monitoring.ts +191 -0
- package/src/cli/commands/schedules.ts +2 -3
- package/src/cli/program.ts +2 -0
- package/src/config/schema.ts +7 -1
- package/src/config/schemas/monitoring.ts +61 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +31 -89
- package/src/daemon/conversation-agent-loop.ts +20 -47
- package/src/daemon/conversation-surfaces.ts +17 -0
- package/src/daemon/conversation-turn-finalize.ts +211 -0
- package/src/daemon/lifecycle.ts +5 -0
- package/src/daemon/message-types/integrations.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +1 -0
- package/src/daemon/shutdown-handlers.ts +4 -0
- package/src/daemon/trust-context.ts +14 -6
- package/src/export/__tests__/transcript-formatter.test.ts +11 -0
- package/src/export/transcript-formatter.ts +49 -67
- package/src/monitoring/__tests__/control.test.ts +235 -0
- package/src/monitoring/__tests__/sample-ring-buffer.test.ts +96 -0
- package/src/monitoring/control.ts +248 -0
- package/src/monitoring/resource-sampler.ts +258 -0
- package/src/monitoring/sample-ring-buffer.ts +108 -0
- package/src/monitoring/worker.ts +94 -0
- package/src/persistence/__tests__/slow-query-log.test.ts +190 -0
- package/src/persistence/conversation-crud.ts +106 -36
- package/src/persistence/db-connection.ts +3 -0
- package/src/persistence/raw-query.ts +21 -42
- package/src/persistence/slow-query-log.ts +261 -0
- package/src/plugins/defaults/memory/job-handlers/backfill.ts +4 -26
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +4 -3
- package/src/prompts/__tests__/system-prompt.test.ts +8 -35
- package/src/prompts/system-prompt.ts +6 -8
- package/src/prompts/templates/system-sections.ts +0 -12
- package/src/runtime/actor-trust-resolver.ts +7 -21
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +194 -0
- package/src/runtime/routes/__tests__/schedule-routes-create.test.ts +13 -15
- package/src/runtime/routes/avatar-routes.ts +0 -4
- package/src/runtime/routes/identity-routes.ts +4 -87
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/monitoring-routes.ts +237 -0
- package/src/runtime/routes/schedule-routes.ts +4 -4
- package/src/runtime/slack-reply-session.test.ts +1 -17
- package/src/runtime/slack-reply-session.ts +0 -4
- package/src/runtime/trust-class.ts +33 -0
- package/src/tools/terminal/safe-env.ts +1 -1
- package/src/tools/ui-surface/definitions.ts +3 -1
- package/src/util/cgroup-memory.ts +142 -0
- package/src/util/platform.ts +17 -0
- package/src/workspace/git-service.ts +1 -0
- package/src/workspace/migrations/120-revise-onboarding-threads.ts +47 -0
- 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: {
|
|
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
|
-
|
|
22864
|
-
type:
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
22868
|
-
|
|
22869
|
-
|
|
22870
|
-
|
|
22871
|
-
|
|
22872
|
-
|
|
22873
|
-
|
|
22874
|
-
|
|
22875
|
-
|
|
22876
|
-
|
|
22877
|
-
|
|
22878
|
-
|
|
22879
|
-
|
|
22880
|
-
|
|
22881
|
-
|
|
22882
|
-
|
|
22883
|
-
|
|
22884
|
-
|
|
22885
|
-
|
|
22886
|
-
|
|
22887
|
-
|
|
22888
|
-
|
|
22889
|
-
|
|
22890
|
-
|
|
22891
|
-
|
|
22892
|
-
|
|
22893
|
-
|
|
22894
|
-
|
|
22895
|
-
|
|
22896
|
-
|
|
22897
|
-
|
|
22898
|
-
|
|
22899
|
-
|
|
22900
|
-
|
|
22901
|
-
|
|
22902
|
-
|
|
22903
|
-
|
|
22904
|
-
|
|
22905
|
-
|
|
22906
|
-
|
|
22907
|
-
|
|
22908
|
-
|
|
22909
|
-
|
|
22910
|
-
|
|
22911
|
-
|
|
22912
|
-
|
|
22913
|
-
|
|
22914
|
-
|
|
22915
|
-
|
|
22916
|
-
|
|
22917
|
-
|
|
22918
|
-
|
|
22919
|
-
|
|
22920
|
-
|
|
22921
|
-
|
|
22922
|
-
|
|
22923
|
-
|
|
22924
|
-
|
|
22925
|
-
|
|
22926
|
-
|
|
22927
|
-
|
|
22928
|
-
|
|
22929
|
-
|
|
22930
|
-
|
|
22931
|
-
|
|
22932
|
-
|
|
22933
|
-
|
|
22934
|
-
|
|
22935
|
-
|
|
22936
|
-
|
|
22937
|
-
|
|
22938
|
-
|
|
22939
|
-
|
|
22940
|
-
|
|
22941
|
-
|
|
22942
|
-
|
|
22943
|
-
|
|
22944
|
-
|
|
22945
|
-
|
|
22946
|
-
|
|
22947
|
-
|
|
22948
|
-
|
|
22949
|
-
|
|
22950
|
-
|
|
22951
|
-
|
|
22952
|
-
|
|
22953
|
-
|
|
22954
|
-
|
|
22955
|
-
|
|
22956
|
-
|
|
22957
|
-
|
|
22958
|
-
|
|
22959
|
-
|
|
22960
|
-
|
|
22961
|
-
|
|
22962
|
-
|
|
22963
|
-
|
|
22964
|
-
|
|
22965
|
-
|
|
22966
|
-
|
|
22967
|
-
|
|
22968
|
-
|
|
22969
|
-
|
|
22970
|
-
|
|
22971
|
-
|
|
22972
|
-
|
|
22973
|
-
|
|
22974
|
-
|
|
22975
|
-
|
|
22976
|
-
|
|
22977
|
-
|
|
22978
|
-
|
|
22979
|
-
|
|
22980
|
-
|
|
22981
|
-
|
|
22982
|
-
|
|
22983
|
-
|
|
22984
|
-
|
|
22985
|
-
|
|
22986
|
-
|
|
22987
|
-
|
|
22988
|
-
|
|
22989
|
-
|
|
22990
|
-
|
|
22991
|
-
|
|
22992
|
-
|
|
22993
|
-
|
|
22994
|
-
|
|
22995
|
-
|
|
22996
|
-
|
|
22997
|
-
|
|
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
|
-
-
|
|
23168
|
+
- schedule
|
|
23002
23169
|
additionalProperties: false
|
|
23003
23170
|
/v1/schedules/{id}:
|
|
23004
23171
|
delete:
|
package/package.json
CHANGED
|
@@ -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
|
+
});
|