@vellumai/assistant 0.11.8 → 0.11.9-staging.2
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 +2 -2
- package/Dockerfile +8 -48
- package/docker-entrypoint.sh +5 -1
- package/docker-kata-apt-env.sh +3 -0
- package/docker-kata-apt-shims.sh +127 -0
- package/docker-kata-apt-wrapper.sh +45 -0
- package/docker-kata-chroot-exec.sh +35 -0
- package/docker-kata-pip.sh +8 -2
- package/docs/architecture/memory.md +8 -4
- package/docs/guardian-request-flow.md +18 -14
- package/docs/trusted-contact-access.md +1 -7
- package/node_modules/@vellumai/avatar-catalog/src/catalog.ts +7 -1
- package/node_modules/@vellumai/avatar-catalog/src/index.ts +1 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-request-contract.test.ts +0 -18
- package/node_modules/@vellumai/gateway-client/src/__tests__/inbound-event-kind.test.ts +110 -5
- package/node_modules/@vellumai/gateway-client/src/guardian-request-contract.ts +5 -33
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +3 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-event-kind.ts +100 -9
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -2
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +9 -0
- package/node_modules/@vellumai/service-contracts/package.json +4 -1
- package/node_modules/@vellumai/service-contracts/src/guardian-requests.ts +18 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/platform-credential.ts +41 -0
- package/node_modules/@vellumai/service-contracts/src/reactions.ts +60 -0
- package/openapi.yaml +193 -4
- package/package.json +2 -2
- package/src/__tests__/access-request-card-view.test.ts +6 -5
- package/src/__tests__/access-request-seed-content-blocks.test.ts +5 -2
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +43 -82
- package/src/__tests__/always-loaded-tools-guard.test.ts +8 -2
- package/src/__tests__/attachment-stored-path-annotation.test.ts +80 -0
- package/src/__tests__/attachments-store.test.ts +27 -0
- package/src/__tests__/attachments.test.ts +43 -0
- package/src/__tests__/canned-reply-release.test.ts +48 -5
- package/src/__tests__/channel-delivery-store.test.ts +129 -18
- package/src/__tests__/channel-reply-delivery.test.ts +553 -93
- package/src/__tests__/channel-retry-sweep.test.ts +199 -0
- package/src/__tests__/client-os-metadata-persistence.test.ts +32 -3
- package/src/__tests__/conversation-error.test.ts +15 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +118 -0
- package/src/__tests__/conversation-pairing.test.ts +141 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +28 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +125 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +79 -0
- package/src/__tests__/conversation-store-ephemeral.test.ts +323 -10
- package/src/__tests__/conversation-sync-tags.test.ts +2 -37
- package/src/__tests__/credential-health-service.test.ts +98 -10
- package/src/__tests__/delete-propagation.test.ts +469 -0
- package/src/__tests__/dm-persistence.test.ts +16 -0
- package/src/__tests__/docker-kata-apt-shims.test.ts +135 -0
- package/src/__tests__/forbidden-legacy-symbols.test.ts +12 -0
- package/src/__tests__/gemini-provider.test.ts +46 -0
- package/src/__tests__/guardian-card-withdrawal.test.ts +0 -22
- package/src/__tests__/guardian-gateway-sim.ts +0 -23
- package/src/__tests__/guardian-question-mode.test.ts +108 -0
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +0 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +26 -12
- package/src/__tests__/host-proxy-interface.test.ts +10 -0
- package/src/__tests__/inbound-slack-persistence.test.ts +16 -0
- package/src/__tests__/injector-v3-suppression.test.ts +43 -9
- package/src/__tests__/list-messages-page-latest.test.ts +127 -0
- package/src/__tests__/list-messages-system-card.test.ts +103 -0
- package/src/__tests__/media-resolve-image-validation.test.ts +77 -0
- package/src/__tests__/notification-decision-fallback.test.ts +199 -77
- package/src/__tests__/notification-decision-strategy.test.ts +198 -213
- package/src/__tests__/notification-discord-adapter.test.ts +25 -0
- package/src/__tests__/notification-slack-adapter.test.ts +133 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +36 -0
- package/src/__tests__/openai-provider.test.ts +5 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +85 -72
- package/src/__tests__/persist-user-message-set-processing-failure.test.ts +83 -65
- package/src/__tests__/platform-client-verify-credential.test.ts +100 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +11 -0
- package/src/__tests__/process-message-display-content.test.ts +20 -9
- package/src/__tests__/processing-acquire-fenced-guard.test.ts +56 -0
- package/src/__tests__/provider-meta-persistence.test.ts +67 -0
- package/src/__tests__/reaction-persistence.test.ts +22 -198
- package/src/__tests__/run-conversation-turn-persistence.test.ts +5 -2
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +16 -0
- package/src/__tests__/skill-load-tool.test.ts +27 -0
- package/src/__tests__/skills.test.ts +34 -1
- package/src/__tests__/strip-memory-injections.test.ts +3 -4
- package/src/__tests__/terminal-tools.test.ts +9 -0
- package/src/__tests__/thread-backfill.test.ts +5 -3
- package/src/__tests__/unified-turn-context-location.test.ts +76 -0
- package/src/__tests__/voice-session-bridge.test.ts +18 -0
- package/src/__tests__/watch-retro-report-payload.test.ts +185 -0
- package/src/__tests__/watch-retro-tool-availability.test.ts +82 -0
- package/src/__tests__/workspace-migration-151-repair-renamed-fireworks-deepseek-pro-model-id.test.ts +235 -0
- package/src/__tests__/workspace-migration-152-repair-retired-fireworks-minimax-m2p7-model-id.test.ts +233 -0
- package/src/agent/attachments.ts +13 -2
- package/src/agent/loop.ts +3 -19
- package/src/api/README.md +9 -5
- package/src/api/index.ts +9 -8
- package/src/api/package.json +1 -0
- package/src/api/responses/conversation-message.ts +8 -0
- package/src/api/responses/home.ts +7 -18
- package/src/api/surfaces.ts +114 -7
- package/src/approvals/AGENTS.md +1 -1
- package/src/channels/__tests__/gateway-guardian-requests.test.ts +1 -23
- package/src/channels/__tests__/types.test.ts +22 -1
- package/src/channels/gateway-guardian-requests.ts +0 -22
- package/src/channels/types.ts +8 -6
- package/src/cli/__tests__/catalog-search-help.test.ts +18 -0
- package/src/cli/commands/channels/__tests__/channels.test.ts +26 -0
- package/src/cli/commands/channels/index.help.ts +19 -6
- package/src/cli/commands/channels/index.ts +6 -2
- package/src/cli/commands/db/__tests__/status.test.ts +22 -0
- package/src/cli/commands/db/index.help.ts +1 -1
- package/src/cli/commands/db/status.ts +172 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +29 -0
- package/src/cli/commands/platform/connect.ts +14 -5
- package/src/cli/commands/plugins.help.ts +6 -5
- package/src/cli/lib/__tests__/install-from-github.test.ts +0 -8
- package/src/cli/lib/__tests__/install-from-platform.test.ts +72 -0
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +33 -0
- package/src/cli/lib/bundled-marketplace.json +14 -0
- package/src/cli/lib/install-from-github.ts +9 -5
- package/src/cli/lib/install-from-platform.ts +12 -1
- package/src/config/__tests__/assistant-initiated-threads-gate.test.ts +61 -0
- package/src/config/assistant-initiated-threads-gate.ts +50 -0
- package/src/config/bundled-skills/acp/SKILL.md +10 -3
- package/src/config/bundled-skills/schedule/SKILL.md +25 -11
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +3 -1
- package/src/config/call-site-defaults.ts +4 -1
- package/src/config/feature-flag-registry.json +21 -4
- package/src/config/schemas/memory-v3.ts +4 -3
- package/src/context/strip-injections.ts +17 -56
- package/src/conversations/__tests__/message-consolidation.test.ts +39 -0
- package/src/conversations/message-consolidation.ts +4 -3
- package/src/credential-health/credential-health-service.ts +130 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +31 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +55 -59
- package/src/daemon/conversation-error.ts +2 -0
- package/src/daemon/conversation-messaging.ts +195 -47
- package/src/daemon/conversation-process.ts +20 -5
- package/src/daemon/conversation-runtime-assembly.ts +48 -39
- package/src/daemon/conversation-store.ts +159 -11
- package/src/daemon/conversation-tool-setup.ts +9 -2
- package/src/daemon/conversation.ts +290 -19
- package/src/daemon/dictation-text-processing.ts +2 -7
- package/src/daemon/handlers/config-channels.ts +33 -3
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/shared.ts +9 -0
- package/src/daemon/port-oversized-content.test.ts +117 -0
- package/src/daemon/port-oversized-content.ts +110 -0
- package/src/daemon/process-message.ts +87 -16
- package/src/daemon/reaction-record.test.ts +23 -11
- package/src/daemon/reaction-record.ts +6 -9
- package/src/documents/document-store.ts +1 -5
- package/src/home/conversation-starter-validation.ts +1 -5
- package/src/live-voice/__tests__/live-voice-photo.test.ts +910 -50
- package/src/live-voice/__tests__/live-voice-sight-frame-inline.test.ts +31 -25
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +70 -1
- package/src/live-voice/live-voice-photo.ts +544 -61
- package/src/live-voice/live-voice-session.ts +6 -2
- package/src/live-voice/protocol.ts +20 -1
- package/src/messaging/provider-message-metadata.ts +40 -1
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +10 -2
- package/src/messaging/providers/channel-transport.ts +28 -0
- package/src/messaging/providers/discord/send.ts +3 -2
- package/src/messaging/providers/slack/api.ts +11 -1
- package/src/messaging/providers/slack/message-metadata.test.ts +133 -0
- package/src/messaging/providers/slack/message-metadata.ts +141 -1
- package/src/messaging/providers/slack/send.test.ts +58 -0
- package/src/messaging/providers/slack/send.ts +4 -4
- package/src/messaging/providers/slack/transport.ts +28 -2
- package/src/messaging/providers/telegram-bot/send.test.ts +159 -0
- package/src/messaging/providers/telegram-bot/send.ts +93 -0
- package/src/messaging/providers/telegram-bot/transport.ts +71 -0
- package/src/messaging/reaction-envelopes.test.ts +73 -0
- package/src/messaging/reaction-envelopes.ts +33 -5
- package/src/messaging/read-provider-metadata.ts +4 -3
- package/src/monitoring/recovery/__tests__/stranded-delivery-events.test.ts +208 -0
- package/src/monitoring/recovery/db.ts +35 -0
- package/src/monitoring/recovery/orphaned-channel-events.ts +3 -22
- package/src/monitoring/recovery/run-recovery.ts +6 -2
- package/src/monitoring/recovery/stale-processing.ts +3 -20
- package/src/monitoring/recovery/stranded-delivery-events.ts +68 -0
- package/src/notifications/AGENTS.md +2 -2
- package/src/notifications/README.md +2 -2
- package/src/notifications/__tests__/assistant-reply-producer.test.ts +11 -9
- package/src/notifications/__tests__/broadcaster.test.ts +35 -4
- package/src/notifications/__tests__/notification-utils.test.ts +31 -0
- package/src/notifications/access-request-copy.ts +126 -114
- package/src/notifications/adapters/discord.ts +9 -5
- package/src/notifications/adapters/shared.ts +17 -4
- package/src/notifications/adapters/slack.ts +14 -4
- package/src/notifications/adapters/telegram.ts +8 -4
- package/src/notifications/approval-card-data.ts +5 -2
- package/src/notifications/assistant-reply-producer.ts +7 -7
- package/src/notifications/broadcaster.ts +57 -25
- package/src/notifications/conversation-pairing.ts +68 -2
- package/src/notifications/copy-composer.ts +13 -32
- package/src/notifications/decision-engine.ts +56 -237
- package/src/notifications/guardian-delivery-recorder.ts +5 -9
- package/src/notifications/guardian-feed-projection.ts +0 -15
- package/src/notifications/guardian-question-mode.ts +147 -6
- package/src/notifications/notification-utils.ts +117 -1
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/prompter.ts +1 -1
- package/src/persistence/conversation-crud.ts +93 -14
- package/src/persistence/conversation-queries.ts +144 -17
- package/src/persistence/conversation-types.ts +39 -5
- package/src/persistence/delivery-crud.ts +224 -28
- package/src/persistence/delivery-status.ts +21 -2
- package/src/persistence/migrations/374-channel-inbound-message-id-index.ts +26 -0
- package/src/persistence/migrations/375-create-channel-outbound-posts.ts +52 -0
- package/src/persistence/migrations/__tests__/375-create-channel-outbound-posts.test.ts +84 -0
- package/src/persistence/schema/conversations.ts +71 -2
- package/src/persistence/schema-contract.test.ts +78 -0
- package/src/persistence/schema-contract.ts +96 -0
- package/src/persistence/steps.ts +4 -0
- package/src/platform/client.ts +55 -0
- package/src/plugins/__tests__/mcp-servers.test.ts +46 -0
- package/src/plugins/defaults/injector-order.ts +2 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +2 -2
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +13 -15
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +10 -0
- package/src/plugins/defaults/memory/injectors.ts +1 -1
- package/src/plugins/defaults/memory/memory-marker.ts +17 -7
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +1 -5
- package/src/plugins/defaults/memory/substrate/__tests__/skill-content.test.ts +17 -0
- package/src/plugins/defaults/memory/substrate/skill-content.ts +7 -0
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +54 -41
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +3 -3
- package/src/plugins/defaults/memory/v3/__tests__/render-injection.test.ts +22 -0
- package/src/plugins/defaults/memory/v3/injector.ts +14 -15
- package/src/plugins/defaults/memory/v3/prune.test.ts +20 -2
- package/src/plugins/defaults/memory/v3/render-injection.ts +10 -1
- package/src/plugins/defaults/memory/v3/types.ts +15 -4
- package/src/plugins/defaults/turn-context/injectors.ts +3 -0
- package/src/plugins/defaults/turn-context/unified-turn-context.ts +24 -0
- package/src/plugins/mcp-servers.ts +14 -2
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +50 -0
- package/src/providers/__tests__/registry-native-web-search.test.ts +49 -2
- package/src/providers/anthropic/client.ts +21 -24
- package/src/providers/call-site-routing.ts +5 -4
- package/src/providers/connection-resolution.ts +29 -1
- package/src/providers/content-block-size.test.ts +82 -0
- package/src/providers/content-block-size.ts +99 -0
- package/src/providers/file-block-text.test.ts +64 -0
- package/src/providers/file-block-text.ts +28 -0
- package/src/providers/gemini/client.ts +15 -9
- package/src/providers/inference/auth.ts +6 -6
- package/src/providers/media-resolve.ts +14 -0
- package/src/providers/model-catalog.ts +47 -34
- package/src/providers/openai/chat-completions-provider.ts +9 -25
- package/src/providers/openai/responses-provider.ts +11 -18
- package/src/providers/registry.ts +10 -7
- package/src/providers/routing-identity.ts +2 -1
- package/src/providers/types.ts +1 -4
- package/src/providers/vellum-model-routing.ts +3 -2
- package/src/runtime/AGENTS.md +40 -15
- package/src/runtime/approval-message-composer.ts +1 -6
- package/src/runtime/assistant-event-hub.ts +2 -39
- package/src/runtime/channel-approval-types.ts +1 -5
- package/src/runtime/channel-reply-delivery.ts +182 -115
- package/src/runtime/{slack-reply-session.test.ts → channel-reply-session.test.ts} +294 -156
- package/src/runtime/{slack-reply-session.ts → channel-reply-session.ts} +107 -86
- package/src/runtime/channel-retry-sweep.ts +102 -1
- package/src/runtime/finalize-event-delivery.ts +4 -4
- package/src/runtime/guardian-action-message-composer.ts +1 -4
- package/src/runtime/guardian-reply-router.ts +4 -75
- package/src/runtime/http-router.ts +1 -5
- package/src/runtime/question-request-guardian-bridge.ts +2 -3
- package/src/runtime/routes/__tests__/conversation-list-assistant-section.test.ts +359 -0
- package/src/runtime/routes/__tests__/dictation-command-mode.test.ts +120 -0
- package/src/runtime/routes/__tests__/sight-frame-routes.test.ts +487 -0
- package/src/runtime/routes/acp-routes.ts +1 -1
- package/src/runtime/routes/canned-reply-release.ts +19 -9
- package/src/runtime/routes/channel-route-shared.ts +0 -39
- package/src/runtime/routes/channel-verification-routes.ts +4 -1
- package/src/runtime/routes/conversation-list-routes.ts +44 -3
- package/src/runtime/routes/conversation-management-routes.ts +2 -1
- package/src/runtime/routes/conversation-routes.ts +138 -59
- package/src/runtime/routes/diagnostics-routes.ts +111 -60
- package/src/runtime/routes/guardian-action-routes.ts +10 -14
- package/src/runtime/routes/guardian-approval-interception.ts +0 -5
- package/src/runtime/routes/inbound-message-handler.ts +170 -48
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +4 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +169 -8
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +82 -14
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +23 -48
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +454 -94
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +309 -102
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/platform-routes.ts +99 -10
- package/src/runtime/routes/sight-frame-routes.ts +136 -0
- package/src/runtime/sync/resource-sync-events.ts +14 -37
- package/src/runtime/sync/sync-publisher.test.ts +5 -4
- package/src/tools/__tests__/tool-input-schemas.test.ts +2 -0
- package/src/tools/client-os.ts +11 -1
- package/src/tools/host-filesystem/edit.ts +2 -2
- package/src/tools/host-filesystem/read.ts +2 -2
- package/src/tools/host-filesystem/transfer.ts +2 -2
- package/src/tools/host-filesystem/write.ts +2 -2
- package/src/tools/host-terminal/host-shell.ts +2 -2
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/tool-input-schemas.ts +2 -0
- package/src/tools/tool-manifest.ts +2 -0
- package/src/tools/ui-surface/definitions.ts +4 -3
- package/src/tools/watch/watch-retro-report.ts +205 -0
- package/src/watch/__tests__/watch-retro.test.ts +268 -40
- package/src/watch/watch-retro.ts +190 -77
- package/src/workspace/migrations/151-repair-renamed-fireworks-deepseek-pro-model-id.ts +195 -0
- package/src/workspace/migrations/152-repair-retired-fireworks-minimax-m2p7-model-id.ts +198 -0
- package/src/workspace/migrations/__tests__/150-stt-flux-provider-to-model-family.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +4 -0
- package/docker-kata-pip-chroot.sh +0 -22
- package/src/__tests__/slack-reaction-approvals.test.ts +0 -97
- package/src/__tests__/slack-reaction-guardian-approval.test.ts +0 -307
- package/src/api/events/conversation-list-invalidated.ts +0 -38
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
|
|
3
3
|
import { cliIpcCall, exitFromIpcResult } from "../../../ipc/cli-client.js";
|
|
4
|
+
import type { PlatformConnectResponse } from "../../../runtime/routes/platform-routes.js";
|
|
4
5
|
import { subcommand } from "../../lib/cli-command-help.js";
|
|
5
6
|
import { log } from "../../logger.js";
|
|
6
7
|
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
@@ -8,11 +9,10 @@ import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
|
8
9
|
export function registerPlatformConnectCommand(platform: Command): void {
|
|
9
10
|
subcommand(platform, "connect").action(
|
|
10
11
|
async (_opts: Record<string, unknown>, cmd: Command) => {
|
|
11
|
-
const r = await cliIpcCall<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}>("platform_connect", {});
|
|
12
|
+
const r = await cliIpcCall<PlatformConnectResponse>(
|
|
13
|
+
"platform_connect",
|
|
14
|
+
{},
|
|
15
|
+
);
|
|
16
16
|
if (!r.ok) {
|
|
17
17
|
return exitFromIpcResult(
|
|
18
18
|
{ ok: false, error: r.error, statusCode: r.statusCode },
|
|
@@ -28,6 +28,15 @@ export function registerPlatformConnectCommand(platform: Command): void {
|
|
|
28
28
|
`Already connected to platform at ${r.result.baseUrl}. ` +
|
|
29
29
|
`Run 'assistant platform disconnect' first to reconnect.`,
|
|
30
30
|
);
|
|
31
|
+
} else if (r.result?.credentialRejected) {
|
|
32
|
+
// No client shows a login screen for the daemon's signal, so this
|
|
33
|
+
// line is what tells the user what replaces the key. A plain sign-in
|
|
34
|
+
// stops at "already logged in" before the credential pass runs;
|
|
35
|
+
// --force runs it.
|
|
36
|
+
log.info(
|
|
37
|
+
"The stored platform credential was rejected by the platform. " +
|
|
38
|
+
"Run 'vellum login --force' to sign in again and replace it.",
|
|
39
|
+
);
|
|
31
40
|
} else {
|
|
32
41
|
log.info(
|
|
33
42
|
"Showing the platform login screen on connected clients. " +
|
|
@@ -10,12 +10,13 @@ import {
|
|
|
10
10
|
|
|
11
11
|
export const pluginsHelp: CliCommandHelp = {
|
|
12
12
|
name: "plugins",
|
|
13
|
-
description:
|
|
13
|
+
description:
|
|
14
|
+
"Manage external plugins, which bundle apps, channels, MCPs, skills and more from other Vellum users",
|
|
14
15
|
helpText: `
|
|
15
|
-
Plugins are superpowers: installable extensions that add
|
|
16
|
-
and so much more from
|
|
17
|
-
install, connect, or integrate a product, service, or app,
|
|
18
|
-
'assistant plugins search <name>' first before searching the web.`,
|
|
16
|
+
Plugins are superpowers: installable extensions that add apps, channels, MCPs,
|
|
17
|
+
skills, tools, integrations, and so much more from other Vellum users. When the
|
|
18
|
+
user asks to set up, install, connect, or integrate a product, service, or app,
|
|
19
|
+
run 'assistant plugins search <name>' first before searching the web.`,
|
|
19
20
|
subcommands: [
|
|
20
21
|
{
|
|
21
22
|
name: "install",
|
|
@@ -201,14 +201,6 @@ const unusedGitRunner: GitRunner = async (args) => {
|
|
|
201
201
|
throw new Error(`git should not run for this install: ${args.join(" ")}`);
|
|
202
202
|
};
|
|
203
203
|
|
|
204
|
-
/**
|
|
205
|
-
* Read the real, committed caveman adapter stub from the repo so the
|
|
206
|
-
* integration test exercises the adapter that ships rather than a fixture
|
|
207
|
-
* copy that could drift from it. Returns every stub file keyed by its
|
|
208
|
-
* Contents-API path (`plugins/caveman/<rel>`) so the fetch fake
|
|
209
|
-
* serves the whole stub — package.json, the adapter, and its templates — to
|
|
210
|
-
* the real postinstall runner. Resolves the stub relative to this test file.
|
|
211
|
-
*/
|
|
212
204
|
function readRealCavemanStub(): Record<string, string> {
|
|
213
205
|
const repoRel = "plugins/caveman";
|
|
214
206
|
const stubDir = join(import.meta.dir, "../../../../../", repoRel);
|
|
@@ -177,6 +177,7 @@ describe("installPluginFromPlatform — success", () => {
|
|
|
177
177
|
);
|
|
178
178
|
expect(existsSync(join(target, "README.md"))).toBe(true);
|
|
179
179
|
expect(existsSync(join(target, "skills", "read", "SKILL.md"))).toBe(true);
|
|
180
|
+
expect(existsSync(join(target, "package.json"))).toBe(true);
|
|
180
181
|
|
|
181
182
|
// Provenance records the pinned commit and the verified ETag.
|
|
182
183
|
const meta = readInstallMeta(target);
|
|
@@ -186,6 +187,77 @@ describe("installPluginFromPlatform — success", () => {
|
|
|
186
187
|
expect(meta?.etag?.startsWith('"sha256:')).toBe(true);
|
|
187
188
|
});
|
|
188
189
|
|
|
190
|
+
test("synthesizes a minimal package.json when the tarball ships none", async () => {
|
|
191
|
+
const fetchFn = makeInstallFetch({
|
|
192
|
+
entries: [
|
|
193
|
+
{
|
|
194
|
+
name: "skills/keyword-research/SKILL.md",
|
|
195
|
+
content:
|
|
196
|
+
"---\nname: keyword-research\ndescription: Discover keyword opportunities.\n---\n",
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
name: "mcp.json",
|
|
200
|
+
content: JSON.stringify({
|
|
201
|
+
mcpServers: { openseo: { url: "https://app.openseo.so/mcp" } },
|
|
202
|
+
}),
|
|
203
|
+
},
|
|
204
|
+
],
|
|
205
|
+
ref: "c".repeat(40),
|
|
206
|
+
repo: "every-app/open-seo",
|
|
207
|
+
sourcePath: "plugins/openseo",
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
const result = await installPluginFromPlatform(
|
|
211
|
+
{ name: "openseo" },
|
|
212
|
+
{
|
|
213
|
+
fetch: fetchFn,
|
|
214
|
+
platformBaseUrl: PLATFORM,
|
|
215
|
+
workspacePluginsDir: pluginsDir,
|
|
216
|
+
},
|
|
217
|
+
);
|
|
218
|
+
|
|
219
|
+
const target = join(pluginsDir, "openseo");
|
|
220
|
+
expect(result.fileCount).toBe(2);
|
|
221
|
+
expect(
|
|
222
|
+
existsSync(join(target, "skills", "keyword-research", "SKILL.md")),
|
|
223
|
+
).toBe(true);
|
|
224
|
+
const pkg = JSON.parse(readFileSync(join(target, "package.json"), "utf-8"));
|
|
225
|
+
expect(pkg.name).toBe("openseo");
|
|
226
|
+
expect(pkg.version).toBe("0.0.0");
|
|
227
|
+
expect(pkg.peerDependencies["@vellumai/plugin-api"]).toBeDefined();
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
test("leaves an upstream package.json in place", async () => {
|
|
231
|
+
const fetchFn = makeInstallFetch({
|
|
232
|
+
entries: [
|
|
233
|
+
{
|
|
234
|
+
name: "package.json",
|
|
235
|
+
content: JSON.stringify({
|
|
236
|
+
name: "reading-pal",
|
|
237
|
+
version: "1.2.3",
|
|
238
|
+
peerDependencies: { "@vellumai/plugin-api": ">=0.8.0" },
|
|
239
|
+
}),
|
|
240
|
+
},
|
|
241
|
+
{ name: "README.md", content: "# reading pal" },
|
|
242
|
+
],
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
await installPluginFromPlatform(
|
|
246
|
+
{ name: "reading-pal" },
|
|
247
|
+
{
|
|
248
|
+
fetch: fetchFn,
|
|
249
|
+
platformBaseUrl: PLATFORM,
|
|
250
|
+
workspacePluginsDir: pluginsDir,
|
|
251
|
+
},
|
|
252
|
+
);
|
|
253
|
+
|
|
254
|
+
const pkg = JSON.parse(
|
|
255
|
+
readFileSync(join(pluginsDir, "reading-pal", "package.json"), "utf-8"),
|
|
256
|
+
);
|
|
257
|
+
expect(pkg.name).toBe("reading-pal");
|
|
258
|
+
expect(pkg.version).toBe("1.2.3");
|
|
259
|
+
});
|
|
260
|
+
|
|
189
261
|
test("sends the API key as an Api-Key Authorization header when present", async () => {
|
|
190
262
|
const captured: { auth: string | null } = { auth: null };
|
|
191
263
|
const fetchFn = makeInstallFetch({
|
|
@@ -5,6 +5,8 @@
|
|
|
5
5
|
* time — no network, no filesystem path resolution.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { readFileSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
8
10
|
import { describe, expect, test } from "bun:test";
|
|
9
11
|
|
|
10
12
|
import bundledManifest from "../bundled-marketplace.json" with { type: "json" };
|
|
@@ -12,6 +14,15 @@ import {
|
|
|
12
14
|
buildBundledPluginCatalog,
|
|
13
15
|
readBundledPluginCatalog,
|
|
14
16
|
} from "../plugin-catalog-local.js";
|
|
17
|
+
import { marketplaceManifestSchema } from "../plugin-marketplace.js";
|
|
18
|
+
import { marketplaceMatch } from "../search-plugins.js";
|
|
19
|
+
|
|
20
|
+
const canonicalManifest = JSON.parse(
|
|
21
|
+
readFileSync(
|
|
22
|
+
join(import.meta.dir, "../../../../../plugins/marketplace.json"),
|
|
23
|
+
"utf8",
|
|
24
|
+
),
|
|
25
|
+
) as unknown;
|
|
15
26
|
|
|
16
27
|
describe("buildBundledPluginCatalog", () => {
|
|
17
28
|
test("yields one match per unique manifest name, sorted alphabetically", () => {
|
|
@@ -53,6 +64,28 @@ describe("buildBundledPluginCatalog", () => {
|
|
|
53
64
|
});
|
|
54
65
|
});
|
|
55
66
|
|
|
67
|
+
test("projects the OpenSEO subdirectory pin from the canonical catalog", () => {
|
|
68
|
+
const parsed = marketplaceManifestSchema.parse(canonicalManifest);
|
|
69
|
+
const entry = parsed.plugins.find((plugin) => plugin.name === "openseo");
|
|
70
|
+
expect(entry).toBeDefined();
|
|
71
|
+
expect(marketplaceMatch(entry!)).toEqual({
|
|
72
|
+
name: "openseo",
|
|
73
|
+
path: "github:every-app/open-seo/plugins/openseo@c469a48ae90ab58413b198fe3d1ac1aa90a9b070",
|
|
74
|
+
description:
|
|
75
|
+
"Keyword research, competitor analysis, site audits, backlinks, and rank tracking with real SEO data, plus guided workflow skills and the hosted OpenSEO MCP server.",
|
|
76
|
+
category: "marketing",
|
|
77
|
+
homepage: "https://openseo.so",
|
|
78
|
+
license: "MIT",
|
|
79
|
+
icon: "🔎",
|
|
80
|
+
source: {
|
|
81
|
+
kind: "github",
|
|
82
|
+
repo: "every-app/open-seo",
|
|
83
|
+
path: "plugins/openseo",
|
|
84
|
+
ref: "c469a48ae90ab58413b198fe3d1ac1aa90a9b070",
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
56
89
|
test("throws on a malformed manifest", () => {
|
|
57
90
|
expect(() => buildBundledPluginCatalog({ plugins: [{}] })).toThrow();
|
|
58
91
|
});
|
|
@@ -318,6 +318,20 @@
|
|
|
318
318
|
"license": "MIT",
|
|
319
319
|
"icon": "💳"
|
|
320
320
|
},
|
|
321
|
+
{
|
|
322
|
+
"name": "openseo",
|
|
323
|
+
"source": {
|
|
324
|
+
"source": "github",
|
|
325
|
+
"repo": "every-app/open-seo",
|
|
326
|
+
"path": "plugins/openseo",
|
|
327
|
+
"ref": "c469a48ae90ab58413b198fe3d1ac1aa90a9b070"
|
|
328
|
+
},
|
|
329
|
+
"description": "Keyword research, competitor analysis, site audits, backlinks, and rank tracking with real SEO data, plus guided workflow skills and the hosted OpenSEO MCP server.",
|
|
330
|
+
"category": "marketing",
|
|
331
|
+
"homepage": "https://openseo.so",
|
|
332
|
+
"license": "MIT",
|
|
333
|
+
"icon": "🔎"
|
|
334
|
+
},
|
|
321
335
|
{
|
|
322
336
|
"name": "originkit",
|
|
323
337
|
"source": {
|
|
@@ -1134,12 +1134,16 @@ function normalizeInstalledManifest(
|
|
|
1134
1134
|
* (`buildPluginFromDir`) hard-requires a `package.json` validated against
|
|
1135
1135
|
* `PluginPackageJsonSchema` and silently skips the plugin when it's missing.
|
|
1136
1136
|
*
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1137
|
+
* Used by both the GitHub clone path and the platform tarball path. The
|
|
1138
|
+
* synthesized manifest carries the install name and the default
|
|
1139
|
+
* `@vellumai/plugin-api` peer dependency range. No foreign-ecosystem
|
|
1140
|
+
* manifest data is read: the install name is the only identity we trust
|
|
1141
|
+
* when upstream ships no Vellum package.json.
|
|
1141
1142
|
*/
|
|
1142
|
-
function synthesizeMinimalPackageJson(
|
|
1143
|
+
export function synthesizeMinimalPackageJson(
|
|
1144
|
+
name: string,
|
|
1145
|
+
stagingDir: string,
|
|
1146
|
+
): void {
|
|
1143
1147
|
const manifestPath = join(stagingDir, "package.json");
|
|
1144
1148
|
|
|
1145
1149
|
const manifest: PackageManifest = {
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
* and extracts it into the plugin's install directory — it does NOT clone the
|
|
9
9
|
* plugin from GitHub itself, and it does NOT emit `plugin_installed` telemetry
|
|
10
10
|
* (hitting this endpoint *is* the recorded install; the server rejects that
|
|
11
|
-
* event type on the usual ingest path).
|
|
11
|
+
* event type on the usual ingest path). A tarball that ships no
|
|
12
|
+
* `package.json` gets the same synthesized manifest the GitHub clone path
|
|
13
|
+
* writes, so the loader still registers the plugin's skills.
|
|
12
14
|
*
|
|
13
15
|
* GET {PLATFORM_BASE_URL}/v1/plugins/{name}/install/
|
|
14
16
|
*
|
|
@@ -42,6 +44,7 @@ import {
|
|
|
42
44
|
PluginNotFoundError,
|
|
43
45
|
PluginSourceUnavailableError,
|
|
44
46
|
sanitizePluginName,
|
|
47
|
+
synthesizeMinimalPackageJson,
|
|
45
48
|
} from "./install-from-github.js";
|
|
46
49
|
|
|
47
50
|
/**
|
|
@@ -198,6 +201,14 @@ export async function installPluginFromPlatform(
|
|
|
198
201
|
throw new PluginNotFoundError(name, meta.ref ?? "", meta.repo ?? name);
|
|
199
202
|
}
|
|
200
203
|
|
|
204
|
+
// Same default as the GitHub clone path: a marketplace tarball that
|
|
205
|
+
// ships skills/mcp.json but no Vellum package.json still has to load.
|
|
206
|
+
// The loader skips a directory with no manifest, so synthesize one
|
|
207
|
+
// before the fingerprint and swap.
|
|
208
|
+
if (!existsSync(join(stagingDir, "package.json"))) {
|
|
209
|
+
synthesizeMinimalPackageJson(name, stagingDir);
|
|
210
|
+
}
|
|
211
|
+
|
|
201
212
|
await confirmStagedOrAbort(name, stagingDir, deps.confirmStaged);
|
|
202
213
|
|
|
203
214
|
// Record provenance for future update/version UX. The endpoint re-roots the
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The gate reads a string-valued flag that does not always arrive as a
|
|
3
|
+
* string.
|
|
4
|
+
*
|
|
5
|
+
* The registry and the gateway's persisted store carry the declared `"on"` /
|
|
6
|
+
* `"off"` strings. The gateway's env-override path does not: its parser
|
|
7
|
+
* (`feature-flag-env-overrides.ts`) treats `on` as a truthy *word* and
|
|
8
|
+
* coerces it to boolean `true`, then applies env overrides last — so
|
|
9
|
+
* `VELLUM_FLAG_ASSISTANT_INITIATED_THREADS=on` reaches the daemon as `true`.
|
|
10
|
+
*
|
|
11
|
+
* A strict `=== "on"` therefore read the documented env kill-switch as OFF,
|
|
12
|
+
* and did it silently: the section just never rendered. That shipped in the
|
|
13
|
+
* first cut of this gate and cost an afternoon of QA, which is why both
|
|
14
|
+
* shapes are pinned here rather than only the one the registry emits.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import { afterEach, describe, expect, mock, test } from "bun:test";
|
|
18
|
+
|
|
19
|
+
let flagValue: boolean | string = "off";
|
|
20
|
+
|
|
21
|
+
mock.module("../assistant-feature-flags.js", () => ({
|
|
22
|
+
getAssistantFeatureFlagValue: () => flagValue,
|
|
23
|
+
}));
|
|
24
|
+
|
|
25
|
+
const { isAssistantInitiatedThreadsEnabled } = await import(
|
|
26
|
+
"../assistant-initiated-threads-gate.js"
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
flagValue = "off";
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("isAssistantInitiatedThreadsEnabled", () => {
|
|
34
|
+
test('enabled by the declared string "on" (registry / persisted store)', () => {
|
|
35
|
+
flagValue = "on";
|
|
36
|
+
expect(isAssistantInitiatedThreadsEnabled()).toBe(true);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
test("enabled by boolean true (the gateway's env-override coercion)", () => {
|
|
40
|
+
// The regression. `VELLUM_FLAG_ASSISTANT_INITIATED_THREADS=on` arrives
|
|
41
|
+
// here as `true`, never as "on".
|
|
42
|
+
flagValue = true;
|
|
43
|
+
expect(isAssistantInitiatedThreadsEnabled()).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('disabled by the declared string "off"', () => {
|
|
47
|
+
flagValue = "off";
|
|
48
|
+
expect(isAssistantInitiatedThreadsEnabled()).toBe(false);
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("disabled by boolean false (env `=off` coercion)", () => {
|
|
52
|
+
flagValue = false;
|
|
53
|
+
expect(isAssistantInitiatedThreadsEnabled()).toBe(false);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("fails closed on an unrecognized arm", () => {
|
|
57
|
+
// A future A/B value this gate has no opinion about must not read as on.
|
|
58
|
+
flagValue = "variant-b";
|
|
59
|
+
expect(isAssistantInitiatedThreadsEnabled()).toBe(false);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { getAssistantFeatureFlagValue } from "./assistant-feature-flags.js";
|
|
2
|
+
import type { AssistantConfig } from "./schema.js";
|
|
3
|
+
|
|
4
|
+
const ASSISTANT_INITIATED_THREADS_FLAG_KEY =
|
|
5
|
+
"assistant-initiated-threads" as const;
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Whether the conversations the assistant started on its own are split into
|
|
9
|
+
* their own sidebar section instead of sitting in Chats.
|
|
10
|
+
*
|
|
11
|
+
* Read through {@link getAssistantFeatureFlagValue} rather than
|
|
12
|
+
* `isAssistantFeatureFlagEnabled`, because the flag is string-valued: that
|
|
13
|
+
* helper coerces with `!!`, and `!!"off"` is `true`, so the boolean form would
|
|
14
|
+
* report the off arm as on.
|
|
15
|
+
*
|
|
16
|
+
* A read-side gate only. The rows exist either way — every notification
|
|
17
|
+
* delivery has always materialized one (`notifications/conversation-pairing.ts`)
|
|
18
|
+
* — so turning the flag off puts them back in Chats and takes the `assistant`
|
|
19
|
+
* row out of the section index, with nothing to migrate in either direction.
|
|
20
|
+
*
|
|
21
|
+
* This is the *only* gate on the feature, which is why the flag is
|
|
22
|
+
* assistant-scope rather than `both`. Clients render the section on the
|
|
23
|
+
* presence of the index row, because that row is what says the daemon has
|
|
24
|
+
* withheld those conversations from Chats. A second, client-side gate could
|
|
25
|
+
* only ever hide a section whose rows have already been withheld — losing
|
|
26
|
+
* those threads rather than reverting the feature — so there deliberately
|
|
27
|
+
* isn't one.
|
|
28
|
+
*/
|
|
29
|
+
export function isAssistantInitiatedThreadsEnabled(
|
|
30
|
+
config?: AssistantConfig,
|
|
31
|
+
): boolean {
|
|
32
|
+
const value = getAssistantFeatureFlagValue(
|
|
33
|
+
ASSISTANT_INITIATED_THREADS_FLAG_KEY,
|
|
34
|
+
config,
|
|
35
|
+
);
|
|
36
|
+
/* Both shapes are the same answer, and the on arm arrives as either one
|
|
37
|
+
depending on which layer resolved it.
|
|
38
|
+
|
|
39
|
+
The registry and the gateway's persisted store carry the declared string
|
|
40
|
+
(`"on"`). The gateway's env-override path does not: its parser treats
|
|
41
|
+
`on` as a truthy word (`TRUTHY = {"true","1","yes","on"}` in
|
|
42
|
+
`feature-flag-env-overrides.ts`) and coerces it to boolean `true`, then
|
|
43
|
+
applies env last — so `VELLUM_FLAG_ASSISTANT_INITIATED_THREADS=on`
|
|
44
|
+
reaches the daemon as `true`, not `"on"`.
|
|
45
|
+
|
|
46
|
+
A strict `=== "on"` therefore reads the env kill-switch as OFF, which is
|
|
47
|
+
the exact opposite of what an operator setting it intends, and it fails
|
|
48
|
+
silently: the section simply does not render. Accept both. */
|
|
49
|
+
return value === true || value === "on";
|
|
50
|
+
}
|
|
@@ -8,12 +8,11 @@ metadata:
|
|
|
8
8
|
display-name: "ACP"
|
|
9
9
|
category: "development"
|
|
10
10
|
activation-hints:
|
|
11
|
-
- "User wants to set up, install, configure, authenticate, or
|
|
12
|
-
- "User asks to use Claude Code or Codex, or delegate a coding task to an ACP agent"
|
|
11
|
+
- "User names Claude Code or Codex, or wants to set up, install, configure, authenticate, connect, use, or delegate work to them"
|
|
13
12
|
- "User wants an agent to work autonomously and report back later"
|
|
14
13
|
- "User mentions ACP, claude-agent-acp, or codex-acp"
|
|
15
14
|
avoid-when:
|
|
16
|
-
- "The task is small enough to do inline"
|
|
15
|
+
- "The task is small enough to do inline and the user did not name Claude Code or Codex"
|
|
17
16
|
---
|
|
18
17
|
|
|
19
18
|
ACP agent orchestration - spawn external coding agents (Claude Code, Codex) to work on tasks via the Agent Client Protocol. Each agent runs as its own subprocess speaking ACP over stdio and streams results back into the conversation.
|
|
@@ -24,6 +23,14 @@ Use `acp_spawn` to delegate a coding task to an external agent. The agent runs a
|
|
|
24
23
|
|
|
25
24
|
Users can refer to agents by natural names: "claude code", "codex cli", and "openai codex" all resolve to the canonical `claude` and `codex` ids (unless the user's config defines an agent literally keyed by that name, which always wins).
|
|
26
25
|
|
|
26
|
+
## When the user names Claude Code or Codex
|
|
27
|
+
|
|
28
|
+
If they name Claude Code or Codex without asking you to run it here (for example they say that tool will do the work), offer once, in one short sentence, that you can connect and run it in this conversation. Then continue with whatever they were doing.
|
|
29
|
+
|
|
30
|
+
- Do not spawn unless they accept.
|
|
31
|
+
- Skip if you already offered this conversation, they declined, or they are already connected.
|
|
32
|
+
- This is not the missing-token card path. Do not invent setup steps.
|
|
33
|
+
|
|
27
34
|
## First-time setup
|
|
28
35
|
|
|
29
36
|
ACP is always available - default profiles for `claude` and `codex` ship out-of-box, so no config edit is needed to start. First-time setup is just making the adapter binary available, then spawning:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: schedule
|
|
3
|
-
description:
|
|
3
|
+
description: Reminders, automations, and recurring page, dashboard, or status monitoring (cron, RRULE, or fire-at)
|
|
4
4
|
compatibility: "Designed for Vellum personal assistants"
|
|
5
5
|
metadata:
|
|
6
6
|
emoji: "📅"
|
|
@@ -8,17 +8,28 @@ metadata:
|
|
|
8
8
|
display-name: "Schedule"
|
|
9
9
|
category: "productivity"
|
|
10
10
|
activation-hints:
|
|
11
|
-
- "User wants
|
|
12
|
-
- "User wants
|
|
13
|
-
- "User wants to
|
|
14
|
-
- "User wants
|
|
11
|
+
- "User wants a reminder"
|
|
12
|
+
- "User wants a recurring task or nightly check"
|
|
13
|
+
- "User wants to monitor a page, dashboard, or status and get alerts"
|
|
14
|
+
- "User wants a one-time future action"
|
|
15
|
+
- "User wants to manage existing schedules"
|
|
15
16
|
avoid-when:
|
|
16
|
-
- "User wants
|
|
17
|
-
- "User wants
|
|
17
|
+
- "User wants a task-list item"
|
|
18
|
+
- "User wants a one-off that finishes now. Recurring-job setup still uses this skill"
|
|
18
19
|
---
|
|
19
20
|
|
|
20
21
|
Manage scheduled automations. Schedules can be **recurring** (cron or RRULE expression) or **one-shot** (a single `fire_at` timestamp). Schedules support four modes: **execute** (run a message through the assistant), **notify** (send a notification to the user), **script** (run a shell command directly without LLM involvement), and **workflow** (run a saved multi-agent workflow by name).
|
|
21
22
|
|
|
23
|
+
## Recurring Monitoring
|
|
24
|
+
|
|
25
|
+
When the user wants something checked on a cadence (a status page, dashboard, site, or similar) and to be told if it is wrong, late, or missing: create a schedule. Do not author a standalone script they have to download, run, or maintain.
|
|
26
|
+
|
|
27
|
+
- Recurrence, cutoff times, escalation, and notifications are schedule and notification primitives. Do not reimplement them in a workspace file the user has to run.
|
|
28
|
+
- Prefer **execute** mode: the scheduled message browses or fetches the source, applies the user's rules, and notifies on exceptions. Use **script** mode only for a cheap deterministic check against a live source the assistant can already reach (curl an API, read a file in the workspace). A script-mode job is still a schedule, not a file you hand the user.
|
|
29
|
+
- Looking at a page, pasting HTML, or gathering a roster is setup for the schedule, not a reason to skip creating one.
|
|
30
|
+
- If browsing cannot reach the page, still create the schedule. Offer the desktop app (https://www.vellum.ai/download) or the Chrome extension (https://chromewebstore.google.com/detail/vellum-assistant-browser/hphbdmpffeigpcdjkckleobjmhhokpne) so a logged-in browser session can run it. Do not replace the schedule with a parser against a pasted export, and do not assign comparison-run homework before anything is scheduled.
|
|
31
|
+
- Watchers cover Gmail, Google Calendar, GitHub, Linear, and Outlook event polling. An arbitrary web page or status dashboard is this skill, not the watcher skill.
|
|
32
|
+
|
|
22
33
|
## Schedule Syntax
|
|
23
34
|
|
|
24
35
|
### Cron
|
|
@@ -119,6 +130,8 @@ assistant conversations wake "$id" --hint "Summarize the new items" --external-c
|
|
|
119
130
|
|
|
120
131
|
**Secrets.** For an OAuth-connected provider (google, slack, notion, …), call its API with `assistant oauth request --provider <p> <url>` — the assistant injects the token, and the script never sees it. For raw secrets with no OAuth provider (PATs, API keys), collect at install time with `assistant credentials prompt --service <s> --field <f> --label "<label>"` (secure input, never printed to chat) and read at runtime with `assistant credentials reveal --service <s> --field <f>`.
|
|
121
132
|
|
|
133
|
+
When a scheduled or background run is blocked on a missing or stale credential, tell the user in the notification that the credential needs refreshing and ask them to reply in the thread so you can open the secure prompt. Never put a CLI command in the notification or the tick summary. The user cannot run those from their terminal.
|
|
134
|
+
|
|
122
135
|
## Inference Profile
|
|
123
136
|
|
|
124
137
|
Every schedule carries a pinned `inference_profile` (a key from `llm.profiles`), so a recurring task keeps running on the model (and the price) it was created under even when the user later changes their default profile. Creating a schedule without `inference_profile` pins it to the user's current default; pass one explicitly when a task should run on a specific model, e.g. a cost-optimized profile for a high-frequency digest. Passing `inference_profile: null` on update re-pins the schedule to the user's current default rather than unpinning it. The pinned profile is shown on the schedule's details page in settings.
|
|
@@ -213,14 +226,15 @@ When `schedule_create` returns, it includes an integration status summary. Cross
|
|
|
213
226
|
|
|
214
227
|
- If the task involves **email** (reading, sending, OTP verification): an email integration must be connected (check the "email" category)
|
|
215
228
|
- If the task involves **making calls**: Twilio must be connected
|
|
216
|
-
- If the task involves **web browsing or form-filling**: browser automation must be available (check client type)
|
|
229
|
+
- If the task involves **web browsing or form-filling**: browser automation must be available (check client type). A timeout, auth wall, or missing logged-in browser is a setup gap, not a reason to skip the schedule or to write a standalone script.
|
|
217
230
|
- If the task involves a **multi-step workflow** (e.g., book appointment → read confirmation email), trace the full dependency chain
|
|
218
231
|
|
|
219
232
|
If any required capability is missing:
|
|
220
233
|
|
|
221
|
-
1. **
|
|
222
|
-
2.
|
|
223
|
-
3.
|
|
234
|
+
1. **Still create the schedule** so timing is preserved. Do not tell the user it is ready to run.
|
|
235
|
+
2. Explain what is missing and why the next fire will fail until that is fixed.
|
|
236
|
+
3. Offer to set up the missing integration first. For a page the assistant cannot reach, offer the desktop app (https://www.vellum.ai/download) or the Chrome extension (https://chromewebstore.google.com/detail/vellum-assistant-browser/hphbdmpffeigpcdjkckleobjmhhokpne) before asking for a screenshot or pasted export.
|
|
237
|
+
4. Do not replace the schedule with a workspace script the user has to run themselves.
|
|
224
238
|
|
|
225
239
|
## Delivering Results
|
|
226
240
|
|
|
@@ -56,4 +56,6 @@ fi
|
|
|
56
56
|
|
|
57
57
|
## Tips
|
|
58
58
|
|
|
59
|
-
Both patterns keep scheduled runs fast and cheap
|
|
59
|
+
Both patterns keep scheduled runs fast and cheap. The script exits immediately when nothing interesting happens, and only reaches for the assistant or notification system when there's something to act on. Use `quiet: true` on the schedule to suppress the per-run completion noise.
|
|
60
|
+
|
|
61
|
+
A script-mode schedule is still a schedule the user can see, pause, and edit. Do not hand them a standalone file to run themselves.
|
|
@@ -123,8 +123,11 @@ export const CALL_SITE_DEFAULTS: Record<LLMCallSite, CallSiteDefaultConfig> = {
|
|
|
123
123
|
effort: "low",
|
|
124
124
|
thinking: { enabled: false },
|
|
125
125
|
},
|
|
126
|
+
// The dictation cleanup pass, and nothing else runs on this site. The
|
|
127
|
+
// caller has already stopped speaking and has nothing on screen until this
|
|
128
|
+
// answers, so it is priced as a latency call.
|
|
126
129
|
interactionClassifier: {
|
|
127
|
-
profile: "
|
|
130
|
+
profile: "latency-optimized",
|
|
128
131
|
effort: "low",
|
|
129
132
|
thinking: { enabled: false },
|
|
130
133
|
},
|
|
@@ -36,6 +36,15 @@
|
|
|
36
36
|
"defaultEnabled": "off",
|
|
37
37
|
"values": ["off", "on"]
|
|
38
38
|
},
|
|
39
|
+
{
|
|
40
|
+
"id": "assistant-initiated-threads",
|
|
41
|
+
"scope": "assistant",
|
|
42
|
+
"key": "assistant-initiated-threads",
|
|
43
|
+
"label": "Assistant-Initiated Threads",
|
|
44
|
+
"description": "Gates the sidebar section collecting the conversations the assistant started on its own: rows stamped `source='assistant_initiated'` at creation by producers that opt a thread in (heartbeat realizations worth the user's time; nothing stamps it yet, so the section starts empty and holds only new threads by construction). Transactional notification trails keep `source='notification'` and stay in Chats and the bell. When on, the daemon emits an `assistant` row from the section index and withholds member conversations from the Chats bucket; when off, they stay in Chats and no `assistant` row is emitted, which is the shipped behavior. Deliberately daemon-scope only: the index row is self-describing, so clients render the section on its presence rather than on a flag of their own. A second client-side gate could only hide a section whose rows the daemon has already withheld from Chats, which would lose those threads instead of reverting the feature. String-valued so future A/B arms can be added as new values.",
|
|
45
|
+
"defaultEnabled": "off",
|
|
46
|
+
"values": ["off", "on"]
|
|
47
|
+
},
|
|
39
48
|
{
|
|
40
49
|
"id": "experiment-activation-flow-2026-06-03",
|
|
41
50
|
"scope": "both",
|
|
@@ -189,6 +198,14 @@
|
|
|
189
198
|
"description": "Show a live HUD in the top-right of the conversation with scroll geometry, velocity, update rate, and anchor-preserver activity. Developer diagnostic for investigating scroll jank.",
|
|
190
199
|
"defaultEnabled": false
|
|
191
200
|
},
|
|
201
|
+
{
|
|
202
|
+
"id": "camera-gate-debug-hud",
|
|
203
|
+
"scope": "client",
|
|
204
|
+
"key": "camera-gate-debug-hud",
|
|
205
|
+
"label": "Camera Gate Debug HUD",
|
|
206
|
+
"description": "Unlock the camera frame gate's tuning readout: the switch in the camera's view options that turns it on, and the live panel over the composer's sight tile and the voice room's viewfinder showing motion, novelty and detail against their thresholds, the check that decided each frame, and sliders that move those thresholds while the camera runs. Staff sessions get it without the flag; the flag is for local gateway sessions, which carry no platform identity and are where the gate is tuned.",
|
|
207
|
+
"defaultEnabled": false
|
|
208
|
+
},
|
|
192
209
|
{
|
|
193
210
|
"id": "compaction-playground",
|
|
194
211
|
"scope": "assistant",
|
|
@@ -391,11 +408,11 @@
|
|
|
391
408
|
"values": ["glm-5p3-flash", "glm-5p3", "glm-5p2"]
|
|
392
409
|
},
|
|
393
410
|
{
|
|
394
|
-
"id": "
|
|
411
|
+
"id": "android-avatar-app-icon",
|
|
395
412
|
"scope": "client",
|
|
396
|
-
"key": "
|
|
397
|
-
"label": "
|
|
398
|
-
"description": "Shows the App icon picker in Settings -> General, where any user chooses an eyes-on-color
|
|
413
|
+
"key": "android-avatar-app-icon",
|
|
414
|
+
"label": "Android Avatar App Icon",
|
|
415
|
+
"description": "Shows the App icon picker in Settings -> General on Android, where any user chooses an eyes-on-color launcher icon, seeds the picker from their assistant's character avatar, or resets to the default. Android applies the change when the app goes to the background, and switching icons can reset a pinned home-screen shortcut. Off hides the picker and leaves the default icon in place.",
|
|
399
416
|
"defaultEnabled": false
|
|
400
417
|
},
|
|
401
418
|
{
|
|
@@ -144,11 +144,12 @@ export const MemoryV3LearnedEdgesSchema = z
|
|
|
144
144
|
);
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
|
-
*
|
|
147
|
+
* Per-turn section-spotlight tuning: how many of the current turn's selected
|
|
148
148
|
* finder hits render their matched section into the `<memory_spotlight>`
|
|
149
149
|
* block, and how many previous turns' spotlight entries are carried along
|
|
150
|
-
* before they age out.
|
|
151
|
-
*
|
|
150
|
+
* before they age out. Each turn keeps the block it was sent with. A new
|
|
151
|
+
* spotlight is added only on the new tail. Size is bounded by
|
|
152
|
+
* `n × (windowTurns + 1)` entries.
|
|
152
153
|
*/
|
|
153
154
|
export const MemoryV3SpotlightSchema = z
|
|
154
155
|
.object({
|