@vellumai/assistant 0.4.33 → 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/package.json +1 -1
- package/src/__tests__/access-request-decision.test.ts +2 -3
- package/src/__tests__/actor-token-service.test.ts +4 -11
- package/src/__tests__/approval-primitive.test.ts +0 -45
- package/src/__tests__/assistant-id-boundary-guard.test.ts +150 -0
- 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 -345
- 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__/deterministic-verification-control-plane.test.ts +0 -2
- package/src/__tests__/guardian-action-conversation-turn.test.ts +1 -7
- 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-grant-minting.test.ts +0 -1
- package/src/__tests__/guardian-routing-state.test.ts +0 -3
- package/src/__tests__/inbound-invite-redemption.test.ts +0 -3
- package/src/__tests__/non-member-access-request.test.ts +0 -7
- 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__/relay-server.test.ts +11 -83
- 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__/slack-inbound-verification.test.ts +2 -4
- 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 +1 -5
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -17
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -13
- package/src/__tests__/trusted-contact-verification.test.ts +3 -15
- package/src/__tests__/twilio-routes.test.ts +2 -2
- package/src/__tests__/voice-invite-redemption.test.ts +0 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +0 -37
- 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 +3 -11
- 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/config/bundled-skills/notifications/tools/send-notification.ts +0 -1
- 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 +16 -42
- package/src/daemon/handlers/config-inbox.ts +6 -6
- package/src/daemon/handlers/contacts.ts +3 -11
- package/src/daemon/handlers/index.ts +0 -2
- package/src/daemon/session-process.ts +0 -4
- package/src/memory/conversation-attention-store.ts +4 -19
- package/src/memory/conversation-crud.ts +0 -2
- package/src/memory/db-init.ts +4 -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 +5 -14
- 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 +1 -0
- package/src/memory/migrations/registry.ts +14 -1
- package/src/memory/schema/calls.ts +0 -7
- package/src/memory/schema/contacts.ts +0 -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/credential-service.ts +1 -15
- package/src/runtime/auth/require-bound-guardian.ts +1 -4
- package/src/runtime/channel-guardian-service.ts +15 -46
- package/src/runtime/channel-invite-transport.ts +8 -0
- package/src/runtime/channel-invite-transports/email.ts +4 -0
- package/src/runtime/channel-invite-transports/slack.ts +6 -0
- package/src/runtime/channel-invite-transports/sms.ts +4 -0
- package/src/runtime/channel-invite-transports/telegram.ts +6 -0
- 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 +1 -14
- package/src/runtime/local-actor-identity.ts +2 -5
- package/src/runtime/routes/access-request-decision.ts +0 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +0 -9
- package/src/runtime/routes/channel-readiness-routes.ts +29 -18
- package/src/runtime/routes/contact-routes.ts +15 -40
- 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 +5 -6
- package/src/runtime/routes/guardian-expiry-sweep.ts +3 -2
- package/src/runtime/routes/inbound-message-handler.ts +0 -3
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +7 -43
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +1 -4
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -6
- 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/pairing-routes.ts +4 -4
- package/src/runtime/tool-grant-request-helper.ts +0 -1
- package/src/tools/browser/browser-manager.ts +22 -21
- package/src/tools/browser/runtime-check.ts +111 -6
- package/src/tools/calls/call-start.ts +1 -3
- package/src/tools/followups/followup_create.ts +1 -2
- package/src/tools/tool-approval-handler.ts +0 -2
package/package.json
CHANGED
|
@@ -99,7 +99,6 @@ function createTestApproval(overrides: Record<string, unknown> = {}) {
|
|
|
99
99
|
return createApprovalRequest({
|
|
100
100
|
runId: `ingress-access-request-${Date.now()}`,
|
|
101
101
|
conversationId: `access-req-telegram-user-unknown-456`,
|
|
102
|
-
assistantId: "self",
|
|
103
102
|
channel: "telegram",
|
|
104
103
|
requesterExternalUserId: "user-unknown-456",
|
|
105
104
|
requesterChatId: "chat-123",
|
|
@@ -157,7 +156,7 @@ describe("access request decision handler", () => {
|
|
|
157
156
|
expect(result.type).toBe("approved");
|
|
158
157
|
|
|
159
158
|
// There should be an active session for this channel
|
|
160
|
-
const session = findActiveSession("
|
|
159
|
+
const session = findActiveSession("telegram");
|
|
161
160
|
expect(session).not.toBeNull();
|
|
162
161
|
expect(session!.expectedExternalUserId).toBe("user-unknown-456");
|
|
163
162
|
expect(session!.expectedChatId).toBe("chat-123");
|
|
@@ -186,7 +185,7 @@ describe("access request decision handler", () => {
|
|
|
186
185
|
expect(updated!.decidedByExternalUserId).toBe("guardian-user-789");
|
|
187
186
|
|
|
188
187
|
// No verification session should be created
|
|
189
|
-
const session = findActiveSession("
|
|
188
|
+
const session = findActiveSession("telegram");
|
|
190
189
|
expect(session).toBeNull();
|
|
191
190
|
});
|
|
192
191
|
|
|
@@ -129,7 +129,6 @@ describe("actor-token store (hash-only)", () => {
|
|
|
129
129
|
|
|
130
130
|
const record = createActorTokenRecord({
|
|
131
131
|
tokenHash,
|
|
132
|
-
assistantId: "self",
|
|
133
132
|
guardianPrincipalId: "principal-store",
|
|
134
133
|
hashedDeviceId: "hashed-dev-store",
|
|
135
134
|
platform: "macos",
|
|
@@ -148,7 +147,6 @@ describe("actor-token store (hash-only)", () => {
|
|
|
148
147
|
|
|
149
148
|
createActorTokenRecord({
|
|
150
149
|
tokenHash,
|
|
151
|
-
assistantId: "self",
|
|
152
150
|
guardianPrincipalId: "principal-bind",
|
|
153
151
|
hashedDeviceId: "hashed-dev-bind",
|
|
154
152
|
platform: "ios",
|
|
@@ -156,7 +154,6 @@ describe("actor-token store (hash-only)", () => {
|
|
|
156
154
|
});
|
|
157
155
|
|
|
158
156
|
const found = findActiveByDeviceBinding(
|
|
159
|
-
"self",
|
|
160
157
|
"principal-bind",
|
|
161
158
|
"hashed-dev-bind",
|
|
162
159
|
);
|
|
@@ -169,7 +166,6 @@ describe("actor-token store (hash-only)", () => {
|
|
|
169
166
|
|
|
170
167
|
createActorTokenRecord({
|
|
171
168
|
tokenHash,
|
|
172
|
-
assistantId: "self",
|
|
173
169
|
guardianPrincipalId: "principal-revoke",
|
|
174
170
|
hashedDeviceId: "hashed-dev-revoke",
|
|
175
171
|
platform: "macos",
|
|
@@ -177,7 +173,6 @@ describe("actor-token store (hash-only)", () => {
|
|
|
177
173
|
});
|
|
178
174
|
|
|
179
175
|
const count = revokeByDeviceBinding(
|
|
180
|
-
"self",
|
|
181
176
|
"principal-revoke",
|
|
182
177
|
"hashed-dev-revoke",
|
|
183
178
|
);
|
|
@@ -192,7 +187,6 @@ describe("actor-token store (hash-only)", () => {
|
|
|
192
187
|
|
|
193
188
|
createActorTokenRecord({
|
|
194
189
|
tokenHash,
|
|
195
|
-
assistantId: "self",
|
|
196
190
|
guardianPrincipalId: "principal-single",
|
|
197
191
|
hashedDeviceId: "hashed-dev-single",
|
|
198
192
|
platform: "macos",
|
|
@@ -213,7 +207,7 @@ describe("guardian vellum migration", () => {
|
|
|
213
207
|
const principalId = ensureVellumGuardianBinding("self");
|
|
214
208
|
expect(principalId).toMatch(/^vellum-principal-/);
|
|
215
209
|
|
|
216
|
-
const guardianResult = findGuardianForChannel("vellum"
|
|
210
|
+
const guardianResult = findGuardianForChannel("vellum");
|
|
217
211
|
expect(guardianResult).not.toBeNull();
|
|
218
212
|
expect(guardianResult!.contact.principalId).toBe(principalId);
|
|
219
213
|
expect(guardianResult!.channel.verifiedVia).toBe("startup-migration");
|
|
@@ -227,7 +221,6 @@ describe("guardian vellum migration", () => {
|
|
|
227
221
|
|
|
228
222
|
test("ensureVellumGuardianBinding preserves existing bindings for other channels", () => {
|
|
229
223
|
createGuardianBinding({
|
|
230
|
-
assistantId: "self",
|
|
231
224
|
channel: "telegram",
|
|
232
225
|
guardianExternalUserId: "tg-user-123",
|
|
233
226
|
guardianDeliveryChatId: "tg-chat-456",
|
|
@@ -237,11 +230,11 @@ describe("guardian vellum migration", () => {
|
|
|
237
230
|
|
|
238
231
|
ensureVellumGuardianBinding("self");
|
|
239
232
|
|
|
240
|
-
const tgGuardian = findGuardianForChannel("telegram"
|
|
233
|
+
const tgGuardian = findGuardianForChannel("telegram");
|
|
241
234
|
expect(tgGuardian).not.toBeNull();
|
|
242
235
|
expect(tgGuardian!.channel.externalUserId).toBe("tg-user-123");
|
|
243
236
|
|
|
244
|
-
const vGuardian = findGuardianForChannel("vellum"
|
|
237
|
+
const vGuardian = findGuardianForChannel("vellum");
|
|
245
238
|
expect(vGuardian).not.toBeNull();
|
|
246
239
|
});
|
|
247
240
|
});
|
|
@@ -439,7 +432,7 @@ describe("resolveLocalIpcAuthContext", () => {
|
|
|
439
432
|
|
|
440
433
|
test("enriches actorPrincipalId from vellum guardian binding when present", () => {
|
|
441
434
|
ensureVellumGuardianBinding("self");
|
|
442
|
-
const guardianResult = findGuardianForChannel("vellum"
|
|
435
|
+
const guardianResult = findGuardianForChannel("vellum");
|
|
443
436
|
expect(guardianResult).toBeTruthy();
|
|
444
437
|
|
|
445
438
|
const ctx = resolveLocalIpcAuthContext("session-123");
|
|
@@ -60,7 +60,6 @@ afterAll(() => {
|
|
|
60
60
|
function mintParams(overrides: Partial<MintGrantParams> = {}): MintGrantParams {
|
|
61
61
|
const futureExpiry = new Date(Date.now() + 60_000).toISOString();
|
|
62
62
|
return {
|
|
63
|
-
assistantId: "self",
|
|
64
63
|
scopeMode: "request_id",
|
|
65
64
|
requestChannel: "telegram",
|
|
66
65
|
decisionChannel: "telegram",
|
|
@@ -177,7 +176,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
177
176
|
toolName: "shell",
|
|
178
177
|
inputDigest: computeToolApprovalDigest("shell", { command: "ls" }),
|
|
179
178
|
consumingRequestId: "consumer-1",
|
|
180
|
-
assistantId: "self",
|
|
181
179
|
});
|
|
182
180
|
|
|
183
181
|
expect(result.ok).toBe(true);
|
|
@@ -200,7 +198,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
200
198
|
toolName: "shell",
|
|
201
199
|
inputDigest: digest,
|
|
202
200
|
consumingRequestId: "consumer-2",
|
|
203
|
-
assistantId: "self",
|
|
204
201
|
});
|
|
205
202
|
|
|
206
203
|
expect(result.ok).toBe(true);
|
|
@@ -224,7 +221,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
224
221
|
toolName: "shell",
|
|
225
222
|
inputDigest: digest,
|
|
226
223
|
consumingRequestId: "consumer-3",
|
|
227
|
-
assistantId: "self",
|
|
228
224
|
});
|
|
229
225
|
|
|
230
226
|
expect(result.ok).toBe(true);
|
|
@@ -242,7 +238,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
242
238
|
toolName: "shell",
|
|
243
239
|
inputDigest: computeToolApprovalDigest("shell", { command: "ls" }),
|
|
244
240
|
consumingRequestId: "consumer-miss",
|
|
245
|
-
assistantId: "self",
|
|
246
241
|
},
|
|
247
242
|
{ maxWaitMs: 0 },
|
|
248
243
|
);
|
|
@@ -267,7 +262,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
267
262
|
toolName: "file_write",
|
|
268
263
|
inputDigest: digest,
|
|
269
264
|
consumingRequestId: "consumer-mismatch-tool",
|
|
270
|
-
assistantId: "self",
|
|
271
265
|
},
|
|
272
266
|
{ maxWaitMs: 0 },
|
|
273
267
|
);
|
|
@@ -293,32 +287,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
293
287
|
command: "rm -rf /",
|
|
294
288
|
}),
|
|
295
289
|
consumingRequestId: "consumer-mismatch-input",
|
|
296
|
-
assistantId: "self",
|
|
297
|
-
},
|
|
298
|
-
{ maxWaitMs: 0 },
|
|
299
|
-
);
|
|
300
|
-
|
|
301
|
-
expect(result.ok).toBe(false);
|
|
302
|
-
if (result.ok) return;
|
|
303
|
-
expect(result.reason).toBe("no_match");
|
|
304
|
-
});
|
|
305
|
-
|
|
306
|
-
test("miss: assistant ID mismatch", async () => {
|
|
307
|
-
mintGrantFromDecision(
|
|
308
|
-
mintParams({
|
|
309
|
-
scopeMode: "request_id",
|
|
310
|
-
requestId: "req-assist",
|
|
311
|
-
assistantId: "assistant-A",
|
|
312
|
-
}),
|
|
313
|
-
);
|
|
314
|
-
|
|
315
|
-
const result = await consumeGrantForInvocation(
|
|
316
|
-
{
|
|
317
|
-
requestId: "req-assist",
|
|
318
|
-
toolName: "shell",
|
|
319
|
-
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
320
|
-
consumingRequestId: "consumer-assist-mismatch",
|
|
321
|
-
assistantId: "assistant-B",
|
|
322
290
|
},
|
|
323
291
|
{ maxWaitMs: 0 },
|
|
324
292
|
);
|
|
@@ -344,7 +312,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
344
312
|
toolName: "shell",
|
|
345
313
|
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
346
314
|
consumingRequestId: "consumer-expired",
|
|
347
|
-
assistantId: "self",
|
|
348
315
|
},
|
|
349
316
|
{ maxWaitMs: 0 },
|
|
350
317
|
);
|
|
@@ -368,7 +335,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
368
335
|
toolName: "shell",
|
|
369
336
|
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
370
337
|
consumingRequestId: "consumer-first",
|
|
371
|
-
assistantId: "self",
|
|
372
338
|
});
|
|
373
339
|
expect(first.ok).toBe(true);
|
|
374
340
|
|
|
@@ -378,7 +344,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
378
344
|
toolName: "shell",
|
|
379
345
|
inputDigest: computeToolApprovalDigest("shell", {}),
|
|
380
346
|
consumingRequestId: "consumer-second",
|
|
381
|
-
assistantId: "self",
|
|
382
347
|
},
|
|
383
348
|
{ maxWaitMs: 0 },
|
|
384
349
|
);
|
|
@@ -401,7 +366,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
401
366
|
toolName: "shell",
|
|
402
367
|
inputDigest: digest,
|
|
403
368
|
consumingRequestId: "consumer-sig-first",
|
|
404
|
-
assistantId: "self",
|
|
405
369
|
});
|
|
406
370
|
expect(first.ok).toBe(true);
|
|
407
371
|
|
|
@@ -410,7 +374,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
410
374
|
toolName: "shell",
|
|
411
375
|
inputDigest: digest,
|
|
412
376
|
consumingRequestId: "consumer-sig-second",
|
|
413
|
-
assistantId: "self",
|
|
414
377
|
},
|
|
415
378
|
{ maxWaitMs: 0 },
|
|
416
379
|
);
|
|
@@ -439,7 +402,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
439
402
|
toolName: "shell",
|
|
440
403
|
inputDigest: digest,
|
|
441
404
|
consumingRequestId: "consumer-ctx",
|
|
442
|
-
assistantId: "self",
|
|
443
405
|
conversationId: "conv-ctx",
|
|
444
406
|
callSessionId: "call-ctx",
|
|
445
407
|
});
|
|
@@ -463,7 +425,6 @@ describe("approval-primitive / consumeGrantForInvocation", () => {
|
|
|
463
425
|
toolName: "shell",
|
|
464
426
|
inputDigest: digest,
|
|
465
427
|
consumingRequestId: "consumer-ctx-mismatch",
|
|
466
|
-
assistantId: "self",
|
|
467
428
|
conversationId: "conv-B",
|
|
468
429
|
},
|
|
469
430
|
{ maxWaitMs: 0 },
|
|
@@ -497,7 +458,6 @@ describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
|
497
458
|
toolName: "shell",
|
|
498
459
|
inputDigest: digest,
|
|
499
460
|
consumingRequestId: "consumer-async-immediate",
|
|
500
|
-
assistantId: "self",
|
|
501
461
|
});
|
|
502
462
|
const elapsed = Date.now() - start;
|
|
503
463
|
|
|
@@ -528,7 +488,6 @@ describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
|
528
488
|
toolName: "shell",
|
|
529
489
|
inputDigest: digest,
|
|
530
490
|
consumingRequestId: "consumer-async-delayed",
|
|
531
|
-
assistantId: "self",
|
|
532
491
|
},
|
|
533
492
|
{ maxWaitMs: 5_000, intervalMs: 100 },
|
|
534
493
|
);
|
|
@@ -553,7 +512,6 @@ describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
|
553
512
|
toolName: "shell",
|
|
554
513
|
inputDigest: digest,
|
|
555
514
|
consumingRequestId: "consumer-async-timeout",
|
|
556
|
-
assistantId: "self",
|
|
557
515
|
},
|
|
558
516
|
{ maxWaitMs: 500, intervalMs: 100 },
|
|
559
517
|
);
|
|
@@ -580,7 +538,6 @@ describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
|
580
538
|
toolName: "shell",
|
|
581
539
|
inputDigest: digest,
|
|
582
540
|
consumingRequestId: "consumer-aborted",
|
|
583
|
-
assistantId: "self",
|
|
584
541
|
},
|
|
585
542
|
{ maxWaitMs: 2_000, intervalMs: 50, signal: controller.signal },
|
|
586
543
|
);
|
|
@@ -606,7 +563,6 @@ describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
|
606
563
|
toolName: "shell",
|
|
607
564
|
inputDigest: digest,
|
|
608
565
|
consumingRequestId: "consumer-pre-aborted",
|
|
609
|
-
assistantId: "self",
|
|
610
566
|
},
|
|
611
567
|
{ maxWaitMs: 2_000, intervalMs: 50, signal: controller.signal },
|
|
612
568
|
);
|
|
@@ -628,7 +584,6 @@ describe("approval-primitive / consumeGrantForInvocation retry", () => {
|
|
|
628
584
|
toolName: "shell",
|
|
629
585
|
inputDigest: digest,
|
|
630
586
|
consumingRequestId: "consumer-no-retry",
|
|
631
|
-
assistantId: "self",
|
|
632
587
|
},
|
|
633
588
|
{ maxWaitMs: 0 },
|
|
634
589
|
);
|
|
@@ -18,6 +18,8 @@ import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
|
18
18
|
* - No assistant-scoped route handlers in the daemon HTTP server
|
|
19
19
|
* - No hardcoded `'self'` string for assistant scoping (use the constant)
|
|
20
20
|
* - The constant itself equals `'self'`
|
|
21
|
+
* - No `assistantId` columns in daemon SQLite schema definitions
|
|
22
|
+
* - No `assistantId` parameter in daemon store function signatures
|
|
21
23
|
*/
|
|
22
24
|
|
|
23
25
|
// ---------------------------------------------------------------------------
|
|
@@ -466,4 +468,152 @@ describe("assistant ID boundary", () => {
|
|
|
466
468
|
).not.toContain("assistantId");
|
|
467
469
|
}
|
|
468
470
|
});
|
|
471
|
+
|
|
472
|
+
// -------------------------------------------------------------------------
|
|
473
|
+
// Rule (f): No assistantId columns in daemon SQLite schema definitions
|
|
474
|
+
//
|
|
475
|
+
// The daemon is assistant-agnostic — it uses DAEMON_INTERNAL_ASSISTANT_ID
|
|
476
|
+
// implicitly. Schema files must not define assistantId columns, which would
|
|
477
|
+
// re-introduce assistant-scoped storage in the daemon layer.
|
|
478
|
+
// -------------------------------------------------------------------------
|
|
479
|
+
|
|
480
|
+
test("no assistantId columns in daemon SQLite schema definitions", () => {
|
|
481
|
+
const repoRoot = getRepoRoot();
|
|
482
|
+
|
|
483
|
+
// Scan all Drizzle schema files for assistantId column definitions.
|
|
484
|
+
// The Drizzle ORM pattern is `assistantId: text(` for defining a text
|
|
485
|
+
// column named assistantId.
|
|
486
|
+
const schemaGlobs = [
|
|
487
|
+
"assistant/src/memory/schema/*.ts",
|
|
488
|
+
"assistant/src/memory/schema/**/*.ts",
|
|
489
|
+
];
|
|
490
|
+
|
|
491
|
+
let grepOutput = "";
|
|
492
|
+
try {
|
|
493
|
+
grepOutput = execFileSync(
|
|
494
|
+
"git",
|
|
495
|
+
["grep", "-nE", "assistantId\\s*:\\s*text\\(", "--", ...schemaGlobs],
|
|
496
|
+
{ encoding: "utf-8", cwd: repoRoot },
|
|
497
|
+
).trim();
|
|
498
|
+
} catch (err) {
|
|
499
|
+
// Exit code 1 means no matches — happy path
|
|
500
|
+
if ((err as { status?: number }).status === 1) {
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
throw err;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
const lines = grepOutput.split("\n").filter((l) => l.length > 0);
|
|
507
|
+
const violations = lines.filter((line) => {
|
|
508
|
+
// Allow comments
|
|
509
|
+
const parts = line.split(":");
|
|
510
|
+
const content = parts.slice(2).join(":").trim();
|
|
511
|
+
if (
|
|
512
|
+
content.startsWith("//") ||
|
|
513
|
+
content.startsWith("*") ||
|
|
514
|
+
content.startsWith("/*")
|
|
515
|
+
) {
|
|
516
|
+
return false;
|
|
517
|
+
}
|
|
518
|
+
return true;
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
if (violations.length > 0) {
|
|
522
|
+
const message = [
|
|
523
|
+
"Found `assistantId` column definitions in daemon SQLite schema files.",
|
|
524
|
+
"`assistantId` columns are not allowed in daemon schema — the daemon uses",
|
|
525
|
+
"`DAEMON_INTERNAL_ASSISTANT_ID` implicitly and is assistant-agnostic.",
|
|
526
|
+
"",
|
|
527
|
+
"Violations:",
|
|
528
|
+
...violations.map((v) => ` - ${v}`),
|
|
529
|
+
].join("\n");
|
|
530
|
+
|
|
531
|
+
expect(violations, message).toEqual([]);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
// -------------------------------------------------------------------------
|
|
536
|
+
// Rule (g): No assistantId parameter in daemon store function signatures
|
|
537
|
+
//
|
|
538
|
+
// Store functions in the daemon layer must not accept assistantId as a
|
|
539
|
+
// parameter. The daemon is assistant-agnostic — all assistant scoping
|
|
540
|
+
// uses DAEMON_INTERNAL_ASSISTANT_ID internally.
|
|
541
|
+
// -------------------------------------------------------------------------
|
|
542
|
+
|
|
543
|
+
test("no assistantId parameter in daemon store function signatures", () => {
|
|
544
|
+
const repoRoot = getRepoRoot();
|
|
545
|
+
|
|
546
|
+
// Scan store files for exported function signatures that include
|
|
547
|
+
// assistantId as a parameter. This covers memory stores, contact stores,
|
|
548
|
+
// notification stores, credential/token stores, and call stores.
|
|
549
|
+
const storeGlobs = [
|
|
550
|
+
"assistant/src/memory/*.ts",
|
|
551
|
+
"assistant/src/contacts/*.ts",
|
|
552
|
+
"assistant/src/notifications/*.ts",
|
|
553
|
+
"assistant/src/runtime/auth/credential-service.ts",
|
|
554
|
+
"assistant/src/runtime/actor-token-store.ts",
|
|
555
|
+
"assistant/src/runtime/actor-refresh-token-store.ts",
|
|
556
|
+
"assistant/src/calls/call-store.ts",
|
|
557
|
+
];
|
|
558
|
+
|
|
559
|
+
// Match exported function declarations/expressions with assistantId in
|
|
560
|
+
// their parameter lists. Patterns:
|
|
561
|
+
// export function foo(assistantId
|
|
562
|
+
// export function foo(bar, assistantId
|
|
563
|
+
// export async function foo(assistantId
|
|
564
|
+
// export const foo = (assistantId
|
|
565
|
+
// export const foo = async (assistantId
|
|
566
|
+
// We use a broad pattern that catches assistantId appearing after an
|
|
567
|
+
// opening paren in an export context.
|
|
568
|
+
const pattern =
|
|
569
|
+
"export\\s+(async\\s+)?function\\s+\\w+\\s*\\([^)]*assistantId|export\\s+const\\s+\\w+\\s*=\\s*(async\\s+)?\\([^)]*assistantId";
|
|
570
|
+
|
|
571
|
+
let grepOutput = "";
|
|
572
|
+
try {
|
|
573
|
+
grepOutput = execFileSync(
|
|
574
|
+
"git",
|
|
575
|
+
["grep", "-nE", pattern, "--", ...storeGlobs],
|
|
576
|
+
{ encoding: "utf-8", cwd: repoRoot },
|
|
577
|
+
).trim();
|
|
578
|
+
} catch (err) {
|
|
579
|
+
// Exit code 1 means no matches — happy path
|
|
580
|
+
if ((err as { status?: number }).status === 1) {
|
|
581
|
+
return;
|
|
582
|
+
}
|
|
583
|
+
throw err;
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
const allLines = grepOutput.split("\n").filter((l) => l.length > 0);
|
|
587
|
+
const violations = allLines.filter((line) => {
|
|
588
|
+
const filePath = line.split(":")[0];
|
|
589
|
+
if (isTestFile(filePath)) return false;
|
|
590
|
+
if (isMigrationFile(filePath)) return false;
|
|
591
|
+
|
|
592
|
+
// Allow comments
|
|
593
|
+
const parts = line.split(":");
|
|
594
|
+
const content = parts.slice(2).join(":").trim();
|
|
595
|
+
if (
|
|
596
|
+
content.startsWith("//") ||
|
|
597
|
+
content.startsWith("*") ||
|
|
598
|
+
content.startsWith("/*")
|
|
599
|
+
) {
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
return true;
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
if (violations.length > 0) {
|
|
607
|
+
const message = [
|
|
608
|
+
"Found daemon store functions with `assistantId` in their parameter signatures.",
|
|
609
|
+
"Store functions must not accept `assistantId` — the daemon is assistant-agnostic",
|
|
610
|
+
"and uses `DAEMON_INTERNAL_ASSISTANT_ID` implicitly.",
|
|
611
|
+
"",
|
|
612
|
+
"Violations:",
|
|
613
|
+
...violations.map((v) => ` - ${v}`),
|
|
614
|
+
].join("\n");
|
|
615
|
+
|
|
616
|
+
expect(violations, message).toEqual([]);
|
|
617
|
+
}
|
|
618
|
+
});
|
|
469
619
|
});
|