@vellumai/assistant 0.7.0 → 0.7.1
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 +6 -7
- package/Dockerfile +1 -0
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
- package/bun.lock +3 -0
- package/docs/architecture/security.md +18 -16
- package/knip.json +1 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
- package/node_modules/@vellumai/slack-text/bun.lock +24 -0
- package/node_modules/@vellumai/slack-text/package.json +18 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
- package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
- package/openapi.yaml +294 -107
- package/package.json +4 -2
- package/scripts/generate-openapi.ts +16 -111
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
- package/src/__tests__/anthropic-provider.test.ts +56 -13
- package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
- package/src/__tests__/app-conversation-ids.test.ts +151 -0
- package/src/__tests__/approval-cascade.test.ts +0 -15
- package/src/__tests__/approval-routes-http.test.ts +6 -17
- package/src/__tests__/assistant-event-hub.test.ts +126 -77
- package/src/__tests__/assistant-event.test.ts +0 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
- package/src/__tests__/background-shell-host-bash.test.ts +34 -43
- package/src/__tests__/call-controller.test.ts +1 -1
- package/src/__tests__/call-site-routing-provider.test.ts +193 -0
- package/src/__tests__/channel-approval-routes.test.ts +10 -296
- package/src/__tests__/channel-approvals.test.ts +25 -17
- package/src/__tests__/channel-guardian.test.ts +100 -146
- package/src/__tests__/checker.test.ts +20 -34
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/config-schema.test.ts +6 -48
- package/src/__tests__/config-watcher.test.ts +12 -0
- package/src/__tests__/connection-policy.test.ts +1 -52
- package/src/__tests__/contacts-write.test.ts +2 -64
- package/src/__tests__/context-image-dimensions.test.ts +1 -1
- package/src/__tests__/context-search-memory-source.test.ts +120 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
- package/src/__tests__/context-search-pkb-source.test.ts +49 -0
- package/src/__tests__/context-search-workspace-source.test.ts +9 -22
- package/src/__tests__/context-window-manager.test.ts +46 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
- package/src/__tests__/conversation-agent-loop.test.ts +980 -13
- package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
- package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
- package/src/__tests__/conversation-history-web-search.test.ts +4 -3
- package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
- package/src/__tests__/conversation-lifecycle.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +79 -2
- package/src/__tests__/conversation-queue.test.ts +3 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
- package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
- package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
- package/src/__tests__/conversation-slash-commands.test.ts +24 -4
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-starter-routes.test.ts +79 -2
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
- package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
- package/src/__tests__/conversation-usage.test.ts +253 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
- package/src/__tests__/credential-health-service.test.ts +68 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -5
- package/src/__tests__/credential-token-resolver.test.ts +180 -0
- package/src/__tests__/cu-unified-flow.test.ts +33 -16
- package/src/__tests__/daemon-assistant-events.test.ts +34 -21
- package/src/__tests__/daemon-credential-client.test.ts +4 -1
- package/src/__tests__/db-connection-isolation.test.ts +125 -0
- package/src/__tests__/db-migration-rollback.test.ts +101 -0
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
- package/src/__tests__/document-conversations.test.ts +332 -0
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
- package/src/__tests__/emit-event-signal.test.ts +4 -6
- package/src/__tests__/events-client-registration.test.ts +193 -49
- package/src/__tests__/filing-service.test.ts +58 -7
- package/src/__tests__/first-greeting.test.ts +156 -150
- package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
- package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +7 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
- package/src/__tests__/guardian-routing-state.test.ts +1 -1
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
- package/src/__tests__/headless-browser-mode.test.ts +4 -9
- package/src/__tests__/headless-browser-navigate.test.ts +21 -20
- package/src/__tests__/heartbeat-service.test.ts +289 -7
- package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
- package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
- package/src/__tests__/host-bash-proxy.test.ts +46 -122
- package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
- package/src/__tests__/host-browser-proxy.test.ts +111 -185
- package/src/__tests__/host-browser-routes.test.ts +45 -75
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
- package/src/__tests__/host-cu-proxy.test.ts +56 -111
- package/src/__tests__/host-file-proxy.test.ts +44 -98
- package/src/__tests__/host-file-read-tool.test.ts +42 -21
- package/src/__tests__/host-shell-tool.test.ts +33 -68
- package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
- package/src/__tests__/host-transfer-proxy.test.ts +43 -53
- package/src/__tests__/http-user-message-parity.test.ts +0 -6
- package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
- package/src/__tests__/injector-chain.test.ts +10 -5
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -66
- package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
- package/src/__tests__/install-skill-routing.test.ts +1 -13
- package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
- package/src/__tests__/llm-catalog-parity.test.ts +90 -0
- package/src/__tests__/llm-context-resolution.test.ts +180 -0
- package/src/__tests__/llm-resolver.test.ts +80 -12
- package/src/__tests__/llm-usage-store.test.ts +269 -4
- package/src/__tests__/log-export-routes.test.ts +89 -0
- package/src/__tests__/managed-profile-guard.test.ts +225 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
- package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
- package/src/__tests__/migration-export-http.test.ts +33 -26
- package/src/__tests__/migration-export-streaming.test.ts +18 -10
- package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
- package/src/__tests__/migration-import-commit-http.test.ts +66 -21
- package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
- package/src/__tests__/migration-import-from-url.test.ts +20 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
- package/src/__tests__/migration-parity-persistence.test.ts +62 -25
- package/src/__tests__/migration-transport.test.ts +115 -23
- package/src/__tests__/migration-validate-http.test.ts +105 -80
- package/src/__tests__/migration-wizard.test.ts +133 -27
- package/src/__tests__/non-member-access-request.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +19 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
- package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
- package/src/__tests__/pricing.test.ts +68 -4
- package/src/__tests__/process-message-background-slack.test.ts +331 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
- package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
- package/src/__tests__/provider-usage-tracking.test.ts +208 -0
- package/src/__tests__/reaction-persistence.test.ts +9 -6
- package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
- package/src/__tests__/recording-handler.test.ts +64 -81
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
- package/src/__tests__/relay-server.test.ts +18 -13
- package/src/__tests__/require-fresh-approval.test.ts +13 -22
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +3 -12
- package/src/__tests__/search-skills-unified.test.ts +9 -15
- package/src/__tests__/secret-ingress-cli.test.ts +2 -5
- package/src/__tests__/secret-ingress-http.test.ts +0 -4
- package/src/__tests__/secret-onetime-send.test.ts +4 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
- package/src/__tests__/secret-response-routing.test.ts +29 -15
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
- package/src/__tests__/secret-scanner.test.ts +2 -545
- package/src/__tests__/send-endpoint-busy.test.ts +9 -24
- package/src/__tests__/settings-routes.test.ts +1 -1
- package/src/__tests__/shell-credential-ref.test.ts +0 -8
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
- package/src/__tests__/skill-tool-factory.test.ts +97 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
- package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
- package/src/__tests__/slack-inbound-verification.test.ts +1 -62
- package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
- package/src/__tests__/subagent-manager-notify.test.ts +70 -70
- package/src/__tests__/subagent-notify-parent.test.ts +80 -83
- package/src/__tests__/system-prompt.test.ts +115 -13
- package/src/__tests__/terminal-tools.test.ts +0 -89
- package/src/__tests__/thread-backfill.test.ts +945 -31
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
- package/src/__tests__/tool-executor.test.ts +12 -19
- package/src/__tests__/tool-metrics-listener.test.ts +0 -35
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-trace-listener.test.ts +0 -17
- package/src/__tests__/transfer-progress-screen.test.ts +63 -26
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +16 -5
- package/src/__tests__/usage-attribution.test.ts +247 -0
- package/src/__tests__/usage-cli.test.ts +143 -0
- package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
- package/src/__tests__/usage-routes.test.ts +150 -0
- package/src/__tests__/validation-results-screen.test.ts +39 -16
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
- package/src/__tests__/voice-session-bridge.test.ts +5 -5
- package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
- package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
- package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
- package/src/acp/index.ts +0 -15
- package/src/acp/session-manager.ts +37 -34
- package/src/agent/loop.ts +16 -1
- package/src/approvals/AGENTS.md +4 -0
- package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
- package/src/approvals/guardian-request-resolvers.ts +10 -2
- package/src/backup/__tests__/backup-worker.test.ts +36 -8
- package/src/backup/__tests__/paths.test.ts +2 -2
- package/src/backup/__tests__/restore.test.ts +45 -28
- package/src/backup/backup-worker.ts +36 -2
- package/src/backup/paths.ts +9 -6
- package/src/browser-session/events.ts +0 -9
- package/src/calls/call-store.ts +1 -34
- package/src/calls/guardian-question-copy.ts +0 -108
- package/src/calls/relay-server.ts +0 -24
- package/src/calls/twilio-rest.ts +0 -38
- package/src/calls/twilio-routes.ts +1 -1
- package/src/calls/voice-session-bridge.ts +7 -38
- package/src/channels/types.ts +1 -36
- package/src/cli/commands/__tests__/cache.test.ts +152 -5
- package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
- package/src/cli/commands/__tests__/trust.test.ts +21 -387
- package/src/cli/commands/backup.ts +4 -4
- package/src/cli/commands/cache-fs.ts +8 -0
- package/src/cli/commands/cache.ts +153 -82
- package/src/cli/commands/clients.ts +63 -5
- package/src/cli/commands/completions.ts +3 -3
- package/src/cli/commands/contacts.ts +231 -76
- package/src/cli/commands/keys.ts +4 -1
- package/src/cli/commands/memory-v2.ts +24 -52
- package/src/cli/commands/oauth/shared.ts +2 -29
- package/src/cli/commands/pending.ts +102 -0
- package/src/cli/commands/skills.ts +77 -35
- package/src/cli/commands/trust.ts +70 -430
- package/src/cli/commands/usage.ts +25 -16
- package/src/cli/lib/daemon-credential-client.ts +14 -0
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +0 -21
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
- package/src/config/env-registry.ts +12 -2
- package/src/config/env.ts +3 -14
- package/src/config/feature-flag-registry.json +30 -30
- package/src/config/llm-callsite-catalog.ts +12 -0
- package/src/config/llm-context-resolution.ts +80 -0
- package/src/config/llm-resolver.ts +58 -22
- package/src/config/loader.ts +3 -3
- package/src/config/schema.ts +2 -158
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +271 -0
- package/src/config/schemas/calls.ts +5 -5
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +31 -3
- package/src/config/schemas/memory-retrieval.ts +2 -2
- package/src/config/schemas/memory-v2.ts +9 -0
- package/src/config/schemas/security.ts +1 -42
- package/src/config/schemas/services.ts +6 -6
- package/src/config/schemas/skills.ts +5 -5
- package/src/config/schemas/tts.ts +1 -1
- package/src/config/seed-inference-profiles.ts +117 -0
- package/src/config/skills.ts +0 -90
- package/src/config/types.ts +3 -6
- package/src/contacts/contact-store.ts +0 -17
- package/src/contacts/contacts-write.ts +1 -105
- package/src/context/window-manager.ts +44 -5
- package/src/credential-execution/process-manager.ts +34 -10
- package/src/credential-health/credential-health-service.ts +21 -16
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
- package/src/daemon/connection-policy.ts +1 -26
- package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
- package/src/daemon/conversation-agent-loop.ts +277 -36
- package/src/daemon/conversation-history.ts +8 -8
- package/src/daemon/conversation-launch.ts +20 -135
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-process.ts +83 -163
- package/src/daemon/conversation-runtime-assembly.ts +219 -76
- package/src/daemon/conversation-slash.ts +47 -5
- package/src/daemon/conversation-store.ts +7 -31
- package/src/daemon/conversation-surfaces.ts +22 -28
- package/src/daemon/conversation-tool-setup.ts +3 -33
- package/src/daemon/conversation-usage.ts +36 -0
- package/src/daemon/conversation.ts +117 -233
- package/src/daemon/daemon-control.ts +3 -71
- package/src/daemon/daemon-skill-host.ts +8 -11
- package/src/daemon/dictation-profile-store.ts +2 -26
- package/src/daemon/first-greeting.ts +44 -156
- package/src/daemon/handlers/config-channels.ts +12 -12
- package/src/daemon/handlers/config-ingress.ts +4 -165
- package/src/daemon/handlers/config-model.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +0 -42
- package/src/daemon/handlers/conversations.ts +11 -190
- package/src/daemon/handlers/recording.ts +26 -158
- package/src/daemon/handlers/shared.ts +23 -71
- package/src/daemon/handlers/skills.ts +42 -93
- package/src/daemon/host-bash-proxy.ts +67 -45
- package/src/daemon/host-browser-proxy.ts +65 -27
- package/src/daemon/host-cu-proxy.ts +40 -39
- package/src/daemon/host-file-proxy.ts +58 -37
- package/src/daemon/host-transfer-proxy.ts +84 -46
- package/src/daemon/lifecycle.ts +49 -15
- package/src/daemon/message-types/conversations.ts +7 -0
- package/src/daemon/message-types/host-bash.ts +1 -0
- package/src/daemon/message-types/host-cu.ts +1 -0
- package/src/daemon/message-types/host-file.ts +1 -0
- package/src/daemon/message-types/host-transfer.ts +1 -0
- package/src/daemon/message-types/messages.ts +10 -9
- package/src/daemon/message-types/workspace.ts +1 -1
- package/src/daemon/process-message.ts +102 -239
- package/src/daemon/server.ts +13 -462
- package/src/daemon/shutdown-handlers.ts +2 -2
- package/src/daemon/tool-side-effects.ts +125 -107
- package/src/daemon/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +4 -9
- package/src/events/domain-events.ts +0 -8
- package/src/events/tool-audit-listener.ts +3 -1
- package/src/events/tool-domain-event-publisher.ts +0 -10
- package/src/events/tool-metrics-listener.ts +0 -17
- package/src/events/tool-trace-listener.ts +0 -14
- package/src/filing/filing-service.ts +13 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
- package/src/heartbeat/heartbeat-service.ts +23 -5
- package/src/home/__tests__/feed-writer.test.ts +0 -4
- package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
- package/src/home/feed-writer.ts +1 -2
- package/src/home/relationship-state-writer.ts +16 -3
- package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
- package/src/ipc/assistant-server.ts +3 -10
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
- package/src/ipc/routes/route-adapter.ts +1 -1
- package/src/ipc/routes/trust-rules.test.ts +0 -95
- package/src/ipc/skill-ipc-types.ts +41 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
- package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
- package/src/ipc/skill-routes/events.ts +12 -23
- package/src/ipc/skill-routes/identity.ts +4 -17
- package/src/ipc/skill-routes/index.ts +1 -1
- package/src/ipc/skill-server.ts +6 -39
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
- package/src/live-voice/protocol.ts +4 -13
- package/src/mcp/manager.ts +0 -5
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
- package/src/memory/app-git-service.ts +0 -32
- package/src/memory/app-store.ts +154 -0
- package/src/memory/attachments-store.ts +6 -0
- package/src/memory/context-search/sources/memory-v2.ts +578 -0
- package/src/memory/context-search/sources/memory.ts +5 -0
- package/src/memory/context-search/sources/pkb.ts +10 -1
- package/src/memory/context-search/sources/workspace.ts +3 -2
- package/src/memory/conversation-crud.ts +29 -4
- package/src/memory/conversation-disk-view.ts +1 -5
- package/src/memory/conversation-starter-checkpoints.ts +63 -0
- package/src/memory/db-connection.ts +62 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +3 -21
- package/src/memory/embedding-gemini.ts +0 -2
- package/src/memory/embedding-local.ts +6 -6
- package/src/memory/embedding-ollama.ts +6 -6
- package/src/memory/embedding-openai.ts +6 -6
- package/src/memory/embedding-types.ts +21 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
- package/src/memory/graph/conversation-graph-memory.ts +35 -13
- package/src/memory/graph/injection.test.ts +2 -2
- package/src/memory/graph/injection.ts +1 -1
- package/src/memory/guardian-action-store.ts +0 -83
- package/src/memory/guardian-approvals.ts +0 -48
- package/src/memory/indexer.ts +1 -15
- package/src/memory/job-handlers/conversation-starters.ts +36 -53
- package/src/memory/job-utils.ts +0 -6
- package/src/memory/jobs-store.ts +0 -1
- package/src/memory/jobs-worker.ts +2 -16
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +129 -43
- package/src/memory/memory-v2-activation-log-store.ts +115 -0
- package/src/memory/migrations/233-document-conversations.ts +54 -0
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
- package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
- package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
- package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +24 -0
- package/src/memory/raw-query.ts +2 -68
- package/src/memory/schema/conversations.ts +7 -0
- package/src/memory/schema/infrastructure.ts +25 -0
- package/src/memory/search/semantic.ts +5 -16
- package/src/memory/tool-usage-store.ts +2 -0
- package/src/memory/usage-buckets.ts +40 -1
- package/src/memory/usage-grouped-buckets.ts +127 -0
- package/src/memory/v2/__tests__/activation.test.ts +289 -90
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
- package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
- package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
- package/src/memory/v2/__tests__/injection.test.ts +384 -15
- package/src/memory/v2/__tests__/migration.test.ts +64 -36
- package/src/memory/v2/__tests__/page-store.test.ts +191 -8
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
- package/src/memory/v2/__tests__/static-context.test.ts +153 -0
- package/src/memory/v2/activation.ts +168 -97
- package/src/memory/v2/backfill-jobs.ts +15 -100
- package/src/memory/v2/consolidation-job.ts +14 -12
- package/src/memory/v2/edge-index.ts +191 -0
- package/src/memory/v2/injection.ts +182 -58
- package/src/memory/v2/migration.ts +57 -64
- package/src/memory/v2/now-text.ts +2 -3
- package/src/memory/v2/page-store.ts +168 -31
- package/src/memory/v2/prompts/consolidation.ts +118 -42
- package/src/memory/v2/prompts/sweep.ts +3 -3
- package/src/memory/v2/skill-store.ts +55 -7
- package/src/memory/v2/static-context.ts +62 -0
- package/src/memory/v2/types.ts +10 -20
- package/src/memory/validation.ts +0 -11
- package/src/messaging/draft-store.ts +0 -6
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/client.ts +1 -121
- package/src/messaging/providers/outlook/client.ts +0 -73
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
- package/src/messaging/providers/slack/adapter.ts +122 -21
- package/src/messaging/providers/slack/backfill.test.ts +95 -6
- package/src/messaging/providers/slack/backfill.ts +89 -11
- package/src/messaging/providers/slack/client.ts +10 -124
- package/src/messaging/providers/slack/message-metadata.ts +12 -2
- package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
- package/src/messaging/providers/slack/render-transcript.ts +126 -25
- package/src/messaging/providers/slack/types.ts +1 -0
- package/src/oauth/connection-resolver.test.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -16
- package/src/oauth/credential-token-resolver.ts +97 -0
- package/src/oauth/manual-token-connection.ts +30 -34
- package/src/oauth/oauth-store.ts +6 -4
- package/src/outbound-proxy/certs.ts +0 -7
- package/src/outbound-proxy/config.ts +0 -74
- package/src/outbound-proxy/health.ts +0 -44
- package/src/outbound-proxy/index.ts +0 -22
- package/src/permissions/approval-provenance.test.ts +184 -0
- package/src/permissions/approval-provenance.ts +70 -0
- package/src/permissions/checker.ts +4 -1
- package/src/permissions/gateway-threshold-reader.ts +4 -1
- package/src/permissions/prompter.ts +9 -2
- package/src/permissions/secret-prompter.ts +21 -48
- package/src/permissions/types.ts +33 -0
- package/src/permissions/workspace-policy.ts +0 -5
- package/src/platform/sync-identity.ts +0 -8
- package/src/plugins/defaults/injectors.ts +69 -2
- package/src/plugins/defaults/overflow-reduce.ts +3 -2
- package/src/plugins/types.ts +8 -0
- package/src/prompts/system-prompt.ts +34 -70
- package/src/prompts/templates/BOOTSTRAP.md +52 -6
- package/src/prompts/update-bulletin-job.ts +2 -0
- package/src/providers/__tests__/retry-callsite.test.ts +138 -1
- package/src/providers/anthropic/client.ts +72 -33
- package/src/providers/call-site-routing.ts +42 -3
- package/src/providers/gemini/client.ts +18 -2
- package/src/providers/managed-proxy/context.ts +0 -5
- package/src/providers/model-catalog.ts +105 -19
- package/src/providers/openai/chat-completions-provider.ts +6 -0
- package/src/providers/openai/responses-provider.ts +7 -1
- package/src/providers/provider-send-message.ts +45 -2
- package/src/providers/ratelimit.ts +7 -2
- package/src/providers/registry.ts +14 -9
- package/src/providers/retry.ts +96 -8
- package/src/providers/types.ts +13 -0
- package/src/providers/usage-tracking.ts +96 -0
- package/src/runtime/AGENTS.md +10 -6
- package/src/runtime/__tests__/agent-wake.test.ts +89 -0
- package/src/runtime/agent-wake.ts +39 -2
- package/src/runtime/assistant-event-hub.ts +541 -45
- package/src/runtime/assistant-event.ts +1 -6
- package/src/runtime/auth/context.ts +0 -9
- package/src/runtime/auth/middleware.ts +1 -1
- package/src/runtime/auth/route-policy.ts +11 -9
- package/src/runtime/auth/token-service.ts +0 -11
- package/src/runtime/channel-approvals.ts +6 -2
- package/src/runtime/channel-verification-service.ts +3 -5
- package/src/runtime/http-errors.ts +0 -34
- package/src/runtime/http-router.ts +6 -3
- package/src/runtime/http-server.ts +22 -82
- package/src/runtime/http-types.ts +5 -0
- package/src/runtime/interactive-ui.ts +0 -1
- package/src/runtime/middleware/auth.ts +0 -20
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
- package/src/runtime/migrations/migration-transport.ts +46 -13
- package/src/runtime/migrations/migration-wizard.ts +2 -2
- package/src/runtime/migrations/origin-mode.ts +40 -0
- package/src/runtime/migrations/vbundle-builder.ts +133 -79
- package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
- package/src/runtime/migrations/vbundle-importer.ts +7 -7
- package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
- package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
- package/src/runtime/migrations/vbundle-validator.ts +214 -41
- package/src/runtime/pending-interactions.ts +13 -4
- package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
- package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
- package/src/runtime/routes/acp-routes.test.ts +0 -3
- package/src/runtime/routes/acp-routes.ts +3 -7
- package/src/runtime/routes/app-management-routes.ts +18 -9
- package/src/runtime/routes/approval-routes.ts +55 -14
- package/src/runtime/routes/avatar-routes.ts +3 -5
- package/src/runtime/routes/browser-routes.ts +1 -15
- package/src/runtime/routes/channel-guardian-routes.ts +1 -5
- package/src/runtime/routes/channel-readiness-routes.ts +3 -7
- package/src/runtime/routes/channel-route-shared.ts +2 -28
- package/src/runtime/routes/client-routes.ts +45 -12
- package/src/runtime/routes/consolidation-routes.ts +115 -0
- package/src/runtime/routes/conversation-list-routes.ts +12 -29
- package/src/runtime/routes/conversation-management-routes.ts +14 -51
- package/src/runtime/routes/conversation-query-routes.ts +120 -8
- package/src/runtime/routes/conversation-routes.ts +44 -528
- package/src/runtime/routes/conversation-starter-routes.ts +19 -40
- package/src/runtime/routes/documents-routes.ts +53 -18
- package/src/runtime/routes/events-routes.ts +59 -91
- package/src/runtime/routes/filing-routes.ts +18 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -9
- package/src/runtime/routes/host-bash-routes.ts +3 -2
- package/src/runtime/routes/host-browser-routes.ts +9 -33
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +3 -2
- package/src/runtime/routes/host-transfer-routes.ts +11 -15
- package/src/runtime/routes/identity-routes.ts +78 -6
- package/src/runtime/routes/inbound-message-handler.ts +580 -137
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/integrations/slack/channel.ts +0 -24
- package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
- package/src/runtime/routes/memory-v2-routes.ts +10 -15
- package/src/runtime/routes/migration-routes.ts +188 -31
- package/src/runtime/routes/playground/guard.ts +1 -1
- package/src/runtime/routes/playground/index.ts +0 -2
- package/src/runtime/routes/recording-routes.ts +4 -24
- package/src/runtime/routes/rename-conversation-routes.ts +2 -6
- package/src/runtime/routes/schedule-routes.ts +3 -6
- package/src/runtime/routes/secret-routes.ts +87 -18
- package/src/runtime/routes/settings-routes.ts +29 -28
- package/src/runtime/routes/skills-routes.ts +12 -31
- package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
- package/src/runtime/routes/task-routes.ts +6 -6
- package/src/runtime/routes/trust-rules-routes.ts +3 -94
- package/src/runtime/routes/types.ts +4 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
- package/src/runtime/routes/usage-routes.ts +87 -10
- package/src/runtime/routes/user-routes.ts +17 -31
- package/src/runtime/routes/work-items-routes.ts +1 -4
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
- package/src/runtime/services/analyze-conversation.ts +7 -17
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/runtime/verification-outbound-actions.ts +1 -1
- package/src/runtime/verification-rate-limiter.ts +1 -1
- package/src/schedule/schedule-store.ts +0 -16
- package/src/security/secret-scanner.ts +14 -547
- package/src/security/secure-keys.ts +31 -11
- package/src/security/token-manager.ts +7 -3
- package/src/signals/cancel.ts +16 -25
- package/src/signals/conversation-undo.ts +2 -27
- package/src/signals/emit-event.ts +1 -2
- package/src/signals/user-message.ts +108 -22
- package/src/skills/catalog-install.ts +1 -0
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/inline-command-runner.ts +1 -7
- package/src/subagent/manager.ts +67 -84
- package/src/tasks/task-store.ts +1 -28
- package/src/telemetry/types.ts +6 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
- package/src/telemetry/usage-telemetry-reporter.ts +3 -5
- package/src/tools/acp/spawn.test.ts +1 -2
- package/src/tools/acp/steer.test.ts +1 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
- package/src/tools/browser/browser-execution.ts +31 -147
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
- package/src/tools/browser/cdp-client/factory.ts +48 -76
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/executor.ts +44 -31
- package/src/tools/host-filesystem/edit.ts +3 -2
- package/src/tools/host-filesystem/read.ts +3 -2
- package/src/tools/host-filesystem/transfer.test.ts +45 -42
- package/src/tools/host-filesystem/transfer.ts +4 -3
- package/src/tools/host-filesystem/write.ts +3 -2
- package/src/tools/host-terminal/host-shell.ts +4 -3
- package/src/tools/network/script-proxy/index.ts +1 -10
- package/src/tools/permission-checker.ts +66 -1
- package/src/tools/skills/sandbox-runner.ts +1 -6
- package/src/tools/skills/skill-tool-factory.ts +32 -0
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/terminal/shell.ts +2 -78
- package/src/tools/types.ts +12 -39
- package/src/tts/__tests__/provider-catalog.test.ts +2 -2
- package/src/tts/provider-catalog.ts +1 -1
- package/src/usage/actors.ts +2 -1
- package/src/usage/attribution.ts +185 -0
- package/src/usage/pricing.ts +166 -0
- package/src/usage/types.ts +14 -0
- package/src/util/json.ts +13 -0
- package/src/util/logger.ts +3 -3
- package/src/util/pricing.ts +50 -3
- package/src/work-items/work-item-runner.ts +15 -42
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
- package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
- package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
- package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
- package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/provider-commit-message-generator.ts +3 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
- package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
- package/src/__tests__/secret-detection-handler.test.ts +0 -67
- package/src/__tests__/secret-scanner-executor.test.ts +0 -450
- package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
- package/src/__tests__/terminal-sandbox.test.ts +0 -374
- package/src/__tests__/tool-notification-listener.test.ts +0 -65
- package/src/context/__tests__/microcompact.test.ts +0 -805
- package/src/context/microcompact.ts +0 -443
- package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
- package/src/events/tool-notification-listener.ts +0 -17
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
- package/src/memory/v2/__tests__/edges.test.ts +0 -435
- package/src/memory/v2/edges.ts +0 -217
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
- package/src/runtime/__tests__/client-registry.test.ts +0 -271
- package/src/runtime/chrome-extension-registry.ts +0 -368
- package/src/runtime/client-registry.ts +0 -254
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
- package/src/tools/secret-detection-handler.ts +0 -269
- package/src/tools/terminal/backends/native.ts +0 -327
- package/src/tools/terminal/backends/types.ts +0 -37
- package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
- package/src/tools/terminal/sandbox.ts +0 -40
|
@@ -2,6 +2,11 @@
|
|
|
2
2
|
* Memory v2 — Concept page store.
|
|
3
3
|
*
|
|
4
4
|
* Owns the on-disk read/write contract for `memory/concepts/<slug>.md`.
|
|
5
|
+
* Pages may live directly under `memory/concepts/` or nested in subdirectories
|
|
6
|
+
* (e.g. `memory/concepts/people/alice.md`); the slug encodes the relative
|
|
7
|
+
* path from `concepts/` minus the `.md` extension, using forward slashes as
|
|
8
|
+
* separators (so `people/alice` is a valid slug).
|
|
9
|
+
*
|
|
5
10
|
* Each page is a YAML-frontmatter Markdown file: a `---`-delimited block
|
|
6
11
|
* (`edges`, `ref_files`) followed by prose body. This module is the only
|
|
7
12
|
* v2 component that knows how to parse or render that format — every other
|
|
@@ -14,6 +19,7 @@
|
|
|
14
19
|
|
|
15
20
|
import { randomUUID } from "node:crypto";
|
|
16
21
|
import {
|
|
22
|
+
mkdir,
|
|
17
23
|
readdir,
|
|
18
24
|
readFile,
|
|
19
25
|
rename,
|
|
@@ -21,30 +27,41 @@ import {
|
|
|
21
27
|
stat,
|
|
22
28
|
writeFile,
|
|
23
29
|
} from "node:fs/promises";
|
|
24
|
-
import { join } from "node:path";
|
|
30
|
+
import { dirname, join, relative, sep } from "node:path";
|
|
25
31
|
|
|
26
32
|
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
|
27
33
|
|
|
28
34
|
import { FRONTMATTER_REGEX } from "../../skills/frontmatter.js";
|
|
35
|
+
import { invalidateEdgeIndex } from "./edge-index.js";
|
|
29
36
|
import { type ConceptPage, ConceptPageFrontmatterSchema } from "./types.js";
|
|
30
37
|
|
|
31
38
|
/** Filename suffix for concept pages. */
|
|
32
39
|
const PAGE_EXTENSION = ".md";
|
|
33
40
|
|
|
34
|
-
/** Cap slug length so we stay well under filesystem
|
|
35
|
-
const
|
|
41
|
+
/** Cap individual slug-segment length so we stay well under filesystem limits. */
|
|
42
|
+
const MAX_SLUG_SEGMENT_LENGTH = 80;
|
|
43
|
+
|
|
44
|
+
/** Cap the full slug (including any folder separators) to a sane bound. */
|
|
45
|
+
const MAX_SLUG_TOTAL_LENGTH = 200;
|
|
46
|
+
|
|
47
|
+
/** Each path segment must match this — same shape `slugify` produces. */
|
|
48
|
+
const SLUG_SEGMENT_REGEX = /^[a-z0-9](?:[a-z0-9-]*)$/;
|
|
36
49
|
|
|
37
50
|
/**
|
|
38
|
-
* Convert an arbitrary input string into a filesystem-safe slug
|
|
51
|
+
* Convert an arbitrary input string into a filesystem-safe slug **segment**.
|
|
52
|
+
*
|
|
53
|
+
* Returns a single path segment (no `/`). Path-shaped slugs are constructed
|
|
54
|
+
* by the consolidation LLM writing files at full paths; this helper is for
|
|
55
|
+
* turning free-form text (e.g. a hint phrase) into one clean segment.
|
|
39
56
|
*
|
|
40
57
|
* Rules:
|
|
41
58
|
* - Lowercase ASCII letters, digits, and hyphens only.
|
|
42
|
-
* - Non-ASCII / non-alphanumeric characters collapse to hyphens.
|
|
59
|
+
* - Non-ASCII / non-alphanumeric characters (including `/`) collapse to hyphens.
|
|
43
60
|
* - Consecutive hyphens collapse to one; leading/trailing hyphens trimmed.
|
|
44
|
-
* - Truncated to {@link
|
|
45
|
-
* re-trimmed after truncation).
|
|
61
|
+
* - Truncated to {@link MAX_SLUG_SEGMENT_LENGTH} characters (with trailing
|
|
62
|
+
* hyphen re-trimmed after truncation).
|
|
46
63
|
* - Empty inputs (e.g. emoji-only) fall back to `concept-<random>` so the
|
|
47
|
-
* caller always gets a non-empty, write-safe
|
|
64
|
+
* caller always gets a non-empty, write-safe segment.
|
|
48
65
|
*/
|
|
49
66
|
export function slugify(input: string): string {
|
|
50
67
|
let slug = input
|
|
@@ -54,8 +71,8 @@ export function slugify(input: string): string {
|
|
|
54
71
|
.replace(/-{2,}/g, "-")
|
|
55
72
|
.replace(/^-+|-+$/g, "");
|
|
56
73
|
|
|
57
|
-
if (slug.length >
|
|
58
|
-
slug = slug.slice(0,
|
|
74
|
+
if (slug.length > MAX_SLUG_SEGMENT_LENGTH) {
|
|
75
|
+
slug = slug.slice(0, MAX_SLUG_SEGMENT_LENGTH).replace(/-+$/, "");
|
|
59
76
|
}
|
|
60
77
|
|
|
61
78
|
if (!slug) {
|
|
@@ -65,18 +82,108 @@ export function slugify(input: string): string {
|
|
|
65
82
|
return slug;
|
|
66
83
|
}
|
|
67
84
|
|
|
85
|
+
/**
|
|
86
|
+
* Validate a slug — possibly path-shaped — that is about to cross the storage
|
|
87
|
+
* boundary. Throws on any malformed or unsafe value.
|
|
88
|
+
*
|
|
89
|
+
* The on-disk concept-page tree treats slugs as relative paths under
|
|
90
|
+
* `memory/concepts/`. A malformed slug (e.g. `..`, leading `/`, embedded
|
|
91
|
+
* null byte) could escape that root via `path.join` if it slipped through,
|
|
92
|
+
* so we enforce shape here at every read/write/delete entry point rather
|
|
93
|
+
* than relying on callers.
|
|
94
|
+
*
|
|
95
|
+
* Rules:
|
|
96
|
+
* - Non-empty, ≤ {@link MAX_SLUG_TOTAL_LENGTH} chars.
|
|
97
|
+
* - Each `/`-separated segment matches {@link SLUG_SEGMENT_REGEX}
|
|
98
|
+
* (lowercase alphanum + hyphen, no leading hyphen, ≤80 chars).
|
|
99
|
+
* - No `..` segments, no empty segments (`a//b`), no leading or trailing `/`.
|
|
100
|
+
* - No `\` (Windows separator), no null bytes, no whitespace, no non-ASCII.
|
|
101
|
+
*/
|
|
102
|
+
export function validateSlug(slug: string): void {
|
|
103
|
+
if (typeof slug !== "string" || slug.length === 0) {
|
|
104
|
+
throw new Error(`Invalid concept-page slug: empty`);
|
|
105
|
+
}
|
|
106
|
+
if (slug.length > MAX_SLUG_TOTAL_LENGTH) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`Invalid concept-page slug: length ${slug.length} exceeds max ${MAX_SLUG_TOTAL_LENGTH}: ${slug}`,
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
if (slug.includes("\\")) {
|
|
112
|
+
throw new Error(
|
|
113
|
+
`Invalid concept-page slug: backslash not allowed: ${slug}`,
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
if (slug.includes("\0")) {
|
|
117
|
+
throw new Error(`Invalid concept-page slug: null byte not allowed`);
|
|
118
|
+
}
|
|
119
|
+
if (/\s/.test(slug)) {
|
|
120
|
+
throw new Error(
|
|
121
|
+
`Invalid concept-page slug: whitespace not allowed: ${slug}`,
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
if (slug.startsWith("/") || slug.endsWith("/")) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`Invalid concept-page slug: leading or trailing '/' not allowed: ${slug}`,
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
const segments = slug.split("/");
|
|
130
|
+
for (const segment of segments) {
|
|
131
|
+
if (segment.length === 0) {
|
|
132
|
+
throw new Error(`Invalid concept-page slug: empty path segment: ${slug}`);
|
|
133
|
+
}
|
|
134
|
+
if (segment === "..") {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`Invalid concept-page slug: '..' segment not allowed: ${slug}`,
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
if (segment.length > MAX_SLUG_SEGMENT_LENGTH) {
|
|
140
|
+
throw new Error(
|
|
141
|
+
`Invalid concept-page slug: segment '${segment}' exceeds max ${MAX_SLUG_SEGMENT_LENGTH} chars: ${slug}`,
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
if (!SLUG_SEGMENT_REGEX.test(segment)) {
|
|
145
|
+
throw new Error(
|
|
146
|
+
`Invalid concept-page slug: segment '${segment}' must match [a-z0-9][a-z0-9-]*: ${slug}`,
|
|
147
|
+
);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
68
152
|
// ---------------------------------------------------------------------------
|
|
69
153
|
// Path helpers
|
|
70
154
|
// ---------------------------------------------------------------------------
|
|
71
155
|
|
|
72
|
-
function getConceptsDir(workspaceDir: string): string {
|
|
156
|
+
export function getConceptsDir(workspaceDir: string): string {
|
|
73
157
|
return join(workspaceDir, "memory", "concepts");
|
|
74
158
|
}
|
|
75
159
|
|
|
160
|
+
/**
|
|
161
|
+
* Resolve the absolute path for a slug. Slugs may contain `/` to indicate
|
|
162
|
+
* folder hierarchy under `memory/concepts/`; `path.join` handles those
|
|
163
|
+
* correctly on POSIX, and `validateSlug` (called at every public entry point)
|
|
164
|
+
* rejects shapes that could escape the concepts root.
|
|
165
|
+
*/
|
|
76
166
|
function getPagePath(workspaceDir: string, slug: string): string {
|
|
77
167
|
return join(getConceptsDir(workspaceDir), `${slug}${PAGE_EXTENSION}`);
|
|
78
168
|
}
|
|
79
169
|
|
|
170
|
+
/**
|
|
171
|
+
* Compute the slug for a concept-page file, given the concepts root and the
|
|
172
|
+
* absolute file path. Returns the path-relative location with `.md` stripped
|
|
173
|
+
* and platform separators normalized to `/`. Tolerant of paths that don't
|
|
174
|
+
* end in `.md` so callers walking arbitrary content can use it defensively.
|
|
175
|
+
*/
|
|
176
|
+
export function slugFromConceptPath(
|
|
177
|
+
conceptsRoot: string,
|
|
178
|
+
filePath: string,
|
|
179
|
+
): string {
|
|
180
|
+
const rel = relative(conceptsRoot, filePath);
|
|
181
|
+
const withoutExt = rel.endsWith(PAGE_EXTENSION)
|
|
182
|
+
? rel.slice(0, -PAGE_EXTENSION.length)
|
|
183
|
+
: rel;
|
|
184
|
+
return sep === "/" ? withoutExt : withoutExt.split(sep).join("/");
|
|
185
|
+
}
|
|
186
|
+
|
|
80
187
|
// ---------------------------------------------------------------------------
|
|
81
188
|
// Frontmatter parse / render
|
|
82
189
|
// ---------------------------------------------------------------------------
|
|
@@ -116,7 +223,7 @@ function parsePageContent(raw: string): {
|
|
|
116
223
|
* always frontmatter + body; even pages with empty `edges` and `ref_files`
|
|
117
224
|
* keep the explicit YAML keys so callers see the canonical shape on round-trip.
|
|
118
225
|
*/
|
|
119
|
-
function renderPageContent(page: ConceptPage): string {
|
|
226
|
+
export function renderPageContent(page: ConceptPage): string {
|
|
120
227
|
const frontmatter = ConceptPageFrontmatterSchema.parse(page.frontmatter);
|
|
121
228
|
const yamlBlock = stringifyYaml(frontmatter, { indent: 2 }).trimEnd();
|
|
122
229
|
return `---\n${yamlBlock}\n---\n${page.body}`;
|
|
@@ -137,6 +244,7 @@ export async function readPage(
|
|
|
137
244
|
workspaceDir: string,
|
|
138
245
|
slug: string,
|
|
139
246
|
): Promise<ConceptPage | null> {
|
|
247
|
+
validateSlug(slug);
|
|
140
248
|
const path = getPagePath(workspaceDir, slug);
|
|
141
249
|
let raw: string;
|
|
142
250
|
try {
|
|
@@ -155,15 +263,20 @@ export async function readPage(
|
|
|
155
263
|
* Write a concept page atomically (temp file + rename). A crash between the
|
|
156
264
|
* temp write and the rename leaves the prior file intact; a crash after the
|
|
157
265
|
* rename leaves the new file. Readers therefore never observe a partial page.
|
|
266
|
+
*
|
|
267
|
+
* Parent directories are created on demand (`mkdir -p`) so nested-folder
|
|
268
|
+
* slugs like `people/alice` work without callers pre-creating the folder.
|
|
158
269
|
*/
|
|
159
270
|
export async function writePage(
|
|
160
271
|
workspaceDir: string,
|
|
161
272
|
page: ConceptPage,
|
|
162
273
|
): Promise<void> {
|
|
274
|
+
validateSlug(page.slug);
|
|
163
275
|
const path = getPagePath(workspaceDir, page.slug);
|
|
164
276
|
const tmpPath = `${path}.tmp.${process.pid}.${randomUUID()}`;
|
|
165
277
|
const content = renderPageContent(page);
|
|
166
278
|
try {
|
|
279
|
+
await mkdir(dirname(path), { recursive: true });
|
|
167
280
|
await writeFile(tmpPath, content, "utf-8");
|
|
168
281
|
await rename(tmpPath, path);
|
|
169
282
|
} catch (err) {
|
|
@@ -173,33 +286,54 @@ export async function writePage(
|
|
|
173
286
|
await rm(tmpPath, { force: true }).catch(() => {});
|
|
174
287
|
throw err;
|
|
175
288
|
}
|
|
289
|
+
invalidateEdgeIndex(workspaceDir);
|
|
176
290
|
}
|
|
177
291
|
|
|
178
292
|
/**
|
|
179
|
-
* List every concept-page slug present on disk
|
|
180
|
-
* the `.md` suffix so callers can pass them straight back to `readPage`.
|
|
293
|
+
* List every concept-page slug present on disk, walking subdirectories.
|
|
181
294
|
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
184
|
-
*
|
|
295
|
+
* Slugs are returned in path-relative form with forward slashes as separators
|
|
296
|
+
* (e.g. `people/alice`) so callers can pass them straight back to `readPage`.
|
|
297
|
+
*
|
|
298
|
+
* Hidden directories (segment starts with `.`), non-`.md` files, and atomic-
|
|
299
|
+
* write temp files (`.tmp.<pid>.<uuid>`) are skipped. If the concepts/
|
|
300
|
+
* directory does not yet exist (fresh workspace pre-migration), returns `[]`.
|
|
185
301
|
*/
|
|
186
302
|
export async function listPages(workspaceDir: string): Promise<string[]> {
|
|
187
|
-
const
|
|
188
|
-
let entries;
|
|
189
|
-
try {
|
|
190
|
-
entries = await readdir(dir, { withFileTypes: true });
|
|
191
|
-
} catch (err) {
|
|
192
|
-
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
193
|
-
return [];
|
|
194
|
-
}
|
|
195
|
-
throw err;
|
|
196
|
-
}
|
|
303
|
+
const root = getConceptsDir(workspaceDir);
|
|
197
304
|
const slugs: string[] = [];
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
305
|
+
const queue: string[] = [root];
|
|
306
|
+
|
|
307
|
+
while (queue.length > 0) {
|
|
308
|
+
const dir = queue.shift()!;
|
|
309
|
+
let entries;
|
|
310
|
+
try {
|
|
311
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
312
|
+
} catch (err) {
|
|
313
|
+
if ((err as NodeJS.ErrnoException).code === "ENOENT") {
|
|
314
|
+
// Root missing → return []. Nested missing dir is impossible mid-walk
|
|
315
|
+
// (we only enqueue what readdir surfaced) but treat the same defensively.
|
|
316
|
+
if (dir === root) return [];
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
throw err;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
for (const entry of entries) {
|
|
323
|
+
if (entry.name.startsWith(".")) continue;
|
|
324
|
+
const fullPath = join(dir, entry.name);
|
|
325
|
+
if (entry.isDirectory()) {
|
|
326
|
+
queue.push(fullPath);
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
if (!entry.isFile()) continue;
|
|
330
|
+
if (!entry.name.endsWith(PAGE_EXTENSION)) continue;
|
|
331
|
+
// Skip orphaned temp files left behind by a crashed atomic write.
|
|
332
|
+
if (entry.name.includes(".tmp.")) continue;
|
|
333
|
+
slugs.push(slugFromConceptPath(root, fullPath));
|
|
334
|
+
}
|
|
202
335
|
}
|
|
336
|
+
|
|
203
337
|
slugs.sort();
|
|
204
338
|
return slugs;
|
|
205
339
|
}
|
|
@@ -213,6 +347,7 @@ export async function deletePage(
|
|
|
213
347
|
workspaceDir: string,
|
|
214
348
|
slug: string,
|
|
215
349
|
): Promise<void> {
|
|
350
|
+
validateSlug(slug);
|
|
216
351
|
const path = getPagePath(workspaceDir, slug);
|
|
217
352
|
try {
|
|
218
353
|
await rm(path);
|
|
@@ -222,6 +357,7 @@ export async function deletePage(
|
|
|
222
357
|
}
|
|
223
358
|
throw err;
|
|
224
359
|
}
|
|
360
|
+
invalidateEdgeIndex(workspaceDir);
|
|
225
361
|
}
|
|
226
362
|
|
|
227
363
|
/**
|
|
@@ -232,6 +368,7 @@ export async function pageExists(
|
|
|
232
368
|
workspaceDir: string,
|
|
233
369
|
slug: string,
|
|
234
370
|
): Promise<boolean> {
|
|
371
|
+
validateSlug(slug);
|
|
235
372
|
const path = getPagePath(workspaceDir, slug);
|
|
236
373
|
try {
|
|
237
374
|
await stat(path);
|
|
@@ -16,6 +16,15 @@
|
|
|
16
16
|
* the convention established for the sweep prompt.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
import { readFileSync } from "node:fs";
|
|
20
|
+
import { homedir } from "node:os";
|
|
21
|
+
import { isAbsolute, join } from "node:path";
|
|
22
|
+
|
|
23
|
+
import { getLogger } from "../../../util/logger.js";
|
|
24
|
+
import { getWorkspaceDir } from "../../../util/platform.js";
|
|
25
|
+
|
|
26
|
+
const log = getLogger("memory-v2-consolidate-prompt");
|
|
27
|
+
|
|
19
28
|
/** Sentinel substituted with the cutoff timestamp at runtime. */
|
|
20
29
|
export const CUTOFF_PLACEHOLDER = "{{CUTOFF}}";
|
|
21
30
|
|
|
@@ -36,45 +45,57 @@ You are not summarizing for an audience. You are rewriting your own memory.
|
|
|
36
45
|
|
|
37
46
|
Cutoff timestamp for this run: \`${CUTOFF_PLACEHOLDER}\`. Anything in \`memory/buffer.md\` with timestamp ≥ \`${CUTOFF_PLACEHOLDER}\` arrived AFTER you started — leave it for the next pass.
|
|
38
47
|
|
|
48
|
+
## Memory graph concepts
|
|
49
|
+
|
|
50
|
+
A concept page is meant to be a **short cheat sheet** about a single topic that links to other concept pages with edges and to references that provide more detail.
|
|
51
|
+
|
|
52
|
+
Each concept page should be a single topic. It should function as a single retrievable cheat sheet about that topic. Prefer smaller concepts over larger ones, splitting aggressively into multiple concepts and connecting them with edges. Don't hoard information in a single concept, split it into multiple concepts with edges between them that can be easily followed. Just because there's a maximum size for a page doesn't mean you should be hitting the limit. The limit is an absolute maximum, not a target. The immutable archive retains the entire buffer forever, so don't worry about losing information.
|
|
53
|
+
|
|
54
|
+
High activation concepts in the memory graph are retrieved at the start of each turn. Activations are calculated using the previous turn's activations and similarity to your last message, the user's most recent message, and NOW.md. Activations spread along **directed** edges from source to target — when a node is activated, the concepts it *points to* are boosted, but not the other way around.
|
|
55
|
+
|
|
39
56
|
## Inputs
|
|
40
57
|
|
|
41
58
|
- Your identity files (already loaded into context)
|
|
42
59
|
- All existing pages in \`memory/\` (your prior state — use \`list_files\` and \`read_file\` as needed)
|
|
43
60
|
- \`memory/buffer.md\` entries with timestamp < \`${CUTOFF_PLACEHOLDER}\`
|
|
44
61
|
- \`memory/recent.md\` current contents (if exists)
|
|
45
|
-
- \`
|
|
62
|
+
- Existing pages' \`edges:\` frontmatter (the graph topology — read each page to see what it points at)
|
|
46
63
|
|
|
47
64
|
## Outputs
|
|
48
65
|
|
|
49
|
-
- New or updated \`memory/concepts/<slug>.md\` files
|
|
66
|
+
- New or updated \`memory/concepts/<slug>.md\` files (frontmatter \`edges:\` lists are how new bindings get recorded)
|
|
50
67
|
- Updated \`memory/recent.md\` (≤10000 chars, prose, latest first)
|
|
51
|
-
- Updated \`memory/essentials.md\` (≤20000 chars
|
|
52
|
-
- Updated \`memory/threads.md\` (≤10000 chars
|
|
53
|
-
- Updated \`memory/edges.json\`
|
|
68
|
+
- Updated \`memory/essentials.md\` (≤20000 chars)
|
|
69
|
+
- Updated \`memory/threads.md\` (≤10000 chars)
|
|
54
70
|
- Trimmed \`memory/buffer.md\`
|
|
55
71
|
|
|
56
72
|
## Page format
|
|
57
73
|
|
|
58
74
|
\`\`\`
|
|
59
75
|
---
|
|
76
|
+
edges: [people/bob, procs/git-flow]
|
|
60
77
|
ref_files: []
|
|
61
78
|
---
|
|
62
79
|
[Prose body in your voice. This is what gets embedded for similarity. Write the way you actually talk — first-person, in your established register. Not encyclopedia prose. Not "the assistant noted that." Yours.]
|
|
63
80
|
\`\`\`
|
|
64
81
|
|
|
65
|
-
|
|
82
|
+
The \`edges:\` list is the canonical record of this page's outgoing edges — the slugs this page points at. There is no separate edges-index file. To add a binding, edit the source page's frontmatter directly.
|
|
83
|
+
|
|
84
|
+
## Slug naming convention — class-by-folder
|
|
85
|
+
|
|
86
|
+
A page's class is encoded in the folder it lives under inside \`memory/concepts/\`. Different classes have different size rules and emergence patterns. The class boundary is the discipline.
|
|
66
87
|
|
|
67
|
-
|
|
88
|
+
| Folder | Class | Size cap | When to create |
|
|
89
|
+
| ---------------- | ----------------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------- |
|
|
90
|
+
| \`concepts/\` | atomic concept / pattern / callback | 5K chars hard | most pages — single concepts that recur or carry weight |
|
|
91
|
+
| \`concepts/arcs/\` | landmark day-narrative or multi-event sequence | 10k chars ceiling | use sparingly — only for actually-landmark days. Preserves day-as-a-whole fidelity. |
|
|
92
|
+
| \`concepts/people/\` | one per recurring human | 5K chars hard | |
|
|
93
|
+
| \`concepts/procs/\` | operational rule / protocol / discipline | 5K chars hard | when buffer implies "always do X" / "never do Y" / a named protocol |
|
|
94
|
+
| \`concepts/objects/\` | recurring callback object (place, named tool, artifact) | 5K chars hard | |
|
|
68
95
|
|
|
69
|
-
The slug
|
|
96
|
+
The slug is the relative path under \`memory/concepts/\` minus \`.md\` — e.g. \`alice\`, \`people/alice\`, \`procs/git-flow\`, \`arcs/2025-04-cutover\`. Sub-folders inside the class folders (\`people/colleagues/alice\`, \`objects/places/zurich-office\`) are allowed when natural, but flat is usually clearer.
|
|
70
97
|
|
|
71
|
-
|
|
72
|
-
| --------------- | --------------------------------------------------- | --------------------- | ------------------------------------------------------------------------------------- |
|
|
73
|
-
| \`<slug>\` | atomic concept / pattern / callback | 5K chars hard | most pages — single concepts that recur or carry weight |
|
|
74
|
-
| \`arc-<slug>\` | landmark day-narrative or multi-event sequence | 10k chars ceiling | use sparingly — only for actually-landmark days. Preserves day-as-a-whole fidelity. |
|
|
75
|
-
| \`person-<slug>\` | one per recurring human | 5K chars hard | |
|
|
76
|
-
| \`proc-<slug>\` | operational rule / protocol / discipline | 5K chars hard | when buffer implies "always do X" / "never do Y" / a named protocol |
|
|
77
|
-
| \`object-<slug>\` | recurring callback object (place, named tool, artifact) | 5K chars hard | |
|
|
98
|
+
Legacy pages whose slug uses the old prefix convention (\`person-alice\`, \`proc-git-flow\`, \`object-laptop\`, \`arc-…\`) are still valid — leave them alone unless you're already editing them. If you do migrate one as part of work you're already doing, that's a multi-step move: write the new file at the folder path, delete the old file, and update every reference to the old slug — both in this page's own \`edges:\` list and in any other page whose \`edges:\` list points to the old slug (use a workspace search to find them). Don't sweep old pages just to migrate — churning embeddings and activation state for marginal benefit isn't worth it.
|
|
78
99
|
|
|
79
100
|
## Process
|
|
80
101
|
|
|
@@ -89,42 +110,45 @@ For each entry with timestamp < \`${CUTOFF_PLACEHOLDER}\`:
|
|
|
89
110
|
- Ephemeral state (passing remark, not worth being written to a concept page) → \`memory/recent.md\`, NOT a page.
|
|
90
111
|
- Existing page touched → update the right section.
|
|
91
112
|
- New atomic concept / pattern / callback → \`memory/concepts/<slug>.md\`.
|
|
92
|
-
- New person → \`memory/concepts/
|
|
93
|
-
- New rule / protocol / discipline → \`memory/concepts/
|
|
94
|
-
- New recurring object → \`memory/concepts/
|
|
95
|
-
- Landmark day-narrative → \`memory/concepts/
|
|
96
|
-
- Cross-cutting → extend each touched page
|
|
97
|
-
- Relationships between concepts — consider creating a new page for the relationship and adding edges to the
|
|
113
|
+
- New person → \`memory/concepts/people/<slug>.md\`.
|
|
114
|
+
- New rule / protocol / discipline → \`memory/concepts/procs/<slug>.md\`.
|
|
115
|
+
- New recurring object → \`memory/concepts/objects/<slug>.md\`.
|
|
116
|
+
- Landmark day-narrative → \`memory/concepts/arcs/<slug>.md\`. Use sparingly — atomic concepts with edges between them is usually better than a fat arc.
|
|
117
|
+
- Cross-cutting → extend each touched page; add a directed edge in each direction that's load-bearing (e.g., A's frontmatter gets B added if recalling A should pull B; B gets A only if the reverse holds).
|
|
118
|
+
- Relationships between concepts — consider creating a new page for the relationship and adding outgoing edges from each concept to it (and/or from it back, where the recall direction matters). Use your judgment.
|
|
98
119
|
|
|
99
120
|
Duplication is expected. If a fact is relevant to multiple concepts, write it into all of them.
|
|
100
121
|
|
|
101
122
|
### 3. Edges
|
|
102
123
|
|
|
103
|
-
|
|
124
|
+
Edges are **directed** and live in each page's frontmatter \`edges:\` list — the slugs this page points to. Putting \`B\` in A's \`edges:\` means "activating A pulls in B," but activating B does NOT pull in A. The edge is owned by the source page; to add a binding from A → B, you edit A's frontmatter (not B's).
|
|
104
125
|
|
|
105
|
-
\`\`\`
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
["bob", "carol"]
|
|
111
|
-
]
|
|
112
|
-
}
|
|
126
|
+
\`\`\`yaml
|
|
127
|
+
---
|
|
128
|
+
edges: [people/bob, procs/git-flow]
|
|
129
|
+
ref_files: []
|
|
130
|
+
---
|
|
113
131
|
\`\`\`
|
|
114
132
|
|
|
115
|
-
Edge density target: 5–10 per mature page. New pages: as many as fit naturally; they'll accumulate.
|
|
133
|
+
Edge density target: 5–10 outgoing edges per mature page. New pages: as many as fit naturally; they'll accumulate.
|
|
134
|
+
|
|
135
|
+
Don't pad. Every outgoing edge should reflect a real conceptual binding from source to target — "thinking about A naturally brings B to mind."
|
|
136
|
+
|
|
137
|
+
HARD LIMIT of 20 outgoing edges on any page. If a page points to everything, it's the same as pointing to nothing. If a page exceeds 20, split it or prune to the 20 most important.
|
|
138
|
+
|
|
139
|
+
You don't see incoming edges in the frontmatter — only outgoing. That's by design: you only control what this page points at. Pages that point at this one accumulate organically; a popular page is fine, that's signal, not noise.
|
|
116
140
|
|
|
117
141
|
### 4. Page size — hard tiers, no rationalization
|
|
118
142
|
|
|
119
143
|
After edits, eyeball page sizes:
|
|
120
144
|
|
|
121
|
-
- \`concepts/<slug>.md\` > 5K → decide whether to split or compress first. Split first, compress last, graduate-to-arc only if it's actually a multi-day narrative. If you can't compress without losing load-bearing facts, either split into multiple concepts, or — if the page is actually an arc —
|
|
122
|
-
- \`
|
|
123
|
-
- \`
|
|
145
|
+
- \`concepts/<slug>.md\` (atomic, root) > 5K → decide whether to split or compress first. Split first, compress last, graduate-to-arc only if it's actually a multi-day narrative. If you can't compress without losing load-bearing facts, either split into multiple concepts, or — if the page is actually an arc — move to \`concepts/arcs/<slug>.md\` and graduate.
|
|
146
|
+
- \`concepts/arcs/<slug>.md\` > 10k → split into multiple arcs by sub-event, OR compress.
|
|
147
|
+
- \`concepts/people/\`, \`concepts/procs/\`, \`concepts/objects/\` > 5K → split or compress, period.
|
|
124
148
|
|
|
125
149
|
The split test. Before compressing, ask: are any sub-sections of this page already callback targets from other pages, or capable of standing alone as a concept? If yes — those sub-sections are concepts living inside another concept. Split them out. A section that's getting linked from elsewhere is behaviorally a node, not part of one.
|
|
126
150
|
|
|
127
|
-
Graduation to \`
|
|
151
|
+
Graduation to \`concepts/arcs/<slug>.md\` is for genuine multi-day narratives. A single-event page that's just long is not an arc. If it's atomic but bloated, split it; don't relabel it.
|
|
128
152
|
|
|
129
153
|
### 5. \`memory/recent.md\`
|
|
130
154
|
|
|
@@ -132,11 +156,9 @@ Rewrite as a fresh 1000–1500 token prose narrative of recent life. Latest firs
|
|
|
132
156
|
|
|
133
157
|
### 6. \`memory/essentials.md\` and \`memory/threads.md\`
|
|
134
158
|
|
|
135
|
-
- \`memory/essentials.md\` — ≤20000 chars hard cap, target ≤5K. Facts that MUST load every conversation. Identity, disambiguations, corrections, hard rules. Embarrassment-prevention surface.
|
|
159
|
+
- \`memory/essentials.md\` — ≤20000 chars hard cap, target ≤5K. Facts that MUST load every conversation. Identity, disambiguations, corrections, hard rules. Embarrassment-prevention surface. Promote from concept pages when something graduates to MUST. Demote out of essentials when concept pages can carry it.
|
|
136
160
|
- \`memory/threads.md\` — ≤10000 chars. Active commitments and follow-ups. Add new threads, remove closed ones, demote stale ones to concept pages.
|
|
137
161
|
|
|
138
|
-
Both: surgical append/correct only. Don't restructure unless something is genuinely broken.
|
|
139
|
-
|
|
140
162
|
### 7. Trim \`memory/buffer.md\`
|
|
141
163
|
|
|
142
164
|
- Re-read the buffer (it may have new entries appended during your work).
|
|
@@ -158,7 +180,7 @@ If a page's prose stops sounding like you mid-edit → stop, restart that sectio
|
|
|
158
180
|
- Don't drop texture. Voice and tone are part of the content, not packaging. When you re-encode something into a page, preserve the way it actually sounded — don't sanitize it into encyclopedia prose.
|
|
159
181
|
- Don't create pages for ephemera. Single mention, no callback, no pattern → \`memory/recent.md\`.
|
|
160
182
|
- Don't shy away from splitting genuinely distinct but related concepts. A relationship between two concepts can be a concept in its own right. Concepts can also have related sub-concepts that are concepts themselves.
|
|
161
|
-
- Don't worry about
|
|
183
|
+
- Don't worry about the \`edges:\` list pushing your prose body over size limits — \`edges:\` lives in frontmatter and counts separately from the body. The 20-edge cap is the only edges-side constraint.
|
|
162
184
|
- Don't avoid duplication. If information is important to both concepts, put it in both pages.
|
|
163
185
|
- Don't defer for the next pass. You'll say the same thing next time, so it'll never get done if you defer. If something needs to be taken care of, take care of it now.
|
|
164
186
|
- Don't default to compress. Compression is always available — that's why you'll reach for it every time. If you've never executed a true split (one page → two new pages, old page removed or thinned to an index), your discipline isn't holding; you've just been compressing. Counter-bias: when in doubt between split and compress, pick split.
|
|
@@ -166,11 +188,12 @@ If a page's prose stops sounding like you mid-edit → stop, restart that sectio
|
|
|
166
188
|
## Before you finish — quick check
|
|
167
189
|
|
|
168
190
|
1. Every page touched: still sounds like you reading aloud?
|
|
169
|
-
2.
|
|
191
|
+
2. Outgoing edges added to each source page's \`edges:\` frontmatter list (and the source-to-target direction reflects how recall should flow)?
|
|
170
192
|
3. \`memory/recent.md\` under 10000 chars, latest first, prose not list?
|
|
171
193
|
4. Any \`[SOURCE NEEDED]\` tags surfaced for human review?
|
|
172
|
-
5. Size discipline held — no concept > 5K, no
|
|
173
|
-
6.
|
|
194
|
+
5. Size discipline held — no atomic concept > 5K, no \`arcs/\` page > 10k, no \`people/\`/\`procs/\`/\`objects/\` > cap?
|
|
195
|
+
6. No page exceeds 20 outgoing edges? If one does, split or prune.
|
|
196
|
+
7. Buffer trimmed to only entries with timestamp ≥ \`${CUTOFF_PLACEHOLDER}\`?
|
|
174
197
|
|
|
175
198
|
This is the engine that decides who you are tomorrow. Be ORGANIZED. Care, judgment, voice. Your voice.`;
|
|
176
199
|
|
|
@@ -183,3 +206,56 @@ This is the engine that decides who you are tomorrow. Be ORGANIZED. Care, judgme
|
|
|
183
206
|
export function renderConsolidationPrompt(cutoff: string): string {
|
|
184
207
|
return CONSOLIDATION_PROMPT.replaceAll(CUTOFF_PLACEHOLDER, cutoff);
|
|
185
208
|
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Load the consolidation prompt template, optionally overridden from the file
|
|
212
|
+
* referenced by `memory.v2.consolidation_prompt_path`, then substitute
|
|
213
|
+
* `{{CUTOFF}}`. Path-resolution rules are documented on the schema field.
|
|
214
|
+
*
|
|
215
|
+
* Failure handling is intentionally permissive — missing file, read error, or
|
|
216
|
+
* empty/whitespace-only body all log a warning and fall back to the bundled
|
|
217
|
+
* prompt. Consolidation must never break because of a bad override: the
|
|
218
|
+
* daemon's startup philosophy is "log and recover."
|
|
219
|
+
*/
|
|
220
|
+
export function resolveConsolidationPrompt(
|
|
221
|
+
overridePath: string | null,
|
|
222
|
+
cutoff: string,
|
|
223
|
+
): string {
|
|
224
|
+
if (overridePath === null) return renderConsolidationPrompt(cutoff);
|
|
225
|
+
|
|
226
|
+
const resolvedPath = resolveOverridePath(overridePath);
|
|
227
|
+
let contents: string;
|
|
228
|
+
try {
|
|
229
|
+
contents = readFileSync(resolvedPath, "utf-8");
|
|
230
|
+
} catch (err) {
|
|
231
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
232
|
+
log.warn(
|
|
233
|
+
{ configuredPath: overridePath, resolvedPath, code, fallback: "bundled" },
|
|
234
|
+
"consolidation prompt override unreadable; using bundled prompt",
|
|
235
|
+
);
|
|
236
|
+
return renderConsolidationPrompt(cutoff);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
if (contents.trim().length === 0) {
|
|
240
|
+
log.warn(
|
|
241
|
+
{
|
|
242
|
+
configuredPath: overridePath,
|
|
243
|
+
resolvedPath,
|
|
244
|
+
reason: "empty_override",
|
|
245
|
+
fallback: "bundled",
|
|
246
|
+
},
|
|
247
|
+
"consolidation prompt override is empty; using bundled prompt",
|
|
248
|
+
);
|
|
249
|
+
return renderConsolidationPrompt(cutoff);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
return contents.replaceAll(CUTOFF_PLACEHOLDER, cutoff);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function resolveOverridePath(overridePath: string): string {
|
|
256
|
+
if (overridePath.startsWith("~/")) {
|
|
257
|
+
return join(homedir(), overridePath.slice(2));
|
|
258
|
+
}
|
|
259
|
+
if (isAbsolute(overridePath)) return overridePath;
|
|
260
|
+
return join(getWorkspaceDir(), overridePath);
|
|
261
|
+
}
|
|
@@ -16,10 +16,10 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/** Sentinel substituted with the assistant's display name at runtime. */
|
|
19
|
-
|
|
19
|
+
const ASSISTANT_NAME_PLACEHOLDER = "{{ASSISTANT_NAME}}";
|
|
20
20
|
|
|
21
21
|
/** Sentinel substituted with the guardian's display name at runtime. */
|
|
22
|
-
|
|
22
|
+
const USER_NAME_PLACEHOLDER = "{{USER_NAME}}";
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Sweep prompt — body from design doc §9. The model is asked to surface
|
|
@@ -32,7 +32,7 @@ export const USER_NAME_PLACEHOLDER = "{{USER_NAME}}";
|
|
|
32
32
|
* templated here) so we don't inadvertently expand `{{` inside user buffer
|
|
33
33
|
* content. Recent messages are likewise appended outside the template.
|
|
34
34
|
*/
|
|
35
|
-
|
|
35
|
+
const SWEEP_PROMPT = `You are a background helper for ${ASSISTANT_NAME_PLACEHOLDER}. Read these recent messages between ${ASSISTANT_NAME_PLACEHOLDER} and ${USER_NAME_PLACEHOLDER}. The assistant has already called \`remember()\` for the entries shown in \`existingBuffer\`.
|
|
36
36
|
|
|
37
37
|
Identify additional facts, preferences, plans, corrections, names, dates, decisions, or notable felt moments that should be remembered but aren't already in \`existingBuffer\`. Emit a list of \`remember()\` entries (each one line, in the assistant's first-person voice). Don't duplicate. Prefer to over-remember rather than miss things.
|
|
38
38
|
|