@vellumai/assistant 0.3.18 → 0.3.20
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 +155 -15
- package/Dockerfile +1 -0
- package/README.md +40 -4
- package/docs/architecture/integrations.md +7 -11
- package/docs/architecture/security.md +80 -0
- package/package.json +1 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +58 -0
- package/src/__tests__/approval-primitive.test.ts +540 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +206 -0
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +198 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +272 -0
- package/src/__tests__/call-controller.test.ts +605 -104
- package/src/__tests__/channel-invite-transport.test.ts +264 -0
- package/src/__tests__/checker.test.ts +60 -0
- package/src/__tests__/cli.test.ts +42 -1
- package/src/__tests__/config-schema.test.ts +11 -127
- package/src/__tests__/config-watcher.test.ts +0 -8
- package/src/__tests__/daemon-lifecycle.test.ts +1 -0
- package/src/__tests__/daemon-server-session-init.test.ts +8 -2
- package/src/__tests__/diff.test.ts +22 -0
- package/src/__tests__/guardian-action-copy-generator.test.ts +5 -0
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +779 -0
- package/src/__tests__/guardian-action-late-reply.test.ts +546 -1
- package/src/__tests__/guardian-actions-endpoint.test.ts +774 -0
- package/src/__tests__/guardian-control-plane-policy.test.ts +36 -3
- package/src/__tests__/guardian-dispatch.test.ts +185 -1
- package/src/__tests__/guardian-grant-minting.test.ts +532 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +367 -0
- package/src/__tests__/invite-redemption-service.test.ts +306 -0
- package/src/__tests__/ipc-snapshot.test.ts +58 -0
- package/src/__tests__/notification-decision-fallback.test.ts +88 -0
- package/src/__tests__/remote-skill-policy.test.ts +215 -0
- package/src/__tests__/sandbox-diagnostics.test.ts +6 -249
- package/src/__tests__/sandbox-host-parity.test.ts +6 -13
- package/src/__tests__/scoped-approval-grants.test.ts +521 -0
- package/src/__tests__/scoped-grant-security-matrix.test.ts +444 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +1 -19
- package/src/__tests__/session-load-history-repair.test.ts +169 -2
- package/src/__tests__/session-runtime-assembly.test.ts +33 -5
- package/src/__tests__/skill-feature-flags-integration.test.ts +171 -0
- package/src/__tests__/skill-feature-flags.test.ts +188 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +141 -0
- package/src/__tests__/skill-mirror-parity.test.ts +1 -0
- package/src/__tests__/skill-projection-feature-flag.test.ts +363 -0
- package/src/__tests__/system-prompt.test.ts +1 -1
- package/src/__tests__/terminal-sandbox.test.ts +142 -9
- package/src/__tests__/terminal-tools.test.ts +2 -93
- package/src/__tests__/thread-seed-composer.test.ts +18 -0
- package/src/__tests__/tool-approval-handler.test.ts +350 -0
- package/src/__tests__/trust-store.test.ts +2 -0
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +8 -10
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +533 -0
- package/src/agent/loop.ts +36 -1
- package/src/approvals/approval-primitive.ts +381 -0
- package/src/approvals/guardian-decision-primitive.ts +191 -0
- package/src/calls/call-controller.ts +276 -212
- package/src/calls/call-domain.ts +56 -6
- package/src/calls/guardian-dispatch.ts +56 -0
- package/src/calls/relay-server.ts +13 -0
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +59 -4
- package/src/cli/core-commands.ts +0 -4
- package/src/cli.ts +76 -34
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +179 -0
- package/src/config/assistant-feature-flags.ts +162 -0
- package/src/config/bundled-skills/api-mapping/icon.svg +18 -0
- package/src/config/bundled-skills/messaging/TOOLS.json +30 -0
- package/src/config/bundled-skills/messaging/tools/slack-delete-message.ts +24 -0
- package/src/config/bundled-skills/notifications/SKILL.md +18 -0
- package/src/config/bundled-skills/reminder/SKILL.md +49 -2
- package/src/config/bundled-skills/time-based-actions/SKILL.md +49 -2
- package/src/config/bundled-skills/voice-setup/SKILL.md +122 -0
- package/src/config/core-schema.ts +1 -1
- package/src/config/env-registry.ts +10 -0
- package/src/config/feature-flag-registry.json +61 -0
- package/src/config/loader.ts +22 -1
- package/src/config/sandbox-schema.ts +0 -39
- package/src/config/schema.ts +12 -2
- package/src/config/skill-state.ts +34 -0
- package/src/config/skills-schema.ts +26 -0
- package/src/config/skills.ts +9 -0
- package/src/config/system-prompt.ts +110 -46
- package/src/config/templates/SOUL.md +1 -1
- package/src/config/types.ts +19 -1
- package/src/config/vellum-skills/catalog.json +1 -1
- package/src/config/vellum-skills/guardian-verify-setup/SKILL.md +1 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +1 -1
- package/src/config/vellum-skills/telegram-setup/SKILL.md +1 -1
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +104 -3
- package/src/config/vellum-skills/twilio-setup/SKILL.md +1 -1
- package/src/daemon/config-watcher.ts +0 -1
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/guardian-invite-intent.ts +124 -0
- package/src/daemon/handlers/avatar.ts +68 -0
- package/src/daemon/handlers/browser.ts +2 -2
- package/src/daemon/handlers/config-channels.ts +18 -0
- package/src/daemon/handlers/guardian-actions.ts +120 -0
- package/src/daemon/handlers/index.ts +4 -0
- package/src/daemon/handlers/sessions.ts +19 -0
- package/src/daemon/handlers/shared.ts +3 -1
- package/src/daemon/handlers/skills.ts +45 -2
- package/src/daemon/install-cli-launchers.ts +58 -13
- package/src/daemon/ipc-contract/guardian-actions.ts +53 -0
- package/src/daemon/ipc-contract/sessions.ts +8 -2
- package/src/daemon/ipc-contract/settings.ts +25 -2
- package/src/daemon/ipc-contract/skills.ts +1 -0
- package/src/daemon/ipc-contract-inventory.json +10 -0
- package/src/daemon/ipc-contract.ts +4 -0
- package/src/daemon/lifecycle.ts +6 -2
- package/src/daemon/main.ts +1 -0
- package/src/daemon/server.ts +1 -0
- package/src/daemon/session-lifecycle.ts +52 -7
- package/src/daemon/session-memory.ts +45 -0
- package/src/daemon/session-process.ts +260 -422
- package/src/daemon/session-runtime-assembly.ts +12 -0
- package/src/daemon/session-skill-tools.ts +14 -1
- package/src/daemon/session-tool-setup.ts +5 -0
- package/src/daemon/session.ts +11 -0
- package/src/daemon/tool-side-effects.ts +35 -9
- package/src/index.ts +0 -2
- package/src/memory/conversation-display-order-migration.ts +44 -0
- package/src/memory/conversation-queries.ts +2 -0
- package/src/memory/conversation-store.ts +91 -0
- package/src/memory/db-init.ts +13 -1
- package/src/memory/embedding-local.ts +22 -8
- package/src/memory/guardian-action-store.ts +133 -2
- package/src/memory/guardian-verification.ts +1 -1
- package/src/memory/ingress-invite-store.ts +95 -1
- package/src/memory/migrations/033-scoped-approval-grants.ts +51 -0
- package/src/memory/migrations/034-guardian-action-tool-metadata.ts +12 -0
- package/src/memory/migrations/035-guardian-action-supersession.ts +23 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/schema.ts +35 -1
- package/src/memory/scoped-approval-grants.ts +518 -0
- package/src/messaging/providers/slack/client.ts +12 -0
- package/src/messaging/providers/slack/types.ts +5 -0
- package/src/notifications/decision-engine.ts +49 -12
- package/src/notifications/emit-signal.ts +7 -0
- package/src/notifications/signal.ts +7 -0
- package/src/notifications/thread-seed-composer.ts +2 -1
- package/src/permissions/checker.ts +27 -0
- package/src/runtime/channel-approval-types.ts +16 -6
- package/src/runtime/channel-approvals.ts +19 -15
- package/src/runtime/channel-invite-transport.ts +85 -0
- package/src/runtime/channel-invite-transports/telegram.ts +105 -0
- package/src/runtime/guardian-action-grant-minter.ts +154 -0
- package/src/runtime/guardian-action-message-composer.ts +30 -0
- package/src/runtime/guardian-decision-types.ts +91 -0
- package/src/runtime/http-server.ts +23 -1
- package/src/runtime/ingress-service.ts +22 -0
- package/src/runtime/invite-redemption-service.ts +181 -0
- package/src/runtime/invite-redemption-templates.ts +39 -0
- package/src/runtime/routes/call-routes.ts +2 -1
- package/src/runtime/routes/guardian-action-routes.ts +206 -0
- package/src/runtime/routes/guardian-approval-interception.ts +66 -74
- package/src/runtime/routes/inbound-message-handler.ts +568 -409
- package/src/runtime/routes/pairing-routes.ts +4 -0
- package/src/security/encrypted-store.ts +31 -17
- package/src/security/keychain.ts +176 -2
- package/src/security/secure-keys.ts +97 -0
- package/src/security/tool-approval-digest.ts +67 -0
- package/src/skills/remote-skill-policy.ts +131 -0
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/browser-manager.ts +46 -32
- package/src/tools/browser/browser-screencast.ts +2 -2
- package/src/tools/calls/call-start.ts +1 -1
- package/src/tools/executor.ts +22 -17
- package/src/tools/network/script-proxy/session-manager.ts +1 -5
- package/src/tools/skills/load.ts +22 -8
- package/src/tools/system/avatar-generator.ts +119 -0
- package/src/tools/system/navigate-settings.ts +65 -0
- package/src/tools/system/open-system-settings.ts +75 -0
- package/src/tools/system/voice-config.ts +121 -32
- package/src/tools/terminal/backends/native.ts +40 -19
- package/src/tools/terminal/backends/types.ts +3 -3
- package/src/tools/terminal/parser.ts +1 -1
- package/src/tools/terminal/sandbox-diagnostics.ts +6 -87
- package/src/tools/terminal/sandbox.ts +1 -12
- package/src/tools/terminal/shell.ts +3 -31
- package/src/tools/tool-approval-handler.ts +141 -3
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +6 -0
- package/src/util/diff.ts +36 -13
- package/Dockerfile.sandbox +0 -5
- package/src/__tests__/doordash-client.test.ts +0 -187
- package/src/__tests__/doordash-session.test.ts +0 -154
- package/src/__tests__/signup-e2e.test.ts +0 -354
- package/src/__tests__/terminal-sandbox-docker.test.ts +0 -1065
- package/src/__tests__/terminal-sandbox.integration.test.ts +0 -180
- package/src/cli/doordash.ts +0 -1057
- package/src/config/bundled-skills/doordash/SKILL.md +0 -163
- package/src/config/templates/LOOKS.md +0 -25
- package/src/doordash/cart-queries.ts +0 -787
- package/src/doordash/client.ts +0 -1016
- package/src/doordash/order-queries.ts +0 -85
- package/src/doordash/queries.ts +0 -13
- package/src/doordash/query-extractor.ts +0 -94
- package/src/doordash/search-queries.ts +0 -203
- package/src/doordash/session.ts +0 -84
- package/src/doordash/store-queries.ts +0 -246
- package/src/doordash/types.ts +0 -367
- package/src/tools/terminal/backends/docker.ts +0 -379
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Approval interception: checks for pending approvals and handles inbound
|
|
3
3
|
* messages as decisions, reminders, or conversational follow-ups.
|
|
4
4
|
*/
|
|
5
|
+
import { applyGuardianDecision } from '../../approvals/guardian-decision-primitive.js';
|
|
5
6
|
import type { ChannelId } from '../../channels/types.js';
|
|
6
7
|
import {
|
|
7
8
|
getAllPendingApprovalsByGuardianChat,
|
|
@@ -185,13 +186,6 @@ export async function handleApprovalInterception(
|
|
|
185
186
|
}
|
|
186
187
|
|
|
187
188
|
if (callbackDecision) {
|
|
188
|
-
// approve_always is not available for guardian approvals — guardians
|
|
189
|
-
// should not be able to permanently allowlist tools on behalf of the
|
|
190
|
-
// requester. Downgrade to approve_once.
|
|
191
|
-
if (callbackDecision.action === 'approve_always') {
|
|
192
|
-
callbackDecision = { ...callbackDecision, action: 'approve_once' };
|
|
193
|
-
}
|
|
194
|
-
|
|
195
189
|
// Access request approvals don't have a pending interaction in the
|
|
196
190
|
// session tracker, so they need a separate decision path that creates
|
|
197
191
|
// a verification session instead of resuming an agent loop.
|
|
@@ -207,27 +201,22 @@ export async function handleApprovalInterception(
|
|
|
207
201
|
return accessResult;
|
|
208
202
|
}
|
|
209
203
|
|
|
210
|
-
// Apply the decision
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
204
|
+
// Apply the decision through the unified guardian decision primitive.
|
|
205
|
+
// The primitive handles approve_always downgrade, approval info capture,
|
|
206
|
+
// record update, and scoped grant minting.
|
|
207
|
+
const result = applyGuardianDecision({
|
|
208
|
+
approval: guardianApproval,
|
|
209
|
+
decision: callbackDecision,
|
|
210
|
+
actorExternalUserId: senderExternalUserId,
|
|
211
|
+
actorChannel: sourceChannel,
|
|
212
|
+
});
|
|
216
213
|
|
|
217
214
|
if (result.applied) {
|
|
218
|
-
// Update the guardian approval request record only when the decision
|
|
219
|
-
// was actually applied. If the request was already resolved (race with
|
|
220
|
-
// expiry sweep or concurrent callback), skip to avoid inconsistency.
|
|
221
|
-
const approvalStatus = callbackDecision.action === 'reject' ? 'denied' as const : 'approved' as const;
|
|
222
|
-
updateApprovalDecision(guardianApproval.id, {
|
|
223
|
-
status: approvalStatus,
|
|
224
|
-
decidedByExternalUserId: senderExternalUserId,
|
|
225
|
-
});
|
|
226
|
-
|
|
227
215
|
// Notify the requester's chat about the outcome with the tool name
|
|
216
|
+
const effectiveAction = callbackDecision.action === 'approve_always' ? 'approve_once' : callbackDecision.action;
|
|
228
217
|
const outcomeText = await composeApprovalMessageGenerative({
|
|
229
218
|
scenario: 'guardian_decision_outcome',
|
|
230
|
-
decision:
|
|
219
|
+
decision: effectiveAction === 'reject' ? 'denied' : 'approved',
|
|
231
220
|
toolName: guardianApproval.toolName,
|
|
232
221
|
channel: sourceChannel,
|
|
233
222
|
}, {}, approvalCopyGenerator);
|
|
@@ -346,21 +335,15 @@ export async function handleApprovalInterception(
|
|
|
346
335
|
...(engineResult.targetRequestId ? { requestId: engineResult.targetRequestId } : {}),
|
|
347
336
|
};
|
|
348
337
|
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
338
|
+
// Apply the decision through the unified guardian decision primitive.
|
|
339
|
+
const result = applyGuardianDecision({
|
|
340
|
+
approval: targetApproval,
|
|
341
|
+
decision: engineDecision,
|
|
342
|
+
actorExternalUserId: senderExternalUserId,
|
|
343
|
+
actorChannel: sourceChannel,
|
|
344
|
+
});
|
|
353
345
|
|
|
354
346
|
if (result.applied) {
|
|
355
|
-
// Update the guardian approval request record only when the decision
|
|
356
|
-
// was actually applied. If the request was already resolved (race with
|
|
357
|
-
// expiry sweep or concurrent callback), skip to avoid inconsistency.
|
|
358
|
-
const approvalStatus = decisionAction === 'reject' ? 'denied' as const : 'approved' as const;
|
|
359
|
-
updateApprovalDecision(targetApproval.id, {
|
|
360
|
-
status: approvalStatus,
|
|
361
|
-
decidedByExternalUserId: senderExternalUserId,
|
|
362
|
-
});
|
|
363
|
-
|
|
364
347
|
// Notify the requester's chat about the outcome
|
|
365
348
|
const outcomeText = await composeApprovalMessageGenerative({
|
|
366
349
|
scenario: 'guardian_decision_outcome',
|
|
@@ -492,18 +475,15 @@ export async function handleApprovalInterception(
|
|
|
492
475
|
return accessResult;
|
|
493
476
|
}
|
|
494
477
|
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
478
|
+
// Apply the decision through the unified guardian decision primitive.
|
|
479
|
+
const result = applyGuardianDecision({
|
|
480
|
+
approval: targetLegacyApproval,
|
|
481
|
+
decision: legacyGuardianDecision,
|
|
482
|
+
actorExternalUserId: senderExternalUserId,
|
|
483
|
+
actorChannel: sourceChannel,
|
|
484
|
+
});
|
|
499
485
|
|
|
500
486
|
if (result.applied) {
|
|
501
|
-
const approvalStatus = legacyGuardianDecision.action === 'reject' ? 'denied' as const : 'approved' as const;
|
|
502
|
-
updateApprovalDecision(targetLegacyApproval.id, {
|
|
503
|
-
status: approvalStatus,
|
|
504
|
-
decidedByExternalUserId: senderExternalUserId,
|
|
505
|
-
});
|
|
506
|
-
|
|
507
487
|
// Notify the requester's chat about the outcome
|
|
508
488
|
const outcomeText = await composeApprovalMessageGenerative({
|
|
509
489
|
scenario: 'guardian_decision_outcome',
|
|
@@ -626,13 +606,15 @@ export async function handleApprovalInterception(
|
|
|
626
606
|
action: 'reject',
|
|
627
607
|
source: 'plain_text',
|
|
628
608
|
};
|
|
629
|
-
|
|
609
|
+
// Apply the cancel decision through the unified primitive.
|
|
610
|
+
// The primitive handles record update and (no-op) grant logic.
|
|
611
|
+
const cancelApplyResult = applyGuardianDecision({
|
|
612
|
+
approval: guardianApprovalForRequest,
|
|
613
|
+
decision: rejectDecision,
|
|
614
|
+
actorExternalUserId: senderExternalUserId,
|
|
615
|
+
actorChannel: sourceChannel,
|
|
616
|
+
});
|
|
630
617
|
if (cancelApplyResult.applied) {
|
|
631
|
-
updateApprovalDecision(guardianApprovalForRequest.id, {
|
|
632
|
-
status: 'denied',
|
|
633
|
-
decidedByExternalUserId: senderExternalUserId,
|
|
634
|
-
});
|
|
635
|
-
|
|
636
618
|
// Notify requester
|
|
637
619
|
const replyText = cancelReplyText ?? await composeApprovalMessageGenerative({
|
|
638
620
|
scenario: 'requester_cancel',
|
|
@@ -1036,29 +1018,39 @@ async function handleAccessRequestApproval(
|
|
|
1036
1018
|
});
|
|
1037
1019
|
}
|
|
1038
1020
|
|
|
1039
|
-
//
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
isAsyncBackground: false,
|
|
1049
|
-
visibleInSourceNow: false,
|
|
1050
|
-
},
|
|
1051
|
-
contextPayload: {
|
|
1021
|
+
// Don't emit guardian_decision for approvals that still require code
|
|
1022
|
+
// verification — the guardian already received the code, and emitting
|
|
1023
|
+
// this signal prematurely causes the notification pipeline to deliver
|
|
1024
|
+
// a confusing "approved" message before the requester has verified.
|
|
1025
|
+
// The guardian_decision signal should only fire once access is fully granted
|
|
1026
|
+
// (i.e. after code consumption), which is handled in the verification path.
|
|
1027
|
+
if (!decisionResult.verificationSessionId) {
|
|
1028
|
+
void emitNotificationSignal({
|
|
1029
|
+
sourceEventName: 'ingress.trusted_contact.guardian_decision',
|
|
1052
1030
|
sourceChannel: approval.channel,
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1031
|
+
sourceSessionId: approval.conversationId,
|
|
1032
|
+
assistantId,
|
|
1033
|
+
attentionHints: {
|
|
1034
|
+
requiresAction: false,
|
|
1035
|
+
urgency: 'medium',
|
|
1036
|
+
isAsyncBackground: false,
|
|
1037
|
+
visibleInSourceNow: false,
|
|
1038
|
+
},
|
|
1039
|
+
contextPayload: {
|
|
1040
|
+
sourceChannel: approval.channel,
|
|
1041
|
+
requesterExternalUserId: approval.requesterExternalUserId,
|
|
1042
|
+
requesterChatId: approval.requesterChatId,
|
|
1043
|
+
decidedByExternalUserId,
|
|
1044
|
+
decision: 'approved',
|
|
1045
|
+
},
|
|
1046
|
+
dedupeKey: `trusted-contact:guardian-decision:${approval.id}`,
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1060
1049
|
|
|
1061
|
-
//
|
|
1050
|
+
// Emit verification_sent with visibleInSourceNow=true so the notification
|
|
1051
|
+
// pipeline suppresses delivery — the guardian already received the
|
|
1052
|
+
// verification code directly. Without this flag, the pipeline generates
|
|
1053
|
+
// a redundant LLM message like "Good news! Your request has been approved."
|
|
1062
1054
|
if (decisionResult.verificationSessionId && codeDelivered) {
|
|
1063
1055
|
void emitNotificationSignal({
|
|
1064
1056
|
sourceEventName: 'ingress.trusted_contact.verification_sent',
|
|
@@ -1069,7 +1061,7 @@ async function handleAccessRequestApproval(
|
|
|
1069
1061
|
requiresAction: false,
|
|
1070
1062
|
urgency: 'low',
|
|
1071
1063
|
isAsyncBackground: true,
|
|
1072
|
-
visibleInSourceNow:
|
|
1064
|
+
visibleInSourceNow: true,
|
|
1073
1065
|
},
|
|
1074
1066
|
contextPayload: {
|
|
1075
1067
|
sourceChannel: approval.channel,
|