@vellumai/assistant 0.3.4 → 0.3.5
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/Dockerfile +2 -0
- package/README.md +37 -2
- package/package.json +1 -1
- package/scripts/ipc/generate-swift.ts +13 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +100 -0
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +41 -0
- package/src/__tests__/approval-message-composer.test.ts +253 -0
- package/src/__tests__/call-domain.test.ts +12 -2
- package/src/__tests__/call-orchestrator.test.ts +70 -1
- package/src/__tests__/call-routes-http.test.ts +27 -2
- package/src/__tests__/channel-approval-routes.test.ts +21 -17
- package/src/__tests__/channel-approvals.test.ts +48 -1
- package/src/__tests__/channel-guardian.test.ts +74 -22
- package/src/__tests__/channel-readiness-service.test.ts +257 -0
- package/src/__tests__/config-schema.test.ts +2 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/daemon-lifecycle.test.ts +13 -12
- package/src/__tests__/dictation-mode-detection.test.ts +63 -0
- package/src/__tests__/entity-search.test.ts +615 -0
- package/src/__tests__/handlers-twilio-config.test.ts +407 -0
- package/src/__tests__/ipc-snapshot.test.ts +63 -0
- package/src/__tests__/messaging-send-tool.test.ts +65 -0
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +4 -0
- package/src/__tests__/run-orchestrator.test.ts +22 -0
- package/src/__tests__/session-runtime-assembly.test.ts +85 -1
- package/src/__tests__/sms-messaging-provider.test.ts +125 -0
- package/src/__tests__/twilio-routes.test.ts +39 -3
- package/src/__tests__/twitter-cli-error-shaping.test.ts +2 -2
- package/src/__tests__/web-search.test.ts +1 -1
- package/src/__tests__/work-item-output.test.ts +110 -0
- package/src/calls/call-domain.ts +8 -5
- package/src/calls/call-orchestrator.ts +22 -11
- package/src/calls/twilio-config.ts +17 -11
- package/src/calls/twilio-rest.ts +276 -0
- package/src/calls/twilio-routes.ts +39 -1
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +15 -0
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +56 -0
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +185 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +199 -0
- package/src/config/bundled-skills/media-processing/TOOLS.json +320 -0
- package/src/config/bundled-skills/media-processing/services/capability-registry.ts +137 -0
- package/src/config/bundled-skills/media-processing/services/event-detection-service.ts +280 -0
- package/src/config/bundled-skills/media-processing/services/feedback-aggregation.ts +144 -0
- package/src/config/bundled-skills/media-processing/services/feedback-store.ts +136 -0
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +261 -0
- package/src/config/bundled-skills/media-processing/services/retrieval-service.ts +95 -0
- package/src/config/bundled-skills/media-processing/services/timeline-service.ts +267 -0
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +301 -0
- package/src/config/bundled-skills/media-processing/tools/detect-events.ts +110 -0
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +190 -0
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +195 -0
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +197 -0
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +166 -0
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +75 -0
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +300 -0
- package/src/config/bundled-skills/media-processing/tools/recalibrate.ts +235 -0
- package/src/config/bundled-skills/media-processing/tools/select-tracking-profile.ts +142 -0
- package/src/config/bundled-skills/media-processing/tools/submit-feedback.ts +150 -0
- package/src/config/bundled-skills/messaging/SKILL.md +21 -6
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +2 -2
- package/src/config/bundled-skills/twitter/SKILL.md +19 -3
- package/src/config/defaults.ts +2 -1
- package/src/config/schema.ts +9 -3
- package/src/config/system-prompt.ts +24 -0
- package/src/config/templates/IDENTITY.md +2 -2
- package/src/config/vellum-skills/catalog.json +6 -0
- package/src/config/vellum-skills/google-oauth-setup/SKILL.md +3 -3
- package/src/config/vellum-skills/slack-oauth-setup/SKILL.md +3 -3
- package/src/config/vellum-skills/sms-setup/SKILL.md +118 -0
- package/src/config/vellum-skills/twilio-setup/SKILL.md +40 -8
- package/src/daemon/handlers/config.ts +783 -9
- package/src/daemon/handlers/dictation.ts +182 -0
- package/src/daemon/handlers/identity.ts +14 -23
- package/src/daemon/handlers/index.ts +2 -0
- package/src/daemon/handlers/sessions.ts +2 -0
- package/src/daemon/handlers/shared.ts +3 -0
- package/src/daemon/handlers/work-items.ts +15 -7
- package/src/daemon/ipc-contract-inventory.json +10 -0
- package/src/daemon/ipc-contract.ts +108 -4
- package/src/daemon/lifecycle.ts +2 -0
- package/src/daemon/ride-shotgun-handler.ts +1 -1
- package/src/daemon/server.ts +6 -2
- package/src/daemon/session-agent-loop.ts +5 -1
- package/src/daemon/session-runtime-assembly.ts +55 -0
- package/src/daemon/session-tool-setup.ts +2 -0
- package/src/daemon/session.ts +11 -1
- package/src/inbound/public-ingress-urls.ts +3 -3
- package/src/memory/channel-guardian-store.ts +2 -1
- package/src/memory/db-init.ts +144 -0
- package/src/memory/job-handlers/media-processing.ts +100 -0
- package/src/memory/jobs-store.ts +2 -1
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/media-store.ts +759 -0
- package/src/memory/retriever.ts +6 -1
- package/src/memory/schema.ts +98 -0
- package/src/memory/search/entity.ts +208 -25
- package/src/memory/search/ranking.ts +6 -1
- package/src/memory/search/types.ts +24 -0
- package/src/messaging/provider-types.ts +2 -0
- package/src/messaging/providers/sms/adapter.ts +204 -0
- package/src/messaging/providers/sms/client.ts +93 -0
- package/src/messaging/providers/sms/types.ts +7 -0
- package/src/permissions/checker.ts +16 -2
- package/src/runtime/approval-message-composer.ts +143 -0
- package/src/runtime/channel-approvals.ts +12 -4
- package/src/runtime/channel-guardian-service.ts +44 -18
- package/src/runtime/channel-readiness-service.ts +292 -0
- package/src/runtime/channel-readiness-types.ts +29 -0
- package/src/runtime/http-server.ts +53 -27
- package/src/runtime/http-types.ts +3 -0
- package/src/runtime/routes/call-routes.ts +2 -1
- package/src/runtime/routes/channel-routes.ts +67 -21
- package/src/runtime/run-orchestrator.ts +35 -2
- package/src/tools/assets/materialize.ts +2 -2
- package/src/tools/calls/call-start.ts +1 -0
- package/src/tools/credentials/vault.ts +1 -1
- package/src/tools/execution-target.ts +11 -1
- package/src/tools/network/web-search.ts +1 -1
- package/src/tools/types.ts +2 -0
- package/src/twitter/router.ts +1 -1
- package/src/util/platform.ts +35 -0
|
@@ -523,6 +523,54 @@ describe('Twilio config handler', () => {
|
|
|
523
523
|
}
|
|
524
524
|
});
|
|
525
525
|
|
|
526
|
+
test('getTwilioConfig with assistantId prefers assistant-scoped mapping over global phone number', () => {
|
|
527
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
528
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
529
|
+
rawConfigStore = {
|
|
530
|
+
sms: {
|
|
531
|
+
phoneNumber: '+15551234567',
|
|
532
|
+
assistantPhoneNumbers: {
|
|
533
|
+
'ast-alpha': '+15550000001',
|
|
534
|
+
},
|
|
535
|
+
},
|
|
536
|
+
ingress: { enabled: true, publicBaseUrl: 'https://test.ngrok.io' },
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
const savedEnv = process.env.TWILIO_PHONE_NUMBER;
|
|
540
|
+
delete process.env.TWILIO_PHONE_NUMBER;
|
|
541
|
+
|
|
542
|
+
try {
|
|
543
|
+
const config = getTwilioConfig('ast-alpha');
|
|
544
|
+
expect(config.phoneNumber).toBe('+15550000001');
|
|
545
|
+
} finally {
|
|
546
|
+
if (savedEnv !== undefined) process.env.TWILIO_PHONE_NUMBER = savedEnv;
|
|
547
|
+
}
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
test('getTwilioConfig with assistantId falls back to global number when mapping is missing', () => {
|
|
551
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
552
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
553
|
+
rawConfigStore = {
|
|
554
|
+
sms: {
|
|
555
|
+
phoneNumber: '+15551234567',
|
|
556
|
+
assistantPhoneNumbers: {
|
|
557
|
+
'ast-alpha': '+15550000001',
|
|
558
|
+
},
|
|
559
|
+
},
|
|
560
|
+
ingress: { enabled: true, publicBaseUrl: 'https://test.ngrok.io' },
|
|
561
|
+
};
|
|
562
|
+
|
|
563
|
+
const savedEnv = process.env.TWILIO_PHONE_NUMBER;
|
|
564
|
+
delete process.env.TWILIO_PHONE_NUMBER;
|
|
565
|
+
|
|
566
|
+
try {
|
|
567
|
+
const config = getTwilioConfig('ast-beta');
|
|
568
|
+
expect(config.phoneNumber).toBe('+15551234567');
|
|
569
|
+
} finally {
|
|
570
|
+
if (savedEnv !== undefined) process.env.TWILIO_PHONE_NUMBER = savedEnv;
|
|
571
|
+
}
|
|
572
|
+
});
|
|
573
|
+
|
|
526
574
|
// ── assign_number ───────────────────────────────────────────────────
|
|
527
575
|
|
|
528
576
|
test('assign_number persists phone number to config', async () => {
|
|
@@ -1389,4 +1437,363 @@ describe('Twilio config handler', () => {
|
|
|
1389
1437
|
expect(responseStr).not.toContain('AC_secret_account_sid_12345');
|
|
1390
1438
|
expect(responseStr).not.toContain('secret_auth_token_67890');
|
|
1391
1439
|
});
|
|
1440
|
+
|
|
1441
|
+
// ── sms_compliance_status ───────────────────────────────────────────
|
|
1442
|
+
|
|
1443
|
+
test('sms_compliance_status returns structured compliance data for toll-free number', async () => {
|
|
1444
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1445
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1446
|
+
rawConfigStore = { sms: { phoneNumber: '+18001234567' } };
|
|
1447
|
+
|
|
1448
|
+
globalThis.fetch = (async (url: string | URL | Request) => {
|
|
1449
|
+
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
1450
|
+
// Phone number SID lookup
|
|
1451
|
+
if (urlStr.includes('IncomingPhoneNumbers.json') && urlStr.includes('PhoneNumber=')) {
|
|
1452
|
+
return new Response(JSON.stringify({
|
|
1453
|
+
incoming_phone_numbers: [{ sid: 'PN123abc', phone_number: '+18001234567' }],
|
|
1454
|
+
}), { status: 200 });
|
|
1455
|
+
}
|
|
1456
|
+
// Toll-free verification lookup
|
|
1457
|
+
if (urlStr.includes('Tollfree/Verifications')) {
|
|
1458
|
+
return new Response(JSON.stringify({
|
|
1459
|
+
verifications: [{
|
|
1460
|
+
sid: 'TF_VER_001',
|
|
1461
|
+
status: 'TWILIO_APPROVED',
|
|
1462
|
+
rejection_reason: null,
|
|
1463
|
+
edit_allowed: false,
|
|
1464
|
+
}],
|
|
1465
|
+
}), { status: 200 });
|
|
1466
|
+
}
|
|
1467
|
+
return originalFetch(url);
|
|
1468
|
+
}) as typeof fetch;
|
|
1469
|
+
|
|
1470
|
+
const msg: TwilioConfigRequest = {
|
|
1471
|
+
type: 'twilio_config',
|
|
1472
|
+
action: 'sms_compliance_status',
|
|
1473
|
+
};
|
|
1474
|
+
|
|
1475
|
+
const { ctx, sent } = createTestContext();
|
|
1476
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1477
|
+
|
|
1478
|
+
expect(sent).toHaveLength(1);
|
|
1479
|
+
const res = sent[0] as { type: string; success: boolean; compliance?: Record<string, unknown> };
|
|
1480
|
+
expect(res.success).toBe(true);
|
|
1481
|
+
expect(res.compliance).toBeDefined();
|
|
1482
|
+
expect(res.compliance!.numberType).toBe('toll_free');
|
|
1483
|
+
expect(res.compliance!.verificationSid).toBe('TF_VER_001');
|
|
1484
|
+
expect(res.compliance!.verificationStatus).toBe('TWILIO_APPROVED');
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
test('sms_compliance_status returns local_10dlc type for non-toll-free number without remote check', async () => {
|
|
1488
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1489
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1490
|
+
rawConfigStore = { sms: { phoneNumber: '+15551234567' } };
|
|
1491
|
+
|
|
1492
|
+
const msg: TwilioConfigRequest = {
|
|
1493
|
+
type: 'twilio_config',
|
|
1494
|
+
action: 'sms_compliance_status',
|
|
1495
|
+
};
|
|
1496
|
+
|
|
1497
|
+
const { ctx, sent } = createTestContext();
|
|
1498
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1499
|
+
|
|
1500
|
+
expect(sent).toHaveLength(1);
|
|
1501
|
+
const res = sent[0] as { type: string; success: boolean; compliance?: Record<string, unknown> };
|
|
1502
|
+
expect(res.success).toBe(true);
|
|
1503
|
+
expect(res.compliance).toBeDefined();
|
|
1504
|
+
expect(res.compliance!.numberType).toBe('local_10dlc');
|
|
1505
|
+
// No verification fields for non-toll-free
|
|
1506
|
+
expect(res.compliance!.verificationSid).toBeUndefined();
|
|
1507
|
+
});
|
|
1508
|
+
|
|
1509
|
+
test('sms_compliance_status returns error when no credentials', async () => {
|
|
1510
|
+
const msg: TwilioConfigRequest = {
|
|
1511
|
+
type: 'twilio_config',
|
|
1512
|
+
action: 'sms_compliance_status',
|
|
1513
|
+
};
|
|
1514
|
+
|
|
1515
|
+
const { ctx, sent } = createTestContext();
|
|
1516
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1517
|
+
|
|
1518
|
+
expect(sent).toHaveLength(1);
|
|
1519
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1520
|
+
expect(res.success).toBe(false);
|
|
1521
|
+
expect(res.error).toContain('Twilio credentials not configured');
|
|
1522
|
+
});
|
|
1523
|
+
|
|
1524
|
+
// ── sms_submit_tollfree_verification ────────────────────────────────
|
|
1525
|
+
|
|
1526
|
+
test('sms_submit_tollfree_verification validates required fields', async () => {
|
|
1527
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1528
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1529
|
+
|
|
1530
|
+
const msg: TwilioConfigRequest = {
|
|
1531
|
+
type: 'twilio_config',
|
|
1532
|
+
action: 'sms_submit_tollfree_verification',
|
|
1533
|
+
verificationParams: {
|
|
1534
|
+
// Missing all required fields
|
|
1535
|
+
businessName: 'Test Biz',
|
|
1536
|
+
},
|
|
1537
|
+
};
|
|
1538
|
+
|
|
1539
|
+
const { ctx, sent } = createTestContext();
|
|
1540
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1541
|
+
|
|
1542
|
+
expect(sent).toHaveLength(1);
|
|
1543
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1544
|
+
expect(res.success).toBe(false);
|
|
1545
|
+
expect(res.error).toContain('Missing required verification fields');
|
|
1546
|
+
expect(res.error).toContain('tollfreePhoneNumberSid');
|
|
1547
|
+
});
|
|
1548
|
+
|
|
1549
|
+
test('sms_submit_tollfree_verification defaults businessType to SOLE_PROPRIETOR', async () => {
|
|
1550
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1551
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1552
|
+
|
|
1553
|
+
let capturedBody = '';
|
|
1554
|
+
globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
|
|
1555
|
+
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
1556
|
+
if (urlStr.includes('Tollfree/Verifications') && init?.method === 'POST') {
|
|
1557
|
+
capturedBody = init?.body?.toString() ?? '';
|
|
1558
|
+
return new Response(JSON.stringify({
|
|
1559
|
+
sid: 'TF_VER_NEW',
|
|
1560
|
+
status: 'PENDING_REVIEW',
|
|
1561
|
+
}), { status: 201 });
|
|
1562
|
+
}
|
|
1563
|
+
return originalFetch(url);
|
|
1564
|
+
}) as typeof fetch;
|
|
1565
|
+
|
|
1566
|
+
const msg: TwilioConfigRequest = {
|
|
1567
|
+
type: 'twilio_config',
|
|
1568
|
+
action: 'sms_submit_tollfree_verification',
|
|
1569
|
+
verificationParams: {
|
|
1570
|
+
tollfreePhoneNumberSid: 'PN123',
|
|
1571
|
+
businessName: 'Test Biz',
|
|
1572
|
+
businessWebsite: 'https://test.com',
|
|
1573
|
+
notificationEmail: 'test@test.com',
|
|
1574
|
+
useCaseCategories: ['CUSTOMER_CARE'],
|
|
1575
|
+
useCaseSummary: 'Customer support messages',
|
|
1576
|
+
productionMessageSample: 'Your order has shipped!',
|
|
1577
|
+
optInImageUrls: ['https://test.com/optin.png'],
|
|
1578
|
+
optInType: 'WEB_FORM',
|
|
1579
|
+
messageVolume: '100',
|
|
1580
|
+
// businessType NOT provided — should default to SOLE_PROPRIETOR
|
|
1581
|
+
},
|
|
1582
|
+
};
|
|
1583
|
+
|
|
1584
|
+
const { ctx, sent } = createTestContext();
|
|
1585
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1586
|
+
|
|
1587
|
+
expect(sent).toHaveLength(1);
|
|
1588
|
+
const res = sent[0] as { type: string; success: boolean; compliance?: Record<string, unknown> };
|
|
1589
|
+
expect(res.success).toBe(true);
|
|
1590
|
+
expect(res.compliance).toBeDefined();
|
|
1591
|
+
expect(res.compliance!.verificationSid).toBe('TF_VER_NEW');
|
|
1592
|
+
expect(res.compliance!.verificationStatus).toBe('PENDING_REVIEW');
|
|
1593
|
+
|
|
1594
|
+
// Verify the default businessType was sent to Twilio
|
|
1595
|
+
expect(capturedBody).toContain('BusinessType=SOLE_PROPRIETOR');
|
|
1596
|
+
});
|
|
1597
|
+
|
|
1598
|
+
test('sms_submit_tollfree_verification rejects invalid useCaseCategories', async () => {
|
|
1599
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1600
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1601
|
+
|
|
1602
|
+
const msg: TwilioConfigRequest = {
|
|
1603
|
+
type: 'twilio_config',
|
|
1604
|
+
action: 'sms_submit_tollfree_verification',
|
|
1605
|
+
verificationParams: {
|
|
1606
|
+
tollfreePhoneNumberSid: 'PN123',
|
|
1607
|
+
businessName: 'Test Biz',
|
|
1608
|
+
businessWebsite: 'https://test.com',
|
|
1609
|
+
notificationEmail: 'test@test.com',
|
|
1610
|
+
useCaseCategories: ['INVALID_CATEGORY'],
|
|
1611
|
+
useCaseSummary: 'Test',
|
|
1612
|
+
productionMessageSample: 'Test message',
|
|
1613
|
+
optInImageUrls: ['https://test.com/optin.png'],
|
|
1614
|
+
optInType: 'WEB_FORM',
|
|
1615
|
+
messageVolume: '100',
|
|
1616
|
+
},
|
|
1617
|
+
};
|
|
1618
|
+
|
|
1619
|
+
const { ctx, sent } = createTestContext();
|
|
1620
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1621
|
+
|
|
1622
|
+
expect(sent).toHaveLength(1);
|
|
1623
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1624
|
+
expect(res.success).toBe(false);
|
|
1625
|
+
expect(res.error).toContain('Invalid useCaseCategories');
|
|
1626
|
+
expect(res.error).toContain('INVALID_CATEGORY');
|
|
1627
|
+
});
|
|
1628
|
+
|
|
1629
|
+
test('sms_submit_tollfree_verification returns error without verificationParams', async () => {
|
|
1630
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1631
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1632
|
+
|
|
1633
|
+
const msg: TwilioConfigRequest = {
|
|
1634
|
+
type: 'twilio_config',
|
|
1635
|
+
action: 'sms_submit_tollfree_verification',
|
|
1636
|
+
};
|
|
1637
|
+
|
|
1638
|
+
const { ctx, sent } = createTestContext();
|
|
1639
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1640
|
+
|
|
1641
|
+
expect(sent).toHaveLength(1);
|
|
1642
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1643
|
+
expect(res.success).toBe(false);
|
|
1644
|
+
expect(res.error).toContain('verificationParams is required');
|
|
1645
|
+
});
|
|
1646
|
+
|
|
1647
|
+
// ── release_number ─────────────────────────────────────────────────
|
|
1648
|
+
|
|
1649
|
+
test('release_number clears config and secure keys', async () => {
|
|
1650
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1651
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1652
|
+
secureKeyStore['credential:twilio:phone_number'] = '+15551234567';
|
|
1653
|
+
rawConfigStore = {
|
|
1654
|
+
sms: {
|
|
1655
|
+
phoneNumber: '+15551234567',
|
|
1656
|
+
assistantPhoneNumbers: { 'ast-alpha': '+15551234567' },
|
|
1657
|
+
},
|
|
1658
|
+
};
|
|
1659
|
+
|
|
1660
|
+
globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
|
|
1661
|
+
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
1662
|
+
// Phone number SID lookup
|
|
1663
|
+
if (urlStr.includes('IncomingPhoneNumbers.json') && urlStr.includes('PhoneNumber=')) {
|
|
1664
|
+
return new Response(JSON.stringify({
|
|
1665
|
+
incoming_phone_numbers: [{ sid: 'PN123abc', phone_number: '+15551234567' }],
|
|
1666
|
+
}), { status: 200 });
|
|
1667
|
+
}
|
|
1668
|
+
// Phone number deletion
|
|
1669
|
+
if (urlStr.includes('IncomingPhoneNumbers/PN123abc.json') && init?.method === 'DELETE') {
|
|
1670
|
+
return new Response('', { status: 204 });
|
|
1671
|
+
}
|
|
1672
|
+
return originalFetch(url);
|
|
1673
|
+
}) as typeof fetch;
|
|
1674
|
+
|
|
1675
|
+
const msg: TwilioConfigRequest = {
|
|
1676
|
+
type: 'twilio_config',
|
|
1677
|
+
action: 'release_number',
|
|
1678
|
+
};
|
|
1679
|
+
|
|
1680
|
+
const { ctx, sent } = createTestContext();
|
|
1681
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1682
|
+
|
|
1683
|
+
expect(sent).toHaveLength(1);
|
|
1684
|
+
const res = sent[0] as { type: string; success: boolean; warning?: string };
|
|
1685
|
+
expect(res.success).toBe(true);
|
|
1686
|
+
expect(res.warning).toContain('Phone number released');
|
|
1687
|
+
|
|
1688
|
+
// Verify config was cleared
|
|
1689
|
+
const sms = rawConfigStore.sms as Record<string, unknown>;
|
|
1690
|
+
expect(sms.phoneNumber).toBeUndefined();
|
|
1691
|
+
expect(sms.assistantPhoneNumbers).toBeUndefined();
|
|
1692
|
+
|
|
1693
|
+
// Verify secure key was cleared
|
|
1694
|
+
expect(secureKeyStore['credential:twilio:phone_number']).toBeUndefined();
|
|
1695
|
+
});
|
|
1696
|
+
|
|
1697
|
+
test('release_number returns error when no credentials', async () => {
|
|
1698
|
+
rawConfigStore = { sms: { phoneNumber: '+15551234567' } };
|
|
1699
|
+
|
|
1700
|
+
const msg: TwilioConfigRequest = {
|
|
1701
|
+
type: 'twilio_config',
|
|
1702
|
+
action: 'release_number',
|
|
1703
|
+
};
|
|
1704
|
+
|
|
1705
|
+
const { ctx, sent } = createTestContext();
|
|
1706
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1707
|
+
|
|
1708
|
+
expect(sent).toHaveLength(1);
|
|
1709
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1710
|
+
expect(res.success).toBe(false);
|
|
1711
|
+
expect(res.error).toContain('Twilio credentials not configured');
|
|
1712
|
+
});
|
|
1713
|
+
|
|
1714
|
+
test('release_number returns error when no phone number assigned', async () => {
|
|
1715
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1716
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1717
|
+
rawConfigStore = {};
|
|
1718
|
+
|
|
1719
|
+
const msg: TwilioConfigRequest = {
|
|
1720
|
+
type: 'twilio_config',
|
|
1721
|
+
action: 'release_number',
|
|
1722
|
+
};
|
|
1723
|
+
|
|
1724
|
+
const { ctx, sent } = createTestContext();
|
|
1725
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1726
|
+
|
|
1727
|
+
expect(sent).toHaveLength(1);
|
|
1728
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1729
|
+
expect(res.success).toBe(false);
|
|
1730
|
+
expect(res.error).toContain('No phone number to release');
|
|
1731
|
+
});
|
|
1732
|
+
|
|
1733
|
+
// ── sms_delete_tollfree_verification ────────────────────────────────
|
|
1734
|
+
|
|
1735
|
+
test('sms_delete_tollfree_verification requires verificationSid', async () => {
|
|
1736
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1737
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1738
|
+
|
|
1739
|
+
const msg: TwilioConfigRequest = {
|
|
1740
|
+
type: 'twilio_config',
|
|
1741
|
+
action: 'sms_delete_tollfree_verification',
|
|
1742
|
+
};
|
|
1743
|
+
|
|
1744
|
+
const { ctx, sent } = createTestContext();
|
|
1745
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1746
|
+
|
|
1747
|
+
expect(sent).toHaveLength(1);
|
|
1748
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1749
|
+
expect(res.success).toBe(false);
|
|
1750
|
+
expect(res.error).toContain('verificationSid is required');
|
|
1751
|
+
});
|
|
1752
|
+
|
|
1753
|
+
test('sms_delete_tollfree_verification includes queue warning', async () => {
|
|
1754
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1755
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1756
|
+
|
|
1757
|
+
globalThis.fetch = (async (url: string | URL | Request, init?: RequestInit) => {
|
|
1758
|
+
const urlStr = typeof url === 'string' ? url : url instanceof URL ? url.toString() : url.url;
|
|
1759
|
+
if (urlStr.includes('Tollfree/Verifications/TF_VER_001') && init?.method === 'DELETE') {
|
|
1760
|
+
return new Response('', { status: 204 });
|
|
1761
|
+
}
|
|
1762
|
+
return originalFetch(url);
|
|
1763
|
+
}) as typeof fetch;
|
|
1764
|
+
|
|
1765
|
+
const msg: TwilioConfigRequest = {
|
|
1766
|
+
type: 'twilio_config',
|
|
1767
|
+
action: 'sms_delete_tollfree_verification',
|
|
1768
|
+
verificationSid: 'TF_VER_001',
|
|
1769
|
+
};
|
|
1770
|
+
|
|
1771
|
+
const { ctx, sent } = createTestContext();
|
|
1772
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1773
|
+
|
|
1774
|
+
expect(sent).toHaveLength(1);
|
|
1775
|
+
const res = sent[0] as { type: string; success: boolean; warning?: string };
|
|
1776
|
+
expect(res.success).toBe(true);
|
|
1777
|
+
expect(res.warning).toContain('review queue');
|
|
1778
|
+
});
|
|
1779
|
+
|
|
1780
|
+
// ── sms_update_tollfree_verification ────────────────────────────────
|
|
1781
|
+
|
|
1782
|
+
test('sms_update_tollfree_verification requires verificationSid', async () => {
|
|
1783
|
+
secureKeyStore['credential:twilio:account_sid'] = 'AC1234567890abcdef1234567890abcdef';
|
|
1784
|
+
secureKeyStore['credential:twilio:auth_token'] = 'test_auth_token';
|
|
1785
|
+
|
|
1786
|
+
const msg: TwilioConfigRequest = {
|
|
1787
|
+
type: 'twilio_config',
|
|
1788
|
+
action: 'sms_update_tollfree_verification',
|
|
1789
|
+
};
|
|
1790
|
+
|
|
1791
|
+
const { ctx, sent } = createTestContext();
|
|
1792
|
+
await handleTwilioConfig(msg, {} as net.Socket, ctx);
|
|
1793
|
+
|
|
1794
|
+
expect(sent).toHaveLength(1);
|
|
1795
|
+
const res = sent[0] as { type: string; success: boolean; error?: string };
|
|
1796
|
+
expect(res.success).toBe(false);
|
|
1797
|
+
expect(res.error).toContain('verificationSid is required');
|
|
1798
|
+
});
|
|
1392
1799
|
});
|
|
@@ -382,6 +382,12 @@ const clientMessages: Record<ClientMessageType, ClientMessage> = {
|
|
|
382
382
|
type: 'twilio_config',
|
|
383
383
|
action: 'get',
|
|
384
384
|
},
|
|
385
|
+
channel_readiness: {
|
|
386
|
+
type: 'channel_readiness',
|
|
387
|
+
action: 'get',
|
|
388
|
+
channel: 'sms',
|
|
389
|
+
includeRemote: true,
|
|
390
|
+
},
|
|
385
391
|
guardian_verification: {
|
|
386
392
|
type: 'guardian_verification',
|
|
387
393
|
action: 'create_challenge',
|
|
@@ -564,6 +570,17 @@ const clientMessages: Record<ClientMessageType, ClientMessage> = {
|
|
|
564
570
|
tool_names_list: {
|
|
565
571
|
type: 'tool_names_list',
|
|
566
572
|
},
|
|
573
|
+
dictation_request: {
|
|
574
|
+
type: 'dictation_request',
|
|
575
|
+
transcription: 'Hello world',
|
|
576
|
+
context: {
|
|
577
|
+
bundleIdentifier: 'com.example.app',
|
|
578
|
+
appName: 'Example App',
|
|
579
|
+
windowTitle: 'Main Window',
|
|
580
|
+
selectedText: 'some selected text',
|
|
581
|
+
cursorInTextField: true,
|
|
582
|
+
},
|
|
583
|
+
},
|
|
567
584
|
};
|
|
568
585
|
|
|
569
586
|
// ---------------------------------------------------------------------------
|
|
@@ -824,6 +841,11 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
|
|
|
824
841
|
sessionId: 'sess-routed-001',
|
|
825
842
|
interactionType: 'computer_use',
|
|
826
843
|
},
|
|
844
|
+
ride_shotgun_progress: {
|
|
845
|
+
type: 'ride_shotgun_progress',
|
|
846
|
+
watchId: 'watch-shotgun-001',
|
|
847
|
+
message: 'Observing user activity...',
|
|
848
|
+
},
|
|
827
849
|
ride_shotgun_result: {
|
|
828
850
|
type: 'ride_shotgun_result',
|
|
829
851
|
sessionId: 'sess-shotgun-001',
|
|
@@ -1227,6 +1249,41 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
|
|
|
1227
1249
|
success: true,
|
|
1228
1250
|
hasCredentials: true,
|
|
1229
1251
|
phoneNumber: '+15551234567',
|
|
1252
|
+
compliance: {
|
|
1253
|
+
numberType: 'toll_free',
|
|
1254
|
+
verificationSid: 'TF_VER_001',
|
|
1255
|
+
verificationStatus: 'TWILIO_APPROVED',
|
|
1256
|
+
},
|
|
1257
|
+
testResult: {
|
|
1258
|
+
messageSid: 'SM-test-001',
|
|
1259
|
+
to: '+15559876543',
|
|
1260
|
+
initialStatus: 'queued',
|
|
1261
|
+
finalStatus: 'delivered',
|
|
1262
|
+
},
|
|
1263
|
+
diagnostics: {
|
|
1264
|
+
readiness: { ready: true, issues: [] },
|
|
1265
|
+
compliance: { status: 'TWILIO_APPROVED', detail: 'Toll-free verification: TWILIO_APPROVED' },
|
|
1266
|
+
overallStatus: 'healthy',
|
|
1267
|
+
actionItems: [],
|
|
1268
|
+
},
|
|
1269
|
+
},
|
|
1270
|
+
channel_readiness_response: {
|
|
1271
|
+
type: 'channel_readiness_response',
|
|
1272
|
+
success: true,
|
|
1273
|
+
snapshots: [
|
|
1274
|
+
{
|
|
1275
|
+
channel: 'sms',
|
|
1276
|
+
ready: false,
|
|
1277
|
+
checkedAt: 1700000000000,
|
|
1278
|
+
stale: false,
|
|
1279
|
+
reasons: [{ code: 'twilio_credentials', text: 'Twilio credentials are not configured' }],
|
|
1280
|
+
localChecks: [
|
|
1281
|
+
{ name: 'twilio_credentials', passed: false, message: 'Twilio credentials are not configured' },
|
|
1282
|
+
{ name: 'phone_number', passed: true, message: 'Phone number is assigned' },
|
|
1283
|
+
{ name: 'ingress', passed: true, message: 'Public ingress URL is configured' },
|
|
1284
|
+
],
|
|
1285
|
+
},
|
|
1286
|
+
],
|
|
1230
1287
|
},
|
|
1231
1288
|
guardian_verification_response: {
|
|
1232
1289
|
type: 'guardian_verification_response',
|
|
@@ -1608,6 +1665,12 @@ const serverMessages: Record<ServerMessageType, ServerMessage> = {
|
|
|
1608
1665
|
type: 'tool_names_list_response',
|
|
1609
1666
|
names: ['bash', 'file_read', 'file_write'],
|
|
1610
1667
|
},
|
|
1668
|
+
dictation_response: {
|
|
1669
|
+
type: 'dictation_response',
|
|
1670
|
+
text: 'Hello world',
|
|
1671
|
+
mode: 'dictation',
|
|
1672
|
+
actionPlan: undefined,
|
|
1673
|
+
},
|
|
1611
1674
|
};
|
|
1612
1675
|
|
|
1613
1676
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, mock, test } from 'bun:test';
|
|
2
|
+
import type { MessagingProvider } from '../messaging/provider.js';
|
|
3
|
+
import type { SendOptions } from '../messaging/provider-types.js';
|
|
4
|
+
|
|
5
|
+
const sendMessageMock = mock(async (..._args: unknown[]) => ({
|
|
6
|
+
id: 'msg-1',
|
|
7
|
+
timestamp: 123,
|
|
8
|
+
conversationId: 'conv-1',
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
const provider: MessagingProvider = {
|
|
12
|
+
id: 'sms',
|
|
13
|
+
displayName: 'SMS',
|
|
14
|
+
credentialService: 'twilio',
|
|
15
|
+
capabilities: new Set(['send']),
|
|
16
|
+
testConnection: async () => ({ connected: true, user: 'x', platform: 'sms' }),
|
|
17
|
+
listConversations: async () => [],
|
|
18
|
+
getHistory: async () => [],
|
|
19
|
+
search: async () => ({ total: 0, messages: [], hasMore: false }),
|
|
20
|
+
sendMessage: (token: string, conversationId: string, text: string, options?: SendOptions) =>
|
|
21
|
+
sendMessageMock(token, conversationId, text, options),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
mock.module('../config/bundled-skills/messaging/tools/shared.js', () => ({
|
|
25
|
+
resolveProvider: () => provider,
|
|
26
|
+
withProviderToken: async (_provider: MessagingProvider, fn: (token: string) => Promise<unknown>) => fn('provider-token'),
|
|
27
|
+
ok: (content: string) => ({ content, isError: false }),
|
|
28
|
+
err: (content: string) => ({ content, isError: true }),
|
|
29
|
+
}));
|
|
30
|
+
|
|
31
|
+
import { run } from '../config/bundled-skills/messaging/tools/messaging-send.js';
|
|
32
|
+
|
|
33
|
+
describe('messaging-send tool', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
sendMessageMock.mockClear();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('passes assistantId from tool context to provider send options', async () => {
|
|
39
|
+
const result = await run(
|
|
40
|
+
{
|
|
41
|
+
platform: 'sms',
|
|
42
|
+
conversation_id: '+15550004444',
|
|
43
|
+
text: 'test message',
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
workingDir: '/tmp',
|
|
47
|
+
sessionId: 'sess-1',
|
|
48
|
+
conversationId: 'conv-1',
|
|
49
|
+
assistantId: 'ast-alpha',
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
expect(result.isError).toBe(false);
|
|
54
|
+
expect(sendMessageMock).toHaveBeenCalledWith(
|
|
55
|
+
'provider-token',
|
|
56
|
+
'+15550004444',
|
|
57
|
+
'test message',
|
|
58
|
+
{
|
|
59
|
+
subject: undefined,
|
|
60
|
+
inReplyTo: undefined,
|
|
61
|
+
assistantId: 'ast-alpha',
|
|
62
|
+
},
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
@@ -68,6 +68,8 @@ function makeSessionEmittingViaClient(...messages: ServerMessage[]): Session {
|
|
|
68
68
|
persistUserMessage: () => undefined as unknown as string,
|
|
69
69
|
memoryPolicy: { scopeId: 'default', includeDefaultFallback: false, strictSideEffects: false },
|
|
70
70
|
setChannelCapabilities: () => {},
|
|
71
|
+
setAssistantId: () => {},
|
|
72
|
+
setGuardianContext: () => {},
|
|
71
73
|
updateClient: (handler: (msg: ServerMessage) => void) => {
|
|
72
74
|
clientHandler = handler;
|
|
73
75
|
},
|
|
@@ -90,6 +92,8 @@ function makeSessionEmittingViaAgentLoop(...messages: ServerMessage[]): Session
|
|
|
90
92
|
persistUserMessage: () => undefined as unknown as string,
|
|
91
93
|
memoryPolicy: { scopeId: 'default', includeDefaultFallback: false, strictSideEffects: false },
|
|
92
94
|
setChannelCapabilities: () => {},
|
|
95
|
+
setAssistantId: () => {},
|
|
96
|
+
setGuardianContext: () => {},
|
|
93
97
|
updateClient: () => {},
|
|
94
98
|
runAgentLoop: async (_content: string, _messageId: string, onEvent: (msg: ServerMessage) => void) => {
|
|
95
99
|
for (const msg of messages) {
|
|
@@ -26,6 +26,12 @@ mock.module('../util/logger.js', () => ({
|
|
|
26
26
|
}),
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
|
+
mock.module('../config/loader.js', () => ({
|
|
30
|
+
getConfig: () => ({
|
|
31
|
+
secretDetection: { enabled: false },
|
|
32
|
+
}),
|
|
33
|
+
}));
|
|
34
|
+
|
|
29
35
|
import { initializeDb, getDb, resetDb } from '../memory/db.js';
|
|
30
36
|
import { createConversation } from '../memory/conversation-store.js';
|
|
31
37
|
import { createRun, getRun, setRunConfirmation } from '../memory/runs-store.js';
|
|
@@ -43,6 +49,8 @@ function makeSessionWithConfirmation(message: ServerMessage): Session {
|
|
|
43
49
|
persistUserMessage: () => undefined as unknown as string,
|
|
44
50
|
memoryPolicy: { scopeId: 'default', includeDefaultFallback: false, strictSideEffects: false },
|
|
45
51
|
setChannelCapabilities: () => {},
|
|
52
|
+
setAssistantId: () => {},
|
|
53
|
+
setGuardianContext: () => {},
|
|
46
54
|
updateClient: (handler: (msg: ServerMessage) => void) => {
|
|
47
55
|
clientHandler = handler;
|
|
48
56
|
},
|
|
@@ -64,6 +72,8 @@ function makeSessionWithEvent(message: ServerMessage): Session {
|
|
|
64
72
|
persistUserMessage: () => undefined as unknown as string,
|
|
65
73
|
memoryPolicy: { scopeId: 'default', includeDefaultFallback: false, strictSideEffects: false },
|
|
66
74
|
setChannelCapabilities: () => {},
|
|
75
|
+
setAssistantId: () => {},
|
|
76
|
+
setGuardianContext: () => {},
|
|
67
77
|
updateClient: () => {},
|
|
68
78
|
runAgentLoop: async (_content: string, _messageId: string, onEvent: (msg: ServerMessage) => void) => {
|
|
69
79
|
onEvent(message);
|
|
@@ -228,6 +238,8 @@ describe('startRun channel capability resolution', () => {
|
|
|
228
238
|
setChannelCapabilities: (caps: ChannelCapabilities | null) => {
|
|
229
239
|
if (caps) capturedCapabilities = caps;
|
|
230
240
|
},
|
|
241
|
+
setAssistantId: () => {},
|
|
242
|
+
setGuardianContext: () => {},
|
|
231
243
|
updateClient: () => {},
|
|
232
244
|
runAgentLoop: async () => {},
|
|
233
245
|
handleConfirmationResponse: () => {},
|
|
@@ -262,6 +274,8 @@ describe('startRun channel capability resolution', () => {
|
|
|
262
274
|
setChannelCapabilities: (caps: ChannelCapabilities | null) => {
|
|
263
275
|
if (caps) capturedCapabilities = caps;
|
|
264
276
|
},
|
|
277
|
+
setAssistantId: () => {},
|
|
278
|
+
setGuardianContext: () => {},
|
|
265
279
|
updateClient: () => {},
|
|
266
280
|
runAgentLoop: async () => {},
|
|
267
281
|
handleConfirmationResponse: () => {},
|
|
@@ -292,6 +306,8 @@ describe('startRun channel capability resolution', () => {
|
|
|
292
306
|
setChannelCapabilities: (caps: ChannelCapabilities | null) => {
|
|
293
307
|
if (caps) capturedCapabilities = caps;
|
|
294
308
|
},
|
|
309
|
+
setAssistantId: () => {},
|
|
310
|
+
setGuardianContext: () => {},
|
|
295
311
|
updateClient: () => {},
|
|
296
312
|
runAgentLoop: async () => {},
|
|
297
313
|
handleConfirmationResponse: () => {},
|
|
@@ -335,6 +351,8 @@ describe('strictSideEffects re-derivation across runs', () => {
|
|
|
335
351
|
persistUserMessage: () => undefined as unknown as string,
|
|
336
352
|
memoryPolicy: { scopeId: 'default', includeDefaultFallback: false, strictSideEffects: false },
|
|
337
353
|
setChannelCapabilities: () => {},
|
|
354
|
+
setAssistantId: () => {},
|
|
355
|
+
setGuardianContext: () => {},
|
|
338
356
|
updateClient: () => {},
|
|
339
357
|
runAgentLoop: async () => {},
|
|
340
358
|
handleConfirmationResponse: () => {},
|
|
@@ -369,6 +387,8 @@ describe('strictSideEffects re-derivation across runs', () => {
|
|
|
369
387
|
persistUserMessage: () => undefined as unknown as string,
|
|
370
388
|
memoryPolicy: { scopeId: 'private-scope', includeDefaultFallback: true, strictSideEffects: true },
|
|
371
389
|
setChannelCapabilities: () => {},
|
|
390
|
+
setAssistantId: () => {},
|
|
391
|
+
setGuardianContext: () => {},
|
|
372
392
|
updateClient: () => {},
|
|
373
393
|
runAgentLoop: async () => {},
|
|
374
394
|
handleConfirmationResponse: () => {},
|
|
@@ -404,6 +424,8 @@ describe('strictSideEffects re-derivation across runs', () => {
|
|
|
404
424
|
persistUserMessage: () => undefined as unknown as string,
|
|
405
425
|
memoryPolicy: { scopeId: 'default', includeDefaultFallback: false, strictSideEffects: true },
|
|
406
426
|
setChannelCapabilities: () => {},
|
|
427
|
+
setAssistantId: () => {},
|
|
428
|
+
setGuardianContext: () => {},
|
|
407
429
|
updateClient: () => {},
|
|
408
430
|
runAgentLoop: async () => {},
|
|
409
431
|
handleConfirmationResponse: () => {},
|