@vellumai/assistant 0.7.2 → 0.7.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 +16 -1
- package/docs/architecture/memory.md +5 -2
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/openapi.yaml +449 -22
- package/package.json +1 -1
- package/src/__tests__/app-control-flow.test.ts +21 -11
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/assistant-event.test.ts +0 -10
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +4 -2
- package/src/__tests__/config-loader-backfill.test.ts +379 -0
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
- package/src/__tests__/config-watcher.test.ts +140 -69
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- package/src/__tests__/credentials-cli.test.ts +7 -0
- package/src/__tests__/cu-unified-flow.test.ts +176 -10
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +3 -4
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +260 -11
- package/src/__tests__/host-app-control-proxy.test.ts +195 -25
- package/src/__tests__/host-bash-proxy.test.ts +227 -34
- package/src/__tests__/host-bash-routes.test.ts +178 -13
- package/src/__tests__/host-cu-proxy.test.ts +210 -3
- package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
- package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
- package/src/__tests__/host-file-proxy.test.ts +268 -6
- package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
- package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
- package/src/__tests__/http-user-message-parity.test.ts +107 -1
- package/src/__tests__/injector-chain.test.ts +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/relay-server.test.ts +15 -4
- package/src/__tests__/runtime-events-sse.test.ts +4 -8
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/contacts.ts +64 -25
- package/src/cli/commands/credentials.ts +56 -0
- package/src/cli/commands/memory-v2.ts +7 -6
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
- package/src/cli/commands/platform/index.ts +16 -7
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/program.ts +4 -2
- package/src/config/assistant-feature-flags.ts +13 -3
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/env.ts +0 -8
- package/src/config/feature-flag-registry.json +27 -3
- package/src/config/loader.ts +127 -8
- package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +13 -0
- package/src/config/schemas/memory-v2.ts +75 -11
- package/src/config/schemas/platform.ts +43 -3
- package/src/config/schemas/services.ts +28 -0
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -25
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/config-watcher.ts +85 -57
- package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
- package/src/daemon/conversation-agent-loop.ts +170 -33
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +1 -3
- package/src/daemon/conversation-process.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +26 -0
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +195 -15
- package/src/daemon/conversation-tool-setup.ts +57 -14
- package/src/daemon/conversation.ts +17 -22
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/handlers/shared.ts +0 -1
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +137 -41
- package/src/daemon/host-bash-proxy.ts +46 -21
- package/src/daemon/host-cu-proxy.ts +49 -3
- package/src/daemon/host-file-proxy.ts +43 -7
- package/src/daemon/host-transfer-proxy.ts +95 -4
- package/src/daemon/lifecycle.ts +79 -28
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +14 -4
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +4 -0
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/messages.ts +3 -0
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +85 -0
- package/src/filing/filing-service.ts +30 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
- package/src/heartbeat/heartbeat-run-store.ts +13 -0
- package/src/heartbeat/heartbeat-service.ts +205 -31
- package/src/home/feed-scheduler.ts +18 -0
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/assistant-server.ts +56 -2
- package/src/ipc/gateway-client.ts +37 -3
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/protocol.ts +5 -7
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/context-search/agent-runner.ts +19 -2
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +5 -4
- package/src/memory/context-search/sources/memory.ts +0 -1
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +4 -12
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
- package/src/memory/graph/conversation-graph-memory.ts +42 -54
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +1 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +6 -10
- package/src/memory/indexer.ts +54 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs-store.ts +48 -0
- package/src/memory/jobs-worker.ts +81 -43
- package/src/memory/memory-v2-activation-log-store.ts +32 -14
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -0
- package/src/memory/qdrant-client.ts +0 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +6 -67
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +311 -250
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +157 -167
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +5 -199
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +76 -1
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +62 -12
- package/src/memory/v2/injection.ts +47 -60
- package/src/memory/v2/prompts/consolidation.ts +36 -1
- package/src/memory/v2/qdrant.ts +99 -0
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +10 -84
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +82 -59
- package/src/memory/v2/static-context.ts +22 -0
- package/src/memory/v2/types.ts +10 -10
- package/src/notifications/copy-composer.ts +13 -0
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/plugins/defaults/injectors.ts +35 -2
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +21 -7
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/assistant-event.ts +0 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +8 -0
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/client-routes.ts +20 -2
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +163 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +6 -2
- package/src/runtime/routes/documents-routes.ts +2 -75
- package/src/runtime/routes/events-routes.ts +41 -9
- package/src/runtime/routes/host-bash-routes.ts +23 -3
- package/src/runtime/routes/host-cu-routes.ts +33 -6
- package/src/runtime/routes/host-file-routes.ts +32 -6
- package/src/runtime/routes/host-transfer-routes.ts +79 -16
- package/src/runtime/routes/identity-routes.ts +7 -138
- package/src/runtime/routes/inbound-message-handler.ts +77 -12
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-v2-routes.ts +33 -0
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/scheduler.ts +20 -1
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/skills/remote-skill-policy.ts +4 -10
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +43 -1
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +43 -1
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +56 -11
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +43 -1
- package/src/tools/host-terminal/host-shell.ts +13 -6
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/types.ts +24 -2
- package/src/tts/provider-catalog.ts +3 -5
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -404
- package/src/signals/bash.ts +0 -198
package/src/config/loader.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
} from "node:fs";
|
|
8
8
|
import { basename, dirname, join } from "node:path";
|
|
9
9
|
|
|
10
|
+
import { safeStatSync } from "../util/fs.js";
|
|
10
11
|
import { getLogger } from "../util/logger.js";
|
|
11
12
|
import {
|
|
12
13
|
ensureDataDir,
|
|
@@ -22,8 +23,22 @@ export { API_KEY_PROVIDERS } from "../providers/provider-secret-catalog.js";
|
|
|
22
23
|
const log = getLogger("config");
|
|
23
24
|
|
|
24
25
|
let cached: AssistantConfig | null = null;
|
|
26
|
+
let cachedFileSignature: ConfigFileSignature | null = null;
|
|
25
27
|
let loading = false;
|
|
26
28
|
|
|
29
|
+
type ConfigFileSignature =
|
|
30
|
+
| {
|
|
31
|
+
path: string;
|
|
32
|
+
exists: true;
|
|
33
|
+
size: number;
|
|
34
|
+
mtimeMs: number;
|
|
35
|
+
ctimeMs: number;
|
|
36
|
+
}
|
|
37
|
+
| {
|
|
38
|
+
path: string;
|
|
39
|
+
exists: false;
|
|
40
|
+
};
|
|
41
|
+
|
|
27
42
|
function getConfigPath(): string {
|
|
28
43
|
return getWorkspaceConfigPath();
|
|
29
44
|
}
|
|
@@ -32,6 +47,48 @@ function ensureMigratedDataDir(): void {
|
|
|
32
47
|
ensureDataDir();
|
|
33
48
|
}
|
|
34
49
|
|
|
50
|
+
function readConfigFileSignature(configPath: string): ConfigFileSignature {
|
|
51
|
+
const stats = safeStatSync(configPath);
|
|
52
|
+
if (!stats) {
|
|
53
|
+
return {
|
|
54
|
+
path: configPath,
|
|
55
|
+
exists: false,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
path: configPath,
|
|
61
|
+
exists: true,
|
|
62
|
+
size: stats.size,
|
|
63
|
+
mtimeMs: stats.mtimeMs,
|
|
64
|
+
ctimeMs: stats.ctimeMs,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function configFileSignaturesEqual(
|
|
69
|
+
a: ConfigFileSignature,
|
|
70
|
+
b: ConfigFileSignature,
|
|
71
|
+
): boolean {
|
|
72
|
+
if (a.path !== b.path || a.exists !== b.exists) return false;
|
|
73
|
+
if (!a.exists || !b.exists) return true;
|
|
74
|
+
return (
|
|
75
|
+
a.size === b.size && a.mtimeMs === b.mtimeMs && a.ctimeMs === b.ctimeMs
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function getCachedConfigIfFresh(): AssistantConfig | null {
|
|
80
|
+
if (!cached || !cachedFileSignature) return null;
|
|
81
|
+
|
|
82
|
+
const currentSignature = readConfigFileSignature(getConfigPath());
|
|
83
|
+
if (configFileSignaturesEqual(cachedFileSignature, currentSignature)) {
|
|
84
|
+
return cached;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
cached = null;
|
|
88
|
+
cachedFileSignature = null;
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
|
|
35
92
|
/**
|
|
36
93
|
* Parse a raw config through the Zod schema, applying all nested defaults.
|
|
37
94
|
*
|
|
@@ -73,6 +130,10 @@ function getDeploymentContextDefaults(): Record<string, unknown> {
|
|
|
73
130
|
"linear-oauth": managed,
|
|
74
131
|
"github-oauth": managed,
|
|
75
132
|
"notion-oauth": managed,
|
|
133
|
+
"asana-oauth": managed,
|
|
134
|
+
"todoist-oauth": managed,
|
|
135
|
+
"discord-oauth": managed,
|
|
136
|
+
"hubspot-oauth": managed,
|
|
76
137
|
},
|
|
77
138
|
};
|
|
78
139
|
}
|
|
@@ -343,6 +404,13 @@ function stripNullLeaves(value: unknown): unknown {
|
|
|
343
404
|
return out;
|
|
344
405
|
}
|
|
345
406
|
|
|
407
|
+
function readPlainObject(value: unknown): Record<string, unknown> | null {
|
|
408
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) {
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
return value as Record<string, unknown>;
|
|
412
|
+
}
|
|
413
|
+
|
|
346
414
|
/**
|
|
347
415
|
* Deep-merge `overrides` into `target`, overwriting leaf values.
|
|
348
416
|
* Recursively merges nested objects; scalars and arrays from `overrides`
|
|
@@ -406,6 +474,18 @@ export function deepMergeOverwrite(
|
|
|
406
474
|
}
|
|
407
475
|
}
|
|
408
476
|
|
|
477
|
+
export type DefaultWorkspaceConfigMergeResult = {
|
|
478
|
+
providedLlmProfileNames: Set<string>;
|
|
479
|
+
providedLlmActiveProfile: boolean;
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
function emptyDefaultWorkspaceConfigMergeResult(): DefaultWorkspaceConfigMergeResult {
|
|
483
|
+
return {
|
|
484
|
+
providedLlmProfileNames: new Set(),
|
|
485
|
+
providedLlmActiveProfile: false,
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
|
|
409
489
|
/**
|
|
410
490
|
* Merge default workspace config from the file referenced by
|
|
411
491
|
* VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH into the workspace config on disk.
|
|
@@ -415,9 +495,11 @@ export function deepMergeOverwrite(
|
|
|
415
495
|
* Schema defaults are no longer materialized into the file on load — the
|
|
416
496
|
* in-memory `loadConfig()` cache applies them at access time instead.
|
|
417
497
|
*/
|
|
418
|
-
export function mergeDefaultWorkspaceConfig():
|
|
498
|
+
export function mergeDefaultWorkspaceConfig(): DefaultWorkspaceConfigMergeResult {
|
|
419
499
|
const defaultConfigPath = process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
|
|
420
|
-
if (!defaultConfigPath || !existsSync(defaultConfigPath))
|
|
500
|
+
if (!defaultConfigPath || !existsSync(defaultConfigPath)) {
|
|
501
|
+
return emptyDefaultWorkspaceConfigMergeResult();
|
|
502
|
+
}
|
|
421
503
|
|
|
422
504
|
let defaults: unknown;
|
|
423
505
|
try {
|
|
@@ -428,7 +510,7 @@ export function mergeDefaultWorkspaceConfig(): void {
|
|
|
428
510
|
"Failed to read default workspace config from %s",
|
|
429
511
|
defaultConfigPath,
|
|
430
512
|
);
|
|
431
|
-
return;
|
|
513
|
+
return emptyDefaultWorkspaceConfigMergeResult();
|
|
432
514
|
}
|
|
433
515
|
|
|
434
516
|
if (
|
|
@@ -436,16 +518,44 @@ export function mergeDefaultWorkspaceConfig(): void {
|
|
|
436
518
|
typeof defaults !== "object" ||
|
|
437
519
|
Array.isArray(defaults)
|
|
438
520
|
) {
|
|
439
|
-
return;
|
|
521
|
+
return emptyDefaultWorkspaceConfigMergeResult();
|
|
440
522
|
}
|
|
441
523
|
|
|
524
|
+
const llmDefaults = readPlainObject(
|
|
525
|
+
(defaults as Record<string, unknown>).llm,
|
|
526
|
+
);
|
|
527
|
+
const providedProfiles = readPlainObject(llmDefaults?.profiles);
|
|
528
|
+
const mergeResult: DefaultWorkspaceConfigMergeResult = {
|
|
529
|
+
providedLlmProfileNames: new Set(
|
|
530
|
+
providedProfiles ? Object.keys(providedProfiles) : [],
|
|
531
|
+
),
|
|
532
|
+
providedLlmActiveProfile:
|
|
533
|
+
llmDefaults != null &&
|
|
534
|
+
Object.prototype.hasOwnProperty.call(llmDefaults, "activeProfile"),
|
|
535
|
+
};
|
|
536
|
+
|
|
442
537
|
const configPath = getConfigPath();
|
|
443
538
|
let existing: Record<string, unknown> = {};
|
|
444
539
|
if (existsSync(configPath)) {
|
|
445
540
|
try {
|
|
446
541
|
existing = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
447
|
-
} catch {
|
|
448
|
-
|
|
542
|
+
} catch (err) {
|
|
543
|
+
quarantineCorruptConfig(configPath, err);
|
|
544
|
+
// After preserving the corrupt file, start fresh so the default overlay
|
|
545
|
+
// can still initialize a valid config for this startup.
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
if (mergeResult.providedLlmProfileNames.size > 0) {
|
|
550
|
+
// Default-config profile entries are authoritative fragments. Remove any
|
|
551
|
+
// old same-name profile first so recursive merge does not leave stale
|
|
552
|
+
// provider-specific leaves behind.
|
|
553
|
+
const existingLlm = readPlainObject(existing.llm);
|
|
554
|
+
const existingProfiles = readPlainObject(existingLlm?.profiles);
|
|
555
|
+
if (existingProfiles) {
|
|
556
|
+
for (const name of mergeResult.providedLlmProfileNames) {
|
|
557
|
+
delete existingProfiles[name];
|
|
558
|
+
}
|
|
449
559
|
}
|
|
450
560
|
}
|
|
451
561
|
|
|
@@ -456,6 +566,7 @@ export function mergeDefaultWorkspaceConfig(): void {
|
|
|
456
566
|
mkdirSync(dir, { recursive: true });
|
|
457
567
|
}
|
|
458
568
|
writeFileSync(configPath, JSON.stringify(existing, null, 2) + "\n");
|
|
569
|
+
invalidateConfigCache();
|
|
459
570
|
|
|
460
571
|
// Move the temp file into the workspace directory as a permanent record.
|
|
461
572
|
// This prevents re-application on daemon restart (the env var still points
|
|
@@ -471,10 +582,13 @@ export function mergeDefaultWorkspaceConfig(): void {
|
|
|
471
582
|
} catch {
|
|
472
583
|
log.info("Merged default workspace config from %s", defaultConfigPath);
|
|
473
584
|
}
|
|
585
|
+
|
|
586
|
+
return mergeResult;
|
|
474
587
|
}
|
|
475
588
|
|
|
476
589
|
export function loadConfig(): AssistantConfig {
|
|
477
|
-
|
|
590
|
+
const freshCached = getCachedConfigIfFresh();
|
|
591
|
+
if (freshCached) return freshCached;
|
|
478
592
|
|
|
479
593
|
// Re-entrancy guard: log calls during loading (e.g. file-mode warning)
|
|
480
594
|
// can trigger loadConfig again. Return defaults to break the cycle
|
|
@@ -593,12 +707,14 @@ export function loadConfig(): AssistantConfig {
|
|
|
593
707
|
}
|
|
594
708
|
|
|
595
709
|
cached = config;
|
|
710
|
+
cachedFileSignature = readConfigFileSignature(configPath);
|
|
596
711
|
|
|
597
712
|
loading = false;
|
|
598
713
|
return config;
|
|
599
714
|
} catch (err) {
|
|
600
715
|
// Loading failed — clear cached so the next call retries
|
|
601
716
|
cached = null;
|
|
717
|
+
cachedFileSignature = null;
|
|
602
718
|
loading = false;
|
|
603
719
|
throw err;
|
|
604
720
|
}
|
|
@@ -632,7 +748,8 @@ export function getConfig(): AssistantConfig {
|
|
|
632
748
|
* workspace-existence check runs.
|
|
633
749
|
*/
|
|
634
750
|
export function getConfigReadOnly(): AssistantConfig {
|
|
635
|
-
|
|
751
|
+
const freshCached = getCachedConfigIfFresh();
|
|
752
|
+
if (freshCached) return freshCached;
|
|
636
753
|
|
|
637
754
|
const configPath = getConfigPath();
|
|
638
755
|
let fileConfig: Record<string, unknown> = {};
|
|
@@ -649,6 +766,7 @@ export function getConfigReadOnly(): AssistantConfig {
|
|
|
649
766
|
|
|
650
767
|
export function invalidateConfigCache(): void {
|
|
651
768
|
cached = null;
|
|
769
|
+
cachedFileSignature = null;
|
|
652
770
|
loading = false;
|
|
653
771
|
}
|
|
654
772
|
|
|
@@ -686,6 +804,7 @@ export function saveRawConfig(config: Record<string, unknown>): void {
|
|
|
686
804
|
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
687
805
|
|
|
688
806
|
cached = null; // invalidate cache
|
|
807
|
+
cachedFileSignature = null;
|
|
689
808
|
}
|
|
690
809
|
|
|
691
810
|
export function getNestedValue(
|
|
@@ -7,7 +7,7 @@ describe("MemoryV2ConfigSchema", () => {
|
|
|
7
7
|
test("parses an empty object to documented defaults", () => {
|
|
8
8
|
const parsed = MemoryV2ConfigSchema.parse({});
|
|
9
9
|
expect(parsed).toEqual({
|
|
10
|
-
enabled:
|
|
10
|
+
enabled: true,
|
|
11
11
|
sweep_enabled: false,
|
|
12
12
|
d: 0.3,
|
|
13
13
|
c_user: 0.3,
|
|
@@ -15,9 +15,8 @@ describe("MemoryV2ConfigSchema", () => {
|
|
|
15
15
|
c_now: 0.2,
|
|
16
16
|
k: 0.5,
|
|
17
17
|
hops: 2,
|
|
18
|
-
top_k:
|
|
18
|
+
top_k: 25,
|
|
19
19
|
ann_candidate_limit: null,
|
|
20
|
-
top_k_skills: 5,
|
|
21
20
|
epsilon: 0.01,
|
|
22
21
|
dense_weight: 0.85,
|
|
23
22
|
sparse_weight: 0.15,
|
|
@@ -26,6 +25,13 @@ describe("MemoryV2ConfigSchema", () => {
|
|
|
26
25
|
consolidation_interval_hours: 4,
|
|
27
26
|
max_page_chars: 5000,
|
|
28
27
|
consolidation_prompt_path: null,
|
|
28
|
+
rerank: {
|
|
29
|
+
enabled: false,
|
|
30
|
+
top_k: 50,
|
|
31
|
+
alpha: 0.3,
|
|
32
|
+
model: "Alibaba-NLP/gte-reranker-modernbert-base",
|
|
33
|
+
dtype: "q8",
|
|
34
|
+
},
|
|
29
35
|
});
|
|
30
36
|
});
|
|
31
37
|
|
|
@@ -155,12 +161,11 @@ describe("MemoryConfigSchema integration with v2 block", () => {
|
|
|
155
161
|
test("parses an empty memory config and includes a v2 block with defaults", () => {
|
|
156
162
|
const parsed = MemoryConfigSchema.parse({});
|
|
157
163
|
expect(parsed.v2).toBeDefined();
|
|
158
|
-
expect(parsed.v2.enabled).toBe(
|
|
164
|
+
expect(parsed.v2.enabled).toBe(true);
|
|
159
165
|
expect(parsed.v2.sweep_enabled).toBe(false);
|
|
160
166
|
expect(parsed.v2.d).toBe(0.3);
|
|
161
167
|
expect(parsed.v2.dense_weight).toBe(0.85);
|
|
162
168
|
expect(parsed.v2.sparse_weight).toBe(0.15);
|
|
163
|
-
expect(parsed.v2.top_k_skills).toBe(5);
|
|
164
169
|
expect(parsed.v2.consolidation_interval_hours).toBe(4);
|
|
165
170
|
expect(parsed.v2.max_page_chars).toBe(5000);
|
|
166
171
|
});
|
|
@@ -264,6 +264,20 @@ const CATALOG_RECORD: CatalogRecord = {
|
|
|
264
264
|
description: "General-purpose LLM inference call site for skill use.",
|
|
265
265
|
domain: "skills",
|
|
266
266
|
},
|
|
267
|
+
proactiveArtifactDecision: {
|
|
268
|
+
id: "proactiveArtifactDecision",
|
|
269
|
+
displayName: "Proactive Artifact Decision",
|
|
270
|
+
description:
|
|
271
|
+
"Decides what personalized artifact to build for new users based on conversation context.",
|
|
272
|
+
domain: "agentLoop",
|
|
273
|
+
},
|
|
274
|
+
proactiveArtifactBuild: {
|
|
275
|
+
id: "proactiveArtifactBuild",
|
|
276
|
+
displayName: "Proactive Artifact Build",
|
|
277
|
+
description:
|
|
278
|
+
"Builds the personalized artifact in a background conversation with tool access.",
|
|
279
|
+
domain: "agentLoop",
|
|
280
|
+
},
|
|
267
281
|
};
|
|
268
282
|
|
|
269
283
|
// Source of truth for call-site display metadata. API responses and usage
|
|
@@ -121,8 +121,3 @@ export const SlackConfigSchema = z
|
|
|
121
121
|
.describe("Slack bot display name"),
|
|
122
122
|
})
|
|
123
123
|
.describe("Slack channel configuration");
|
|
124
|
-
|
|
125
|
-
export type TwilioConfig = z.infer<typeof TwilioConfigSchema>;
|
|
126
|
-
export type WhatsAppConfig = z.infer<typeof WhatsAppConfigSchema>;
|
|
127
|
-
export type TelegramConfig = z.infer<typeof TelegramConfigSchema>;
|
|
128
|
-
export type SlackConfig = z.infer<typeof SlackConfigSchema>;
|
|
@@ -11,7 +11,7 @@ export const HeartbeatConfigSchema = z
|
|
|
11
11
|
.number({ error: "heartbeat.intervalMs must be a number" })
|
|
12
12
|
.int("heartbeat.intervalMs must be an integer")
|
|
13
13
|
.positive("heartbeat.intervalMs must be a positive integer")
|
|
14
|
-
.default(
|
|
14
|
+
.default(30 * 60_000)
|
|
15
15
|
.describe("Time between heartbeat checks in milliseconds"),
|
|
16
16
|
cronExpression: z
|
|
17
17
|
.string()
|
|
@@ -149,6 +149,19 @@ export const MemoryCleanupConfigSchema = z
|
|
|
149
149
|
.describe(
|
|
150
150
|
"Retention period for LLM request/response logs in milliseconds (null keeps forever, 0 prunes immediately)",
|
|
151
151
|
),
|
|
152
|
+
traceEventRetentionDays: z
|
|
153
|
+
.number({
|
|
154
|
+
error: "memory.cleanup.traceEventRetentionDays must be a number",
|
|
155
|
+
})
|
|
156
|
+
.int("memory.cleanup.traceEventRetentionDays must be an integer")
|
|
157
|
+
.nonnegative(
|
|
158
|
+
"memory.cleanup.traceEventRetentionDays must be non-negative",
|
|
159
|
+
)
|
|
160
|
+
.max(365, "memory.cleanup.traceEventRetentionDays must be <= 365 days")
|
|
161
|
+
.default(3)
|
|
162
|
+
.describe(
|
|
163
|
+
"Number of days to retain trace events before cleanup (0 disables pruning)",
|
|
164
|
+
),
|
|
152
165
|
})
|
|
153
166
|
.describe("Automatic memory cleanup and garbage collection settings");
|
|
154
167
|
|
|
@@ -7,6 +7,33 @@ import { z } from "zod";
|
|
|
7
7
|
*/
|
|
8
8
|
const WEIGHT_SUM_TOLERANCE = 0.001;
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Default cross-encoder model for memory v2 reranking.
|
|
12
|
+
* `Alibaba-NLP/gte-reranker-modernbert-base` (149M, Apache-2.0) — 2025
|
|
13
|
+
* ModernBERT-backbone reranker; smaller, newer, and cleaner-licensed than
|
|
14
|
+
* the bge family while matching or beating their retrieval-benchmark scores.
|
|
15
|
+
* Has ONNX exports at the standard `onnx/model.onnx` path.
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_RERANK_MODEL = "Alibaba-NLP/gte-reranker-modernbert-base";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* ONNX weight precision passed to `@huggingface/transformers`. Sourced from
|
|
21
|
+
* transformers.js's supported `dtype` values; `q8` (int8) is ~3× faster than
|
|
22
|
+
* `fp32` on CPU with negligible reranker accuracy loss. Single source of
|
|
23
|
+
* truth for both the schema enum and the `LocalRerankBackend` type.
|
|
24
|
+
*/
|
|
25
|
+
export const RerankDtypeEnum = z.enum([
|
|
26
|
+
"fp32",
|
|
27
|
+
"fp16",
|
|
28
|
+
"q8",
|
|
29
|
+
"int8",
|
|
30
|
+
"uint8",
|
|
31
|
+
"q4",
|
|
32
|
+
"bnb4",
|
|
33
|
+
"q4f16",
|
|
34
|
+
]);
|
|
35
|
+
export type RerankDtype = z.infer<typeof RerankDtypeEnum>;
|
|
36
|
+
|
|
10
37
|
/**
|
|
11
38
|
* Memory v2 (concept-page activation model) configuration.
|
|
12
39
|
*
|
|
@@ -21,7 +48,7 @@ export const MemoryV2ConfigSchema = z
|
|
|
21
48
|
.object({
|
|
22
49
|
enabled: z
|
|
23
50
|
.boolean({ error: "memory.v2.enabled must be a boolean" })
|
|
24
|
-
.default(
|
|
51
|
+
.default(true)
|
|
25
52
|
.describe(
|
|
26
53
|
"Whether the v2 memory subsystem (concept-page activation model) is enabled. Independent of the memory-v2-enabled feature flag — both must be true for v2 to run.",
|
|
27
54
|
),
|
|
@@ -83,9 +110,9 @@ export const MemoryV2ConfigSchema = z
|
|
|
83
110
|
.number({ error: "memory.v2.top_k must be a number" })
|
|
84
111
|
.int("memory.v2.top_k must be an integer")
|
|
85
112
|
.positive("memory.v2.top_k must be a positive integer")
|
|
86
|
-
.default(
|
|
113
|
+
.default(25)
|
|
87
114
|
.describe(
|
|
88
|
-
"Number of top-activation concept pages considered for injection per turn",
|
|
115
|
+
"Number of top-activation entries (concept pages and skills combined) considered for injection per turn. Skills are scored alongside concepts in the same pool; this cap covers both.",
|
|
89
116
|
),
|
|
90
117
|
ann_candidate_limit: z
|
|
91
118
|
.number({ error: "memory.v2.ann_candidate_limit must be a number" })
|
|
@@ -96,14 +123,6 @@ export const MemoryV2ConfigSchema = z
|
|
|
96
123
|
.describe(
|
|
97
124
|
"Per-channel cap on the unrestricted ANN candidate query (dense and sparse each return up to this many hits before they are unioned and fed into the activation pipeline). `null` = unlimited (every page in the v2 collection is eligible). Increase or null this out to surface more candidates at the cost of higher per-turn embedding/scoring work.",
|
|
98
125
|
),
|
|
99
|
-
top_k_skills: z
|
|
100
|
-
.number({ error: "memory.v2.top_k_skills must be a number" })
|
|
101
|
-
.int()
|
|
102
|
-
.nonnegative()
|
|
103
|
-
.default(5)
|
|
104
|
-
.describe(
|
|
105
|
-
"Cap on the per-turn skill-autoinjection slate rendered in `### Skills You Can Use`. 0 disables skill autoinjection without code changes.",
|
|
106
|
-
),
|
|
107
126
|
epsilon: z
|
|
108
127
|
.number({ error: "memory.v2.epsilon must be a number" })
|
|
109
128
|
.min(0, "memory.v2.epsilon must be >= 0")
|
|
@@ -192,6 +211,51 @@ export const MemoryV2ConfigSchema = z
|
|
|
192
211
|
.describe(
|
|
193
212
|
"Optional path to a file whose contents replace the bundled consolidation 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 `{{CUTOFF}}`, which is substituted with the run's ISO-8601 cutoff timestamp. If the file is missing, unreadable, or empty, the bundled prompt is used and a warning is logged.",
|
|
194
213
|
),
|
|
214
|
+
rerank: z
|
|
215
|
+
.object({
|
|
216
|
+
enabled: z
|
|
217
|
+
.boolean()
|
|
218
|
+
.default(false)
|
|
219
|
+
.describe(
|
|
220
|
+
"Whether to apply cross-encoder reranking as an additive A_o boost on the user + assistant channels. Disabled by default — opt in once measured.",
|
|
221
|
+
),
|
|
222
|
+
top_k: z
|
|
223
|
+
.number()
|
|
224
|
+
.int()
|
|
225
|
+
.positive()
|
|
226
|
+
.max(200)
|
|
227
|
+
.default(50)
|
|
228
|
+
.describe(
|
|
229
|
+
"Number of candidates from the top of the pre-rerank-A_o pool to send through the reranker. Tail candidates contribute zero rerank boost and keep their pure fused activation.",
|
|
230
|
+
),
|
|
231
|
+
alpha: z
|
|
232
|
+
.number()
|
|
233
|
+
.min(0)
|
|
234
|
+
.max(1)
|
|
235
|
+
.default(0.3)
|
|
236
|
+
.describe(
|
|
237
|
+
"Per-channel rerank weight: each top-K slug gets `alpha · normalized_rerank` added to A_o weighted by `c_user` (user channel) or `c_assistant` (assistant channel). Top reranker hit can lift A_o by up to `(c_user + c_assistant) · alpha`; bottom of top_k stays roughly unchanged.",
|
|
238
|
+
),
|
|
239
|
+
model: z
|
|
240
|
+
.string()
|
|
241
|
+
.default(DEFAULT_RERANK_MODEL)
|
|
242
|
+
.describe(
|
|
243
|
+
"HuggingFace model id for the cross-encoder. Must have an ONNX export reachable from huggingface.co/<model>/resolve/main/onnx/model.onnx.",
|
|
244
|
+
),
|
|
245
|
+
dtype: RerankDtypeEnum.default("q8").describe(
|
|
246
|
+
"ONNX weight precision passed to `@huggingface/transformers`. `q8` (int8) is ~3× faster than `fp32` on CPU with negligible reranker accuracy loss. The worker fails to spawn if the configured model has no matching quantized export — `reranker.ts` then falls back to pure fused scores for the turn.",
|
|
247
|
+
),
|
|
248
|
+
})
|
|
249
|
+
.default({
|
|
250
|
+
enabled: false,
|
|
251
|
+
top_k: 50,
|
|
252
|
+
alpha: 0.3,
|
|
253
|
+
model: DEFAULT_RERANK_MODEL,
|
|
254
|
+
dtype: "q8",
|
|
255
|
+
})
|
|
256
|
+
.describe(
|
|
257
|
+
"Cross-encoder rerank configuration. When enabled, picks the top-K candidates by pre-rerank A_o, runs the cross-encoder once per channel (user, assistant) on that unified set, and adds an alpha-weighted normalized boost to A_o for each scored slug.",
|
|
258
|
+
),
|
|
195
259
|
})
|
|
196
260
|
.describe(
|
|
197
261
|
"Memory v2 — concept-page activation model with hourly LLM-driven consolidation",
|
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
+
const IANA_TIMEZONE_IDENTIFIER_RE =
|
|
4
|
+
/^(?:UTC|[A-Za-z][A-Za-z0-9_+-]*(?:\/[A-Za-z0-9_+-]+)+)$/;
|
|
5
|
+
|
|
6
|
+
function canonicalizeIanaTimezone(timezone: string): string | null {
|
|
7
|
+
const trimmed = timezone.trim();
|
|
8
|
+
if (trimmed.length === 0) {
|
|
9
|
+
return "";
|
|
10
|
+
}
|
|
11
|
+
if (!IANA_TIMEZONE_IDENTIFIER_RE.test(trimmed)) {
|
|
12
|
+
return null;
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
return new Intl.DateTimeFormat("en-US", {
|
|
16
|
+
timeZone: trimmed,
|
|
17
|
+
}).resolvedOptions().timeZone;
|
|
18
|
+
} catch {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function timezoneConfigField(path: string) {
|
|
24
|
+
return z
|
|
25
|
+
.string({ error: `${path} must be a string` })
|
|
26
|
+
.transform((value, ctx) => {
|
|
27
|
+
const canonical = canonicalizeIanaTimezone(value);
|
|
28
|
+
if (canonical === null) {
|
|
29
|
+
ctx.addIssue({
|
|
30
|
+
code: "custom",
|
|
31
|
+
message: `${path} must be a valid IANA timezone identifier or an empty string`,
|
|
32
|
+
});
|
|
33
|
+
return z.NEVER;
|
|
34
|
+
}
|
|
35
|
+
return canonical;
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
|
|
3
39
|
export const PlatformConfigSchema = z
|
|
4
40
|
.object({
|
|
5
41
|
baseUrl: z
|
|
@@ -56,11 +92,15 @@ export const DaemonConfigSchema = z
|
|
|
56
92
|
|
|
57
93
|
export const UiConfigSchema = z
|
|
58
94
|
.object({
|
|
59
|
-
userTimezone:
|
|
60
|
-
.
|
|
95
|
+
userTimezone: timezoneConfigField("ui.userTimezone")
|
|
96
|
+
.optional()
|
|
97
|
+
.describe(
|
|
98
|
+
"Manual IANA timezone override used for assistant temporal grounding and date/time display (e.g. 'America/New_York'). Use an empty string to clear the setting.",
|
|
99
|
+
),
|
|
100
|
+
detectedTimezone: timezoneConfigField("ui.detectedTimezone")
|
|
61
101
|
.optional()
|
|
62
102
|
.describe(
|
|
63
|
-
"IANA timezone identifier for
|
|
103
|
+
"IANA timezone identifier detected from the client environment for assistant temporal grounding when no manual override is configured (e.g. 'America/New_York'). Use an empty string to clear the setting.",
|
|
64
104
|
),
|
|
65
105
|
})
|
|
66
106
|
.describe(
|
|
@@ -72,6 +72,22 @@ const TwitterOAuthServiceSchema = BaseServiceSchema.extend({
|
|
|
72
72
|
mode: ServiceModeSchema.default("your-own"),
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
const AsanaOAuthServiceSchema = BaseServiceSchema.extend({
|
|
76
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
const TodoistOAuthServiceSchema = BaseServiceSchema.extend({
|
|
80
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
const DiscordOAuthServiceSchema = BaseServiceSchema.extend({
|
|
84
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
const HubspotOAuthServiceSchema = BaseServiceSchema.extend({
|
|
88
|
+
mode: ServiceModeSchema.default("your-own"),
|
|
89
|
+
});
|
|
90
|
+
|
|
75
91
|
/**
|
|
76
92
|
* `services.meet.host.*` — daemon-side knobs for the externalized meet-join
|
|
77
93
|
* skill process. Kept narrow: only the values the daemon reads before the
|
|
@@ -140,6 +156,18 @@ export const ServicesSchema = z.object({
|
|
|
140
156
|
"twitter-oauth": TwitterOAuthServiceSchema.default(
|
|
141
157
|
TwitterOAuthServiceSchema.parse({}),
|
|
142
158
|
),
|
|
159
|
+
"asana-oauth": AsanaOAuthServiceSchema.default(
|
|
160
|
+
AsanaOAuthServiceSchema.parse({}),
|
|
161
|
+
),
|
|
162
|
+
"todoist-oauth": TodoistOAuthServiceSchema.default(
|
|
163
|
+
TodoistOAuthServiceSchema.parse({}),
|
|
164
|
+
),
|
|
165
|
+
"discord-oauth": DiscordOAuthServiceSchema.default(
|
|
166
|
+
DiscordOAuthServiceSchema.parse({}),
|
|
167
|
+
),
|
|
168
|
+
"hubspot-oauth": HubspotOAuthServiceSchema.default(
|
|
169
|
+
HubspotOAuthServiceSchema.parse({}),
|
|
170
|
+
),
|
|
143
171
|
meet: MeetDaemonServiceSchema.default(MeetDaemonServiceSchema.parse({})),
|
|
144
172
|
});
|
|
145
173
|
export type Services = z.infer<typeof ServicesSchema>;
|