@vellumai/assistant 0.3.26 → 0.3.28
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/ARCHITECTURE.md +48 -1
- package/Dockerfile +2 -2
- package/package.json +1 -1
- package/scripts/ipc/generate-swift.ts +6 -2
- package/src/__tests__/agent-loop.test.ts +119 -0
- package/src/__tests__/bundled-asset.test.ts +107 -0
- package/src/__tests__/canonical-guardian-store.test.ts +636 -0
- package/src/__tests__/channel-approval-routes.test.ts +174 -1
- package/src/__tests__/emit-signal-routing-intent.test.ts +43 -1
- package/src/__tests__/guardian-actions-endpoint.test.ts +205 -345
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +599 -0
- package/src/__tests__/guardian-dispatch.test.ts +19 -19
- package/src/__tests__/guardian-routing-invariants.test.ts +954 -0
- package/src/__tests__/mcp-cli.test.ts +77 -0
- package/src/__tests__/non-member-access-request.test.ts +31 -29
- package/src/__tests__/notification-decision-fallback.test.ts +61 -3
- package/src/__tests__/notification-decision-strategy.test.ts +17 -0
- package/src/__tests__/notification-guardian-path.test.ts +13 -15
- package/src/__tests__/onboarding-template-contract.test.ts +116 -21
- package/src/__tests__/secret-scanner-executor.test.ts +59 -0
- package/src/__tests__/secret-scanner.test.ts +8 -0
- package/src/__tests__/sensitive-output-placeholders.test.ts +208 -0
- package/src/__tests__/session-runtime-assembly.test.ts +76 -47
- package/src/__tests__/tool-grant-request-escalation.test.ts +497 -0
- package/src/agent/loop.ts +46 -3
- package/src/approvals/guardian-decision-primitive.ts +285 -0
- package/src/approvals/guardian-request-resolvers.ts +539 -0
- package/src/calls/guardian-dispatch.ts +46 -40
- package/src/calls/relay-server.ts +147 -2
- package/src/calls/types.ts +1 -1
- package/src/config/system-prompt.ts +2 -1
- package/src/config/templates/BOOTSTRAP.md +47 -31
- package/src/config/templates/USER.md +5 -0
- package/src/config/update-bulletin-template-path.ts +4 -1
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +22 -17
- package/src/daemon/handlers/guardian-actions.ts +45 -66
- package/src/daemon/ipc-contract/guardian-actions.ts +7 -0
- package/src/daemon/lifecycle.ts +3 -16
- package/src/daemon/server.ts +18 -0
- package/src/daemon/session-agent-loop-handlers.ts +5 -4
- package/src/daemon/session-agent-loop.ts +32 -5
- package/src/daemon/session-process.ts +68 -307
- package/src/daemon/session-runtime-assembly.ts +112 -24
- package/src/daemon/session-tool-setup.ts +1 -0
- package/src/daemon/session.ts +1 -0
- package/src/home-base/prebuilt/seed.ts +2 -1
- package/src/hooks/templates.ts +2 -1
- package/src/memory/canonical-guardian-store.ts +524 -0
- package/src/memory/channel-guardian-store.ts +1 -0
- package/src/memory/db-init.ts +16 -0
- package/src/memory/guardian-action-store.ts +7 -60
- package/src/memory/guardian-approvals.ts +9 -4
- package/src/memory/migrations/036-normalize-phone-identities.ts +289 -0
- package/src/memory/migrations/118-reminder-routing-intent.ts +3 -3
- package/src/memory/migrations/121-canonical-guardian-requests.ts +59 -0
- package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +15 -0
- package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +15 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/migrations/registry.ts +5 -0
- package/src/memory/schema-migration.ts +1 -0
- package/src/memory/schema.ts +52 -0
- package/src/notifications/copy-composer.ts +16 -4
- package/src/notifications/decision-engine.ts +57 -0
- package/src/permissions/defaults.ts +2 -0
- package/src/runtime/access-request-helper.ts +137 -0
- package/src/runtime/actor-trust-resolver.ts +225 -0
- package/src/runtime/channel-guardian-service.ts +12 -4
- package/src/runtime/guardian-context-resolver.ts +32 -7
- package/src/runtime/guardian-decision-types.ts +6 -0
- package/src/runtime/guardian-reply-router.ts +687 -0
- package/src/runtime/http-server.ts +8 -0
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +116 -0
- package/src/runtime/routes/conversation-routes.ts +18 -0
- package/src/runtime/routes/guardian-action-routes.ts +100 -109
- package/src/runtime/routes/inbound-message-handler.ts +170 -525
- package/src/runtime/tool-grant-request-helper.ts +195 -0
- package/src/tools/executor.ts +13 -1
- package/src/tools/sensitive-output-placeholders.ts +203 -0
- package/src/tools/tool-approval-handler.ts +44 -1
- package/src/tools/types.ts +11 -0
- package/src/util/bundled-asset.ts +31 -0
- package/src/util/canonicalize-identity.ts +52 -0
|
@@ -103,6 +103,8 @@ function ensureConversation(id: string): void {
|
|
|
103
103
|
|
|
104
104
|
function resetTables(): void {
|
|
105
105
|
const db = getDb();
|
|
106
|
+
db.run('DELETE FROM canonical_guardian_deliveries');
|
|
107
|
+
db.run('DELETE FROM canonical_guardian_requests');
|
|
106
108
|
db.run('DELETE FROM guardian_action_deliveries');
|
|
107
109
|
db.run('DELETE FROM guardian_action_requests');
|
|
108
110
|
db.run('DELETE FROM call_pending_questions');
|
|
@@ -160,7 +162,7 @@ describe('guardian-dispatch', () => {
|
|
|
160
162
|
|
|
161
163
|
const db = getDb();
|
|
162
164
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
163
|
-
const request = raw.query('SELECT * FROM
|
|
165
|
+
const request = raw.query('SELECT * FROM canonical_guardian_requests WHERE call_session_id = ?').get(session.id) as
|
|
164
166
|
| { id: string; status: string; question_text: string }
|
|
165
167
|
| undefined;
|
|
166
168
|
expect(request).toBeDefined();
|
|
@@ -168,7 +170,7 @@ describe('guardian-dispatch', () => {
|
|
|
168
170
|
expect(request!.question_text).toBe('What is the gate code?');
|
|
169
171
|
|
|
170
172
|
const vellumDelivery = raw.query(
|
|
171
|
-
'SELECT * FROM
|
|
173
|
+
'SELECT * FROM canonical_guardian_deliveries WHERE request_id = ? AND destination_channel = ?',
|
|
172
174
|
).get(request!.id, 'vellum') as { status: string; destination_conversation_id: string | null } | undefined;
|
|
173
175
|
expect(vellumDelivery).toBeDefined();
|
|
174
176
|
expect(vellumDelivery!.status).toBe('sent');
|
|
@@ -224,18 +226,17 @@ describe('guardian-dispatch', () => {
|
|
|
224
226
|
|
|
225
227
|
const db = getDb();
|
|
226
228
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
227
|
-
const request = raw.query('SELECT * FROM
|
|
229
|
+
const request = raw.query('SELECT * FROM canonical_guardian_requests WHERE call_session_id = ?').get(session.id) as
|
|
228
230
|
| { id: string }
|
|
229
231
|
| undefined;
|
|
230
232
|
const telegramDelivery = raw.query(
|
|
231
|
-
'SELECT * FROM
|
|
233
|
+
'SELECT * FROM canonical_guardian_deliveries WHERE request_id = ? AND destination_channel = ?',
|
|
232
234
|
).get(request!.id, 'telegram') as
|
|
233
|
-
| { status: string; destination_chat_id: string | null
|
|
235
|
+
| { status: string; destination_chat_id: string | null }
|
|
234
236
|
| undefined;
|
|
235
237
|
expect(telegramDelivery).toBeDefined();
|
|
236
238
|
expect(telegramDelivery!.status).toBe('sent');
|
|
237
239
|
expect(telegramDelivery!.destination_chat_id).toBe('tg-chat-999');
|
|
238
|
-
expect(telegramDelivery!.destination_external_user_id).toBe('tg-user-888');
|
|
239
240
|
});
|
|
240
241
|
|
|
241
242
|
test('marks non-sent pipeline delivery results as failed', async () => {
|
|
@@ -275,15 +276,14 @@ describe('guardian-dispatch', () => {
|
|
|
275
276
|
|
|
276
277
|
const db = getDb();
|
|
277
278
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
278
|
-
const request = raw.query('SELECT * FROM
|
|
279
|
+
const request = raw.query('SELECT * FROM canonical_guardian_requests WHERE call_session_id = ?').get(session.id) as
|
|
279
280
|
| { id: string }
|
|
280
281
|
| undefined;
|
|
281
282
|
const vellumDelivery = raw.query(
|
|
282
|
-
'SELECT * FROM
|
|
283
|
-
).get(request!.id, 'vellum') as { status: string
|
|
283
|
+
'SELECT * FROM canonical_guardian_deliveries WHERE request_id = ? AND destination_channel = ?',
|
|
284
|
+
).get(request!.id, 'vellum') as { status: string } | undefined;
|
|
284
285
|
expect(vellumDelivery).toBeDefined();
|
|
285
286
|
expect(vellumDelivery!.status).toBe('failed');
|
|
286
|
-
expect(vellumDelivery!.last_error).toContain('IPC unavailable');
|
|
287
287
|
});
|
|
288
288
|
|
|
289
289
|
test('uses onThreadCreated callback conversation when delivery result omits conversationId', async () => {
|
|
@@ -326,17 +326,17 @@ describe('guardian-dispatch', () => {
|
|
|
326
326
|
|
|
327
327
|
const db = getDb();
|
|
328
328
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
329
|
-
const request = raw.query('SELECT * FROM
|
|
329
|
+
const request = raw.query('SELECT * FROM canonical_guardian_requests WHERE call_session_id = ?').get(session.id) as
|
|
330
330
|
| { id: string }
|
|
331
331
|
| undefined;
|
|
332
332
|
const vellumDelivery = raw.query(
|
|
333
|
-
'SELECT * FROM
|
|
333
|
+
'SELECT * FROM canonical_guardian_deliveries WHERE request_id = ? AND destination_channel = ?',
|
|
334
334
|
).get(request!.id, 'vellum') as { destination_conversation_id: string | null } | undefined;
|
|
335
335
|
expect(vellumDelivery).toBeDefined();
|
|
336
336
|
expect(vellumDelivery!.destination_conversation_id).toBe('conv-from-thread-created');
|
|
337
337
|
});
|
|
338
338
|
|
|
339
|
-
test('persists toolName and inputDigest on guardian
|
|
339
|
+
test('persists toolName and inputDigest on canonical guardian request for tool-approval dispatches', async () => {
|
|
340
340
|
const convId = 'conv-dispatch-5';
|
|
341
341
|
ensureConversation(convId);
|
|
342
342
|
|
|
@@ -359,7 +359,7 @@ describe('guardian-dispatch', () => {
|
|
|
359
359
|
|
|
360
360
|
const db = getDb();
|
|
361
361
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
362
|
-
const request = raw.query('SELECT * FROM
|
|
362
|
+
const request = raw.query('SELECT * FROM canonical_guardian_requests WHERE call_session_id = ?').get(session.id) as
|
|
363
363
|
| { id: string; tool_name: string | null; input_digest: string | null }
|
|
364
364
|
| undefined;
|
|
365
365
|
expect(request).toBeDefined();
|
|
@@ -388,7 +388,7 @@ describe('guardian-dispatch', () => {
|
|
|
388
388
|
|
|
389
389
|
const db = getDb();
|
|
390
390
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
391
|
-
const request = raw.query('SELECT * FROM
|
|
391
|
+
const request = raw.query('SELECT * FROM canonical_guardian_requests WHERE call_session_id = ?').get(session.id) as
|
|
392
392
|
| { id: string; tool_name: string | null; input_digest: string | null }
|
|
393
393
|
| undefined;
|
|
394
394
|
expect(request).toBeDefined();
|
|
@@ -485,11 +485,11 @@ describe('guardian-dispatch', () => {
|
|
|
485
485
|
pendingQuestion: pq2,
|
|
486
486
|
});
|
|
487
487
|
|
|
488
|
-
// Both dispatches should have created separate
|
|
488
|
+
// Both dispatches should have created separate canonical requests
|
|
489
489
|
const db = getDb();
|
|
490
490
|
const raw = (db as unknown as { $client: import('bun:sqlite').Database }).$client;
|
|
491
491
|
const requests = raw.query(
|
|
492
|
-
'SELECT * FROM
|
|
492
|
+
'SELECT * FROM canonical_guardian_requests WHERE call_session_id = ? ORDER BY created_at ASC',
|
|
493
493
|
).all(session.id) as Array<{ id: string; question_text: string }>;
|
|
494
494
|
expect(requests).toHaveLength(2);
|
|
495
495
|
expect(requests[0].question_text).toBe('What is the gate code?');
|
|
@@ -498,7 +498,7 @@ describe('guardian-dispatch', () => {
|
|
|
498
498
|
// Each request should have its own delivery row, both pointing to the shared conversation
|
|
499
499
|
for (const req of requests) {
|
|
500
500
|
const delivery = raw.query(
|
|
501
|
-
'SELECT * FROM
|
|
501
|
+
'SELECT * FROM canonical_guardian_deliveries WHERE request_id = ? AND destination_channel = ?',
|
|
502
502
|
).get(req.id, 'vellum') as { status: string; destination_conversation_id: string | null } | undefined;
|
|
503
503
|
expect(delivery).toBeDefined();
|
|
504
504
|
expect(delivery!.status).toBe('sent');
|
|
@@ -507,7 +507,7 @@ describe('guardian-dispatch', () => {
|
|
|
507
507
|
|
|
508
508
|
// Total delivery rows should be 2 (one per request), not 1
|
|
509
509
|
const allDeliveries = raw.query(
|
|
510
|
-
'SELECT * FROM
|
|
510
|
+
'SELECT * FROM canonical_guardian_deliveries WHERE destination_conversation_id = ?',
|
|
511
511
|
).all(sharedConversationId) as Array<{ request_id: string }>;
|
|
512
512
|
expect(allDeliveries).toHaveLength(2);
|
|
513
513
|
|