@vellumai/assistant 0.4.3 → 0.4.4
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/.env.example +3 -0
- package/ARCHITECTURE.md +40 -3
- package/README.md +43 -35
- package/package.json +1 -1
- package/scripts/ipc/generate-swift.ts +1 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +58 -120
- package/src/__tests__/actor-token-service.test.ts +1099 -0
- package/src/__tests__/agent-loop.test.ts +51 -0
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -5
- package/src/__tests__/assistant-id-boundary-guard.test.ts +125 -0
- package/src/__tests__/call-controller.test.ts +49 -0
- package/src/__tests__/call-pointer-message-composer.test.ts +171 -0
- package/src/__tests__/call-pointer-messages.test.ts +93 -3
- package/src/__tests__/call-pointer-no-hardcoded-copy.guard.test.ts +42 -0
- package/src/__tests__/callback-handoff-copy.test.ts +186 -0
- package/src/__tests__/channel-approval-routes.test.ts +133 -12
- package/src/__tests__/channel-guardian.test.ts +0 -87
- package/src/__tests__/channel-readiness-service.test.ts +10 -16
- package/src/__tests__/checker.test.ts +33 -12
- package/src/__tests__/config-schema.test.ts +4 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +410 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +256 -0
- package/src/__tests__/conversation-routes.test.ts +12 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/daemon-server-session-init.test.ts +4 -0
- package/src/__tests__/guardian-actions-endpoint.test.ts +19 -14
- package/src/__tests__/guardian-dispatch.test.ts +8 -0
- package/src/__tests__/guardian-outbound-http.test.ts +4 -4
- package/src/__tests__/guardian-question-mode.test.ts +200 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +178 -0
- package/src/__tests__/guardian-routing-state.test.ts +525 -0
- package/src/__tests__/handle-user-message-secret-resume.test.ts +2 -0
- package/src/__tests__/handlers-telegram-config.test.ts +0 -83
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +55 -0
- package/src/__tests__/headless-browser-navigate.test.ts +2 -0
- package/src/__tests__/ipc-snapshot.test.ts +18 -51
- package/src/__tests__/non-member-access-request.test.ts +131 -8
- package/src/__tests__/notification-decision-fallback.test.ts +129 -4
- package/src/__tests__/notification-decision-strategy.test.ts +62 -2
- package/src/__tests__/notification-guardian-path.test.ts +3 -0
- package/src/__tests__/recording-intent-handler.test.ts +1 -0
- package/src/__tests__/relay-server.test.ts +841 -39
- package/src/__tests__/send-endpoint-busy.test.ts +5 -0
- package/src/__tests__/session-agent-loop.test.ts +1 -0
- package/src/__tests__/session-confirmation-signals.test.ts +523 -0
- package/src/__tests__/session-init.benchmark.test.ts +0 -1
- package/src/__tests__/session-surfaces-task-progress.test.ts +1 -1
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +81 -2
- package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -1
- package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +21 -2
- package/src/__tests__/tool-grant-request-escalation.test.ts +333 -27
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +678 -0
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1064 -0
- package/src/__tests__/twilio-config.test.ts +2 -13
- package/src/agent/loop.ts +1 -1
- package/src/approvals/guardian-decision-primitive.ts +10 -2
- package/src/approvals/guardian-request-resolvers.ts +128 -9
- package/src/calls/call-constants.ts +21 -0
- package/src/calls/call-controller.ts +9 -2
- package/src/calls/call-domain.ts +28 -7
- package/src/calls/call-pointer-message-composer.ts +154 -0
- package/src/calls/call-pointer-messages.ts +106 -27
- package/src/calls/guardian-dispatch.ts +4 -2
- package/src/calls/relay-server.ts +424 -12
- package/src/calls/twilio-config.ts +4 -11
- package/src/calls/twilio-routes.ts +1 -1
- package/src/calls/types.ts +3 -1
- package/src/cli.ts +5 -4
- package/src/config/bundled-skills/agentmail/SKILL.md +4 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +146 -10
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -1
- package/src/config/bundled-skills/email-setup/SKILL.md +1 -1
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +105 -81
- package/src/config/bundled-skills/messaging/SKILL.md +61 -12
- package/src/config/bundled-skills/messaging/TOOLS.json +58 -0
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +6 -1
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +35 -0
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +52 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +30 -39
- package/src/config/bundled-skills/twitter/SKILL.md +3 -3
- package/src/config/bundled-skills/vercel-token-setup/SKILL.md +1 -0
- package/src/config/calls-schema.ts +24 -0
- package/src/config/env.ts +22 -0
- package/src/config/feature-flag-registry.json +8 -0
- package/src/config/schema.ts +2 -2
- package/src/config/skills.ts +11 -0
- package/src/config/system-prompt.ts +11 -1
- package/src/config/templates/SOUL.md +2 -0
- package/src/config/vellum-skills/sms-setup/SKILL.md +71 -82
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +10 -9
- package/src/config/vellum-skills/twilio-setup/SKILL.md +88 -73
- package/src/daemon/call-pointer-generators.ts +59 -0
- package/src/daemon/computer-use-session.ts +2 -5
- package/src/daemon/handlers/apps.ts +76 -20
- package/src/daemon/handlers/config-channels.ts +5 -55
- package/src/daemon/handlers/config-inbox.ts +9 -3
- package/src/daemon/handlers/config-ingress.ts +28 -3
- package/src/daemon/handlers/config-telegram.ts +12 -0
- package/src/daemon/handlers/config.ts +2 -6
- package/src/daemon/handlers/pairing.ts +2 -0
- package/src/daemon/handlers/sessions.ts +48 -3
- package/src/daemon/handlers/shared.ts +17 -2
- package/src/daemon/ipc-contract/integrations.ts +1 -99
- package/src/daemon/ipc-contract/messages.ts +47 -1
- package/src/daemon/ipc-contract/notifications.ts +11 -0
- package/src/daemon/ipc-contract-inventory.json +2 -4
- package/src/daemon/lifecycle.ts +17 -0
- package/src/daemon/server.ts +14 -1
- package/src/daemon/session-agent-loop-handlers.ts +20 -0
- package/src/daemon/session-agent-loop.ts +22 -11
- package/src/daemon/session-lifecycle.ts +1 -1
- package/src/daemon/session-process.ts +11 -1
- package/src/daemon/session-runtime-assembly.ts +3 -0
- package/src/daemon/session-surfaces.ts +3 -2
- package/src/daemon/session.ts +88 -1
- package/src/daemon/tool-side-effects.ts +22 -0
- package/src/home-base/prebuilt/brain-graph.html +1483 -0
- package/src/home-base/prebuilt/index.html +40 -0
- package/src/inbound/platform-callback-registration.ts +157 -0
- package/src/memory/canonical-guardian-store.ts +1 -1
- package/src/memory/db-init.ts +4 -0
- package/src/memory/migrations/038-actor-token-records.ts +39 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/schema.ts +16 -0
- package/src/messaging/provider-types.ts +24 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/adapter.ts +127 -0
- package/src/messaging/providers/sms/adapter.ts +40 -37
- package/src/notifications/adapters/macos.ts +45 -2
- package/src/notifications/broadcaster.ts +16 -0
- package/src/notifications/copy-composer.ts +39 -1
- package/src/notifications/decision-engine.ts +22 -9
- package/src/notifications/destination-resolver.ts +16 -2
- package/src/notifications/emit-signal.ts +16 -8
- package/src/notifications/guardian-question-mode.ts +419 -0
- package/src/notifications/signal.ts +14 -3
- package/src/permissions/checker.ts +13 -1
- package/src/permissions/prompter.ts +14 -0
- package/src/providers/anthropic/client.ts +20 -0
- package/src/providers/provider-send-message.ts +15 -3
- package/src/runtime/access-request-helper.ts +71 -1
- package/src/runtime/actor-token-service.ts +234 -0
- package/src/runtime/actor-token-store.ts +236 -0
- package/src/runtime/channel-approvals.ts +5 -3
- package/src/runtime/channel-readiness-service.ts +23 -64
- package/src/runtime/channel-readiness-types.ts +3 -4
- package/src/runtime/channel-retry-sweep.ts +4 -1
- package/src/runtime/confirmation-request-guardian-bridge.ts +197 -0
- package/src/runtime/guardian-action-followup-executor.ts +1 -1
- package/src/runtime/guardian-context-resolver.ts +82 -0
- package/src/runtime/guardian-outbound-actions.ts +0 -3
- package/src/runtime/guardian-reply-router.ts +67 -30
- package/src/runtime/guardian-vellum-migration.ts +57 -0
- package/src/runtime/http-server.ts +65 -12
- package/src/runtime/http-types.ts +13 -0
- package/src/runtime/invite-redemption-service.ts +8 -0
- package/src/runtime/local-actor-identity.ts +76 -0
- package/src/runtime/middleware/actor-token.ts +271 -0
- package/src/runtime/routes/approval-routes.ts +82 -7
- package/src/runtime/routes/brain-graph-routes.ts +222 -0
- package/src/runtime/routes/channel-readiness-routes.ts +71 -0
- package/src/runtime/routes/conversation-routes.ts +140 -52
- package/src/runtime/routes/events-routes.ts +20 -5
- package/src/runtime/routes/guardian-action-routes.ts +45 -3
- package/src/runtime/routes/guardian-approval-interception.ts +29 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +145 -0
- package/src/runtime/routes/inbound-message-handler.ts +143 -2
- package/src/runtime/routes/integration-routes.ts +7 -15
- package/src/runtime/routes/pairing-routes.ts +163 -0
- package/src/runtime/routes/twilio-routes.ts +934 -0
- package/src/runtime/tool-grant-request-helper.ts +3 -1
- package/src/security/oauth2.ts +27 -2
- package/src/security/token-manager.ts +46 -10
- package/src/tools/browser/browser-execution.ts +4 -3
- package/src/tools/browser/browser-handoff.ts +10 -18
- package/src/tools/browser/browser-manager.ts +80 -25
- package/src/tools/browser/browser-screencast.ts +35 -119
- package/src/tools/permission-checker.ts +15 -4
- package/src/tools/tool-approval-handler.ts +242 -18
- package/src/__tests__/handlers-twilio-config.test.ts +0 -1928
- package/src/daemon/handlers/config-twilio.ts +0 -1082
package/src/daemon/session.ts
CHANGED
|
@@ -36,6 +36,7 @@ import type { Message } from '../providers/types.js';
|
|
|
36
36
|
import type { Provider } from '../providers/types.js';
|
|
37
37
|
import { ToolExecutor } from '../tools/executor.js';
|
|
38
38
|
import type { AssistantAttachmentDraft } from './assistant-attachments.js';
|
|
39
|
+
import type { AssistantActivityState, ConfirmationStateChanged } from './ipc-contract/messages.js';
|
|
39
40
|
import type { ServerMessage, SurfaceData,SurfaceType, UsageStats, UserMessageAttachment } from './ipc-protocol.js';
|
|
40
41
|
import {
|
|
41
42
|
classifyResponseTierAsync,
|
|
@@ -146,7 +147,7 @@ export class Session {
|
|
|
146
147
|
/** @internal */ commandIntent?: { type: string; payload?: string; languageCode?: string };
|
|
147
148
|
/** @internal */ pendingSurfaceActions = new Map<string, { surfaceType: SurfaceType }>();
|
|
148
149
|
/** @internal */ lastSurfaceAction = new Map<string, { actionId: string; data?: Record<string, unknown> }>();
|
|
149
|
-
/** @internal */ surfaceState = new Map<string, { surfaceType: SurfaceType; data: SurfaceData }>();
|
|
150
|
+
/** @internal */ surfaceState = new Map<string, { surfaceType: SurfaceType; data: SurfaceData; title?: string }>();
|
|
150
151
|
/** @internal */ surfaceUndoStacks = new Map<string, string[]>();
|
|
151
152
|
/** @internal */ withSurface = createSurfaceMutex();
|
|
152
153
|
/** @internal */ currentTurnSurfaces: Array<{ surfaceId: string; surfaceType: SurfaceType; title?: string; data: SurfaceData; actions?: Array<{ id: string; label: string; style?: string }>; display?: string }> = [];
|
|
@@ -161,6 +162,16 @@ export class Session {
|
|
|
161
162
|
public lastAttachmentWarnings: string[] = [];
|
|
162
163
|
/** @internal */ currentTurnChannelContext: TurnChannelContext | null = null;
|
|
163
164
|
/** @internal */ currentTurnInterfaceContext: TurnInterfaceContext | null = null;
|
|
165
|
+
/** @internal */ activityVersion = 0;
|
|
166
|
+
/**
|
|
167
|
+
* Optional callback invoked whenever a server-authoritative state signal
|
|
168
|
+
* (confirmation_state_changed or assistant_activity_state) is emitted.
|
|
169
|
+
*
|
|
170
|
+
* HTTP/SSE sessions set this so the hub publisher receives these events —
|
|
171
|
+
* without it, the signals only travel through `sendToClient`, which is a
|
|
172
|
+
* no-op for socketless sessions.
|
|
173
|
+
*/
|
|
174
|
+
private onStateSignal?: (msg: ServerMessage) => void;
|
|
164
175
|
|
|
165
176
|
constructor(
|
|
166
177
|
conversationId: string,
|
|
@@ -180,6 +191,22 @@ export class Session {
|
|
|
180
191
|
this.memoryPolicy = memoryPolicy ? { ...memoryPolicy } : { ...DEFAULT_MEMORY_POLICY };
|
|
181
192
|
this.traceEmitter = new TraceEmitter(conversationId, sendToClient);
|
|
182
193
|
this.prompter = new PermissionPrompter(sendToClient);
|
|
194
|
+
this.prompter.setOnStateChanged((requestId, state, source) => {
|
|
195
|
+
// Route through emitConfirmationStateChanged so the onStateSignal
|
|
196
|
+
// listener publishes to the SSE hub for HTTP/SSE consumers.
|
|
197
|
+
this.emitConfirmationStateChanged({
|
|
198
|
+
sessionId: this.conversationId,
|
|
199
|
+
requestId,
|
|
200
|
+
state,
|
|
201
|
+
source,
|
|
202
|
+
});
|
|
203
|
+
// Emit activity state transitions for confirmation lifecycle
|
|
204
|
+
if (state === 'pending') {
|
|
205
|
+
this.emitActivityState('awaiting_confirmation', 'confirmation_requested', 'assistant_turn');
|
|
206
|
+
} else if (state === 'timed_out') {
|
|
207
|
+
this.emitActivityState('thinking', 'confirmation_resolved', 'assistant_turn');
|
|
208
|
+
}
|
|
209
|
+
});
|
|
183
210
|
this.secretPrompter = new SecretPrompter(sendToClient);
|
|
184
211
|
|
|
185
212
|
// Register watch/call notifiers (reads ctx properties lazily)
|
|
@@ -356,6 +383,17 @@ export class Session {
|
|
|
356
383
|
return this.sendToClient;
|
|
357
384
|
}
|
|
358
385
|
|
|
386
|
+
/**
|
|
387
|
+
* Register a callback for server-authoritative state signals
|
|
388
|
+
* (confirmation_state_changed, assistant_activity_state).
|
|
389
|
+
*
|
|
390
|
+
* This enables HTTP/SSE sessions to receive these events through the
|
|
391
|
+
* hub publisher, since `sendToClient` is a no-op for socketless sessions.
|
|
392
|
+
*/
|
|
393
|
+
setStateSignalListener(listener: (msg: ServerMessage) => void): void {
|
|
394
|
+
this.onStateSignal = listener;
|
|
395
|
+
}
|
|
396
|
+
|
|
359
397
|
setSandboxOverride(enabled: boolean | undefined): void {
|
|
360
398
|
this.sandboxOverride = enabled;
|
|
361
399
|
}
|
|
@@ -453,6 +491,11 @@ export class Session {
|
|
|
453
491
|
selectedPattern?: string,
|
|
454
492
|
selectedScope?: string,
|
|
455
493
|
decisionContext?: string,
|
|
494
|
+
emissionContext?: {
|
|
495
|
+
source?: ConfirmationStateChanged['source'];
|
|
496
|
+
causedByRequestId?: string;
|
|
497
|
+
decisionText?: string;
|
|
498
|
+
},
|
|
456
499
|
): void {
|
|
457
500
|
this.prompter.resolveConfirmation(
|
|
458
501
|
requestId,
|
|
@@ -461,12 +504,56 @@ export class Session {
|
|
|
461
504
|
selectedScope,
|
|
462
505
|
decisionContext,
|
|
463
506
|
);
|
|
507
|
+
|
|
508
|
+
// Emit authoritative confirmation state and activity transition centrally
|
|
509
|
+
// so ALL callers (IPC handlers, /v1/confirm, channel bridges) get
|
|
510
|
+
// consistent events without duplicating emission logic.
|
|
511
|
+
const resolvedState = (decision === 'deny' || decision === 'always_deny')
|
|
512
|
+
? 'denied' as const
|
|
513
|
+
: 'approved' as const;
|
|
514
|
+
this.emitConfirmationStateChanged({
|
|
515
|
+
sessionId: this.conversationId,
|
|
516
|
+
requestId,
|
|
517
|
+
state: resolvedState,
|
|
518
|
+
source: emissionContext?.source ?? 'button',
|
|
519
|
+
...(emissionContext?.causedByRequestId ? { causedByRequestId: emissionContext.causedByRequestId } : {}),
|
|
520
|
+
...(emissionContext?.decisionText ? { decisionText: emissionContext.decisionText } : {}),
|
|
521
|
+
});
|
|
522
|
+
this.emitActivityState('thinking', 'confirmation_resolved', 'assistant_turn');
|
|
464
523
|
}
|
|
465
524
|
|
|
466
525
|
handleSecretResponse(requestId: string, value?: string, delivery?: 'store' | 'transient_send'): void {
|
|
467
526
|
this.secretPrompter.resolveSecret(requestId, value, delivery);
|
|
468
527
|
}
|
|
469
528
|
|
|
529
|
+
// ── Server-authoritative state signals ─────────────────────────────
|
|
530
|
+
|
|
531
|
+
emitConfirmationStateChanged(params: Omit<ConfirmationStateChanged, 'type'>): void {
|
|
532
|
+
const msg: ServerMessage = { type: 'confirmation_state_changed', ...params } as ServerMessage;
|
|
533
|
+
this.sendToClient(msg);
|
|
534
|
+
this.onStateSignal?.(msg);
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
emitActivityState(
|
|
538
|
+
phase: AssistantActivityState['phase'],
|
|
539
|
+
reason: AssistantActivityState['reason'],
|
|
540
|
+
anchor: AssistantActivityState['anchor'] = 'assistant_turn',
|
|
541
|
+
requestId?: string,
|
|
542
|
+
): void {
|
|
543
|
+
this.activityVersion++;
|
|
544
|
+
const msg: ServerMessage = {
|
|
545
|
+
type: 'assistant_activity_state',
|
|
546
|
+
sessionId: this.conversationId,
|
|
547
|
+
activityVersion: this.activityVersion,
|
|
548
|
+
phase,
|
|
549
|
+
anchor,
|
|
550
|
+
requestId,
|
|
551
|
+
reason,
|
|
552
|
+
} as ServerMessage;
|
|
553
|
+
this.sendToClient(msg);
|
|
554
|
+
this.onStateSignal?.(msg);
|
|
555
|
+
}
|
|
556
|
+
|
|
470
557
|
setChannelCapabilities(caps: ChannelCapabilities | null): void {
|
|
471
558
|
this.channelCapabilities = caps ?? undefined;
|
|
472
559
|
}
|
|
@@ -68,6 +68,19 @@ function registerHook(toolNames: string | string[], hook: PostExecutionHook): vo
|
|
|
68
68
|
}
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// Broadcast app_files_changed when a new app is created so clients
|
|
72
|
+
// (e.g. macOS "Things" sidebar) refresh their app list immediately.
|
|
73
|
+
registerHook('app_create', (_name, _input, result, { ctx, broadcastToAllClients }) => {
|
|
74
|
+
try {
|
|
75
|
+
const parsed = JSON.parse(result.content) as { id?: string };
|
|
76
|
+
if (parsed.id) {
|
|
77
|
+
handleAppChange(ctx, parsed.id, broadcastToAllClients);
|
|
78
|
+
}
|
|
79
|
+
} catch {
|
|
80
|
+
// Result wasn't valid JSON — skip the broadcast.
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
71
84
|
// Auto-refresh workspace surfaces when a persisted app is updated.
|
|
72
85
|
// If no surface is currently showing the app, auto-open it.
|
|
73
86
|
registerHook('app_update', (_name, input, _result, { ctx, broadcastToAllClients }) => {
|
|
@@ -77,6 +90,15 @@ registerHook('app_update', (_name, input, _result, { ctx, broadcastToAllClients
|
|
|
77
90
|
}
|
|
78
91
|
});
|
|
79
92
|
|
|
93
|
+
// Broadcast app_files_changed when an app is deleted so clients remove it
|
|
94
|
+
// from their cached app lists.
|
|
95
|
+
registerHook('app_delete', (_name, input, _result, { broadcastToAllClients }) => {
|
|
96
|
+
const appId = input.app_id as string | undefined;
|
|
97
|
+
if (appId) {
|
|
98
|
+
broadcastToAllClients?.({ type: 'app_files_changed', appId });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
80
102
|
// Broadcast tasks_changed so connected clients (e.g. macOS Tasks window)
|
|
81
103
|
// auto-refresh when the LLM mutates the task queue via tools
|
|
82
104
|
registerHook(
|