@vellumai/assistant 0.4.32 → 0.4.34
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/docs/architecture/memory.md +1 -1
- package/package.json +1 -1
- package/src/__tests__/access-request-decision.test.ts +85 -4
- package/src/__tests__/actor-token-service.test.ts +4 -12
- package/src/__tests__/approval-primitive.test.ts +0 -45
- package/src/__tests__/approval-routes-http.test.ts +0 -1
- package/src/__tests__/assistant-id-boundary-guard.test.ts +150 -0
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +0 -1
- package/src/__tests__/callback-handoff-copy.test.ts +0 -1
- package/src/__tests__/channel-approval-routes.test.ts +5 -45
- package/src/__tests__/channel-guardian.test.ts +122 -346
- package/src/__tests__/channel-invite-transport.test.ts +52 -40
- package/src/__tests__/commit-message-enrichment-service.test.ts +4 -38
- package/src/__tests__/computer-use-session-working-dir.test.ts +0 -1
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -3
- package/src/__tests__/contacts-tools.test.ts +4 -5
- package/src/__tests__/conversation-attention-store.test.ts +2 -65
- package/src/__tests__/conversation-attention-telegram.test.ts +0 -2
- package/src/__tests__/conversation-pairing.test.ts +0 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -3
- package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -7
- package/src/__tests__/guardian-action-followup-executor.test.ts +0 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -74
- package/src/__tests__/guardian-action-late-reply.test.ts +1 -8
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-grant-minting.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +0 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -3
- package/src/__tests__/handlers-telegram-config.test.ts +0 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +1 -7
- package/src/__tests__/ingress-reconcile.test.ts +3 -36
- package/src/__tests__/migration-cross-version-compatibility.test.ts +0 -1
- package/src/__tests__/migration-export-http.test.ts +0 -1
- package/src/__tests__/migration-import-commit-http.test.ts +0 -1
- package/src/__tests__/migration-import-preflight-http.test.ts +0 -1
- package/src/__tests__/migration-validate-http.test.ts +0 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -8
- package/src/__tests__/notification-broadcaster.test.ts +1 -2
- package/src/__tests__/notification-decision-fallback.test.ts +0 -2
- package/src/__tests__/notification-decision-strategy.test.ts +0 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-telegram-adapter.test.ts +0 -4
- package/src/__tests__/relay-server.test.ts +151 -80
- package/src/__tests__/sandbox-host-parity.test.ts +5 -2
- package/src/__tests__/scoped-approval-grants.test.ts +9 -40
- package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -36
- package/src/__tests__/send-endpoint-busy.test.ts +0 -1
- package/src/__tests__/send-notification-tool.test.ts +0 -1
- package/src/__tests__/session-init.benchmark.test.ts +0 -2
- package/src/__tests__/slack-channel-config.test.ts +0 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -5
- package/src/__tests__/sms-messaging-provider.test.ts +0 -4
- package/src/__tests__/terminal-tools.test.ts +5 -2
- package/src/__tests__/thread-seed-composer.test.ts +0 -1
- package/src/__tests__/tool-approval-handler.test.ts +0 -1
- package/src/__tests__/tool-grant-request-escalation.test.ts +0 -4
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +65 -77
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +0 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -18
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -14
- package/src/__tests__/trusted-contact-verification.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +2 -3
- package/src/__tests__/update-bulletin.test.ts +0 -2
- package/src/__tests__/user-reference.test.ts +47 -1
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -38
- package/src/__tests__/workspace-git-service.test.ts +2 -2
- package/src/approvals/approval-primitive.ts +0 -15
- package/src/approvals/guardian-decision-primitive.ts +0 -3
- package/src/approvals/guardian-request-resolvers.ts +0 -5
- package/src/calls/call-domain.ts +0 -3
- package/src/calls/call-store.ts +0 -3
- package/src/calls/guardian-action-sweep.ts +2 -1
- package/src/calls/guardian-dispatch.ts +1 -2
- package/src/calls/relay-access-wait.ts +0 -4
- package/src/calls/relay-server.ts +8 -66
- package/src/calls/relay-setup-router.ts +1 -2
- package/src/calls/relay-verification.ts +0 -1
- package/src/calls/twilio-routes.ts +0 -3
- package/src/calls/types.ts +0 -1
- package/src/calls/voice-session-bridge.ts +0 -1
- package/src/channels/config.ts +41 -2
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -1
- package/src/config/bundled-skills/slack/SKILL.md +2 -0
- package/src/config/bundled-skills/slack-digest-setup/SKILL.md +164 -0
- package/src/config/env.ts +0 -4
- package/src/config/feature-flag-registry.json +4 -4
- package/src/config/user-reference.ts +47 -9
- package/src/contacts/contact-store.ts +13 -88
- package/src/contacts/contacts-write.ts +3 -11
- package/src/contacts/types.ts +0 -1
- package/src/daemon/handlers/config-channels.ts +19 -44
- package/src/daemon/handlers/config-inbox.ts +6 -6
- package/src/daemon/handlers/contacts.ts +8 -12
- package/src/daemon/handlers/index.ts +0 -2
- package/src/daemon/lifecycle.ts +18 -26
- package/src/daemon/session-process.ts +0 -4
- package/src/memory/channel-delivery-store.ts +1 -0
- package/src/memory/conversation-attention-store.ts +4 -19
- package/src/memory/conversation-crud.ts +0 -2
- package/src/memory/db-init.ts +8 -0
- package/src/memory/delivery-crud.ts +13 -0
- package/src/memory/guardian-action-store.ts +0 -12
- package/src/memory/guardian-approvals.ts +35 -80
- package/src/memory/guardian-rate-limits.ts +1 -14
- package/src/memory/guardian-verification.ts +6 -34
- package/src/memory/invite-store.ts +76 -15
- package/src/memory/migrations/040-invite-code-hash-column.ts +16 -0
- package/src/memory/migrations/134-contacts-notes-column.ts +64 -45
- package/src/memory/migrations/136-drop-assistant-id-columns.ts +263 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/migrations/registry.ts +14 -1
- package/src/memory/schema/calls.ts +0 -7
- package/src/memory/schema/contacts.ts +2 -8
- package/src/memory/schema/guardian.ts +0 -5
- package/src/memory/schema/infrastructure.ts +0 -2
- package/src/memory/schema/notifications.ts +3 -17
- package/src/memory/scoped-approval-grants.ts +2 -24
- package/src/notifications/adapters/sms.ts +2 -1
- package/src/notifications/broadcaster.ts +1 -6
- package/src/notifications/decision-engine.ts +3 -4
- package/src/notifications/deliveries-store.ts +0 -4
- package/src/notifications/destination-resolver.ts +4 -6
- package/src/notifications/deterministic-checks.ts +1 -6
- package/src/notifications/emit-signal.ts +4 -11
- package/src/notifications/events-store.ts +7 -17
- package/src/notifications/preference-summary.ts +2 -2
- package/src/notifications/preferences-store.ts +2 -9
- package/src/notifications/signal.ts +0 -1
- package/src/notifications/thread-candidates.ts +1 -11
- package/src/notifications/types.ts +0 -3
- package/src/runtime/access-request-helper.ts +3 -10
- package/src/runtime/actor-refresh-token-store.ts +0 -6
- package/src/runtime/actor-token-store.ts +3 -16
- package/src/runtime/actor-trust-resolver.ts +1 -4
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -9
- package/src/runtime/auth/__tests__/guard-tests.test.ts +1 -3
- package/src/runtime/auth/credential-service.ts +1 -15
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/auth/token-service.ts +50 -0
- package/src/runtime/channel-guardian-service.ts +16 -49
- package/src/runtime/channel-invite-transport.ts +129 -34
- package/src/runtime/channel-invite-transports/email.ts +54 -0
- package/src/runtime/channel-invite-transports/slack.ts +87 -0
- package/src/runtime/channel-invite-transports/sms.ts +74 -0
- package/src/runtime/channel-invite-transports/telegram.ts +35 -11
- package/src/runtime/channel-invite-transports/voice.ts +12 -12
- package/src/runtime/confirmation-request-guardian-bridge.ts +0 -1
- package/src/runtime/guardian-action-followup-executor.ts +3 -2
- package/src/runtime/guardian-action-grant-minter.ts +0 -1
- package/src/runtime/guardian-outbound-actions.ts +2 -12
- package/src/runtime/guardian-vellum-migration.ts +2 -3
- package/src/runtime/http-server.ts +0 -1
- package/src/runtime/invite-redemption-service.ts +191 -11
- package/src/runtime/invite-redemption-templates.ts +6 -6
- package/src/runtime/invite-service.ts +81 -11
- package/src/runtime/local-actor-identity.ts +2 -5
- package/src/runtime/routes/access-request-decision.ts +52 -7
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +6 -9
- package/src/runtime/routes/channel-readiness-routes.ts +29 -18
- package/src/runtime/routes/contact-routes.ts +48 -46
- package/src/runtime/routes/conversation-attention-routes.ts +0 -2
- package/src/runtime/routes/global-search-routes.ts +0 -2
- package/src/runtime/routes/guardian-bootstrap-routes.ts +6 -12
- package/src/runtime/routes/guardian-expiry-sweep.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +1 -6
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +296 -47
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +6 -42
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -6
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +10 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +0 -1
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +0 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +3 -7
- package/src/runtime/routes/invite-routes.ts +1 -0
- package/src/runtime/routes/pairing-routes.ts +4 -4
- package/src/runtime/tool-grant-request-helper.ts +0 -1
- package/src/tools/browser/browser-manager.ts +22 -12
- package/src/tools/browser/runtime-check.ts +110 -3
- package/src/tools/calls/call-start.ts +1 -3
- package/src/tools/followups/followup_create.ts +1 -2
- package/src/tools/shared/shell-output.ts +7 -2
- package/src/tools/tool-approval-handler.ts +0 -2
- package/src/util/platform.ts +0 -4
- package/src/workspace/git-service.ts +10 -4
|
@@ -31,7 +31,6 @@ mock.module("../util/platform.js", () => ({
|
|
|
31
31
|
getDbPath: () => join(testDir, "test.db"),
|
|
32
32
|
getLogPath: () => join(testDir, "test.log"),
|
|
33
33
|
ensureDataDir: () => {},
|
|
34
|
-
readHttpToken: () => "test-bearer-token",
|
|
35
34
|
}));
|
|
36
35
|
|
|
37
36
|
mock.module("../util/logger.js", () => ({
|
|
@@ -92,7 +91,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
92
91
|
test("successful verification creates active member with allow policy", () => {
|
|
93
92
|
// Simulate M3: guardian approves, outbound session created for the requester
|
|
94
93
|
const session = createOutboundSession({
|
|
95
|
-
assistantId: "self",
|
|
96
94
|
channel: "telegram",
|
|
97
95
|
expectedExternalUserId: "requester-user-123",
|
|
98
96
|
expectedChatId: "requester-chat-123",
|
|
@@ -103,7 +101,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
103
101
|
|
|
104
102
|
// Requester enters the 6-digit code
|
|
105
103
|
const result = validateAndConsumeChallenge(
|
|
106
|
-
"self",
|
|
107
104
|
"telegram",
|
|
108
105
|
session.secret,
|
|
109
106
|
"requester-user-123",
|
|
@@ -238,7 +235,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
238
235
|
test("post-verify message is accepted (ACL check passes)", () => {
|
|
239
236
|
// Create and verify a trusted contact
|
|
240
237
|
const session = createOutboundSession({
|
|
241
|
-
assistantId: "self",
|
|
242
238
|
channel: "telegram",
|
|
243
239
|
expectedExternalUserId: "requester-user-456",
|
|
244
240
|
expectedChatId: "requester-chat-456",
|
|
@@ -248,7 +244,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
248
244
|
});
|
|
249
245
|
|
|
250
246
|
validateAndConsumeChallenge(
|
|
251
|
-
"self",
|
|
252
247
|
"telegram",
|
|
253
248
|
session.secret,
|
|
254
249
|
"requester-user-456",
|
|
@@ -279,7 +274,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
279
274
|
test("member lookup is scoped by channel type", () => {
|
|
280
275
|
// Create member on the telegram channel
|
|
281
276
|
const session = createOutboundSession({
|
|
282
|
-
assistantId: "self",
|
|
283
277
|
channel: "telegram",
|
|
284
278
|
expectedExternalUserId: "user-cross-test",
|
|
285
279
|
expectedChatId: "chat-cross-test",
|
|
@@ -289,7 +283,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
289
283
|
});
|
|
290
284
|
|
|
291
285
|
validateAndConsumeChallenge(
|
|
292
|
-
"self",
|
|
293
286
|
"telegram",
|
|
294
287
|
session.secret,
|
|
295
288
|
"user-cross-test",
|
|
@@ -346,7 +339,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
346
339
|
|
|
347
340
|
// Guardian re-approves, new outbound session created
|
|
348
341
|
const session = createOutboundSession({
|
|
349
|
-
assistantId: "self",
|
|
350
342
|
channel: "telegram",
|
|
351
343
|
expectedExternalUserId: "user-revoked",
|
|
352
344
|
expectedChatId: "chat-revoked",
|
|
@@ -357,7 +349,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
357
349
|
|
|
358
350
|
// Requester enters the new code
|
|
359
351
|
const result = validateAndConsumeChallenge(
|
|
360
|
-
"self",
|
|
361
352
|
"telegram",
|
|
362
353
|
session.secret,
|
|
363
354
|
"user-revoked",
|
|
@@ -390,7 +381,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
390
381
|
test("trusted contact verification does NOT create a guardian binding", () => {
|
|
391
382
|
// Ensure there's an existing guardian binding we want to preserve
|
|
392
383
|
createGuardianBinding({
|
|
393
|
-
assistantId: "self",
|
|
394
384
|
channel: "telegram",
|
|
395
385
|
guardianExternalUserId: "guardian-user-original",
|
|
396
386
|
guardianDeliveryChatId: "guardian-chat-original",
|
|
@@ -401,7 +391,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
401
391
|
|
|
402
392
|
// Create an outbound session for a requester (different user than guardian)
|
|
403
393
|
const session = createOutboundSession({
|
|
404
|
-
assistantId: "self",
|
|
405
394
|
channel: "telegram",
|
|
406
395
|
expectedExternalUserId: "requester-user-789",
|
|
407
396
|
expectedChatId: "requester-chat-789",
|
|
@@ -411,7 +400,6 @@ describe("trusted contact verification → member activation", () => {
|
|
|
411
400
|
});
|
|
412
401
|
|
|
413
402
|
const result = validateAndConsumeChallenge(
|
|
414
|
-
"self",
|
|
415
403
|
"telegram",
|
|
416
404
|
session.secret,
|
|
417
405
|
"requester-user-789",
|
|
@@ -426,7 +414,7 @@ describe("trusted contact verification → member activation", () => {
|
|
|
426
414
|
}
|
|
427
415
|
|
|
428
416
|
// The original guardian binding should remain intact
|
|
429
|
-
const guardianResult = findGuardianForChannel("telegram"
|
|
417
|
+
const guardianResult = findGuardianForChannel("telegram");
|
|
430
418
|
expect(guardianResult).not.toBeNull();
|
|
431
419
|
expect(guardianResult!.channel.externalUserId).toBe(
|
|
432
420
|
"guardian-user-original",
|
|
@@ -438,10 +426,9 @@ describe("trusted contact verification → member activation", () => {
|
|
|
438
426
|
|
|
439
427
|
const { createVerificationChallenge } =
|
|
440
428
|
await import("../runtime/channel-guardian-service.js");
|
|
441
|
-
const { secret } = createVerificationChallenge("
|
|
429
|
+
const { secret } = createVerificationChallenge("telegram");
|
|
442
430
|
|
|
443
431
|
const result = validateAndConsumeChallenge(
|
|
444
|
-
"self",
|
|
445
432
|
"telegram",
|
|
446
433
|
secret,
|
|
447
434
|
"guardian-user",
|
|
@@ -453,7 +440,7 @@ describe("trusted contact verification → member activation", () => {
|
|
|
453
440
|
expect(result.verificationType).toBe("guardian");
|
|
454
441
|
}
|
|
455
442
|
|
|
456
|
-
const guardianResult = findGuardianForChannel("telegram"
|
|
443
|
+
const guardianResult = findGuardianForChannel("telegram");
|
|
457
444
|
expect(guardianResult).toBeNull();
|
|
458
445
|
});
|
|
459
446
|
});
|
|
@@ -43,7 +43,6 @@ mock.module("../util/platform.js", () => ({
|
|
|
43
43
|
getDbPath: () => join(testDir, "test.db"),
|
|
44
44
|
getLogPath: () => join(testDir, "test.log"),
|
|
45
45
|
ensureDataDir: () => {},
|
|
46
|
-
readHttpToken: () => null,
|
|
47
46
|
}));
|
|
48
47
|
|
|
49
48
|
mock.module("../util/logger.js", () => ({
|
|
@@ -818,8 +817,8 @@ describe("twilio webhook routes", () => {
|
|
|
818
817
|
expect(res.status).toBe(200);
|
|
819
818
|
const session = getCallSessionByCallSid("CA_inbound_assist_1");
|
|
820
819
|
expect(session).not.toBeNull();
|
|
821
|
-
//
|
|
822
|
-
expect(session!.
|
|
820
|
+
// Session was created for the inbound call.
|
|
821
|
+
expect(session!.status).toBe("initiated");
|
|
823
822
|
});
|
|
824
823
|
|
|
825
824
|
test("outbound call flow remains non-regressed with callSessionId present", async () => {
|
|
@@ -57,7 +57,6 @@ mock.module("../util/platform.js", () => ({
|
|
|
57
57
|
getHooksDir: () => "",
|
|
58
58
|
getSocketPath: () => "",
|
|
59
59
|
getSessionTokenPath: () => "",
|
|
60
|
-
getHttpTokenPath: () => "",
|
|
61
60
|
getPlatformTokenPath: () => "",
|
|
62
61
|
getPidPath: () => "",
|
|
63
62
|
getWorkspaceConfigPath: () => "",
|
|
@@ -72,7 +71,6 @@ mock.module("../util/platform.js", () => ({
|
|
|
72
71
|
writeLockfile: () => {},
|
|
73
72
|
readPlatformToken: () => null,
|
|
74
73
|
readSessionToken: () => null,
|
|
75
|
-
readHttpToken: () => null,
|
|
76
74
|
removeSocketFile: () => {},
|
|
77
75
|
getTCPPort: () => 8765,
|
|
78
76
|
isTCPEnabled: () => false,
|
|
@@ -26,7 +26,8 @@ mock.module("node:fs", () => ({
|
|
|
26
26
|
}));
|
|
27
27
|
|
|
28
28
|
// Import after mocks are in place
|
|
29
|
-
const { resolveUserReference } =
|
|
29
|
+
const { resolveUserReference, resolveGuardianName, DEFAULT_USER_REFERENCE } =
|
|
30
|
+
await import("../config/user-reference.js");
|
|
30
31
|
|
|
31
32
|
describe("resolveUserReference", () => {
|
|
32
33
|
beforeEach(() => {
|
|
@@ -69,3 +70,48 @@ describe("resolveUserReference", () => {
|
|
|
69
70
|
expect(resolveUserReference()).toBe("Alice");
|
|
70
71
|
});
|
|
71
72
|
});
|
|
73
|
+
|
|
74
|
+
describe("resolveGuardianName", () => {
|
|
75
|
+
beforeEach(() => {
|
|
76
|
+
mockFileExists = false;
|
|
77
|
+
mockFileContent = "";
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
test("returns USER.md name when present, ignoring guardianDisplayName", () => {
|
|
81
|
+
mockFileExists = true;
|
|
82
|
+
mockFileContent = [
|
|
83
|
+
"## Onboarding Snapshot",
|
|
84
|
+
"",
|
|
85
|
+
"- Preferred name/reference: John",
|
|
86
|
+
].join("\n");
|
|
87
|
+
expect(resolveGuardianName("Jane")).toBe("John");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test('returns "my human" when USER.md explicitly sets name to default value', () => {
|
|
91
|
+
mockFileExists = true;
|
|
92
|
+
mockFileContent = [
|
|
93
|
+
"## Onboarding Snapshot",
|
|
94
|
+
"",
|
|
95
|
+
"- Preferred name/reference: my human",
|
|
96
|
+
].join("\n");
|
|
97
|
+
// The user's explicit choice must be respected even though it matches the default sentinel
|
|
98
|
+
expect(resolveGuardianName("Jane")).toBe("my human");
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
test("falls back to guardianDisplayName when USER.md is empty", () => {
|
|
102
|
+
mockFileExists = false;
|
|
103
|
+
expect(resolveGuardianName("Jane")).toBe("Jane");
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
test("falls back to DEFAULT_USER_REFERENCE when both are empty", () => {
|
|
107
|
+
mockFileExists = false;
|
|
108
|
+
expect(resolveGuardianName()).toBe(DEFAULT_USER_REFERENCE);
|
|
109
|
+
expect(resolveGuardianName(null)).toBe(DEFAULT_USER_REFERENCE);
|
|
110
|
+
expect(resolveGuardianName("")).toBe(DEFAULT_USER_REFERENCE);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("trims whitespace on guardianDisplayName fallback", () => {
|
|
114
|
+
mockFileExists = false;
|
|
115
|
+
expect(resolveGuardianName(" Jane ")).toBe("Jane");
|
|
116
|
+
});
|
|
117
|
+
});
|
|
@@ -147,7 +147,6 @@ describe("redeemVoiceInviteCode", () => {
|
|
|
147
147
|
const codeHash = hashVoiceCode(code);
|
|
148
148
|
|
|
149
149
|
const { invite } = createInvite({
|
|
150
|
-
assistantId: opts.assistantId ?? "self",
|
|
151
150
|
sourceChannel: "voice",
|
|
152
151
|
maxUses: opts.maxUses ?? 1,
|
|
153
152
|
expiresInMs: opts.expiresInMs,
|
|
@@ -38,7 +38,6 @@ mock.module("../util/platform.js", () => ({
|
|
|
38
38
|
getDbPath: () => join(testDir, "test.db"),
|
|
39
39
|
getLogPath: () => join(testDir, "test.log"),
|
|
40
40
|
ensureDataDir: () => {},
|
|
41
|
-
readHttpToken: () => null,
|
|
42
41
|
}));
|
|
43
42
|
|
|
44
43
|
mock.module("../util/logger.js", () => ({
|
|
@@ -255,7 +254,6 @@ function grantParams(
|
|
|
255
254
|
): CreateScopedApprovalGrantParams {
|
|
256
255
|
const futureExpiry = new Date(Date.now() + 60_000).toISOString();
|
|
257
256
|
return {
|
|
258
|
-
assistantId: ASSISTANT_ID,
|
|
259
257
|
scopeMode: "tool_signature",
|
|
260
258
|
toolName: TOOL_NAME,
|
|
261
259
|
inputDigest: computeToolApprovalDigest(TOOL_NAME, TOOL_INPUT),
|
|
@@ -423,42 +421,6 @@ describe("voice bridge confirmation handling (grant consumption via primitive)",
|
|
|
423
421
|
expect(decision!.reason).toContain("guardian voice call");
|
|
424
422
|
});
|
|
425
423
|
|
|
426
|
-
test("non-guardian with grant for different assistantId: auto-denied", async () => {
|
|
427
|
-
// Create a grant scoped to a different assistant
|
|
428
|
-
createScopedApprovalGrant(
|
|
429
|
-
grantParams({
|
|
430
|
-
assistantId: "other-assistant",
|
|
431
|
-
}),
|
|
432
|
-
);
|
|
433
|
-
|
|
434
|
-
const mockData = createMockSession();
|
|
435
|
-
setupBridgeDeps(() => mockData.session);
|
|
436
|
-
|
|
437
|
-
const trustContext: TrustContext = {
|
|
438
|
-
sourceChannel: "voice",
|
|
439
|
-
trustClass: "trusted_contact",
|
|
440
|
-
requesterExternalUserId: "caller-123",
|
|
441
|
-
};
|
|
442
|
-
|
|
443
|
-
await startVoiceTurn({
|
|
444
|
-
conversationId: CONVERSATION_ID,
|
|
445
|
-
callSessionId: CALL_SESSION_ID,
|
|
446
|
-
content: "test utterance",
|
|
447
|
-
assistantId: ASSISTANT_ID,
|
|
448
|
-
trustContext,
|
|
449
|
-
isInbound: true,
|
|
450
|
-
onTextDelta: () => {},
|
|
451
|
-
onComplete: () => {},
|
|
452
|
-
onError: () => {},
|
|
453
|
-
});
|
|
454
|
-
|
|
455
|
-
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
456
|
-
|
|
457
|
-
const decision = mockData.getConfirmationDecision();
|
|
458
|
-
expect(decision).not.toBeNull();
|
|
459
|
-
expect(decision!.decision).toBe("deny");
|
|
460
|
-
});
|
|
461
|
-
|
|
462
424
|
test("grants revoked when revokeScopedApprovalGrantsForContext is called with callSessionId", () => {
|
|
463
425
|
const db = getDb();
|
|
464
426
|
const testCallSessionId = "call-session-revoke-test";
|
|
@@ -655,7 +655,7 @@ describe("WorkspaceGitService", () => {
|
|
|
655
655
|
cwd: testDir,
|
|
656
656
|
});
|
|
657
657
|
const oldGitignore =
|
|
658
|
-
"# Runtime state - excluded from git tracking\ndata/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\
|
|
658
|
+
"# Runtime state - excluded from git tracking\ndata/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\n";
|
|
659
659
|
writeFileSync(join(testDir, ".gitignore"), oldGitignore);
|
|
660
660
|
writeFileSync(join(testDir, "file.txt"), "content");
|
|
661
661
|
execFileSync("git", ["add", "-A"], { cwd: testDir });
|
|
@@ -725,7 +725,7 @@ describe("WorkspaceGitService", () => {
|
|
|
725
725
|
cwd: testDir,
|
|
726
726
|
});
|
|
727
727
|
const gitignoreContent =
|
|
728
|
-
"# Runtime state - excluded from git tracking\ndata/db/\ndata/qdrant/\ndata/ipc-blobs/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\
|
|
728
|
+
"# Runtime state - excluded from git tracking\ndata/db/\ndata/qdrant/\ndata/ipc-blobs/\nlogs/\n*.log\n*.sock\n*.pid\n*.sqlite\n*.sqlite-journal\n*.sqlite-wal\n*.sqlite-shm\n*.db\n*.db-journal\n*.db-wal\n*.db-shm\nvellum.sock\nvellum.pid\nsession-token\n";
|
|
729
729
|
writeFileSync(join(testDir, ".gitignore"), gitignoreContent);
|
|
730
730
|
writeFileSync(join(testDir, "file.txt"), "content");
|
|
731
731
|
execFileSync("git", ["add", "-A"], { cwd: testDir });
|
|
@@ -32,7 +32,6 @@ const log = getLogger("approval-primitive");
|
|
|
32
32
|
// ---------------------------------------------------------------------------
|
|
33
33
|
|
|
34
34
|
export interface MintGrantParams {
|
|
35
|
-
assistantId: string;
|
|
36
35
|
scopeMode: "request_id" | "tool_signature";
|
|
37
36
|
requestId?: string | null;
|
|
38
37
|
toolName?: string | null;
|
|
@@ -76,7 +75,6 @@ export function mintGrantFromDecision(
|
|
|
76
75
|
event: "approval_primitive_mint_rejected",
|
|
77
76
|
reason: "missing_request_id",
|
|
78
77
|
scopeMode: params.scopeMode,
|
|
79
|
-
assistantId: params.assistantId,
|
|
80
78
|
requestChannel: params.requestChannel,
|
|
81
79
|
decisionChannel: params.decisionChannel,
|
|
82
80
|
},
|
|
@@ -96,7 +94,6 @@ export function mintGrantFromDecision(
|
|
|
96
94
|
scopeMode: params.scopeMode,
|
|
97
95
|
toolName: params.toolName ?? null,
|
|
98
96
|
inputDigest: params.inputDigest ?? null,
|
|
99
|
-
assistantId: params.assistantId,
|
|
100
97
|
requestChannel: params.requestChannel,
|
|
101
98
|
decisionChannel: params.decisionChannel,
|
|
102
99
|
},
|
|
@@ -107,7 +104,6 @@ export function mintGrantFromDecision(
|
|
|
107
104
|
|
|
108
105
|
try {
|
|
109
106
|
const grant = createScopedApprovalGrant({
|
|
110
|
-
assistantId: params.assistantId,
|
|
111
107
|
scopeMode: params.scopeMode,
|
|
112
108
|
requestId: params.requestId ?? null,
|
|
113
109
|
toolName: params.toolName ?? null,
|
|
@@ -129,7 +125,6 @@ export function mintGrantFromDecision(
|
|
|
129
125
|
scopeMode: params.scopeMode,
|
|
130
126
|
toolName: params.toolName ?? null,
|
|
131
127
|
requestId: params.requestId ?? null,
|
|
132
|
-
assistantId: params.assistantId,
|
|
133
128
|
requestChannel: params.requestChannel,
|
|
134
129
|
decisionChannel: params.decisionChannel,
|
|
135
130
|
conversationId: params.conversationId ?? null,
|
|
@@ -146,7 +141,6 @@ export function mintGrantFromDecision(
|
|
|
146
141
|
event: "approval_primitive_mint_error",
|
|
147
142
|
scopeMode: params.scopeMode,
|
|
148
143
|
toolName: params.toolName ?? null,
|
|
149
|
-
assistantId: params.assistantId,
|
|
150
144
|
err: error,
|
|
151
145
|
},
|
|
152
146
|
"Failed to mint approval grant (storage error)",
|
|
@@ -162,7 +156,6 @@ export function mintGrantFromDecision(
|
|
|
162
156
|
export interface ConsumeByRequestIdParams {
|
|
163
157
|
requestId: string;
|
|
164
158
|
consumingRequestId: string;
|
|
165
|
-
assistantId: string;
|
|
166
159
|
now?: string;
|
|
167
160
|
}
|
|
168
161
|
|
|
@@ -170,7 +163,6 @@ export interface ConsumeByToolSignatureParams {
|
|
|
170
163
|
toolName: string;
|
|
171
164
|
inputDigest: string;
|
|
172
165
|
consumingRequestId: string;
|
|
173
|
-
assistantId?: string;
|
|
174
166
|
executionChannel?: string;
|
|
175
167
|
conversationId?: string;
|
|
176
168
|
callSessionId?: string;
|
|
@@ -195,7 +187,6 @@ export interface ConsumeGrantParams {
|
|
|
195
187
|
toolName: string;
|
|
196
188
|
inputDigest: string;
|
|
197
189
|
consumingRequestId: string;
|
|
198
|
-
assistantId: string;
|
|
199
190
|
executionChannel?: string;
|
|
200
191
|
conversationId?: string;
|
|
201
192
|
callSessionId?: string;
|
|
@@ -221,7 +212,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
|
|
|
221
212
|
consumeScopedApprovalGrantByRequestId(
|
|
222
213
|
params.requestId,
|
|
223
214
|
params.consumingRequestId,
|
|
224
|
-
params.assistantId,
|
|
225
215
|
params.now,
|
|
226
216
|
);
|
|
227
217
|
|
|
@@ -233,7 +223,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
|
|
|
233
223
|
grantId: reqResult.grant.id,
|
|
234
224
|
requestId: params.requestId,
|
|
235
225
|
consumingRequestId: params.consumingRequestId,
|
|
236
|
-
assistantId: params.assistantId,
|
|
237
226
|
toolName: params.toolName,
|
|
238
227
|
},
|
|
239
228
|
"Approval grant consumed via request_id",
|
|
@@ -248,7 +237,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
|
|
|
248
237
|
reason: "no_match",
|
|
249
238
|
requestId: params.requestId,
|
|
250
239
|
consumingRequestId: params.consumingRequestId,
|
|
251
|
-
assistantId: params.assistantId,
|
|
252
240
|
toolName: params.toolName,
|
|
253
241
|
},
|
|
254
242
|
"No request_id grant match, falling through to tool_signature",
|
|
@@ -261,7 +249,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
|
|
|
261
249
|
toolName: params.toolName,
|
|
262
250
|
inputDigest: params.inputDigest,
|
|
263
251
|
consumingRequestId: params.consumingRequestId,
|
|
264
|
-
assistantId: params.assistantId,
|
|
265
252
|
executionChannel: params.executionChannel,
|
|
266
253
|
conversationId: params.conversationId,
|
|
267
254
|
callSessionId: params.callSessionId,
|
|
@@ -277,7 +264,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
|
|
|
277
264
|
grantId: sigResult.grant.id,
|
|
278
265
|
toolName: params.toolName,
|
|
279
266
|
consumingRequestId: params.consumingRequestId,
|
|
280
|
-
assistantId: params.assistantId,
|
|
281
267
|
conversationId: params.conversationId ?? null,
|
|
282
268
|
callSessionId: params.callSessionId ?? null,
|
|
283
269
|
},
|
|
@@ -293,7 +279,6 @@ function consumeGrantSync(params: ConsumeGrantParams): ConsumeGrantResult {
|
|
|
293
279
|
reason: "no_match",
|
|
294
280
|
toolName: params.toolName,
|
|
295
281
|
consumingRequestId: params.consumingRequestId,
|
|
296
|
-
assistantId: params.assistantId,
|
|
297
282
|
conversationId: params.conversationId ?? null,
|
|
298
283
|
callSessionId: params.callSessionId ?? null,
|
|
299
284
|
executionChannel: params.executionChannel ?? null,
|
|
@@ -36,7 +36,6 @@ import {
|
|
|
36
36
|
type GuardianApprovalRequest,
|
|
37
37
|
updateApprovalDecision,
|
|
38
38
|
} from "../memory/channel-guardian-store.js";
|
|
39
|
-
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
40
39
|
import type {
|
|
41
40
|
ApprovalAction,
|
|
42
41
|
ApprovalDecisionResult,
|
|
@@ -107,7 +106,6 @@ export function tryMintToolApprovalGrant(params: {
|
|
|
107
106
|
}
|
|
108
107
|
|
|
109
108
|
const result = mintGrantFromDecision({
|
|
110
|
-
assistantId: approval.assistantId,
|
|
111
109
|
scopeMode: "tool_signature",
|
|
112
110
|
toolName: approvalInfo.toolName,
|
|
113
111
|
inputDigest,
|
|
@@ -277,7 +275,6 @@ export function mintCanonicalRequestGrant(params: {
|
|
|
277
275
|
}
|
|
278
276
|
|
|
279
277
|
const result = mintGrantFromDecision({
|
|
280
|
-
assistantId: DAEMON_INTERNAL_ASSISTANT_ID,
|
|
281
278
|
scopeMode: "tool_signature",
|
|
282
279
|
toolName: request.toolName,
|
|
283
280
|
inputDigest: request.inputDigest,
|
|
@@ -393,7 +393,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
393
393
|
sourceEventName: "ingress.trusted_contact.guardian_decision",
|
|
394
394
|
sourceChannel: channel,
|
|
395
395
|
sourceSessionId: request.conversationId ?? "",
|
|
396
|
-
assistantId,
|
|
397
396
|
attentionHints: {
|
|
398
397
|
requiresAction: false,
|
|
399
398
|
urgency: "medium",
|
|
@@ -408,7 +407,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
408
407
|
sourceEventName: "ingress.trusted_contact.denied",
|
|
409
408
|
sourceChannel: channel,
|
|
410
409
|
sourceSessionId: request.conversationId ?? "",
|
|
411
|
-
assistantId,
|
|
412
410
|
attentionHints: {
|
|
413
411
|
requiresAction: false,
|
|
414
412
|
urgency: "low",
|
|
@@ -454,7 +452,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
454
452
|
if (channel === "voice") {
|
|
455
453
|
try {
|
|
456
454
|
upsertMember({
|
|
457
|
-
assistantId,
|
|
458
455
|
sourceChannel: "voice",
|
|
459
456
|
externalUserId: requesterExternalUserId,
|
|
460
457
|
externalChatId: requesterChatId,
|
|
@@ -484,7 +481,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
484
481
|
// Non-voice approvals: mint an identity-bound verification session so the
|
|
485
482
|
// requester can verify their identity.
|
|
486
483
|
const session = createOutboundSession({
|
|
487
|
-
assistantId,
|
|
488
484
|
channel,
|
|
489
485
|
expectedExternalUserId: requesterExternalUserId,
|
|
490
486
|
expectedChatId: requesterChatId,
|
|
@@ -582,7 +578,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
582
578
|
sourceEventName: "ingress.trusted_contact.verification_sent",
|
|
583
579
|
sourceChannel: channel,
|
|
584
580
|
sourceSessionId: request.conversationId ?? "",
|
|
585
|
-
assistantId,
|
|
586
581
|
attentionHints: {
|
|
587
582
|
requiresAction: false,
|
|
588
583
|
urgency: "low",
|
package/src/calls/call-domain.ts
CHANGED
|
@@ -290,7 +290,6 @@ export function createInboundVoiceSession(
|
|
|
290
290
|
provider: "twilio",
|
|
291
291
|
fromNumber,
|
|
292
292
|
toNumber,
|
|
293
|
-
assistantId,
|
|
294
293
|
});
|
|
295
294
|
|
|
296
295
|
updateCallSession(session.id, { providerCallSid: callSid });
|
|
@@ -411,7 +410,6 @@ export async function startCall(
|
|
|
411
410
|
task: callContext ? `${task}\n\nContext: ${callContext}` : task,
|
|
412
411
|
callerIdentityMode: identityResult.mode,
|
|
413
412
|
callerIdentitySource: identityResult.source,
|
|
414
|
-
assistantId,
|
|
415
413
|
initiatedFromConversationId: conversationId,
|
|
416
414
|
});
|
|
417
415
|
sessionId = session.id;
|
|
@@ -935,7 +933,6 @@ export async function startGuardianVerificationCall(
|
|
|
935
933
|
toNumber: phoneNumber,
|
|
936
934
|
callMode: "guardian_verification",
|
|
937
935
|
guardianVerificationSessionId,
|
|
938
|
-
assistantId,
|
|
939
936
|
initiatedFromConversationId: originConversationId,
|
|
940
937
|
});
|
|
941
938
|
sessionId = session.id;
|
package/src/calls/call-store.ts
CHANGED
|
@@ -38,7 +38,6 @@ const parseCallSession = createRowMapper<
|
|
|
38
38
|
guardianVerificationSessionId: "guardianVerificationSessionId",
|
|
39
39
|
callerIdentityMode: "callerIdentityMode",
|
|
40
40
|
callerIdentitySource: "callerIdentitySource",
|
|
41
|
-
assistantId: "assistantId",
|
|
42
41
|
initiatedFromConversationId: "initiatedFromConversationId",
|
|
43
42
|
startedAt: "startedAt",
|
|
44
43
|
endedAt: "endedAt",
|
|
@@ -83,7 +82,6 @@ export function createCallSession(opts: {
|
|
|
83
82
|
guardianVerificationSessionId?: string;
|
|
84
83
|
callerIdentityMode?: string;
|
|
85
84
|
callerIdentitySource?: string;
|
|
86
|
-
assistantId?: string;
|
|
87
85
|
initiatedFromConversationId?: string;
|
|
88
86
|
}): CallSession {
|
|
89
87
|
const db = getDb();
|
|
@@ -101,7 +99,6 @@ export function createCallSession(opts: {
|
|
|
101
99
|
guardianVerificationSessionId: opts.guardianVerificationSessionId ?? null,
|
|
102
100
|
callerIdentityMode: opts.callerIdentityMode ?? null,
|
|
103
101
|
callerIdentitySource: opts.callerIdentitySource ?? null,
|
|
104
|
-
assistantId: opts.assistantId ?? null,
|
|
105
102
|
initiatedFromConversationId: opts.initiatedFromConversationId ?? null,
|
|
106
103
|
startedAt: null,
|
|
107
104
|
endedAt: null,
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
getDeliveriesByRequestId,
|
|
16
16
|
getExpiredGuardianActionRequests,
|
|
17
17
|
} from "../memory/guardian-action-store.js";
|
|
18
|
+
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
18
19
|
import { deliverChannelReply } from "../runtime/gateway-client.js";
|
|
19
20
|
import { composeGuardianActionMessageGenerative } from "../runtime/guardian-action-message-composer.js";
|
|
20
21
|
import type { GuardianActionCopyGenerator } from "../runtime/http-types.js";
|
|
@@ -132,7 +133,7 @@ export async function sweepExpiredGuardianActions(
|
|
|
132
133
|
|
|
133
134
|
await sendGuardianExpiryNotices(
|
|
134
135
|
deliveries,
|
|
135
|
-
|
|
136
|
+
DAEMON_INTERNAL_ASSISTANT_ID,
|
|
136
137
|
gatewayBaseUrl,
|
|
137
138
|
mintBearerToken,
|
|
138
139
|
guardianActionCopyGenerator,
|
|
@@ -101,7 +101,7 @@ async function dispatchGuardianQuestionInner(
|
|
|
101
101
|
// level guardian identity. Resolve the principal from the contacts table.
|
|
102
102
|
let guardianPrincipalId: string | undefined;
|
|
103
103
|
|
|
104
|
-
const guardianResult = findGuardianForChannel("vellum"
|
|
104
|
+
const guardianResult = findGuardianForChannel("vellum");
|
|
105
105
|
if (guardianResult?.contact.principalId) {
|
|
106
106
|
guardianPrincipalId = guardianResult.contact.principalId;
|
|
107
107
|
}
|
|
@@ -205,7 +205,6 @@ async function dispatchGuardianQuestionInner(
|
|
|
205
205
|
sourceEventName: "guardian.question",
|
|
206
206
|
sourceChannel: "voice",
|
|
207
207
|
sourceSessionId: callSessionId,
|
|
208
|
-
assistantId,
|
|
209
208
|
attentionHints: {
|
|
210
209
|
requiresAction: true,
|
|
211
210
|
urgency: "high",
|
|
@@ -9,7 +9,6 @@
|
|
|
9
9
|
import { findContactChannel } from "../contacts/contact-store.js";
|
|
10
10
|
import { getCanonicalGuardianRequest } from "../memory/canonical-guardian-store.js";
|
|
11
11
|
import { emitNotificationSignal } from "../notifications/emit-signal.js";
|
|
12
|
-
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
13
12
|
import { getLogger } from "../util/logger.js";
|
|
14
13
|
import {
|
|
15
14
|
getGuardianWaitUpdateInitialIntervalMs,
|
|
@@ -240,8 +239,6 @@ export function emitAccessRequestCallbackHandoff(
|
|
|
240
239
|
return { emitted: false, callbackHandoffNotified: true };
|
|
241
240
|
}
|
|
242
241
|
|
|
243
|
-
const assistantId =
|
|
244
|
-
params.accessRequestAssistantId ?? DAEMON_INTERNAL_ASSISTANT_ID;
|
|
245
242
|
const fromNumber = params.accessRequestFromNumber ?? null;
|
|
246
243
|
|
|
247
244
|
// Resolve canonical request for requestCode and conversationId
|
|
@@ -282,7 +279,6 @@ export function emitAccessRequestCallbackHandoff(
|
|
|
282
279
|
sourceEventName: "ingress.access_request.callback_handoff",
|
|
283
280
|
sourceChannel: "voice",
|
|
284
281
|
sourceSessionId,
|
|
285
|
-
assistantId,
|
|
286
282
|
attentionHints: {
|
|
287
283
|
requiresAction: false,
|
|
288
284
|
urgency: "medium",
|