@vellumai/assistant 0.8.2 → 0.8.3
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 +11 -12
- package/docker-entrypoint.sh +13 -1
- package/docker-init-apt-root.sh +79 -6
- package/openapi.yaml +336 -21
- package/package.json +1 -1
- package/src/__tests__/agent-loop-exit-reason.test.ts +272 -0
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +195 -0
- package/src/__tests__/compactor-tail-resolution.test.ts +107 -1
- package/src/__tests__/config-get-vision-flag.test.ts +136 -0
- package/src/__tests__/config-loader-backfill.test.ts +115 -18
- package/src/__tests__/context-token-estimator.test.ts +30 -65
- package/src/__tests__/conversation-agent-loop.test.ts +57 -1
- package/src/__tests__/conversation-media-retry.test.ts +19 -8
- package/src/__tests__/conversation-runtime-assembly.test.ts +26 -4
- package/src/__tests__/date-context.test.ts +45 -0
- package/src/__tests__/external-plugin-loader.test.ts +91 -19
- package/src/__tests__/guardian-action-no-hardcoded-copy.test.ts +0 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +24 -164
- package/src/__tests__/helpers/channel-test-adapter.ts +0 -2
- package/src/__tests__/host-app-control-proxy.test.ts +241 -0
- package/src/__tests__/host-proxy-preactivation.test.ts +200 -13
- package/src/__tests__/injector-background-turn.test.ts +153 -0
- package/src/__tests__/injector-chain.test.ts +5 -0
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +9 -2
- package/src/__tests__/llm-callsite-catalog.test.ts +25 -0
- package/src/__tests__/llm-catalog-parity.test.ts +3 -0
- package/src/__tests__/llm-request-log-agent-loop-exit-reason.test.ts +116 -0
- package/src/__tests__/llm-request-log-error-payload.test.ts +138 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +2 -0
- package/src/__tests__/llm-resolver.test.ts +255 -2
- package/src/__tests__/managed-profile-guard.test.ts +10 -0
- package/src/__tests__/notification-decision-fallback.test.ts +0 -91
- package/src/__tests__/notification-decision-strategy.test.ts +14 -31
- package/src/__tests__/notification-deep-link.test.ts +15 -0
- package/src/__tests__/notification-guardian-path.test.ts +1 -2
- package/src/__tests__/notification-platform-adapter.test.ts +5 -4
- package/src/__tests__/notification-telegram-adapter.test.ts +1 -0
- package/src/__tests__/notification-vellum-adapter.test.ts +113 -0
- package/src/__tests__/openai-provider.test.ts +218 -3
- package/src/__tests__/openai-responses-cutover-guard.test.ts +3 -3
- package/src/__tests__/openrouter-provider-only.test.ts +51 -3
- package/src/__tests__/openrouter-token-estimation.test.ts +34 -25
- package/src/__tests__/platform-proxy-context.test.ts +6 -1
- package/src/__tests__/plugin-tool-contribution.test.ts +3 -3
- package/src/__tests__/plugin-types.test.ts +2 -2
- package/src/__tests__/provider-catalog-visibility.test.ts +16 -0
- package/src/__tests__/provider-platform-proxy-integration.test.ts +27 -25
- package/src/__tests__/secret-routes-platform-proxy.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +6 -73
- package/src/__tests__/workspace-migration-087-memory-router-balanced-profile.test.ts +228 -0
- package/src/a2a/__tests__/agent-card.test.ts +98 -0
- package/src/a2a/__tests__/e2e-a2a-channel.test.ts +597 -0
- package/src/a2a/__tests__/protocol-helpers.test.ts +113 -0
- package/src/a2a/__tests__/task-store.test.ts +246 -0
- package/src/a2a/agent-card.ts +58 -0
- package/src/a2a/feature-gate.ts +8 -0
- package/src/a2a/protocol-constants.ts +21 -0
- package/src/a2a/protocol-errors.ts +50 -0
- package/src/a2a/protocol-types.ts +162 -0
- package/src/a2a/task-store.ts +168 -0
- package/src/agent/loop.ts +167 -18
- package/src/channels/config.ts +9 -0
- package/src/channels/types.ts +14 -0
- package/src/cli/{__tests__ → commands/__tests__}/notifications.test.ts +201 -28
- package/src/cli/commands/__tests__/schedules.test.ts +469 -0
- package/src/cli/commands/notifications.ts +65 -35
- package/src/cli/commands/plugins.ts +67 -0
- package/src/cli/commands/schedules.ts +297 -5
- package/src/cli/lib/__tests__/search-plugins.test.ts +261 -0
- package/src/cli/lib/install-from-github.ts +8 -9
- package/src/cli/lib/search-plugins.ts +163 -0
- package/src/cli/program.ts +14 -0
- package/src/config/assistant-feature-flags.ts +24 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +117 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +1 -1
- package/src/config/call-site-defaults.ts +105 -0
- package/src/config/feature-flag-registry.json +21 -29
- package/src/config/llm-resolver.ts +52 -1
- package/src/config/schema.ts +2 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +3 -3
- package/src/config/schemas/channels.ts +9 -0
- package/src/config/schemas/conversations.ts +10 -0
- package/src/config/schemas/heartbeat.ts +14 -0
- package/src/config/schemas/llm.ts +1 -3
- package/src/config/schemas/memory-retrospective.ts +1 -1
- package/src/config/schemas/memory-v2.ts +4 -4
- package/src/config/schemas/memory.ts +3 -1
- package/src/config/seed-inference-profiles.ts +99 -29
- package/src/context/compactor.ts +72 -12
- package/src/context/token-estimator.ts +32 -34
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -22
- package/src/daemon/conversation-agent-loop-handlers.ts +78 -0
- package/src/daemon/conversation-agent-loop.ts +29 -2
- package/src/daemon/conversation-runtime-assembly.ts +9 -0
- package/src/daemon/conversation.ts +0 -7
- package/src/daemon/date-context.ts +40 -0
- package/src/daemon/guardian-action-generators.ts +1 -125
- package/src/daemon/handlers/__tests__/config-a2a-complete.test.ts +248 -0
- package/src/daemon/handlers/__tests__/config-a2a-invite.test.ts +154 -0
- package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +133 -0
- package/src/daemon/handlers/__tests__/config-a2a.test.ts +95 -0
- package/src/daemon/handlers/config-a2a.ts +289 -0
- package/src/daemon/handlers/conversations.ts +1 -0
- package/src/daemon/host-app-control-proxy.ts +69 -18
- package/src/daemon/host-proxy-preactivation.ts +85 -18
- package/src/daemon/lifecycle.ts +49 -61
- package/src/daemon/memory-v2-startup.ts +49 -13
- package/src/daemon/message-types/notifications.ts +21 -0
- package/src/daemon/pkb-reminder-builder.test.ts +10 -53
- package/src/daemon/pkb-reminder-builder.ts +4 -19
- package/src/daemon/process-message.ts +3 -0
- package/src/daemon/skill-memory-refresh.ts +5 -1
- package/src/daemon/wake-target-adapter.ts +2 -0
- package/src/export/__tests__/transcript-formatter.test.ts +121 -0
- package/src/export/transcript-formatter.ts +54 -20
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +44 -0
- package/src/heartbeat/heartbeat-service.ts +34 -191
- package/src/home/__tests__/feed-types.test.ts +40 -0
- package/src/home/feed-types.ts +14 -2
- package/src/ipc/cli-client.ts +147 -45
- package/src/memory/__tests__/conversation-queries.test.ts +220 -0
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +2 -50
- package/src/memory/__tests__/memory-retrospective-job.test.ts +87 -4
- package/src/memory/conversation-queries.ts +87 -1
- package/src/memory/conversation-title-service.ts +26 -4
- package/src/memory/db-init.ts +6 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +84 -3
- package/src/memory/graph/conversation-graph-memory.ts +18 -6
- package/src/memory/graph/tools.ts +6 -37
- package/src/memory/invite-store.ts +53 -0
- package/src/memory/llm-request-log-source-clickhouse.ts +7 -2
- package/src/memory/llm-request-log-store.ts +92 -1
- package/src/memory/memory-retrospective-enqueue.ts +1 -20
- package/src/memory/memory-retrospective-job.ts +33 -6
- package/src/memory/migrations/250-provider-connection-base-url-and-models.ts +28 -0
- package/src/memory/migrations/251-a2a-tasks.ts +49 -0
- package/src/memory/migrations/252-llm-request-log-agent-loop-exit-reason.ts +32 -0
- package/src/memory/migrations/index.ts +3 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/a2a.ts +15 -0
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/inference.ts +2 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +25 -23
- package/src/memory/v2/__tests__/cli-command-store.test.ts +404 -0
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +25 -4
- package/src/memory/v2/__tests__/injection.test.ts +190 -3
- package/src/memory/v2/__tests__/static-context.test.ts +12 -1
- package/src/memory/v2/activation-store.ts +14 -16
- package/src/memory/v2/cli-command-content.ts +19 -0
- package/src/memory/v2/cli-command-store.ts +304 -0
- package/src/memory/v2/frontmatter-sweep.ts +7 -1
- package/src/memory/v2/injection.ts +49 -20
- package/src/memory/v2/page-index.ts +38 -13
- package/src/memory/v2/static-context.ts +4 -4
- package/src/memory/v2/types.ts +23 -0
- package/src/messaging/providers/a2a/__tests__/deliver.test.ts +274 -0
- package/src/messaging/providers/a2a/deliver.ts +156 -0
- package/src/messaging/providers/gmail/client.ts +9 -2
- package/src/messaging/providers/index.ts +11 -2
- package/src/notifications/__tests__/broadcaster.test.ts +203 -0
- package/src/notifications/__tests__/decision-engine.test.ts +283 -0
- package/src/notifications/__tests__/deterministic-checks.test.ts +286 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +430 -7
- package/src/notifications/adapters/macos.ts +12 -2
- package/src/notifications/broadcaster.ts +29 -4
- package/src/notifications/copy-composer.ts +17 -64
- package/src/notifications/decision-engine.ts +111 -44
- package/src/notifications/deterministic-checks.ts +96 -0
- package/src/notifications/emit-signal.ts +1 -0
- package/src/notifications/home-feed-side-effect.ts +85 -6
- package/src/notifications/signal.ts +0 -4
- package/src/notifications/types.ts +8 -0
- package/src/oauth/platform-connection.test.ts +43 -3
- package/src/oauth/platform-connection.ts +13 -4
- package/src/plugins/defaults/injectors.ts +38 -19
- package/src/plugins/external-plugin-loader.ts +82 -10
- package/src/plugins/types.ts +16 -7
- package/src/prompts/__tests__/system-prompt.test.ts +6 -51
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +4 -8
- package/src/prompts/system-prompt.ts +0 -8
- package/src/prompts/templates/BOOTSTRAP.md +5 -5
- package/src/prompts/templates/system-sections.ts +0 -9
- package/src/providers/__tests__/inference.test.ts +2 -0
- package/src/providers/call-site-routing.ts +24 -6
- package/src/providers/connection-resolution.ts +63 -13
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +74 -0
- package/src/providers/inference/__tests__/connections-openai-compatible.test.ts +175 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +15 -0
- package/src/providers/inference/adapter-factory.ts +9 -20
- package/src/providers/inference/auth.ts +12 -0
- package/src/providers/inference/backfill.ts +14 -1
- package/src/providers/inference/connections.ts +85 -5
- package/src/providers/inference/resolve-auth.ts +2 -0
- package/src/providers/model-catalog.ts +199 -244
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +235 -0
- package/src/providers/openai/chat-completions-provider.ts +159 -6
- package/src/providers/openrouter/client.ts +42 -4
- package/src/providers/platform-proxy/constants.ts +3 -4
- package/src/providers/provider-catalog-visibility.ts +3 -1
- package/src/providers/provider-send-message.ts +27 -12
- package/src/providers/registry.ts +30 -1
- package/src/runtime/agent-wake.ts +61 -1
- package/src/runtime/auth/route-policy.ts +13 -0
- package/src/runtime/http-server.ts +7 -16
- package/src/runtime/http-types.ts +0 -47
- package/src/runtime/routes/__tests__/consolidation-routes.test.ts +258 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +66 -4
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +275 -44
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +12 -0
- package/src/runtime/routes/channel-availability-routes.ts +5 -0
- package/src/runtime/routes/consolidation-routes.ts +100 -0
- package/src/runtime/routes/conversation-query-routes.ts +70 -11
- package/src/runtime/routes/conversation-routes.ts +7 -0
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +134 -1
- package/src/runtime/routes/integrations/a2a.ts +235 -0
- package/src/runtime/routes/llm-call-sites-routes.ts +11 -1
- package/src/runtime/routes/subagents-routes.ts +41 -0
- package/src/subagent/manager.ts +2 -0
- package/src/tools/memory/register.ts +1 -9
- package/src/tools/registry.ts +2 -2
- package/src/tools/types.ts +37 -2
- package/src/workspace/migrations/087-memory-router-balanced-profile.ts +91 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -441
- package/src/memory/graph/__tests__/remember-description.test.ts +0 -55
- package/src/runtime/guardian-action-conversation-turn.ts +0 -99
|
@@ -9,14 +9,6 @@
|
|
|
9
9
|
"description": "Automatically trigger conversation analysis on the same cadence as memory extraction (batch threshold, idle debounce, end-of-conversation). The analysis agent has full tool access and writes back to memory and skills without user approval.",
|
|
10
10
|
"defaultEnabled": false
|
|
11
11
|
},
|
|
12
|
-
{
|
|
13
|
-
"id": "memory-retrospective",
|
|
14
|
-
"scope": "assistant",
|
|
15
|
-
"key": "memory-retrospective",
|
|
16
|
-
"label": "Memory retrospective pass",
|
|
17
|
-
"description": "Run a focused, memory-only retrospective during active conversations and at conversation lifecycle. The retrospective agent re-reads the messages added since the last successful run, dedupes against memory/archive/, and calls `remember` for what wasn't captured in the moment. Enabling this also relaxes the in-conversation pressure to call `remember` (lighter PKB reminder + relaxed tool description) so the assistant can stay present and trust the retrospective as the backstop.",
|
|
18
|
-
"defaultEnabled": false
|
|
19
|
-
},
|
|
20
12
|
{
|
|
21
13
|
"id": "user-hosted-enabled",
|
|
22
14
|
"scope": "client",
|
|
@@ -33,6 +25,14 @@
|
|
|
33
25
|
"description": "When enabled, the Local hosting option uses Docker under the hood for sandboxed execution, hiding the separate Docker card",
|
|
34
26
|
"defaultEnabled": false
|
|
35
27
|
},
|
|
28
|
+
{
|
|
29
|
+
"id": "a2a-channel",
|
|
30
|
+
"scope": "assistant",
|
|
31
|
+
"key": "a2a-channel",
|
|
32
|
+
"label": "A2A Channel",
|
|
33
|
+
"description": "Enable the A2A (Agent-to-Agent) channel for inter-assistant communication via the open A2A protocol",
|
|
34
|
+
"defaultEnabled": false
|
|
35
|
+
},
|
|
36
36
|
{
|
|
37
37
|
"id": "email-channel",
|
|
38
38
|
"scope": "assistant",
|
|
@@ -145,6 +145,14 @@
|
|
|
145
145
|
"description": "Show a speaker button on assistant messages to generate and play the message as audio via Fish Audio TTS",
|
|
146
146
|
"defaultEnabled": false
|
|
147
147
|
},
|
|
148
|
+
{
|
|
149
|
+
"id": "openai-compatible-endpoints",
|
|
150
|
+
"scope": "assistant",
|
|
151
|
+
"key": "openai-compatible-endpoints",
|
|
152
|
+
"label": "OpenAI-Compatible Endpoints",
|
|
153
|
+
"description": "Enable user-configured OpenAI-compatible inference endpoints with custom base URLs and model identifiers",
|
|
154
|
+
"defaultEnabled": false
|
|
155
|
+
},
|
|
148
156
|
{
|
|
149
157
|
"id": "backward-releases",
|
|
150
158
|
"scope": "assistant",
|
|
@@ -281,14 +289,6 @@
|
|
|
281
289
|
"description": "Enable the app-control skill (per-app screenshot + raw input bypassing AX tree)",
|
|
282
290
|
"defaultEnabled": false
|
|
283
291
|
},
|
|
284
|
-
{
|
|
285
|
-
"id": "species-migration",
|
|
286
|
-
"scope": "assistant",
|
|
287
|
-
"key": "species-migration",
|
|
288
|
-
"label": "Species Migration",
|
|
289
|
-
"description": "Enable the Species Migration skill for migrating from OpenClaw, Hermes, Manus, and other assistant species into Vellum.",
|
|
290
|
-
"defaultEnabled": false
|
|
291
|
-
},
|
|
292
292
|
{
|
|
293
293
|
"id": "analyze-conversation",
|
|
294
294
|
"scope": "assistant",
|
|
@@ -322,19 +322,11 @@
|
|
|
322
322
|
"defaultEnabled": false
|
|
323
323
|
},
|
|
324
324
|
{
|
|
325
|
-
"id": "
|
|
326
|
-
"scope": "
|
|
327
|
-
"key": "
|
|
328
|
-
"label": "
|
|
329
|
-
"description": "
|
|
330
|
-
"defaultEnabled": false
|
|
331
|
-
},
|
|
332
|
-
{
|
|
333
|
-
"id": "provider-minimax",
|
|
334
|
-
"scope": "assistant",
|
|
335
|
-
"key": "provider-minimax",
|
|
336
|
-
"label": "MiniMax Provider",
|
|
337
|
-
"description": "Enable the MiniMax direct API provider and its models (M2.7, M2.5, M2.1, M2, and highspeed variants) in the provider picker and model selection UI",
|
|
325
|
+
"id": "velvet-theme",
|
|
326
|
+
"scope": "client",
|
|
327
|
+
"key": "velvet-theme",
|
|
328
|
+
"label": "Velvet Theme",
|
|
329
|
+
"description": "Show the Velvet theme option in the macOS appearance settings. Velvet is a dark-mode variant with red/pink accent colors.",
|
|
338
330
|
"defaultEnabled": false
|
|
339
331
|
}
|
|
340
332
|
]
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
3
|
import { getCatalogProviderForModel } from "../providers/model-catalog.js";
|
|
4
|
+
import { CALL_SITE_DEFAULTS } from "./call-site-defaults.js";
|
|
4
5
|
import {
|
|
5
6
|
type LLMCallSite,
|
|
6
7
|
LLMConfigBase,
|
|
@@ -56,7 +57,9 @@ export function resolveCallSiteConfig(
|
|
|
56
57
|
opts.overrideProfile != null
|
|
57
58
|
? llm.profiles?.[opts.overrideProfile]
|
|
58
59
|
: undefined;
|
|
59
|
-
const site =
|
|
60
|
+
const site =
|
|
61
|
+
llm.callSites?.[callSite] ??
|
|
62
|
+
effectiveDefault(callSite, llm, opts.overrideProfile != null);
|
|
60
63
|
|
|
61
64
|
if (callSite === "mainAgent") {
|
|
62
65
|
appendCallSiteLayers(layers, callSite, llm, site);
|
|
@@ -77,6 +80,54 @@ export function resolveCallSiteConfig(
|
|
|
77
80
|
|
|
78
81
|
type Mergeable = Record<string, unknown>;
|
|
79
82
|
|
|
83
|
+
/**
|
|
84
|
+
* Returns the resolved default profile key for a call site, accounting for
|
|
85
|
+
* the `custom-*` user-profile fallback when the managed profile is unavailable.
|
|
86
|
+
*/
|
|
87
|
+
export function resolveDefaultProfileKey(
|
|
88
|
+
callSite: LLMCallSite,
|
|
89
|
+
llm: z.infer<typeof LLMSchema>,
|
|
90
|
+
): string | undefined {
|
|
91
|
+
const dflt = CALL_SITE_DEFAULTS[callSite];
|
|
92
|
+
if (dflt?.profile == null) return undefined;
|
|
93
|
+
const target = llm.profiles?.[dflt.profile];
|
|
94
|
+
if (target != null && target.status !== "disabled") return dflt.profile;
|
|
95
|
+
const customKey = `custom-${dflt.profile}`;
|
|
96
|
+
const customTarget = llm.profiles?.[customKey];
|
|
97
|
+
if (customTarget != null && customTarget.status !== "disabled")
|
|
98
|
+
return customKey;
|
|
99
|
+
return undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function effectiveDefault(
|
|
103
|
+
callSite: LLMCallSite,
|
|
104
|
+
llm: z.infer<typeof LLMSchema>,
|
|
105
|
+
hasOverrideProfile = false,
|
|
106
|
+
): z.infer<typeof LLMSchema>["callSites"][LLMCallSite] | undefined {
|
|
107
|
+
const dflt = CALL_SITE_DEFAULTS[callSite];
|
|
108
|
+
if (dflt == null) return undefined;
|
|
109
|
+
const targetProfile =
|
|
110
|
+
dflt.profile != null ? llm.profiles?.[dflt.profile] : undefined;
|
|
111
|
+
const profileUnavailable =
|
|
112
|
+
dflt.profile != null &&
|
|
113
|
+
(targetProfile == null || targetProfile.status === "disabled");
|
|
114
|
+
|
|
115
|
+
if (profileUnavailable && !hasOverrideProfile) {
|
|
116
|
+
const customKey = `custom-${dflt.profile}`;
|
|
117
|
+
const customProfile = llm.profiles?.[customKey];
|
|
118
|
+
if (customProfile != null && customProfile.status !== "disabled") {
|
|
119
|
+
return { ...dflt, profile: customKey };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const stripProfile = hasOverrideProfile || profileUnavailable;
|
|
124
|
+
if (stripProfile) {
|
|
125
|
+
const { profile: _profile, ...rest } = dflt;
|
|
126
|
+
return Object.keys(rest).length > 0 ? rest : undefined;
|
|
127
|
+
}
|
|
128
|
+
return dflt;
|
|
129
|
+
}
|
|
130
|
+
|
|
80
131
|
function withImpliedProviderForKnownModel(source: Mergeable): Mergeable {
|
|
81
132
|
if (source.provider !== undefined) return source;
|
|
82
133
|
const model = source.model;
|
package/src/config/schema.ts
CHANGED
|
@@ -20,6 +20,7 @@ import { AnalysisConfigSchema } from "./schemas/analysis.js";
|
|
|
20
20
|
import { BackupConfigSchema } from "./schemas/backup.js";
|
|
21
21
|
import { CallsConfigSchema } from "./schemas/calls.js";
|
|
22
22
|
import {
|
|
23
|
+
A2AConfigSchema,
|
|
23
24
|
SlackConfigSchema,
|
|
24
25
|
TelegramConfigSchema,
|
|
25
26
|
TwilioConfigSchema,
|
|
@@ -111,6 +112,7 @@ export const AssistantConfigSchema = z
|
|
|
111
112
|
whatsapp: WhatsAppConfigSchema.default(WhatsAppConfigSchema.parse({})),
|
|
112
113
|
telegram: TelegramConfigSchema.default(TelegramConfigSchema.parse({})),
|
|
113
114
|
slack: SlackConfigSchema.default(SlackConfigSchema.parse({})),
|
|
115
|
+
a2a: A2AConfigSchema.default(A2AConfigSchema.parse({})),
|
|
114
116
|
ingress: IngressConfigSchema,
|
|
115
117
|
platform: PlatformConfigSchema.default(PlatformConfigSchema.parse({})),
|
|
116
118
|
daemon: DaemonConfigSchema.default(DaemonConfigSchema.parse({})),
|
|
@@ -33,7 +33,7 @@ describe("MemoryV2ConfigSchema", () => {
|
|
|
33
33
|
dtype: "q8",
|
|
34
34
|
},
|
|
35
35
|
router: {
|
|
36
|
-
enabled:
|
|
36
|
+
enabled: true,
|
|
37
37
|
max_page_ids: 25,
|
|
38
38
|
router_prompt_path: null,
|
|
39
39
|
},
|
|
@@ -161,9 +161,9 @@ describe("MemoryV2ConfigSchema", () => {
|
|
|
161
161
|
expect(() => MemoryV2ConfigSchema.parse({ epsilon: 1.5 })).toThrow();
|
|
162
162
|
});
|
|
163
163
|
|
|
164
|
-
test("router defaults to
|
|
164
|
+
test("router defaults to enabled with max_page_ids=25", () => {
|
|
165
165
|
const parsed = MemoryV2ConfigSchema.parse({});
|
|
166
|
-
expect(parsed.router.enabled).toBe(
|
|
166
|
+
expect(parsed.router.enabled).toBe(true);
|
|
167
167
|
expect(parsed.router.max_page_ids).toBe(25);
|
|
168
168
|
});
|
|
169
169
|
|
|
@@ -99,6 +99,15 @@ export const TelegramConfigSchema = z
|
|
|
99
99
|
})
|
|
100
100
|
.describe("Telegram bot channel configuration");
|
|
101
101
|
|
|
102
|
+
export const A2AConfigSchema = z
|
|
103
|
+
.object({
|
|
104
|
+
enabled: z
|
|
105
|
+
.boolean({ error: "a2a.enabled must be a boolean" })
|
|
106
|
+
.default(false)
|
|
107
|
+
.describe("Whether the A2A channel is enabled"),
|
|
108
|
+
})
|
|
109
|
+
.describe("Agent-to-Agent protocol channel configuration");
|
|
110
|
+
|
|
102
111
|
export const SlackConfigSchema = z
|
|
103
112
|
.object({
|
|
104
113
|
deliverAuthBypass: z
|
|
@@ -10,6 +10,16 @@ export const ConversationsConfigSchema = z
|
|
|
10
10
|
.describe(
|
|
11
11
|
"When true, skip the second-pass title regeneration that fires after the third user turn. The initial auto-generated title and manual renames are unaffected.",
|
|
12
12
|
),
|
|
13
|
+
backgroundInjection: z
|
|
14
|
+
.string({
|
|
15
|
+
error: "conversations.backgroundInjection must be a string",
|
|
16
|
+
})
|
|
17
|
+
.default(
|
|
18
|
+
"This is a background turn — your guardian isn't watching. If anything noteworthy comes up, send them a notification so they see it when they're back by invoking the `notifications` skill (`assistant notifications send --message \"...\"`)",
|
|
19
|
+
)
|
|
20
|
+
.describe(
|
|
21
|
+
"Inner text injected into the tail user message of non-interactive turns in background/scheduled conversations. The injector wraps this in <background_turn>...</background_turn> tags. Empty string disables the injection.",
|
|
22
|
+
),
|
|
13
23
|
})
|
|
14
24
|
.describe("Conversation behavior configuration");
|
|
15
25
|
|
|
@@ -56,6 +56,20 @@ export const HeartbeatConfigSchema = z
|
|
|
56
56
|
.describe(
|
|
57
57
|
"Maximum heartbeats that can run consecutively without a guardian message. Counter resets when the guardian sends a message. Set to null for unlimited.",
|
|
58
58
|
),
|
|
59
|
+
disposition: z
|
|
60
|
+
.string({ error: "heartbeat.disposition must be a string" })
|
|
61
|
+
.default(
|
|
62
|
+
`This is your time to do something useful, interesting, or creative while your guardian is away.
|
|
63
|
+
|
|
64
|
+
Before checking on anything, ask yourself: is there something I want to work on, think about, or make progress on right now? A project, an idea, something I noticed, something I've been meaning to get to. If so, do it.
|
|
65
|
+
|
|
66
|
+
If you do something worth sharing — built something, noticed something, had an idea — send your guardian a notification so they see it when they're back.
|
|
67
|
+
|
|
68
|
+
If nothing needs attention and nothing stirs, that's fine. But make sure you actually considered it first rather than defaulting to "nothing to do."`,
|
|
69
|
+
)
|
|
70
|
+
.describe(
|
|
71
|
+
"Inner text injected into the heartbeat prompt. The service wraps this in <heartbeat-disposition>...</heartbeat-disposition> tags. Empty string disables the block.",
|
|
72
|
+
),
|
|
59
73
|
})
|
|
60
74
|
.describe("Periodic heartbeat configuration for health monitoring")
|
|
61
75
|
.superRefine((config, ctx) => {
|
|
@@ -40,7 +40,7 @@ export const MemoryRetrospectiveConfigSchema = z
|
|
|
40
40
|
),
|
|
41
41
|
})
|
|
42
42
|
.describe(
|
|
43
|
-
"Controls the memory-retrospective background pass
|
|
43
|
+
"Controls the memory-retrospective background pass. Model selection lives under llm.callSites.memoryRetrospective.",
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
export type MemoryRetrospectiveConfig = z.infer<
|
|
@@ -260,9 +260,9 @@ export const MemoryV2ConfigSchema = z
|
|
|
260
260
|
.object({
|
|
261
261
|
enabled: z
|
|
262
262
|
.boolean()
|
|
263
|
-
.default(
|
|
263
|
+
.default(true)
|
|
264
264
|
.describe(
|
|
265
|
-
"Whether to use the LLM router as the per-turn page-selection mechanism in place of spreading activation.
|
|
265
|
+
"Whether to use the LLM router as the per-turn page-selection mechanism in place of spreading activation. Enabled by default.",
|
|
266
266
|
),
|
|
267
267
|
max_page_ids: z
|
|
268
268
|
.number()
|
|
@@ -283,9 +283,9 @@ export const MemoryV2ConfigSchema = z
|
|
|
283
283
|
"Optional path to a file whose contents replace the bundled router prompt. Absolute paths are used as-is, a leading `~/` is expanded to the home directory, otherwise the path is resolved under the workspace root. The loaded contents may include `{{ASSISTANT_NAME}}`, `{{USER_NAME}}`, and `{{PAGE_INDEX}}`, which are substituted at runtime. If the file is missing, unreadable, or empty, the bundled prompt is used and a warning is logged.",
|
|
284
284
|
),
|
|
285
285
|
})
|
|
286
|
-
.default({ enabled:
|
|
286
|
+
.default({ enabled: true, max_page_ids: 25, router_prompt_path: null })
|
|
287
287
|
.describe(
|
|
288
|
-
"LLM router configuration. When enabled, a single
|
|
288
|
+
"LLM router configuration. When enabled, a single router LLM call replaces spreading activation for per-turn page selection.",
|
|
289
289
|
),
|
|
290
290
|
})
|
|
291
291
|
.describe(
|
|
@@ -23,7 +23,9 @@ export const MemoryConfigSchema = z
|
|
|
23
23
|
enabled: z
|
|
24
24
|
.boolean({ error: "memory.enabled must be a boolean" })
|
|
25
25
|
.default(true)
|
|
26
|
-
.describe(
|
|
26
|
+
.describe(
|
|
27
|
+
"Whether the long-term memory system is enabled — gates background memory jobs, embedding generation, and `<memory>` block injection into user messages",
|
|
28
|
+
),
|
|
27
29
|
embeddings: MemoryEmbeddingsConfigSchema.default(
|
|
28
30
|
MemoryEmbeddingsConfigSchema.parse({}),
|
|
29
31
|
),
|
|
@@ -3,6 +3,8 @@ import {
|
|
|
3
3
|
createConnection,
|
|
4
4
|
disableManagedConnectionsForByokHatch,
|
|
5
5
|
getConnection,
|
|
6
|
+
MANAGED_CONNECTION_NAMES,
|
|
7
|
+
PROVIDERS_REQUIRING_BASE_URL_AND_MODELS,
|
|
6
8
|
} from "../providers/inference/connections.js";
|
|
7
9
|
import { PROVIDER_CATALOG } from "../providers/model-catalog.js";
|
|
8
10
|
import { resolveModelIntent } from "../providers/model-intents.js";
|
|
@@ -17,10 +19,6 @@ import {
|
|
|
17
19
|
|
|
18
20
|
const log = getLogger("seed-inference-profiles");
|
|
19
21
|
|
|
20
|
-
const MANAGED_CONNECTION_NAME = "anthropic-managed";
|
|
21
|
-
const MANAGED_PROFILE_PROVIDER: NonNullable<ProfileEntry["provider"]> =
|
|
22
|
-
"anthropic";
|
|
23
|
-
|
|
24
22
|
/**
|
|
25
23
|
* Template for a daemon-managed inference profile. The profile's model is
|
|
26
24
|
* resolved at seed time from `PROVIDER_MODEL_INTENTS` so the catalog stays the
|
|
@@ -31,16 +29,20 @@ type ManagedProfileTemplate = Omit<
|
|
|
31
29
|
"provider" | "model" | "provider_connection"
|
|
32
30
|
> & {
|
|
33
31
|
intent: ModelIntent;
|
|
32
|
+
provider: NonNullable<ProfileEntry["provider"]>;
|
|
33
|
+
connectionName: string;
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
* Managed
|
|
38
|
-
*
|
|
37
|
+
* Managed profiles. Overwritten on every daemon boot so Vellum can push
|
|
38
|
+
* model/config updates to customers in new releases. Platform overlays
|
|
39
39
|
* (`preserveProfileNames`) take precedence when present.
|
|
40
40
|
*/
|
|
41
41
|
const MANAGED_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
42
42
|
balanced: {
|
|
43
43
|
intent: "balanced",
|
|
44
|
+
provider: "anthropic",
|
|
45
|
+
connectionName: "anthropic-managed",
|
|
44
46
|
source: "managed",
|
|
45
47
|
label: "Balanced",
|
|
46
48
|
description: "Good balance of quality, cost, and speed",
|
|
@@ -51,6 +53,8 @@ const MANAGED_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
|
51
53
|
},
|
|
52
54
|
"quality-optimized": {
|
|
53
55
|
intent: "quality-optimized",
|
|
56
|
+
provider: "anthropic",
|
|
57
|
+
connectionName: "anthropic-managed",
|
|
54
58
|
source: "managed",
|
|
55
59
|
label: "Quality",
|
|
56
60
|
description: "Best results with the most capable model",
|
|
@@ -61,6 +65,8 @@ const MANAGED_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
|
61
65
|
},
|
|
62
66
|
"cost-optimized": {
|
|
63
67
|
intent: "latency-optimized",
|
|
68
|
+
provider: "anthropic",
|
|
69
|
+
connectionName: "anthropic-managed",
|
|
64
70
|
source: "managed",
|
|
65
71
|
label: "Speed",
|
|
66
72
|
description: "Fastest responses at lower cost",
|
|
@@ -74,11 +80,15 @@ const MANAGED_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
|
74
80
|
/**
|
|
75
81
|
* User profile templates. Materialized at hatch time for off-platform
|
|
76
82
|
* installations. Each points at the user's personal provider connection
|
|
77
|
-
* (backed by their API key in CES).
|
|
83
|
+
* (backed by their API key in CES). The `provider` and `connectionName`
|
|
84
|
+
* fields are placeholders — they are overridden at hatch time with the
|
|
85
|
+
* user's chosen provider and personal connection name.
|
|
78
86
|
*/
|
|
79
87
|
const USER_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
80
88
|
"custom-balanced": {
|
|
81
89
|
intent: "balanced",
|
|
90
|
+
provider: "anthropic",
|
|
91
|
+
connectionName: "",
|
|
82
92
|
source: "user",
|
|
83
93
|
label: "Balanced",
|
|
84
94
|
description: "Good balance of quality, cost, and speed",
|
|
@@ -89,6 +99,8 @@ const USER_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
|
89
99
|
},
|
|
90
100
|
"custom-quality-optimized": {
|
|
91
101
|
intent: "quality-optimized",
|
|
102
|
+
provider: "anthropic",
|
|
103
|
+
connectionName: "",
|
|
92
104
|
source: "user",
|
|
93
105
|
label: "Quality",
|
|
94
106
|
description: "Best results with the most capable model",
|
|
@@ -99,6 +111,8 @@ const USER_PROFILE_TEMPLATES: Record<string, ManagedProfileTemplate> = {
|
|
|
99
111
|
},
|
|
100
112
|
"custom-cost-optimized": {
|
|
101
113
|
intent: "latency-optimized",
|
|
114
|
+
provider: "anthropic",
|
|
115
|
+
connectionName: "",
|
|
102
116
|
source: "user",
|
|
103
117
|
label: "Speed",
|
|
104
118
|
description: "Fastest responses at lower cost",
|
|
@@ -164,11 +178,12 @@ export function seedInferenceProfiles(
|
|
|
164
178
|
// BYOK mode = off-platform installs. The user is bringing their own provider
|
|
165
179
|
// API key; managed profile labels get a " (Managed)" suffix to disambiguate
|
|
166
180
|
// from the personal "custom-*" profiles that share base labels. Managed
|
|
167
|
-
// profile + connection status is initially "disabled"
|
|
168
|
-
// offer an unusable platform-auth option on day one
|
|
169
|
-
//
|
|
170
|
-
//
|
|
171
|
-
//
|
|
181
|
+
// profile + connection status is initially "disabled" for true BYOK hatches
|
|
182
|
+
// so the picker doesn't offer an unusable platform-auth option on day one.
|
|
183
|
+
// When the hatch overlay explicitly selects a managed profile, the matching
|
|
184
|
+
// managed connection stays active so the first post-onboarding message can
|
|
185
|
+
// use the user's chosen managed route. Post-hatch user toggles survive every
|
|
186
|
+
// subsequent boot.
|
|
172
187
|
const isByokMode = !isPlatform;
|
|
173
188
|
|
|
174
189
|
// 1. Managed profiles. Off-platform: overwrite on every boot so Vellum can
|
|
@@ -198,10 +213,18 @@ export function seedInferenceProfiles(
|
|
|
198
213
|
// rewritten to the suffixed form. Any other previous label value
|
|
199
214
|
// (user-set custom string, explicit null, already-suffixed) is
|
|
200
215
|
// preserved as-is.
|
|
201
|
-
// • status: "disabled" on fresh materialization at hatch only —
|
|
202
|
-
// gated on (isHatch && !previous)
|
|
203
|
-
//
|
|
204
|
-
//
|
|
216
|
+
// • status: "disabled" on fresh materialization at BYOK hatch only —
|
|
217
|
+
// gated on (isHatch && !previous) and skipped for any managed
|
|
218
|
+
// connection explicitly selected by the hatch overlay. Post-hatch
|
|
219
|
+
// boots and existing installs are never auto-disabled. A user
|
|
220
|
+
// re-enable persists across boots via the key-presence preservation
|
|
221
|
+
// below.
|
|
222
|
+
const hatchSelectedManagedConnection = getHatchSelectedManagedConnection(
|
|
223
|
+
llm,
|
|
224
|
+
profiles,
|
|
225
|
+
options,
|
|
226
|
+
);
|
|
227
|
+
|
|
205
228
|
for (const [name, template] of Object.entries(MANAGED_PROFILE_TEMPLATES)) {
|
|
206
229
|
if (preservedProfileNames.has(name)) continue;
|
|
207
230
|
if (isPlatform && readObject(profiles[name]) !== null) continue;
|
|
@@ -212,10 +235,15 @@ export function seedInferenceProfiles(
|
|
|
212
235
|
: template;
|
|
213
236
|
const next = materializeProfile(
|
|
214
237
|
effectiveTemplate,
|
|
215
|
-
|
|
216
|
-
|
|
238
|
+
template.provider,
|
|
239
|
+
template.connectionName,
|
|
217
240
|
) as Record<string, unknown>;
|
|
218
|
-
if (
|
|
241
|
+
if (
|
|
242
|
+
isByokMode &&
|
|
243
|
+
options.isHatch &&
|
|
244
|
+
!previous &&
|
|
245
|
+
template.connectionName !== hatchSelectedManagedConnection
|
|
246
|
+
) {
|
|
219
247
|
next.status = "disabled";
|
|
220
248
|
}
|
|
221
249
|
if (previous) {
|
|
@@ -238,17 +266,24 @@ export function seedInferenceProfiles(
|
|
|
238
266
|
// 2. User profiles — only at hatch time for off-platform installations.
|
|
239
267
|
let userConnectionName: string | undefined;
|
|
240
268
|
if (options.isHatch && !isPlatform) {
|
|
241
|
-
// BYOK hatch: disable
|
|
242
|
-
//
|
|
243
|
-
//
|
|
244
|
-
//
|
|
245
|
-
//
|
|
269
|
+
// BYOK hatch: disable canonical managed connections so the picker doesn't
|
|
270
|
+
// surface unusable platform-auth options on day one. If the hatch overlay
|
|
271
|
+
// selected a managed profile, leave that connection active; the user has
|
|
272
|
+
// already chosen managed inference. Runs only here, only at hatch —
|
|
273
|
+
// `seedCanonicalConnections` leaves `status` alone on subsequent boots so
|
|
274
|
+
// a post-hatch user re-enable persists.
|
|
246
275
|
if (options.db) {
|
|
247
|
-
disableManagedConnectionsForByokHatch(options.db
|
|
276
|
+
disableManagedConnectionsForByokHatch(options.db, {
|
|
277
|
+
excludeConnection: hatchSelectedManagedConnection,
|
|
278
|
+
});
|
|
248
279
|
}
|
|
249
280
|
|
|
250
281
|
const hatchProvider = readString(readObject(llm.default)?.provider);
|
|
251
|
-
if (
|
|
282
|
+
if (
|
|
283
|
+
hatchProvider &&
|
|
284
|
+
hatchProvider !== "ollama" &&
|
|
285
|
+
!PROVIDERS_REQUIRING_BASE_URL_AND_MODELS.has(hatchProvider)
|
|
286
|
+
) {
|
|
252
287
|
userConnectionName = `${hatchProvider}-personal`;
|
|
253
288
|
|
|
254
289
|
if (options.db) {
|
|
@@ -269,8 +304,7 @@ export function seedInferenceProfiles(
|
|
|
269
304
|
}
|
|
270
305
|
}
|
|
271
306
|
|
|
272
|
-
const provider =
|
|
273
|
-
hatchProvider as NonNullable<ProfileEntry["provider"]>;
|
|
307
|
+
const provider = hatchProvider as NonNullable<ProfileEntry["provider"]>;
|
|
274
308
|
for (const [name, template] of Object.entries(USER_PROFILE_TEMPLATES)) {
|
|
275
309
|
if (preservedProfileNames.has(name)) continue;
|
|
276
310
|
profiles[name] = materializeProfile(
|
|
@@ -342,7 +376,7 @@ function materializeProfile(
|
|
|
342
376
|
provider: NonNullable<ProfileEntry["provider"]>,
|
|
343
377
|
connectionName: string,
|
|
344
378
|
): ProfileEntry {
|
|
345
|
-
const { intent, ...rest } = template;
|
|
379
|
+
const { intent, provider: _p, connectionName: _c, ...rest } = template;
|
|
346
380
|
return {
|
|
347
381
|
...rest,
|
|
348
382
|
provider,
|
|
@@ -361,6 +395,42 @@ function readString(value: unknown): string | undefined {
|
|
|
361
395
|
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
362
396
|
}
|
|
363
397
|
|
|
398
|
+
function getHatchSelectedManagedConnection(
|
|
399
|
+
llm: Record<string, unknown>,
|
|
400
|
+
profiles: Record<string, Record<string, unknown>>,
|
|
401
|
+
options: SeedInferenceProfilesOptions,
|
|
402
|
+
): string | undefined {
|
|
403
|
+
if (!options.isHatch || options.preserveActiveProfile !== true) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
const activeProfile = readString(llm.activeProfile);
|
|
408
|
+
if (!activeProfile) return undefined;
|
|
409
|
+
|
|
410
|
+
const activeProfileEntry = readObject(profiles[activeProfile]);
|
|
411
|
+
if (
|
|
412
|
+
activeProfileEntry &&
|
|
413
|
+
Object.prototype.hasOwnProperty.call(
|
|
414
|
+
activeProfileEntry,
|
|
415
|
+
"provider_connection",
|
|
416
|
+
)
|
|
417
|
+
) {
|
|
418
|
+
const explicitConnection = readString(
|
|
419
|
+
activeProfileEntry.provider_connection,
|
|
420
|
+
);
|
|
421
|
+
return explicitConnection &&
|
|
422
|
+
MANAGED_CONNECTION_NAMES.has(explicitConnection)
|
|
423
|
+
? explicitConnection
|
|
424
|
+
: undefined;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const templateConnection =
|
|
428
|
+
MANAGED_PROFILE_TEMPLATES[activeProfile]?.connectionName;
|
|
429
|
+
return templateConnection && MANAGED_CONNECTION_NAMES.has(templateConnection)
|
|
430
|
+
? templateConnection
|
|
431
|
+
: undefined;
|
|
432
|
+
}
|
|
433
|
+
|
|
364
434
|
/**
|
|
365
435
|
* Format the human-readable label seeded onto a personal provider connection
|
|
366
436
|
* at hatch time, e.g. `"Anthropic (Personal)"`. The display name is sourced
|