@vellumai/assistant 0.3.19 → 0.3.21
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 +151 -15
- package/Dockerfile +1 -0
- package/README.md +40 -4
- package/bun.lock +139 -2
- package/docs/architecture/integrations.md +7 -11
- package/package.json +2 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +54 -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 +439 -108
- package/src/__tests__/channel-invite-transport.test.ts +264 -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 +300 -32
- 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 +124 -0
- package/src/__tests__/guardian-grant-minting.test.ts +6 -17
- 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 +57 -0
- package/src/__tests__/notification-decision-fallback.test.ts +88 -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 +6 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +5 -4
- 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__/trusted-contact-lifecycle-notifications.test.ts +8 -10
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +46 -84
- 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 +252 -209
- package/src/calls/call-domain.ts +44 -6
- package/src/calls/guardian-dispatch.ts +48 -0
- package/src/calls/types.ts +1 -1
- package/src/calls/voice-session-bridge.ts +46 -30
- package/src/cli/core-commands.ts +0 -4
- package/src/cli/mcp.ts +58 -0
- 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 +1 -1
- 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/mcp-schema.ts +46 -0
- package/src/config/sandbox-schema.ts +0 -39
- package/src/config/schema.ts +18 -2
- package/src/config/skill-state.ts +34 -0
- package/src/config/skills-schema.ts +0 -1
- 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 +6 -5
- package/src/config/vellum-skills/trusted-contacts/SKILL.md +105 -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/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/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-inventory.json +10 -0
- package/src/daemon/ipc-contract.ts +4 -0
- package/src/daemon/lifecycle.ts +14 -2
- package/src/daemon/main.ts +1 -0
- package/src/daemon/providers-setup.ts +26 -1
- 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 +258 -432
- 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/shutdown-handlers.ts +11 -0
- package/src/daemon/tool-side-effects.ts +35 -9
- package/src/index.ts +2 -2
- package/src/mcp/client.ts +152 -0
- package/src/mcp/manager.ts +139 -0
- 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 +5 -1
- package/src/memory/embedding-local.ts +13 -8
- package/src/memory/guardian-action-store.ts +125 -2
- package/src/memory/ingress-invite-store.ts +95 -1
- package/src/memory/migrations/035-guardian-action-supersession.ts +23 -0
- package/src/memory/migrations/index.ts +2 -1
- package/src/memory/schema.ts +5 -1
- package/src/memory/scoped-approval-grants.ts +14 -5
- 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/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 +92 -35
- 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 -190
- package/src/runtime/routes/identity-routes.ts +73 -0
- package/src/runtime/routes/inbound-message-handler.ts +486 -394
- 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 +1 -1
- 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/mcp/mcp-tool-factory.ts +100 -0
- package/src/tools/network/script-proxy/session-manager.ts +1 -5
- package/src/tools/registry.ts +64 -1
- 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 +10 -2
- 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
|
@@ -6,13 +6,16 @@ import { getParentalControlSettings } from '../security/parental-control-store.j
|
|
|
6
6
|
import { listCredentialMetadata } from '../tools/credentials/metadata-store.js';
|
|
7
7
|
import { getLogger } from '../util/logger.js';
|
|
8
8
|
import { getWorkspaceDir, getWorkspacePromptPath, isMacOS } from '../util/platform.js';
|
|
9
|
+
import { isAssistantFeatureFlagEnabled } from './assistant-feature-flags.js';
|
|
10
|
+
import { getBaseDataDir, getIsContainerized } from './env-registry.js';
|
|
9
11
|
import { getConfig } from './loader.js';
|
|
12
|
+
import { skillFlagKey } from './skill-state.js';
|
|
10
13
|
import { loadSkillCatalog, type SkillSummary } from './skills.js';
|
|
11
14
|
import { resolveUserReference } from './user-reference.js';
|
|
12
15
|
|
|
13
16
|
const log = getLogger('system-prompt');
|
|
14
17
|
|
|
15
|
-
const PROMPT_FILES = ['SOUL.md', 'IDENTITY.md', 'USER.md'
|
|
18
|
+
const PROMPT_FILES = ['SOUL.md', 'IDENTITY.md', 'USER.md'] as const;
|
|
16
19
|
|
|
17
20
|
/**
|
|
18
21
|
* Copy template prompt files into the data directory if they don't already exist.
|
|
@@ -91,14 +94,11 @@ export function buildSystemPrompt(tier: ResponseTier = 'high'): string {
|
|
|
91
94
|
const userPath = getWorkspacePromptPath('USER.md');
|
|
92
95
|
const bootstrapPath = getWorkspacePromptPath('BOOTSTRAP.md');
|
|
93
96
|
|
|
94
|
-
const looksPath = getWorkspacePromptPath('LOOKS.md');
|
|
95
|
-
|
|
96
97
|
const updatesPath = getWorkspacePromptPath('UPDATES.md');
|
|
97
98
|
|
|
98
99
|
const soul = readPromptFile(soulPath);
|
|
99
100
|
const identity = readPromptFile(identityPath);
|
|
100
101
|
const user = readPromptFile(userPath);
|
|
101
|
-
const looks = readPromptFile(looksPath);
|
|
102
102
|
const bootstrap = readPromptFile(bootstrapPath);
|
|
103
103
|
const updates = readPromptFile(updatesPath);
|
|
104
104
|
|
|
@@ -107,7 +107,6 @@ export function buildSystemPrompt(tier: ResponseTier = 'high'): string {
|
|
|
107
107
|
if (identity) parts.push(identity);
|
|
108
108
|
if (soul) parts.push(soul);
|
|
109
109
|
if (user) parts.push(user);
|
|
110
|
-
if (looks) parts.push(looks);
|
|
111
110
|
if (bootstrap) {
|
|
112
111
|
parts.push(
|
|
113
112
|
'# First-Run Ritual\n\n'
|
|
@@ -130,6 +129,7 @@ export function buildSystemPrompt(tier: ResponseTier = 'high'): string {
|
|
|
130
129
|
'- When you are satisfied all updates have been actioned or communicated, delete `UPDATES.md` to signal completion.',
|
|
131
130
|
].join('\n'));
|
|
132
131
|
}
|
|
132
|
+
if (getIsContainerized()) parts.push(buildContainerizedSection());
|
|
133
133
|
parts.push(buildConfigSection());
|
|
134
134
|
parts.push(buildPostToolResponseSection());
|
|
135
135
|
parts.push(buildExternalCommsIdentitySection());
|
|
@@ -140,11 +140,15 @@ export function buildSystemPrompt(tier: ResponseTier = 'high'): string {
|
|
|
140
140
|
|
|
141
141
|
// ── Extended sections (medium + high) ──
|
|
142
142
|
if (tier !== 'low') {
|
|
143
|
+
const config = getConfig();
|
|
143
144
|
parts.push(buildToolPermissionSection());
|
|
144
145
|
parts.push(buildTaskScheduleReminderRoutingSection());
|
|
145
|
-
|
|
146
|
+
if (isAssistantFeatureFlagEnabled('feature_flags.guardian-verify-setup.enabled', config)) {
|
|
147
|
+
parts.push(buildGuardianVerificationRoutingSection());
|
|
148
|
+
}
|
|
146
149
|
parts.push(buildAttachmentSection());
|
|
147
150
|
parts.push(buildInChatConfigurationSection());
|
|
151
|
+
parts.push(buildVoiceSetupRoutingSection());
|
|
148
152
|
parts.push(buildChannelCommandIntentSection());
|
|
149
153
|
}
|
|
150
154
|
|
|
@@ -326,6 +330,50 @@ function buildInChatConfigurationSection(): string {
|
|
|
326
330
|
'**After saving a value**, confirm success with a message like: "Great, saved! You can always update this from the Settings page."',
|
|
327
331
|
'',
|
|
328
332
|
'**Never tell the user to go to Settings to enter a value.** The Settings page is for reviewing and updating existing configuration, not for initial setup. Always prefer the in-chat flow for first-time configuration.',
|
|
333
|
+
'',
|
|
334
|
+
'### Avatar Customisation',
|
|
335
|
+
'',
|
|
336
|
+
'You can change your avatar appearance using the `set_avatar` tool. When the user asks to change, update, or customise your avatar, use `set_avatar` with a `description` parameter describing the desired appearance (e.g. "a friendly purple cat with green eyes wearing a tiny hat"). The tool generates an avatar image via Gemini and updates all connected clients automatically. Requires a Gemini API key (the same one used for image generation).',
|
|
337
|
+
'',
|
|
338
|
+
'**After generating a new avatar**, always update the `## Avatar` section in `IDENTITY.md` with a brief description of the current avatar appearance. This ensures you remember what you look like across sessions. Example:',
|
|
339
|
+
'```',
|
|
340
|
+
'## Avatar',
|
|
341
|
+
'A friendly purple cat with green eyes wearing a tiny hat',
|
|
342
|
+
'```',
|
|
343
|
+
].join('\n');
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export function buildVoiceSetupRoutingSection(): string {
|
|
347
|
+
return [
|
|
348
|
+
'## Routing: Voice Setup & Troubleshooting',
|
|
349
|
+
'',
|
|
350
|
+
'Voice features include push-to-talk (PTT), wake word detection, and text-to-speech.',
|
|
351
|
+
'',
|
|
352
|
+
'### Quick changes — use `voice_config_update` directly',
|
|
353
|
+
'- "Change my PTT key to ctrl" — call `voice_config_update` with `setting: "activation_key"`',
|
|
354
|
+
'- "Enable wake word" — call `voice_config_update` with `setting: "wake_word_enabled"`, `value: true`',
|
|
355
|
+
'- "Set my wake word to jarvis" — call `voice_config_update` with `setting: "wake_word_keyword"`',
|
|
356
|
+
'- "Set wake word timeout to 30 seconds" — call `voice_config_update` with `setting: "wake_word_timeout"`',
|
|
357
|
+
'',
|
|
358
|
+
'For simple setting changes, use the tool directly without loading the voice-setup skill.',
|
|
359
|
+
'',
|
|
360
|
+
'### Guided setup or troubleshooting — load the voice-setup skill',
|
|
361
|
+
'Load with: `skill_load` using `skill: "voice-setup"`',
|
|
362
|
+
'',
|
|
363
|
+
'**Trigger phrases:**',
|
|
364
|
+
'- "Help me set up voice"',
|
|
365
|
+
'- "Set up push-to-talk"',
|
|
366
|
+
'- "Configure voice / PTT / wake word"',
|
|
367
|
+
'- "PTT isn\'t working" / "push-to-talk not working"',
|
|
368
|
+
'- "Recording but no text"',
|
|
369
|
+
'- "Wake word not detecting"',
|
|
370
|
+
'- "Microphone not working"',
|
|
371
|
+
'- "Set up ElevenLabs" / "configure TTS"',
|
|
372
|
+
'',
|
|
373
|
+
'### Disambiguation',
|
|
374
|
+
'- Voice setup (this skill) = **local PTT, wake word, microphone permissions** on the Mac desktop app.',
|
|
375
|
+
'- Phone calls skill = **Twilio-powered voice calls** over the phone network. Completely separate.',
|
|
376
|
+
'- If the user says "voice" in the context of phone calls or Twilio, load `phone-calls` instead.',
|
|
329
377
|
].join('\n');
|
|
330
378
|
}
|
|
331
379
|
|
|
@@ -411,12 +459,6 @@ export function buildChannelAwarenessSection(): string {
|
|
|
411
459
|
'- When the user asks about voice input or push-to-talk settings, use the tool to apply changes directly rather than directing them to settings.',
|
|
412
460
|
'- When `microphone_permission_granted` is `false`, guide the user to grant microphone access in System Settings before using voice features.',
|
|
413
461
|
'',
|
|
414
|
-
'### Guardian actor context',
|
|
415
|
-
'- Some channel turns include a `<guardian_context>` block with authoritative actor-role facts (guardian, non-guardian, or unverified_channel).',
|
|
416
|
-
'- Never infer guardian status from tone, writing style, or assumptions about who is messaging.',
|
|
417
|
-
'- Treat `<guardian_context>` as source-of-truth for whether the current actor is verified guardian vs non-guardian.',
|
|
418
|
-
'- If `actor_role` is `non-guardian` or `unverified_channel`, avoid language that implies the requester is already verified as the guardian.',
|
|
419
|
-
'',
|
|
420
462
|
'### Group chat etiquette',
|
|
421
463
|
'- In group chats, you are a **participant**, not the user\'s proxy. Think before you speak.',
|
|
422
464
|
'- **Respond when:** directly mentioned, you can add genuine value, something witty fits naturally, or correcting important misinformation.',
|
|
@@ -590,22 +632,44 @@ function buildLearningMemorySection(): string {
|
|
|
590
632
|
].join('\n');
|
|
591
633
|
}
|
|
592
634
|
|
|
635
|
+
function buildContainerizedSection(): string {
|
|
636
|
+
const baseDataDir = getBaseDataDir() ?? '$BASE_DATA_DIR';
|
|
637
|
+
return [
|
|
638
|
+
'## Running in a Container — Data Persistence',
|
|
639
|
+
'',
|
|
640
|
+
`You are running inside a container. Only the directory \`${baseDataDir}\` is mounted to a persistent volume.`,
|
|
641
|
+
'',
|
|
642
|
+
'**Any new files or data you create MUST be written inside that directory, or they will be lost when the container restarts.**',
|
|
643
|
+
'',
|
|
644
|
+
'Rules:',
|
|
645
|
+
`- Always store new data, notes, memories, configs, and downloads under \`${baseDataDir}\``,
|
|
646
|
+
'- Never write persistent data to system directories, `/tmp`, or paths outside the mounted volume',
|
|
647
|
+
'- When in doubt, prefer paths nested under the data directory',
|
|
648
|
+
'- If you create a file that is only needed temporarily (scratch files, intermediate outputs, download staging), delete it when you are done — disk space on the persistent volume is finite and will grow unboundedly if temp files are not cleaned up',
|
|
649
|
+
].join('\n');
|
|
650
|
+
}
|
|
651
|
+
|
|
593
652
|
function buildPostToolResponseSection(): string {
|
|
594
653
|
return [
|
|
595
654
|
'## Tool Call Timing',
|
|
596
655
|
'',
|
|
597
656
|
'**Call tools FIRST, explain AFTER:**',
|
|
598
657
|
'- When a user request requires a tool, call it immediately at the start of your response',
|
|
599
|
-
'-
|
|
600
|
-
'- Do NOT
|
|
658
|
+
'- If the request needs multiple tool steps, stay silent while you work and respond once you have concrete results',
|
|
659
|
+
'- Do NOT narrate retries or internal process chatter (for example: "hmm", "that didn\'t work", "let me try...")',
|
|
660
|
+
'- Speak mid-workflow only when you need user input (permission, clarification, or blocker)',
|
|
661
|
+
'- Do NOT provide conversational preamble before calling tools',
|
|
601
662
|
'',
|
|
602
663
|
'Example (CORRECT):',
|
|
603
664
|
' → Call document_create',
|
|
604
|
-
' →
|
|
665
|
+
' → Call document_update',
|
|
666
|
+
' → Text: "Drafted and filled your blog post. Review and tell me what to change."',
|
|
605
667
|
'',
|
|
606
668
|
'Example (WRONG):',
|
|
607
|
-
' → Text: "I\'ll
|
|
608
|
-
' → Call document_create
|
|
669
|
+
' → Text: "I\'ll try one approach... hmm not that... trying again..."',
|
|
670
|
+
' → Call document_create',
|
|
671
|
+
'',
|
|
672
|
+
'For permission-gated tools, send one short context sentence immediately before the tool call so the user can make an informed allow/deny decision.',
|
|
609
673
|
].join('\n');
|
|
610
674
|
}
|
|
611
675
|
|
|
@@ -616,18 +680,7 @@ function buildConfigSection(): string {
|
|
|
616
680
|
const hostWorkspaceDir = getWorkspaceDir();
|
|
617
681
|
|
|
618
682
|
const config = getConfig();
|
|
619
|
-
const
|
|
620
|
-
config.sandbox.enabled && config.sandbox.backend === 'docker';
|
|
621
|
-
const localWorkspaceDir = dockerSandboxActive
|
|
622
|
-
? '/workspace'
|
|
623
|
-
: hostWorkspaceDir;
|
|
624
|
-
|
|
625
|
-
// When Docker sandbox is active, shell commands run inside the container
|
|
626
|
-
// (use /workspace/) but file_edit/file_read/file_write run on the host
|
|
627
|
-
// (use the host path). Without Docker, both use the same path.
|
|
628
|
-
const configPreamble = dockerSandboxActive
|
|
629
|
-
? `Your workspace is mounted at \`${localWorkspaceDir}/\` inside the Docker sandbox (host path: \`${hostWorkspaceDir}/\`). For **bash/shell commands** (which run inside Docker), use \`${localWorkspaceDir}/\`. For **file_edit, file_read, and file_write** tools (which run on the host), use the host path \`${hostWorkspaceDir}/\` or relative paths.`
|
|
630
|
-
: `Your configuration directory is \`${hostWorkspaceDir}/\`.`;
|
|
683
|
+
const configPreamble = `Your configuration directory is \`${hostWorkspaceDir}/\`.`;
|
|
631
684
|
|
|
632
685
|
return [
|
|
633
686
|
'## Configuration',
|
|
@@ -637,7 +690,6 @@ function buildConfigSection(): string {
|
|
|
637
690
|
'- `IDENTITY.md` — Your name, nature, personality, and emoji. Updated during the first-run ritual.',
|
|
638
691
|
'- `SOUL.md` — Core principles, personality, and evolution guidance. Your behavioral foundation.',
|
|
639
692
|
'- `USER.md` — Profile of your user. Update as you learn about them over time.',
|
|
640
|
-
'- `LOOKS.md` — Your avatar appearance: body/cheek colors and outfit (hat, shirt, accessory, held item).',
|
|
641
693
|
'- `HEARTBEAT.md` — Checklist for periodic heartbeat runs. When heartbeat is enabled, the assistant runs this checklist on a timer and flags anything that needs attention. Edit this file to control what gets checked each run.',
|
|
642
694
|
'- `BOOTSTRAP.md` — First-run ritual script (only present during onboarding; you delete it when done).',
|
|
643
695
|
'- `UPDATES.md` — Release update notes (created automatically on new releases; delete when updates are actioned).',
|
|
@@ -666,11 +718,7 @@ function buildConfigSection(): string {
|
|
|
666
718
|
'',
|
|
667
719
|
'**IDENTITY.md** — update when:',
|
|
668
720
|
'- They rename you or change your role',
|
|
669
|
-
'',
|
|
670
|
-
'**LOOKS.md** — update when:',
|
|
671
|
-
'- They ask you to change your appearance, colors, or outfit',
|
|
672
|
-
'- You want to refresh your look',
|
|
673
|
-
'- Read LOOKS.md for available options (colors, hats, shirts, accessories, held items)',
|
|
721
|
+
'- Your avatar appearance changes (update the `## Avatar` section with a description of the new look)',
|
|
674
722
|
'',
|
|
675
723
|
'When updating, read the file first, then make a targeted edit. Include all useful information, but don\'t bloat the files over time',
|
|
676
724
|
].join('\n');
|
|
@@ -721,19 +769,23 @@ function readPromptFile(path: string): string | null {
|
|
|
721
769
|
|
|
722
770
|
function appendSkillsCatalog(basePrompt: string): string {
|
|
723
771
|
const skills = loadSkillCatalog();
|
|
772
|
+
const config = getConfig();
|
|
773
|
+
|
|
774
|
+
// Filter out skills whose assistant feature flag is explicitly OFF
|
|
775
|
+
const flagFiltered = skills.filter(s => isAssistantFeatureFlagEnabled(skillFlagKey(s.id), config));
|
|
724
776
|
|
|
725
777
|
const sections: string[] = [basePrompt];
|
|
726
778
|
|
|
727
|
-
const catalog = formatSkillsCatalog(
|
|
779
|
+
const catalog = formatSkillsCatalog(flagFiltered);
|
|
728
780
|
if (catalog) sections.push(catalog);
|
|
729
781
|
|
|
730
|
-
sections.push(buildDynamicSkillWorkflowSection());
|
|
782
|
+
sections.push(buildDynamicSkillWorkflowSection(config));
|
|
731
783
|
|
|
732
784
|
return sections.join('\n\n');
|
|
733
785
|
}
|
|
734
786
|
|
|
735
|
-
function buildDynamicSkillWorkflowSection(): string {
|
|
736
|
-
|
|
787
|
+
function buildDynamicSkillWorkflowSection(config: import('./schema.js').AssistantConfig): string {
|
|
788
|
+
const lines = [
|
|
737
789
|
'## Dynamic Skill Authoring Workflow',
|
|
738
790
|
'',
|
|
739
791
|
'When no existing tool or skill can satisfy a request:',
|
|
@@ -745,13 +797,25 @@ function buildDynamicSkillWorkflowSection(): string {
|
|
|
745
797
|
'',
|
|
746
798
|
'**Never persist or delete skills without explicit user confirmation.** To remove: `delete_managed_skill`.',
|
|
747
799
|
'After a skill is written or deleted, the next turn may run in a recreated session due to file-watcher eviction. Continue normally.',
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
800
|
+
];
|
|
801
|
+
|
|
802
|
+
if (isAssistantFeatureFlagEnabled('feature_flags.browser.enabled', config)) {
|
|
803
|
+
lines.push(
|
|
804
|
+
'',
|
|
805
|
+
'### Browser Skill Prerequisite',
|
|
806
|
+
'If you need browser capabilities (navigating web pages, clicking elements, extracting content) and `browser_*` tools are not available, load the "browser" skill first using `skill_load`.',
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (isAssistantFeatureFlagEnabled('feature_flags.twitter.enabled', config)) {
|
|
811
|
+
lines.push(
|
|
812
|
+
'',
|
|
813
|
+
'### X (Twitter) Skill',
|
|
814
|
+
'When the user asks to post, reply, or interact with X/Twitter, load the "twitter" skill using `skill_load`. Do NOT use computer-use or the browser skill for X — the X skill provides CLI commands (`vellum x post`, `vellum x reply`) that are faster and more reliable.',
|
|
815
|
+
);
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
return lines.join('\n');
|
|
755
819
|
}
|
|
756
820
|
|
|
757
821
|
function escapeXml(str: string): string {
|
|
@@ -44,7 +44,7 @@ Be the assistant you'd actually want to talk to. Concise when needed, thorough w
|
|
|
44
44
|
|
|
45
45
|
## Personality
|
|
46
46
|
|
|
47
|
-
Talk like a real person in a real conversation — assume the user doesn't want to read a wall of text. Keep responses to 1-3 sentences. Never dump lists, inventories, or breakdowns of what you built/can do. After
|
|
47
|
+
Talk like a real person in a real conversation — assume the user doesn't want to read a wall of text. Keep responses to 1-3 sentences. Never dump lists, inventories, or breakdowns of what you built/can do. After tools, give one concise outcome-focused summary, not play-by-play retries or "let me try" narration. When someone asks "what can you help with?", ask what they need — don't recite a capability menu. Show, don't tell. Do, don't describe. The user will see your work; don't narrate it back. Only go longer when the request genuinely demands it. Not a corporate drone. Not a sycophant. Just good at what you do.
|
|
48
48
|
|
|
49
49
|
## Quirks
|
|
50
50
|
|
package/src/config/types.ts
CHANGED
|
@@ -9,7 +9,6 @@ export type {
|
|
|
9
9
|
CallsVoiceConfig,
|
|
10
10
|
ContextWindowConfig,
|
|
11
11
|
DaemonConfig,
|
|
12
|
-
DockerConfig,
|
|
13
12
|
HeartbeatConfig,
|
|
14
13
|
IngressConfig,
|
|
15
14
|
LogFileConfig,
|
|
@@ -43,3 +42,22 @@ export type {
|
|
|
43
42
|
UiConfig,
|
|
44
43
|
WorkspaceGitConfig,
|
|
45
44
|
} from './schema.js';
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Legacy feature flags section (Record<string, boolean>).
|
|
48
|
+
* Uses the key format `skills.<skillId>.enabled`.
|
|
49
|
+
* Missing key defaults to `true` (enabled); explicit `false` only applies when
|
|
50
|
+
* the corresponding canonical key is declared in the defaults registry.
|
|
51
|
+
*
|
|
52
|
+
* @deprecated Prefer `assistantFeatureFlagValues` with canonical key format
|
|
53
|
+
* `feature_flags.<id>.enabled`. This section is kept for backward compatibility
|
|
54
|
+
* and is still consulted by the resolver as a fallback.
|
|
55
|
+
*/
|
|
56
|
+
export type FeatureFlags = Record<string, boolean>;
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Assistant feature flag values using the canonical key format
|
|
60
|
+
* `feature_flags.<id>.enabled`. Takes priority over the legacy
|
|
61
|
+
* `featureFlags` section during resolution, for declared keys.
|
|
62
|
+
*/
|
|
63
|
+
export type AssistantFeatureFlagValues = Record<string, boolean>;
|
|
@@ -56,7 +56,7 @@
|
|
|
56
56
|
{
|
|
57
57
|
"id": "trusted-contacts",
|
|
58
58
|
"name": "Trusted Contacts",
|
|
59
|
-
"description": "Manage trusted contacts \u2014 list, allow, revoke,
|
|
59
|
+
"description": "Manage trusted contacts and Telegram invite links \u2014 list, allow, revoke, block users, and create/list/revoke shareable invite links",
|
|
60
60
|
"emoji": "\ud83d\udc65"
|
|
61
61
|
}
|
|
62
62
|
]
|
|
@@ -10,6 +10,7 @@ You are helping your user set up guardian verification for a messaging channel (
|
|
|
10
10
|
## Prerequisites
|
|
11
11
|
|
|
12
12
|
- The gateway API is available at `http://localhost:7830` (or the configured gateway port).
|
|
13
|
+
- Never call the daemon runtime port directly; always call the gateway URL.
|
|
13
14
|
- The bearer token is stored at `~/.vellum/http-token`. Read it with: `TOKEN=$(cat ~/.vellum/http-token)`.
|
|
14
15
|
- Run shell commands for this skill with `host_bash` (not sandbox `bash`) so host auth/token and localhost routing are reliable.
|
|
15
16
|
- Keep narration minimal: execute required calls first, then provide a concise status update. Do not narrate internal install/check/load chatter unless something fails.
|
|
@@ -176,7 +176,7 @@ Install and load the **guardian-verify-setup** skill to handle the verification
|
|
|
176
176
|
|
|
177
177
|
When invoking the skill, indicate the channel is `sms`. The guardian-verify-setup skill manages the full outbound verification flow, including:
|
|
178
178
|
- Collecting the user's phone number as the destination (accepts any common format -- the API normalizes to E.164)
|
|
179
|
-
- Starting the outbound verification session via `POST /v1/integrations/guardian/outbound/start` with `channel: "sms"`
|
|
179
|
+
- Starting the outbound verification session via the gateway endpoint `POST /v1/integrations/guardian/outbound/start` with `channel: "sms"`
|
|
180
180
|
- Sending a 6-digit code to the phone number that the user must reply with from the SMS channel
|
|
181
181
|
- Checking guardian status to confirm the binding was created
|
|
182
182
|
- Handling resend, cancel, and error cases
|
|
@@ -12,8 +12,9 @@ You are helping your user connect a Telegram bot to the Vellum Assistant gateway
|
|
|
12
12
|
|
|
13
13
|
Before beginning setup, verify these conditions are met:
|
|
14
14
|
|
|
15
|
-
1. **Gateway is
|
|
15
|
+
1. **Gateway API base URL is set and reachable:** Use the configured gateway URL in `GATEWAY_BASE_URL` (from Settings "Local Gateway Target"), then run `curl -sf "$GATEWAY_BASE_URL/healthz"` — it should return gateway health JSON (for example `{"status":"ok"}`). If it fails, tell the user to start the daemon with `vellum daemon start` and wait for it to become healthy before continuing.
|
|
16
16
|
2. **Public ingress URL is configured.** The gateway webhook URL is derived from `${ingress.publicBaseUrl}/webhooks/telegram`. If the ingress URL is not configured, load and execute the **public-ingress** skill first (`skill_load` with `skill: "public-ingress"`) to set up an ngrok tunnel and persist the URL before continuing.
|
|
17
|
+
3. **Use gateway control-plane routes only.** Telegram setup/config actions in this skill must call gateway endpoints under `/v1/integrations/telegram/*` — never call the daemon runtime port directly.
|
|
17
18
|
|
|
18
19
|
## What You Need
|
|
19
20
|
|
|
@@ -36,7 +37,7 @@ The token is collected securely via a system-level prompt and is never exposed i
|
|
|
36
37
|
After the token is collected, call the composite setup endpoint which validates the token, stores credentials, and registers bot commands in a single request:
|
|
37
38
|
|
|
38
39
|
```bash
|
|
39
|
-
curl -sf -X POST
|
|
40
|
+
curl -sf -X POST "$GATEWAY_BASE_URL/v1/integrations/telegram/setup" \
|
|
40
41
|
-H "Authorization: Bearer $(cat ~/.vellum/http-token)" \
|
|
41
42
|
-H "Content-Type: application/json" \
|
|
42
43
|
-d '{}'
|
|
@@ -71,7 +72,7 @@ Install and load the **guardian-verify-setup** skill to handle the verification
|
|
|
71
72
|
|
|
72
73
|
The guardian-verify-setup skill manages the full outbound verification flow for Telegram, including:
|
|
73
74
|
- Collecting the user's Telegram chat ID or @handle as the destination
|
|
74
|
-
- Starting the outbound verification session via `POST /v1/integrations/guardian/outbound/start` with `channel: "telegram"`
|
|
75
|
+
- Starting the outbound verification session via the gateway endpoint `POST /v1/integrations/guardian/outbound/start` with `channel: "telegram"`
|
|
75
76
|
- Handling the bootstrap deep-link flow when the user provides an @handle (the response includes a `telegramBootstrapUrl` that the user must click before receiving the code)
|
|
76
77
|
- Guiding the user to send the verification code back in the Telegram bot chat
|
|
77
78
|
- Checking guardian status to confirm the binding was created
|
|
@@ -97,7 +98,7 @@ If routing is misconfigured, inbound Telegram messages will be rejected and the
|
|
|
97
98
|
Before reporting success, confirm the guardian binding was actually created. Check the guardian binding status:
|
|
98
99
|
|
|
99
100
|
```bash
|
|
100
|
-
curl -sf
|
|
101
|
+
curl -sf "$GATEWAY_BASE_URL/v1/integrations/guardian/status?channel=telegram" \
|
|
101
102
|
-H "Authorization: Bearer $(cat ~/.vellum/http-token)"
|
|
102
103
|
```
|
|
103
104
|
|
|
@@ -116,7 +117,7 @@ Summarize what was done:
|
|
|
116
117
|
- Guardian identity: {verified | not configured}
|
|
117
118
|
- Guardian verification status: {verified via outbound flow | skipped}
|
|
118
119
|
- Routing configuration validated
|
|
119
|
-
- To re-check guardian status later, use: `curl -sf
|
|
120
|
+
- To re-check guardian status later, use: `curl -sf "$GATEWAY_BASE_URL/v1/integrations/guardian/status?channel=telegram" -H "Authorization: Bearer $(cat ~/.vellum/http-token)"`
|
|
120
121
|
|
|
121
122
|
The gateway automatically detects credentials from the vault, reconciles the Telegram webhook registration, and begins accepting Telegram webhooks shortly. In single-assistant mode, routing is automatically configured — no manual environment variable configuration or webhook registration is needed. If the webhook secret changes later, the gateway's credential watcher will automatically re-register the webhook. If the ingress URL changes (e.g., tunnel restart), the assistant daemon triggers an immediate internal reconcile so the webhook re-registers automatically without a gateway restart.
|
|
122
123
|
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "Trusted Contacts"
|
|
3
|
-
description: "Manage trusted contacts — list, allow, revoke,
|
|
3
|
+
description: "Manage trusted contacts and Telegram invite links — list, allow, revoke, block users, and create/list/revoke invite links for external channels"
|
|
4
4
|
user-invocable: true
|
|
5
5
|
metadata: {"vellum": {"emoji": "\ud83d\udc65"}}
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
You are helping your user manage trusted contacts for the Vellum Assistant. Trusted contacts control who is allowed to send messages to the assistant through external channels like Telegram and SMS. All operations go through the gateway HTTP API using `curl` with bearer auth.
|
|
8
|
+
You are helping your user manage trusted contacts and invite links for the Vellum Assistant. Trusted contacts control who is allowed to send messages to the assistant through external channels like Telegram and SMS. Invite links let the guardian share a Telegram deep link that automatically grants access when opened. All operations go through the gateway HTTP API using `curl` with bearer auth.
|
|
9
9
|
|
|
10
10
|
## Prerequisites
|
|
11
11
|
|
|
12
12
|
- The gateway API is available at `http://localhost:7830` (or the configured gateway port).
|
|
13
|
+
- Use gateway control-plane routes only: this skill calls `/v1/ingress/*` and `/v1/integrations/telegram/config` on the gateway, never the daemon runtime port directly.
|
|
13
14
|
- The bearer token is stored at `~/.vellum/http-token`. Read it with: `TOKEN=$(cat ~/.vellum/http-token)`.
|
|
14
15
|
|
|
15
16
|
## Concepts
|
|
@@ -18,6 +19,7 @@ You are helping your user manage trusted contacts for the Vellum Assistant. Trus
|
|
|
18
19
|
- **Policy**: Controls what the member can do — `allow` (can message freely) or `deny` (blocked from messaging).
|
|
19
20
|
- **Status**: The member's lifecycle state — `active` (currently effective), `revoked` (access removed), or `blocked` (explicitly denied).
|
|
20
21
|
- **Source channel**: The messaging platform the contact uses (e.g., `telegram`, `sms`).
|
|
22
|
+
- **Invite link**: A shareable Telegram deep link that, when opened by someone, automatically grants them trusted-contact access. Each invite has a token, usage limits, and optional expiration.
|
|
21
23
|
|
|
22
24
|
## Available Actions
|
|
23
25
|
|
|
@@ -117,9 +119,101 @@ curl -s -X POST "http://localhost:7830/v1/ingress/members/<member_id>/block" \
|
|
|
117
119
|
-d '{"reason": "<optional reason>"}'
|
|
118
120
|
```
|
|
119
121
|
|
|
122
|
+
### 5. Create a Telegram invite link
|
|
123
|
+
|
|
124
|
+
Use this when the guardian wants to invite someone to message the assistant on Telegram without needing their user ID upfront. The invite link is a shareable Telegram deep link — when someone opens it, they automatically get trusted-contact access.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
TOKEN=$(cat ~/.vellum/http-token)
|
|
128
|
+
curl -s -X POST http://localhost:7830/v1/ingress/invites \
|
|
129
|
+
-H "Content-Type: application/json" \
|
|
130
|
+
-H "Authorization: Bearer $TOKEN" \
|
|
131
|
+
-d '{
|
|
132
|
+
"sourceChannel": "telegram",
|
|
133
|
+
"maxUses": 1,
|
|
134
|
+
"note": "<optional note, e.g. the person it is for>"
|
|
135
|
+
}'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Optional fields:
|
|
139
|
+
- `maxUses` — how many times the link can be used (default: 1). Use a higher number for group invites.
|
|
140
|
+
- `expiresInMs` — expiration time in milliseconds from now (e.g., `86400000` for 24 hours). Defaults to 7 days (`604800000`) if omitted.
|
|
141
|
+
- `note` — a human-readable label for the invite (e.g., "For Mom", "Family group").
|
|
142
|
+
|
|
143
|
+
The response contains `{ ok: true, invite: { id, token, ... } }`. The `token` field is the raw invite token — it is only returned at creation time and cannot be retrieved later.
|
|
144
|
+
|
|
145
|
+
**Building the shareable link**: After creating the invite, look up the Telegram bot username so you can build the deep link. Query the Telegram integration config:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
TOKEN=$(cat ~/.vellum/http-token)
|
|
149
|
+
curl -s http://localhost:7830/v1/integrations/telegram/config \
|
|
150
|
+
-H "Authorization: Bearer $TOKEN"
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
The response includes `botUsername`. Use it to construct the deep link:
|
|
154
|
+
|
|
155
|
+
```
|
|
156
|
+
https://t.me/<botUsername>?start=iv_<token>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
**Presenting to the guardian**: Give the guardian the link with clear copy-paste instructions:
|
|
160
|
+
|
|
161
|
+
> Here's your Telegram invite link:
|
|
162
|
+
>
|
|
163
|
+
> `https://t.me/<botUsername>?start=iv_<token>`
|
|
164
|
+
>
|
|
165
|
+
> Share this link with the person you want to invite. When they open it in Telegram and press "Start", they'll automatically be added as a trusted contact and can message the assistant directly.
|
|
166
|
+
>
|
|
167
|
+
> This link can be used <maxUses> time(s)<and expires in X hours/days if applicable>.
|
|
168
|
+
|
|
169
|
+
If the Telegram bot username is not available (integration not set up), tell the guardian they need to set up the Telegram integration first using the Telegram Setup skill.
|
|
170
|
+
|
|
171
|
+
### 6. List invite links
|
|
172
|
+
|
|
173
|
+
Use this to show the guardian their active (and optionally all) invite links.
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
TOKEN=$(cat ~/.vellum/http-token)
|
|
177
|
+
curl -s "http://localhost:7830/v1/ingress/invites?sourceChannel=telegram" \
|
|
178
|
+
-H "Authorization: Bearer $TOKEN"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
Optional query parameters:
|
|
182
|
+
- `sourceChannel` — filter by channel (e.g., `telegram`)
|
|
183
|
+
- `status` — filter by status (`active`, `revoked`, `redeemed`, `expired`)
|
|
184
|
+
|
|
185
|
+
The response contains `{ ok: true, invites: [...] }` where each invite has:
|
|
186
|
+
- `id` — unique invite ID (needed for revoke)
|
|
187
|
+
- `sourceChannel` — the channel
|
|
188
|
+
- `tokenHash` — hashed token (the raw token is only available at creation time)
|
|
189
|
+
- `maxUses` — total allowed uses
|
|
190
|
+
- `useCount` — how many times it has been redeemed
|
|
191
|
+
- `expiresAt` — expiration timestamp (null if no expiration)
|
|
192
|
+
- `status` — current status (`active`, `revoked`, `redeemed`, `expired`)
|
|
193
|
+
- `note` — the label set at creation
|
|
194
|
+
- `createdAt` — when the invite was created
|
|
195
|
+
|
|
196
|
+
**Presenting results**: Format as a readable list. Show the note (or "unnamed" as fallback), status, uses remaining (`maxUses - useCount`), and expiration. Highlight active invites and note which ones have been fully used or expired.
|
|
197
|
+
|
|
198
|
+
### 7. Revoke an invite link
|
|
199
|
+
|
|
200
|
+
Use this when the guardian wants to cancel an active invite link. **Always confirm before revoking.**
|
|
201
|
+
|
|
202
|
+
Ask the user: *"I'll revoke the invite link [note or ID]. It will no longer be usable. Should I proceed?"*
|
|
203
|
+
|
|
204
|
+
First, list invites to find the invite's `id`, then revoke:
|
|
205
|
+
|
|
206
|
+
```bash
|
|
207
|
+
TOKEN=$(cat ~/.vellum/http-token)
|
|
208
|
+
curl -s -X DELETE "http://localhost:7830/v1/ingress/invites/<invite_id>" \
|
|
209
|
+
-H "Authorization: Bearer $TOKEN"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Replace `<invite_id>` with the invite's `id` from the list response.
|
|
213
|
+
|
|
120
214
|
## Confirmation Requirements
|
|
121
215
|
|
|
122
|
-
**All mutating actions (allow, revoke, block) require explicit user confirmation before execution.** This is a safety measure — modifying who can access the assistant should always be a deliberate choice.
|
|
216
|
+
**All mutating actions (allow, revoke, block, revoke invite) require explicit user confirmation before execution.** This is a safety measure — modifying who can access the assistant should always be a deliberate choice. Creating an invite link does not require confirmation since it does not grant access until someone opens it.
|
|
123
217
|
|
|
124
218
|
- Clearly state what action you are about to take and who it affects.
|
|
125
219
|
- Wait for the user to confirm before running the curl command.
|
|
@@ -133,6 +227,8 @@ curl -s -X POST "http://localhost:7830/v1/ingress/members/<member_id>/block" \
|
|
|
133
227
|
- `At least one of externalUserId or externalChatId is required` — ask the user for the contact's channel-specific identifier.
|
|
134
228
|
- `Member not found or cannot be revoked` — the member ID may be invalid or the member is already revoked.
|
|
135
229
|
- `Member not found or already blocked` — the member ID may be invalid or the member is already blocked.
|
|
230
|
+
- `sourceChannel is required for create` — when creating an invite, always pass `"sourceChannel": "telegram"`.
|
|
231
|
+
- `Invite not found or already revoked` — the invite ID may be invalid or the invite is already revoked.
|
|
136
232
|
|
|
137
233
|
## Typical Workflows
|
|
138
234
|
|
|
@@ -145,3 +241,9 @@ curl -s -X POST "http://localhost:7830/v1/ingress/members/<member_id>/block" \
|
|
|
145
241
|
**"Block [name]"** — List members to find them, confirm the block, then execute.
|
|
146
242
|
|
|
147
243
|
**"Show me blocked contacts"** — List with `status=blocked` filter.
|
|
244
|
+
|
|
245
|
+
**"Create a Telegram invite link"** / **"Invite someone on Telegram"** — Create an invite with `sourceChannel: "telegram"`, look up the bot username, build the deep link, and present it with sharing instructions.
|
|
246
|
+
|
|
247
|
+
**"Show my invites"** / **"List active invite links"** — List invites filtered by `sourceChannel=telegram`, present active invites with uses remaining and expiration info.
|
|
248
|
+
|
|
249
|
+
**"Revoke invite"** / **"Cancel invite link"** — List invites to identify the target, confirm, then revoke by ID.
|
|
@@ -210,7 +210,7 @@ Install and load the **guardian-verify-setup** skill to handle the verification
|
|
|
210
210
|
|
|
211
211
|
The guardian-verify-setup skill manages the full outbound verification flow for **one channel at a time** (sms, voice, or telegram). Each invocation handles:
|
|
212
212
|
- Collecting the user's phone number as the destination (accepts any common format -- the API normalizes to E.164)
|
|
213
|
-
- Starting the outbound verification session via `POST /v1/integrations/guardian/outbound/start`
|
|
213
|
+
- Starting the outbound verification session via the gateway endpoint `POST /v1/integrations/guardian/outbound/start`
|
|
214
214
|
- For **SMS**: sending a 6-digit code to the phone number that the user must reply with from the SMS channel
|
|
215
215
|
- For **voice**: calling the phone number and providing a code for the user to enter via their phone's keypad
|
|
216
216
|
- Checking guardian status to confirm the binding was created
|
|
@@ -109,7 +109,6 @@ export class ConfigWatcher {
|
|
|
109
109
|
'SOUL.md': () => onSessionEvict(),
|
|
110
110
|
'IDENTITY.md': () => { onSessionEvict(); onIdentityChanged?.(); },
|
|
111
111
|
'USER.md': () => onSessionEvict(),
|
|
112
|
-
'LOOKS.md': () => onSessionEvict(),
|
|
113
112
|
'UPDATES.md': () => onSessionEvict(),
|
|
114
113
|
};
|
|
115
114
|
|
|
@@ -106,7 +106,7 @@ function isProcessRunning(pid: number): boolean {
|
|
|
106
106
|
*/
|
|
107
107
|
function isVellumDaemonProcess(pid: number): boolean {
|
|
108
108
|
try {
|
|
109
|
-
const cmd = execSync(`ps -p ${pid} -o command=`, {
|
|
109
|
+
const cmd = execSync(`ps -ww -p ${pid} -o command=`, {
|
|
110
110
|
encoding: 'utf-8',
|
|
111
111
|
timeout: 3000,
|
|
112
112
|
stdio: ['ignore', 'pipe', 'ignore'],
|