@vellumai/assistant 0.4.49 → 0.4.51
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 +24 -33
- package/README.md +3 -3
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/keychain-broker.md +6 -6
- package/docs/architecture/memory.md +180 -119
- package/knip.json +32 -0
- package/package.json +3 -2
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +114 -23
- package/src/__tests__/approval-cascade.test.ts +1 -15
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/btw-routes.test.ts +61 -5
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/checker.test.ts +13 -0
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +8 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -7
- package/src/__tests__/credential-vault-unit.test.ts +23 -18
- package/src/__tests__/credential-vault.test.ts +30 -18
- package/src/__tests__/credentials-cli.test.ts +257 -82
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +165 -3
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
- package/src/__tests__/integration-status.test.ts +31 -30
- package/src/__tests__/invite-redemption-service.test.ts +166 -13
- package/src/__tests__/invite-routes-http.test.ts +166 -5
- package/src/__tests__/keychain-broker-client.test.ts +4 -4
- package/src/__tests__/list-messages-attachments.test.ts +193 -0
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +824 -31
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +363 -17
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/registry.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +55 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
- package/src/__tests__/secure-keys.test.ts +78 -18
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills.test.ts +2 -2
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +10 -8
- package/src/__tests__/trust-store.test.ts +15 -0
- package/src/__tests__/twilio-config.test.ts +11 -10
- package/src/__tests__/twilio-provider.test.ts +9 -4
- package/src/__tests__/voice-invite-redemption.test.ts +85 -5
- package/src/agent/ax-tree-compaction.test.ts +51 -0
- package/src/agent/loop.ts +39 -12
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +134 -3
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +44 -6
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +5 -4
- package/src/calls/twilio-provider.ts +14 -9
- package/src/calls/twilio-rest.ts +10 -7
- package/src/calls/types.ts +3 -1
- package/src/cli/commands/config.ts +14 -9
- package/src/cli/commands/contacts.ts +3 -0
- package/src/cli/commands/credentials.ts +170 -174
- package/src/cli/commands/doctor.ts +11 -8
- package/src/cli/commands/keys.ts +9 -9
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +68 -10
- package/src/cli/commands/oauth/connections.ts +475 -105
- package/src/cli/commands/oauth/index.ts +3 -3
- package/src/cli/commands/oauth/providers.ts +18 -4
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +173 -1
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +5 -6
- package/src/cli.ts +20 -22
- package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
- package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
- package/src/config/bundled-skills/contacts/SKILL.md +35 -11
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
- package/src/config/bundled-skills/messaging/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/loader.ts +6 -42
- package/src/config/schema.ts +1 -12
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/types.ts +0 -4
- package/src/contacts/contact-store.ts +39 -2
- package/src/contacts/contacts-write.ts +9 -0
- package/src/context/window-manager.ts +4 -1
- package/src/daemon/config-watcher.ts +55 -2
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +59 -39
- package/src/daemon/handlers/config-telegram.ts +23 -14
- package/src/daemon/handlers/session-history.ts +1 -358
- package/src/daemon/handlers/sessions.ts +18 -13
- package/src/daemon/handlers/shared.ts +3 -17
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +55 -26
- package/src/daemon/lifecycle.ts +39 -4
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-types/computer-use.ts +1 -12
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/sessions.ts +4 -42
- package/src/daemon/server.ts +6 -1
- package/src/daemon/session-agent-loop-handlers.ts +38 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +3 -5
- package/src/daemon/session-surfaces.ts +4 -1
- package/src/daemon/session-tool-setup.ts +7 -1
- package/src/daemon/session.ts +12 -2
- package/src/email/providers/index.ts +2 -2
- package/src/instrument.ts +61 -1
- package/src/media/avatar-router.ts +1 -1
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-queries.ts +25 -83
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/invite-store.ts +19 -0
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +2 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/157-invite-contact-id.ts +104 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +6 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +2 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +1 -1
- package/src/messaging/providers/gmail/adapter.ts +1 -1
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
- package/src/messaging/providers/whatsapp/adapter.ts +13 -9
- package/src/messaging/registry.ts +9 -5
- package/src/oauth/byo-connection.test.ts +40 -25
- package/src/oauth/connect-orchestrator.ts +4 -10
- package/src/oauth/connection-resolver.ts +20 -6
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +183 -31
- package/src/oauth/platform-connection.test.ts +1 -1
- package/src/oauth/provider-behaviors.ts +503 -4
- package/src/oauth/seed-providers.ts +214 -8
- package/src/oauth/token-persistence.ts +31 -16
- package/src/permissions/defaults.ts +1 -0
- package/src/permissions/trust-store.ts +23 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -2
- package/src/providers/anthropic/client.ts +56 -126
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -3
- package/src/runtime/channel-readiness-service.ts +48 -40
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/invite-redemption-service.ts +72 -12
- package/src/runtime/invite-service.ts +43 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -1
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/btw-routes.ts +10 -5
- package/src/runtime/routes/conversation-routes.ts +56 -11
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/integrations/slack/channel.ts +2 -2
- package/src/runtime/routes/integrations/telegram.ts +2 -2
- package/src/runtime/routes/integrations/twilio.ts +17 -17
- package/src/runtime/routes/invite-routes.ts +29 -4
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/secret-routes.ts +17 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +3 -3
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/workspace-routes.ts +9 -4
- package/src/runtime/routes/workspace-utils.ts +8 -2
- package/src/schedule/integration-status.ts +26 -19
- package/src/security/keychain-broker-client.ts +17 -4
- package/src/security/oauth2.ts +6 -7
- package/src/security/secure-keys.ts +44 -19
- package/src/security/token-manager.ts +46 -39
- package/src/services/vercel-deploy.ts +0 -24
- package/src/signals/confirm.ts +78 -0
- package/src/signals/mcp-reload.ts +18 -0
- package/src/skills/catalog-install.ts +74 -18
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/computer-use/definitions.ts +0 -10
- package/src/tools/computer-use/registry.ts +1 -1
- package/src/tools/credentials/vault.ts +22 -7
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/network/script-proxy/session-manager.ts +8 -8
- package/src/tools/schedule/create.ts +10 -3
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +25 -2
- package/src/watcher/provider-types.ts +1 -1
- package/src/watcher/providers/github.ts +1 -1
- package/src/watcher/providers/gmail.ts +3 -3
- package/src/watcher/providers/google-calendar.ts +3 -3
- package/src/watcher/providers/linear.ts +1 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/runtime/routes/mcp-routes.ts +0 -20
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
const VALID_MEMORY_ITEM_KINDS = [
|
|
4
|
-
"preference",
|
|
5
|
-
"profile",
|
|
6
|
-
"project",
|
|
7
|
-
"decision",
|
|
8
|
-
"todo",
|
|
9
|
-
"fact",
|
|
10
|
-
"constraint",
|
|
11
|
-
"relationship",
|
|
12
|
-
"event",
|
|
13
|
-
"opinion",
|
|
14
|
-
"instruction",
|
|
15
|
-
"style",
|
|
16
|
-
] as const;
|
|
17
|
-
|
|
18
|
-
const DEFAULT_CONFLICTABLE_KINDS = [
|
|
19
|
-
"preference",
|
|
20
|
-
"profile",
|
|
21
|
-
"constraint",
|
|
22
|
-
"instruction",
|
|
23
|
-
"style",
|
|
24
|
-
] as const;
|
|
25
|
-
|
|
26
3
|
export const MemoryExtractionConfigSchema = z.object({
|
|
27
4
|
useLLM: z
|
|
28
5
|
.boolean({ error: "memory.extraction.useLLM must be a boolean" })
|
|
@@ -50,166 +27,9 @@ export const MemorySummarizationConfigSchema = z.object({
|
|
|
50
27
|
.default("latency-optimized"),
|
|
51
28
|
});
|
|
52
29
|
|
|
53
|
-
export const MemoryEntityConfigSchema = z.object({
|
|
54
|
-
enabled: z
|
|
55
|
-
.boolean({ error: "memory.entity.enabled must be a boolean" })
|
|
56
|
-
.default(true),
|
|
57
|
-
modelIntent: z
|
|
58
|
-
.enum(["latency-optimized", "quality-optimized", "vision-optimized"], {
|
|
59
|
-
error: "memory.entity.modelIntent must be a valid model intent",
|
|
60
|
-
})
|
|
61
|
-
.default("latency-optimized"),
|
|
62
|
-
extractRelations: z
|
|
63
|
-
.object({
|
|
64
|
-
enabled: z
|
|
65
|
-
.boolean({
|
|
66
|
-
error: "memory.entity.extractRelations.enabled must be a boolean",
|
|
67
|
-
})
|
|
68
|
-
.default(true),
|
|
69
|
-
backfillBatchSize: z
|
|
70
|
-
.number({
|
|
71
|
-
error:
|
|
72
|
-
"memory.entity.extractRelations.backfillBatchSize must be a number",
|
|
73
|
-
})
|
|
74
|
-
.int(
|
|
75
|
-
"memory.entity.extractRelations.backfillBatchSize must be an integer",
|
|
76
|
-
)
|
|
77
|
-
.positive(
|
|
78
|
-
"memory.entity.extractRelations.backfillBatchSize must be a positive integer",
|
|
79
|
-
)
|
|
80
|
-
.default(200),
|
|
81
|
-
})
|
|
82
|
-
.default({ enabled: true, backfillBatchSize: 200 }),
|
|
83
|
-
relationRetrieval: z
|
|
84
|
-
.object({
|
|
85
|
-
enabled: z
|
|
86
|
-
.boolean({
|
|
87
|
-
error: "memory.entity.relationRetrieval.enabled must be a boolean",
|
|
88
|
-
})
|
|
89
|
-
.default(true),
|
|
90
|
-
maxSeedEntities: z
|
|
91
|
-
.number({
|
|
92
|
-
error:
|
|
93
|
-
"memory.entity.relationRetrieval.maxSeedEntities must be a number",
|
|
94
|
-
})
|
|
95
|
-
.int(
|
|
96
|
-
"memory.entity.relationRetrieval.maxSeedEntities must be an integer",
|
|
97
|
-
)
|
|
98
|
-
.positive(
|
|
99
|
-
"memory.entity.relationRetrieval.maxSeedEntities must be a positive integer",
|
|
100
|
-
)
|
|
101
|
-
.default(8),
|
|
102
|
-
maxNeighborEntities: z
|
|
103
|
-
.number({
|
|
104
|
-
error:
|
|
105
|
-
"memory.entity.relationRetrieval.maxNeighborEntities must be a number",
|
|
106
|
-
})
|
|
107
|
-
.int(
|
|
108
|
-
"memory.entity.relationRetrieval.maxNeighborEntities must be an integer",
|
|
109
|
-
)
|
|
110
|
-
.positive(
|
|
111
|
-
"memory.entity.relationRetrieval.maxNeighborEntities must be a positive integer",
|
|
112
|
-
)
|
|
113
|
-
.default(20),
|
|
114
|
-
maxEdges: z
|
|
115
|
-
.number({
|
|
116
|
-
error: "memory.entity.relationRetrieval.maxEdges must be a number",
|
|
117
|
-
})
|
|
118
|
-
.int("memory.entity.relationRetrieval.maxEdges must be an integer")
|
|
119
|
-
.positive(
|
|
120
|
-
"memory.entity.relationRetrieval.maxEdges must be a positive integer",
|
|
121
|
-
)
|
|
122
|
-
.default(40),
|
|
123
|
-
neighborScoreMultiplier: z
|
|
124
|
-
.number({
|
|
125
|
-
error:
|
|
126
|
-
"memory.entity.relationRetrieval.neighborScoreMultiplier must be a number",
|
|
127
|
-
})
|
|
128
|
-
.gt(
|
|
129
|
-
0,
|
|
130
|
-
"memory.entity.relationRetrieval.neighborScoreMultiplier must be > 0",
|
|
131
|
-
)
|
|
132
|
-
.lte(
|
|
133
|
-
1,
|
|
134
|
-
"memory.entity.relationRetrieval.neighborScoreMultiplier must be <= 1",
|
|
135
|
-
)
|
|
136
|
-
.default(0.7),
|
|
137
|
-
maxDepth: z
|
|
138
|
-
.number({
|
|
139
|
-
error: "memory.entity.relationRetrieval.maxDepth must be a number",
|
|
140
|
-
})
|
|
141
|
-
.int("memory.entity.relationRetrieval.maxDepth must be an integer")
|
|
142
|
-
.positive(
|
|
143
|
-
"memory.entity.relationRetrieval.maxDepth must be a positive integer",
|
|
144
|
-
)
|
|
145
|
-
.default(3),
|
|
146
|
-
depthDecay: z
|
|
147
|
-
.boolean({
|
|
148
|
-
error: "memory.entity.relationRetrieval.depthDecay must be a boolean",
|
|
149
|
-
})
|
|
150
|
-
.default(true),
|
|
151
|
-
})
|
|
152
|
-
.default({
|
|
153
|
-
enabled: true,
|
|
154
|
-
maxSeedEntities: 8,
|
|
155
|
-
maxNeighborEntities: 20,
|
|
156
|
-
maxEdges: 40,
|
|
157
|
-
neighborScoreMultiplier: 0.7,
|
|
158
|
-
maxDepth: 3,
|
|
159
|
-
depthDecay: true,
|
|
160
|
-
}),
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
export const MemoryConflictsConfigSchema = z.object({
|
|
164
|
-
enabled: z
|
|
165
|
-
.boolean({ error: "memory.conflicts.enabled must be a boolean" })
|
|
166
|
-
.default(true),
|
|
167
|
-
gateMode: z
|
|
168
|
-
.enum(["soft"], { error: 'memory.conflicts.gateMode must be "soft"' })
|
|
169
|
-
.default("soft"),
|
|
170
|
-
resolverLlmTimeoutMs: z
|
|
171
|
-
.number({ error: "memory.conflicts.resolverLlmTimeoutMs must be a number" })
|
|
172
|
-
.int("memory.conflicts.resolverLlmTimeoutMs must be an integer")
|
|
173
|
-
.positive(
|
|
174
|
-
"memory.conflicts.resolverLlmTimeoutMs must be a positive integer",
|
|
175
|
-
)
|
|
176
|
-
.default(12000),
|
|
177
|
-
relevanceThreshold: z
|
|
178
|
-
.number({ error: "memory.conflicts.relevanceThreshold must be a number" })
|
|
179
|
-
.min(0, "memory.conflicts.relevanceThreshold must be >= 0")
|
|
180
|
-
.max(1, "memory.conflicts.relevanceThreshold must be <= 1")
|
|
181
|
-
.default(0.3),
|
|
182
|
-
conflictableKinds: z
|
|
183
|
-
.array(
|
|
184
|
-
z.enum(VALID_MEMORY_ITEM_KINDS, {
|
|
185
|
-
error: `memory.conflicts.conflictableKinds entries must be one of: ${VALID_MEMORY_ITEM_KINDS.join(
|
|
186
|
-
", ",
|
|
187
|
-
)}`,
|
|
188
|
-
}),
|
|
189
|
-
)
|
|
190
|
-
.nonempty({
|
|
191
|
-
message: "memory.conflicts.conflictableKinds must not be empty",
|
|
192
|
-
})
|
|
193
|
-
.default([...DEFAULT_CONFLICTABLE_KINDS]),
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
export const MemoryProfileConfigSchema = z.object({
|
|
197
|
-
enabled: z
|
|
198
|
-
.boolean({ error: "memory.profile.enabled must be a boolean" })
|
|
199
|
-
.default(true),
|
|
200
|
-
maxInjectTokens: z
|
|
201
|
-
.number({ error: "memory.profile.maxInjectTokens must be a number" })
|
|
202
|
-
.int("memory.profile.maxInjectTokens must be an integer")
|
|
203
|
-
.positive("memory.profile.maxInjectTokens must be a positive integer")
|
|
204
|
-
.default(800),
|
|
205
|
-
});
|
|
206
|
-
|
|
207
30
|
export type MemoryExtractionConfig = z.infer<
|
|
208
31
|
typeof MemoryExtractionConfigSchema
|
|
209
32
|
>;
|
|
210
33
|
export type MemorySummarizationConfig = z.infer<
|
|
211
34
|
typeof MemorySummarizationConfigSchema
|
|
212
35
|
>;
|
|
213
|
-
export type MemoryEntityConfig = z.infer<typeof MemoryEntityConfigSchema>;
|
|
214
|
-
export type MemoryConflictsConfig = z.infer<typeof MemoryConflictsConfigSchema>;
|
|
215
|
-
export type MemoryProfileConfig = z.infer<typeof MemoryProfileConfigSchema>;
|
|
@@ -1,22 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
|
|
3
|
-
export const MemoryRerankingConfigSchema = z.object({
|
|
4
|
-
enabled: z
|
|
5
|
-
.boolean({ error: "memory.retrieval.reranking.enabled must be a boolean" })
|
|
6
|
-
.default(false),
|
|
7
|
-
modelIntent: z
|
|
8
|
-
.enum(["latency-optimized", "quality-optimized", "vision-optimized"], {
|
|
9
|
-
error:
|
|
10
|
-
"memory.retrieval.reranking.modelIntent must be a valid model intent",
|
|
11
|
-
})
|
|
12
|
-
.default("latency-optimized"),
|
|
13
|
-
topK: z
|
|
14
|
-
.number({ error: "memory.retrieval.reranking.topK must be a number" })
|
|
15
|
-
.int("memory.retrieval.reranking.topK must be an integer")
|
|
16
|
-
.positive("memory.retrieval.reranking.topK must be a positive integer")
|
|
17
|
-
.default(20),
|
|
18
|
-
});
|
|
19
|
-
|
|
20
3
|
export const MemoryDynamicBudgetConfigSchema = z.object({
|
|
21
4
|
enabled: z
|
|
22
5
|
.boolean({
|
|
@@ -55,49 +38,6 @@ export const MemoryDynamicBudgetConfigSchema = z.object({
|
|
|
55
38
|
.default(10000),
|
|
56
39
|
});
|
|
57
40
|
|
|
58
|
-
export const MemoryEarlyTerminationConfigSchema = z.object({
|
|
59
|
-
enabled: z
|
|
60
|
-
.boolean({
|
|
61
|
-
error: "memory.retrieval.earlyTermination.enabled must be a boolean",
|
|
62
|
-
})
|
|
63
|
-
.default(true),
|
|
64
|
-
minCandidates: z
|
|
65
|
-
.number({
|
|
66
|
-
error: "memory.retrieval.earlyTermination.minCandidates must be a number",
|
|
67
|
-
})
|
|
68
|
-
.int("memory.retrieval.earlyTermination.minCandidates must be an integer")
|
|
69
|
-
.positive(
|
|
70
|
-
"memory.retrieval.earlyTermination.minCandidates must be a positive integer",
|
|
71
|
-
)
|
|
72
|
-
.default(20),
|
|
73
|
-
minHighConfidence: z
|
|
74
|
-
.number({
|
|
75
|
-
error:
|
|
76
|
-
"memory.retrieval.earlyTermination.minHighConfidence must be a number",
|
|
77
|
-
})
|
|
78
|
-
.int(
|
|
79
|
-
"memory.retrieval.earlyTermination.minHighConfidence must be an integer",
|
|
80
|
-
)
|
|
81
|
-
.positive(
|
|
82
|
-
"memory.retrieval.earlyTermination.minHighConfidence must be a positive integer",
|
|
83
|
-
)
|
|
84
|
-
.default(10),
|
|
85
|
-
confidenceThreshold: z
|
|
86
|
-
.number({
|
|
87
|
-
error:
|
|
88
|
-
"memory.retrieval.earlyTermination.confidenceThreshold must be a number",
|
|
89
|
-
})
|
|
90
|
-
.min(
|
|
91
|
-
0,
|
|
92
|
-
"memory.retrieval.earlyTermination.confidenceThreshold must be >= 0",
|
|
93
|
-
)
|
|
94
|
-
.max(
|
|
95
|
-
1,
|
|
96
|
-
"memory.retrieval.earlyTermination.confidenceThreshold must be <= 1",
|
|
97
|
-
)
|
|
98
|
-
.default(0.7),
|
|
99
|
-
});
|
|
100
|
-
|
|
101
41
|
/**
|
|
102
42
|
* Per-kind freshness windows (in days). Items older than their window
|
|
103
43
|
* (based on lastSeenAt) are down-ranked unless recently reinforced.
|
|
@@ -109,12 +49,13 @@ const MemoryFreshnessConfigSchema = z.object({
|
|
|
109
49
|
.default(true),
|
|
110
50
|
maxAgeDays: z
|
|
111
51
|
.object({
|
|
112
|
-
|
|
52
|
+
identity: z
|
|
113
53
|
.number({
|
|
114
|
-
error:
|
|
54
|
+
error:
|
|
55
|
+
"memory.retrieval.freshness.maxAgeDays.identity must be a number",
|
|
115
56
|
})
|
|
116
57
|
.nonnegative(
|
|
117
|
-
"memory.retrieval.freshness.maxAgeDays.
|
|
58
|
+
"memory.retrieval.freshness.maxAgeDays.identity must be non-negative",
|
|
118
59
|
)
|
|
119
60
|
.default(0),
|
|
120
61
|
preference: z
|
|
@@ -126,34 +67,50 @@ const MemoryFreshnessConfigSchema = z.object({
|
|
|
126
67
|
"memory.retrieval.freshness.maxAgeDays.preference must be non-negative",
|
|
127
68
|
)
|
|
128
69
|
.default(0),
|
|
129
|
-
|
|
70
|
+
project: z
|
|
130
71
|
.number({
|
|
131
72
|
error:
|
|
132
|
-
"memory.retrieval.freshness.maxAgeDays.
|
|
73
|
+
"memory.retrieval.freshness.maxAgeDays.project must be a number",
|
|
133
74
|
})
|
|
134
75
|
.nonnegative(
|
|
135
|
-
"memory.retrieval.freshness.maxAgeDays.
|
|
76
|
+
"memory.retrieval.freshness.maxAgeDays.project must be non-negative",
|
|
136
77
|
)
|
|
137
|
-
.default(
|
|
138
|
-
|
|
78
|
+
.default(30),
|
|
79
|
+
decision: z
|
|
139
80
|
.number({
|
|
140
|
-
error:
|
|
81
|
+
error:
|
|
82
|
+
"memory.retrieval.freshness.maxAgeDays.decision must be a number",
|
|
141
83
|
})
|
|
142
84
|
.nonnegative(
|
|
143
|
-
"memory.retrieval.freshness.maxAgeDays.
|
|
85
|
+
"memory.retrieval.freshness.maxAgeDays.decision must be non-negative",
|
|
144
86
|
)
|
|
145
87
|
.default(30),
|
|
146
|
-
|
|
88
|
+
constraint: z
|
|
147
89
|
.number({
|
|
148
90
|
error:
|
|
149
|
-
"memory.retrieval.freshness.maxAgeDays.
|
|
91
|
+
"memory.retrieval.freshness.maxAgeDays.constraint must be a number",
|
|
92
|
+
})
|
|
93
|
+
.nonnegative(
|
|
94
|
+
"memory.retrieval.freshness.maxAgeDays.constraint must be non-negative",
|
|
95
|
+
)
|
|
96
|
+
.default(90),
|
|
97
|
+
event: z
|
|
98
|
+
.number({
|
|
99
|
+
error: "memory.retrieval.freshness.maxAgeDays.event must be a number",
|
|
150
100
|
})
|
|
151
101
|
.nonnegative(
|
|
152
|
-
"memory.retrieval.freshness.maxAgeDays.
|
|
102
|
+
"memory.retrieval.freshness.maxAgeDays.event must be non-negative",
|
|
153
103
|
)
|
|
154
|
-
.default(
|
|
104
|
+
.default(30),
|
|
155
105
|
})
|
|
156
|
-
.default({
|
|
106
|
+
.default({
|
|
107
|
+
identity: 0,
|
|
108
|
+
preference: 0,
|
|
109
|
+
project: 30,
|
|
110
|
+
decision: 30,
|
|
111
|
+
constraint: 90,
|
|
112
|
+
event: 30,
|
|
113
|
+
}),
|
|
157
114
|
staleDecay: z
|
|
158
115
|
.number({ error: "memory.retrieval.freshness.staleDecay must be a number" })
|
|
159
116
|
.min(0, "memory.retrieval.freshness.staleDecay must be >= 0")
|
|
@@ -171,36 +128,11 @@ const MemoryFreshnessConfigSchema = z.object({
|
|
|
171
128
|
});
|
|
172
129
|
|
|
173
130
|
export const MemoryRetrievalConfigSchema = z.object({
|
|
174
|
-
lexicalTopK: z
|
|
175
|
-
.number({ error: "memory.retrieval.lexicalTopK must be a number" })
|
|
176
|
-
.int("memory.retrieval.lexicalTopK must be an integer")
|
|
177
|
-
.positive("memory.retrieval.lexicalTopK must be a positive integer")
|
|
178
|
-
.default(80),
|
|
179
|
-
semanticTopK: z
|
|
180
|
-
.number({ error: "memory.retrieval.semanticTopK must be a number" })
|
|
181
|
-
.int("memory.retrieval.semanticTopK must be an integer")
|
|
182
|
-
.positive("memory.retrieval.semanticTopK must be a positive integer")
|
|
183
|
-
.default(40),
|
|
184
131
|
maxInjectTokens: z
|
|
185
132
|
.number({ error: "memory.retrieval.maxInjectTokens must be a number" })
|
|
186
133
|
.int("memory.retrieval.maxInjectTokens must be an integer")
|
|
187
134
|
.positive("memory.retrieval.maxInjectTokens must be a positive integer")
|
|
188
135
|
.default(10000),
|
|
189
|
-
injectionFormat: z
|
|
190
|
-
.enum(["markdown", "structured_v1"], {
|
|
191
|
-
error:
|
|
192
|
-
'memory.retrieval.injectionFormat must be "markdown" or "structured_v1"',
|
|
193
|
-
})
|
|
194
|
-
.default("markdown"),
|
|
195
|
-
injectionStrategy: z
|
|
196
|
-
.enum(["prepend_user_block", "separate_context_message"], {
|
|
197
|
-
error:
|
|
198
|
-
'memory.retrieval.injectionStrategy must be "prepend_user_block" or "separate_context_message"',
|
|
199
|
-
})
|
|
200
|
-
.default("prepend_user_block"),
|
|
201
|
-
reranking: MemoryRerankingConfigSchema.default(
|
|
202
|
-
MemoryRerankingConfigSchema.parse({}),
|
|
203
|
-
),
|
|
204
136
|
freshness: MemoryFreshnessConfigSchema.default(
|
|
205
137
|
MemoryFreshnessConfigSchema.parse({}),
|
|
206
138
|
),
|
|
@@ -213,10 +145,6 @@ export const MemoryRetrievalConfigSchema = z.object({
|
|
|
213
145
|
dynamicBudget: MemoryDynamicBudgetConfigSchema.default(
|
|
214
146
|
MemoryDynamicBudgetConfigSchema.parse({}),
|
|
215
147
|
),
|
|
216
|
-
earlyTermination: MemoryEarlyTerminationConfigSchema.default(
|
|
217
|
-
MemoryEarlyTerminationConfigSchema.parse({}),
|
|
218
|
-
),
|
|
219
148
|
});
|
|
220
149
|
|
|
221
|
-
export type MemoryRerankingConfig = z.infer<typeof MemoryRerankingConfigSchema>;
|
|
222
150
|
export type MemoryRetrievalConfig = z.infer<typeof MemoryRetrievalConfigSchema>;
|
|
@@ -6,10 +6,7 @@ import {
|
|
|
6
6
|
MemoryRetentionConfigSchema,
|
|
7
7
|
} from "./memory-lifecycle.js";
|
|
8
8
|
import {
|
|
9
|
-
MemoryConflictsConfigSchema,
|
|
10
|
-
MemoryEntityConfigSchema,
|
|
11
9
|
MemoryExtractionConfigSchema,
|
|
12
|
-
MemoryProfileConfigSchema,
|
|
13
10
|
MemorySummarizationConfigSchema,
|
|
14
11
|
} from "./memory-processing.js";
|
|
15
12
|
import { MemoryRetrievalConfigSchema } from "./memory-retrieval.js";
|
|
@@ -46,13 +43,6 @@ export const MemoryConfigSchema = z.object({
|
|
|
46
43
|
summarization: MemorySummarizationConfigSchema.default(
|
|
47
44
|
MemorySummarizationConfigSchema.parse({}),
|
|
48
45
|
),
|
|
49
|
-
entity: MemoryEntityConfigSchema.default(MemoryEntityConfigSchema.parse({})),
|
|
50
|
-
conflicts: MemoryConflictsConfigSchema.default(
|
|
51
|
-
MemoryConflictsConfigSchema.parse({}),
|
|
52
|
-
),
|
|
53
|
-
profile: MemoryProfileConfigSchema.default(
|
|
54
|
-
MemoryProfileConfigSchema.parse({}),
|
|
55
|
-
),
|
|
56
46
|
});
|
|
57
47
|
|
|
58
48
|
export type MemoryConfig = z.infer<typeof MemoryConfigSchema>;
|
package/src/config/types.ts
CHANGED
|
@@ -12,13 +12,9 @@ export type {
|
|
|
12
12
|
IngressConfig,
|
|
13
13
|
LogFileConfig,
|
|
14
14
|
MemoryConfig,
|
|
15
|
-
MemoryConflictsConfig,
|
|
16
15
|
MemoryEmbeddingsConfig,
|
|
17
|
-
MemoryEntityConfig,
|
|
18
16
|
MemoryExtractionConfig,
|
|
19
17
|
MemoryJobsConfig,
|
|
20
|
-
MemoryProfileConfig,
|
|
21
|
-
MemoryRerankingConfig,
|
|
22
18
|
MemoryRetentionConfig,
|
|
23
19
|
MemoryRetrievalConfig,
|
|
24
20
|
MemorySegmentationConfig,
|
|
@@ -140,6 +140,10 @@ export function upsertContact(params: {
|
|
|
140
140
|
contactType?: ContactType;
|
|
141
141
|
principalId?: string | null;
|
|
142
142
|
channels?: SyncChannelData[];
|
|
143
|
+
/** When true, conflicting channels on other contacts are reassigned to this
|
|
144
|
+
* contact instead of being skipped. Used by invite redemption to bind a
|
|
145
|
+
* redeemer's existing channel identity to the invite's target contact. */
|
|
146
|
+
reassignConflictingChannels?: boolean;
|
|
143
147
|
}): ContactWithChannels & { created: boolean } {
|
|
144
148
|
const db = getDb();
|
|
145
149
|
const now = Date.now();
|
|
@@ -171,7 +175,12 @@ export function upsertContact(params: {
|
|
|
171
175
|
.run();
|
|
172
176
|
|
|
173
177
|
if (params.channels) {
|
|
174
|
-
syncChannels(
|
|
178
|
+
syncChannels(
|
|
179
|
+
contactId,
|
|
180
|
+
params.channels,
|
|
181
|
+
now,
|
|
182
|
+
params.reassignConflictingChannels,
|
|
183
|
+
);
|
|
175
184
|
}
|
|
176
185
|
|
|
177
186
|
emitContactChange();
|
|
@@ -253,6 +262,7 @@ function syncChannels(
|
|
|
253
262
|
contactId: string,
|
|
254
263
|
channels: SyncChannelData[],
|
|
255
264
|
now: number,
|
|
265
|
+
reassignConflicting?: boolean,
|
|
256
266
|
): void {
|
|
257
267
|
const db = getDb();
|
|
258
268
|
|
|
@@ -312,7 +322,34 @@ function syncChannels(
|
|
|
312
322
|
.get();
|
|
313
323
|
|
|
314
324
|
if (conflicting) {
|
|
315
|
-
|
|
325
|
+
if (reassignConflicting) {
|
|
326
|
+
// Reassign the channel to the target contact. Used by invite redemption
|
|
327
|
+
// to bind a redeemer's existing channel identity to the invite's target.
|
|
328
|
+
const reassignSet: Record<string, unknown> = {
|
|
329
|
+
contactId,
|
|
330
|
+
updatedAt: now,
|
|
331
|
+
};
|
|
332
|
+
if (ch.externalUserId !== undefined)
|
|
333
|
+
reassignSet.externalUserId = ch.externalUserId;
|
|
334
|
+
if (ch.externalChatId !== undefined)
|
|
335
|
+
reassignSet.externalChatId = ch.externalChatId;
|
|
336
|
+
if (ch.status !== undefined) reassignSet.status = ch.status;
|
|
337
|
+
if (ch.policy !== undefined) reassignSet.policy = ch.policy;
|
|
338
|
+
if (ch.verifiedAt !== undefined) reassignSet.verifiedAt = ch.verifiedAt;
|
|
339
|
+
if (ch.verifiedVia !== undefined)
|
|
340
|
+
reassignSet.verifiedVia = ch.verifiedVia;
|
|
341
|
+
if (ch.inviteId !== undefined) reassignSet.inviteId = ch.inviteId;
|
|
342
|
+
if (ch.revokedReason !== undefined)
|
|
343
|
+
reassignSet.revokedReason = ch.revokedReason;
|
|
344
|
+
if (ch.blockedReason !== undefined)
|
|
345
|
+
reassignSet.blockedReason = ch.blockedReason;
|
|
346
|
+
|
|
347
|
+
db.update(contactChannels)
|
|
348
|
+
.set(reassignSet)
|
|
349
|
+
.where(eq(contactChannels.id, conflicting.id))
|
|
350
|
+
.run();
|
|
351
|
+
}
|
|
352
|
+
// When not reassigning, skip to avoid unique constraint violation.
|
|
316
353
|
// The caller should use contact_merge to combine the two contacts.
|
|
317
354
|
continue;
|
|
318
355
|
}
|
|
@@ -24,6 +24,7 @@ import {
|
|
|
24
24
|
import type {
|
|
25
25
|
ChannelPolicy,
|
|
26
26
|
ChannelStatus,
|
|
27
|
+
ContactRole,
|
|
27
28
|
ContactWriteResult,
|
|
28
29
|
} from "./types.js";
|
|
29
30
|
|
|
@@ -146,6 +147,8 @@ export function upsertContactChannel(params: {
|
|
|
146
147
|
createdBySessionId?: string;
|
|
147
148
|
verifiedAt?: number;
|
|
148
149
|
verifiedVia?: string;
|
|
150
|
+
role?: ContactRole;
|
|
151
|
+
contactId?: string;
|
|
149
152
|
}): ContactWriteResult | null {
|
|
150
153
|
let address: string;
|
|
151
154
|
|
|
@@ -173,7 +176,9 @@ export function upsertContactChannel(params: {
|
|
|
173
176
|
: null;
|
|
174
177
|
|
|
175
178
|
upsertContact({
|
|
179
|
+
id: params.contactId,
|
|
176
180
|
displayName,
|
|
181
|
+
role: params.role,
|
|
177
182
|
channels: [
|
|
178
183
|
{
|
|
179
184
|
type: params.sourceChannel,
|
|
@@ -189,6 +194,10 @@ export function upsertContactChannel(params: {
|
|
|
189
194
|
verifiedVia: params.verifiedVia ?? undefined,
|
|
190
195
|
},
|
|
191
196
|
],
|
|
197
|
+
// When a specific contactId is provided, reassign conflicting channels from
|
|
198
|
+
// other contacts. This enables invite redemption to bind a redeemer's
|
|
199
|
+
// existing channel identity to the invite's target contact.
|
|
200
|
+
reassignConflictingChannels: !!params.contactId,
|
|
192
201
|
});
|
|
193
202
|
|
|
194
203
|
const contactResult = findContactChannel({
|
|
@@ -671,7 +671,10 @@ function countPersistedMessages(messages: Message[]): number {
|
|
|
671
671
|
function isToolResultOnly(message: Message): boolean {
|
|
672
672
|
return (
|
|
673
673
|
message.content.length > 0 &&
|
|
674
|
-
message.content.every(
|
|
674
|
+
message.content.every(
|
|
675
|
+
(block) =>
|
|
676
|
+
block.type === "tool_result" || block.type === "web_search_tool_result",
|
|
677
|
+
)
|
|
675
678
|
);
|
|
676
679
|
}
|
|
677
680
|
|
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
* Watches workspace files (config, prompts), protected directory
|
|
4
4
|
* (trust rules, secret allowlist), and skills directories for changes.
|
|
5
5
|
*/
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
existsSync,
|
|
8
|
+
type FSWatcher,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
readdirSync,
|
|
11
|
+
watch,
|
|
12
|
+
} from "node:fs";
|
|
7
13
|
import { join } from "node:path";
|
|
8
14
|
|
|
9
15
|
import { getConfig, invalidateConfigCache } from "../config/loader.js";
|
|
@@ -14,6 +20,8 @@ import {
|
|
|
14
20
|
resetAllowlist,
|
|
15
21
|
validateAllowlistFile,
|
|
16
22
|
} from "../security/secret-allowlist.js";
|
|
23
|
+
import { handleConfirmationSignal } from "../signals/confirm.js";
|
|
24
|
+
import { handleMcpReloadSignal } from "../signals/mcp-reload.js";
|
|
17
25
|
import { DebouncerMap } from "../util/debounce.js";
|
|
18
26
|
import { getLogger } from "../util/logger.js";
|
|
19
27
|
import {
|
|
@@ -107,8 +115,17 @@ export class ConfigWatcher {
|
|
|
107
115
|
"config.json": () => {
|
|
108
116
|
if (this.suppressReload) return;
|
|
109
117
|
try {
|
|
118
|
+
const prevConfig = getConfig();
|
|
119
|
+
const prevMcpFingerprint = JSON.stringify(prevConfig.mcp ?? {});
|
|
110
120
|
const changed = this.refreshConfigFromSources();
|
|
111
|
-
if (changed)
|
|
121
|
+
if (changed) {
|
|
122
|
+
onSessionEvict();
|
|
123
|
+
const newConfig = getConfig();
|
|
124
|
+
const newMcpFingerprint = JSON.stringify(newConfig.mcp ?? {});
|
|
125
|
+
if (newMcpFingerprint !== prevMcpFingerprint) {
|
|
126
|
+
handleMcpReloadSignal();
|
|
127
|
+
}
|
|
128
|
+
}
|
|
112
129
|
} catch (err) {
|
|
113
130
|
log.error(
|
|
114
131
|
{ err, configPath: join(workspaceDir, "config.json") },
|
|
@@ -185,6 +202,7 @@ export class ConfigWatcher {
|
|
|
185
202
|
);
|
|
186
203
|
}
|
|
187
204
|
|
|
205
|
+
this.startSignalsWatcher();
|
|
188
206
|
this.startSkillsWatchers(onSessionEvict);
|
|
189
207
|
}
|
|
190
208
|
|
|
@@ -196,6 +214,41 @@ export class ConfigWatcher {
|
|
|
196
214
|
this.watchers = [];
|
|
197
215
|
}
|
|
198
216
|
|
|
217
|
+
private startSignalsWatcher(): void {
|
|
218
|
+
const signalsDir = join(getWorkspaceDir(), "signals");
|
|
219
|
+
try {
|
|
220
|
+
if (!existsSync(signalsDir)) {
|
|
221
|
+
mkdirSync(signalsDir, { recursive: true });
|
|
222
|
+
}
|
|
223
|
+
} catch {
|
|
224
|
+
// If we can't create it, watching will also fail — handled below.
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const signalHandlers: Record<string, () => void> = {
|
|
228
|
+
"mcp-reload": handleMcpReloadSignal,
|
|
229
|
+
confirm: handleConfirmationSignal,
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
try {
|
|
233
|
+
const watcher = watch(signalsDir, (_eventType, filename) => {
|
|
234
|
+
if (!filename) return;
|
|
235
|
+
const file = String(filename);
|
|
236
|
+
if (!signalHandlers[file]) return;
|
|
237
|
+
this.debounceTimers.schedule(`signal:${file}`, () => {
|
|
238
|
+
log.info({ file }, "Signal file detected");
|
|
239
|
+
signalHandlers[file]();
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
this.watchers.push(watcher);
|
|
243
|
+
log.info({ dir: signalsDir }, "Watching signals directory");
|
|
244
|
+
} catch (err) {
|
|
245
|
+
log.warn(
|
|
246
|
+
{ err, dir: signalsDir },
|
|
247
|
+
"Failed to watch signals directory. Signal-based reload will be unavailable.",
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
199
252
|
private startSkillsWatchers(onSessionEvict: () => void): void {
|
|
200
253
|
const skillsDir = getWorkspaceSkillsDir();
|
|
201
254
|
if (!existsSync(skillsDir)) return;
|
|
@@ -143,7 +143,7 @@ function healthCheckHost(host: string): string {
|
|
|
143
143
|
/** Hit the daemon's HTTP /healthz endpoint. Returns true if it responds
|
|
144
144
|
* with HTTP 200 within the timeout — false on connection refused, timeout,
|
|
145
145
|
* or any other error. */
|
|
146
|
-
async function isHttpHealthy(): Promise<boolean> {
|
|
146
|
+
export async function isHttpHealthy(): Promise<boolean> {
|
|
147
147
|
const host = healthCheckHost(getRuntimeHttpHost());
|
|
148
148
|
const port = getRuntimeHttpPort();
|
|
149
149
|
try {
|