@vellumai/assistant 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +163 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- package/docs/skills.md +100 -0
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +111 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
- package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
- package/src/__tests__/app-dir-path-guard.test.ts +78 -0
- package/src/__tests__/app-executors.test.ts +1 -291
- package/src/__tests__/app-git-history.test.ts +4 -4
- package/src/__tests__/app-routes-csp.test.ts +1 -0
- package/src/__tests__/app-store-dir-names.test.ts +426 -0
- package/src/__tests__/attachments-store.test.ts +169 -21
- package/src/__tests__/attachments.test.ts +115 -1
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/canonical-guardian-store.test.ts +38 -0
- package/src/__tests__/channel-reply-delivery.test.ts +55 -0
- package/src/__tests__/checker.test.ts +54 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/config-schema-cmd.test.ts +68 -21
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +156 -5
- package/src/__tests__/conversation-agent-loop.test.ts +297 -2
- package/src/__tests__/conversation-attachments.test.ts +17 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
- package/src/__tests__/conversation-disk-view.test.ts +810 -0
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +551 -0
- package/src/__tests__/conversation-fork-route.test.ts +386 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
- package/src/__tests__/conversation-media-retry.test.ts +8 -2
- package/src/__tests__/conversation-memory-dirty-tail.test.ts +150 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +7 -0
- package/src/__tests__/conversation-queue.test.ts +36 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
- package/src/__tests__/conversation-skill-tools.test.ts +4 -9
- package/src/__tests__/conversation-slash-commands.test.ts +149 -0
- package/src/__tests__/conversation-store.test.ts +24 -21
- package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
- package/src/__tests__/conversation-title-service.test.ts +137 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/conversation-wipe.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-vault-unit.test.ts +5 -10
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
- package/src/__tests__/db-memory-archive-migration.test.ts +372 -0
- package/src/__tests__/db-memory-brief-state-migration.test.ts +213 -0
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +273 -0
- package/src/__tests__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/first-greeting.test.ts +80 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
- package/src/__tests__/history-repair.test.ts +32 -10
- package/src/__tests__/http-conversation-lineage.test.ts +251 -0
- package/src/__tests__/image-source-path-reinject.test.ts +136 -0
- package/src/__tests__/inline-command-runner.test.ts +311 -0
- package/src/__tests__/inline-skill-authoring-guard.test.ts +220 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +435 -0
- package/src/__tests__/list-messages-attachments.test.ts +96 -0
- package/src/__tests__/llm-context-normalization.test.ts +1116 -0
- package/src/__tests__/llm-context-route-provider.test.ts +217 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
- package/src/__tests__/media-generate-image.test.ts +47 -94
- package/src/__tests__/memory-brief-open-loops.test.ts +530 -0
- package/src/__tests__/memory-brief-time.test.ts +285 -0
- package/src/__tests__/memory-brief-wrapper.test.ts +311 -0
- package/src/__tests__/memory-chunk-archive.test.ts +400 -0
- package/src/__tests__/memory-chunk-dual-write.test.ts +453 -0
- package/src/__tests__/memory-episode-archive.test.ts +370 -0
- package/src/__tests__/memory-episode-dual-write.test.ts +626 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-observation-archive.test.ts +375 -0
- package/src/__tests__/memory-observation-dual-write.test.ts +318 -0
- package/src/__tests__/memory-recall-quality.test.ts +7 -7
- package/src/__tests__/memory-reducer-store.test.ts +728 -0
- package/src/__tests__/memory-reducer-types.test.ts +699 -0
- package/src/__tests__/memory-reducer.test.ts +698 -0
- package/src/__tests__/memory-regressions.test.ts +6 -4
- package/src/__tests__/memory-simplified-config.test.ts +281 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
- package/src/__tests__/migration-export-http.test.ts +3 -1
- package/src/__tests__/migration-import-commit-http.test.ts +18 -4
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
- package/src/__tests__/mime-builder.test.ts +3 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -1
- package/src/__tests__/notification-decision-identity.test.ts +52 -0
- package/src/__tests__/oauth-apps-routes.test.ts +103 -0
- package/src/__tests__/oauth-store.test.ts +115 -0
- package/src/__tests__/parse-identity-fields.test.ts +129 -0
- package/src/__tests__/provider-error-scenarios.test.ts +1 -3
- package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
- package/src/__tests__/recording-handler.test.ts +17 -0
- package/src/__tests__/registry.test.ts +3 -8
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
- package/src/__tests__/schema-transforms.test.ts +165 -5
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/skill-load-inline-command.test.ts +598 -0
- package/src/__tests__/skill-load-inline-includes.test.ts +644 -0
- package/src/__tests__/skills-inline-command-expansions.test.ts +301 -0
- package/src/__tests__/skills-transitive-hash.test.ts +333 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -0
- package/src/__tests__/suggestion-routes.test.ts +443 -0
- package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
- package/src/__tests__/top-level-renderer.test.ts +22 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +320 -0
- package/src/__tests__/web-fetch.test.ts +6 -2
- package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
- package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
- package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
- package/src/agent/attachments.ts +27 -1
- package/src/agent/loop.ts +29 -1
- package/src/avatar/traits-png-sync.ts +80 -25
- package/src/bundler/app-bundler.ts +4 -4
- package/src/calls/call-domain.ts +1 -0
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/commands/auth.ts +92 -0
- package/src/cli/commands/avatar.ts +7 -6
- package/src/cli/commands/config.ts +2 -0
- package/src/cli/commands/oauth/providers.ts +29 -0
- package/src/cli/program.ts +12 -0
- package/src/cli.ts +15 -48
- package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
- package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
- package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
- package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
- package/src/config/bundled-tool-registry.ts +2 -14
- package/src/config/feature-flag-registry.json +24 -0
- package/src/config/loader.ts +65 -0
- package/src/config/raw-config-utils.ts +58 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +20 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-simplified.ts +101 -0
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +8 -6
- package/src/config/skills.ts +50 -4
- package/src/contacts/contact-store.ts +13 -6
- package/src/contacts/contacts-write.ts +0 -1
- package/src/context/window-manager.ts +13 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +54 -8
- package/src/daemon/conversation-agent-loop.ts +127 -20
- package/src/daemon/conversation-attachments.ts +18 -36
- package/src/daemon/conversation-error.ts +2 -1
- package/src/daemon/conversation-history.ts +18 -4
- package/src/daemon/conversation-lifecycle.ts +50 -16
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +22 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +170 -24
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +69 -30
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +156 -0
- package/src/daemon/handlers/config-model.ts +62 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/identity.ts +12 -1
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +115 -65
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +18 -0
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/shared.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +23 -0
- package/src/daemon/server.ts +83 -12
- package/src/daemon/shutdown-handlers.ts +8 -5
- package/src/daemon/startup-error.ts +9 -0
- package/src/daemon/tool-side-effects.ts +11 -28
- package/src/events/tool-permission-telemetry-listener.ts +1 -3
- package/src/followups/followup-store.ts +47 -1
- package/src/instrument.ts +0 -4
- package/src/media/app-icon-generator.ts +2 -2
- package/src/memory/app-git-service.ts +28 -16
- package/src/memory/app-store.ts +230 -41
- package/src/memory/archive-store.ts +400 -0
- package/src/memory/attachments-store.ts +558 -130
- package/src/memory/brief-formatting.ts +33 -0
- package/src/memory/brief-open-loops.ts +266 -0
- package/src/memory/brief-time.ts +161 -0
- package/src/memory/brief.ts +75 -0
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +591 -8
- package/src/memory/conversation-directories.ts +125 -0
- package/src/memory/conversation-disk-view.ts +390 -0
- package/src/memory/conversation-key-store.ts +17 -5
- package/src/memory/conversation-queries.ts +5 -1
- package/src/memory/conversation-title-service.ts +21 -49
- package/src/memory/db-init.ts +40 -0
- package/src/memory/embedding-backend.ts +42 -53
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-local.ts +1 -3
- package/src/memory/embedding-ollama.ts +1 -3
- package/src/memory/embedding-openai.ts +1 -3
- package/src/memory/indexer.ts +114 -21
- package/src/memory/items-extractor.ts +42 -13
- package/src/memory/job-handlers/conversation-starters.ts +6 -1
- package/src/memory/job-handlers/embedding.test.ts +2 -4
- package/src/memory/job-handlers/embedding.ts +83 -0
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +6 -0
- package/src/memory/jobs-worker.ts +12 -0
- package/src/memory/llm-request-log-store.ts +100 -1
- package/src/memory/migrations/102-alter-table-columns.ts +5 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
- package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
- package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
- package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
- package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
- package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
- package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
- package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
- package/src/memory/migrations/185-memory-brief-state.ts +52 -0
- package/src/memory/migrations/186-memory-archive.ts +109 -0
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +19 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/qdrant-client.ts +23 -4
- package/src/memory/reducer-store.ts +271 -0
- package/src/memory/reducer-types.ts +99 -0
- package/src/memory/reducer.ts +453 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +9 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/memory-archive.ts +121 -0
- package/src/memory/schema/memory-brief.ts +55 -0
- package/src/memory/schema/oauth.ts +6 -0
- package/src/memory/search/semantic.ts +17 -4
- package/src/messaging/providers/gmail/mime-builder.ts +3 -1
- package/src/notifications/copy-composer.ts +26 -0
- package/src/notifications/decision-engine.ts +14 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +36 -0
- package/src/oauth/byo-connection.test.ts +1 -45
- package/src/oauth/byo-connection.ts +2 -8
- package/src/oauth/connect-orchestrator.ts +15 -11
- package/src/oauth/connection-resolver.test.ts +191 -0
- package/src/oauth/connection-resolver.ts +66 -38
- package/src/oauth/connection.ts +0 -1
- package/src/oauth/oauth-store.ts +99 -47
- package/src/oauth/platform-connection.test.ts +0 -1
- package/src/oauth/platform-connection.ts +11 -3
- package/src/oauth/seed-providers.ts +78 -3
- package/src/oauth/token-persistence.ts +16 -10
- package/src/permissions/checker.ts +160 -14
- package/src/permissions/defaults.ts +14 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -0
- package/src/providers/anthropic/client.ts +8 -1
- package/src/providers/failover.ts +4 -1
- package/src/providers/gemini/client.ts +50 -0
- package/src/providers/model-catalog.ts +92 -0
- package/src/providers/model-intents.ts +29 -20
- package/src/providers/openai/client.ts +49 -0
- package/src/providers/types.ts +2 -0
- package/src/runtime/access-request-helper.ts +16 -7
- package/src/runtime/auth/credential-service.ts +3 -1
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/btw-sidechain.ts +101 -0
- package/src/runtime/channel-reply-delivery.ts +17 -1
- package/src/runtime/http-router.ts +3 -1
- package/src/runtime/http-server.ts +196 -141
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +5 -1
- package/src/runtime/routes/access-request-decision.ts +41 -0
- package/src/runtime/routes/app-management-routes.ts +6 -3
- package/src/runtime/routes/app-routes.ts +7 -3
- package/src/runtime/routes/approval-routes.ts +1 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
- package/src/runtime/routes/attachment-routes.ts +45 -15
- package/src/runtime/routes/btw-routes.ts +21 -61
- package/src/runtime/routes/conversation-management-routes.ts +74 -0
- package/src/runtime/routes/conversation-query-routes.ts +187 -10
- package/src/runtime/routes/conversation-routes.ts +269 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/identity-routes.ts +2 -35
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1212 -0
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/memory-item-routes.test.ts +34 -0
- package/src/runtime/routes/memory-item-routes.ts +94 -5
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/oauth-apps.ts +291 -0
- package/src/runtime/routes/secret-routes.ts +30 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/surface-action-routes.ts +68 -1
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +30 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/skills/inline-command-expansions.ts +204 -0
- package/src/skills/inline-command-render.ts +127 -0
- package/src/skills/inline-command-runner.ts +242 -0
- package/src/skills/transitive-version-hash.ts +88 -0
- package/src/swarm/backend-claude-code.ts +3 -6
- package/src/tasks/task-store.ts +43 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +3 -1
- package/src/tools/AGENTS.md +6 -10
- package/src/tools/apps/executors.ts +17 -232
- package/src/tools/claude-code/claude-code.ts +2 -3
- package/src/tools/credentials/vault.ts +7 -12
- package/src/tools/host-filesystem/read.ts +13 -10
- package/src/tools/network/__tests__/web-search.test.ts +4 -2
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +2 -7
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +140 -6
- package/src/tools/tool-manifest.ts +0 -6
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/device-id.ts +28 -5
- package/src/util/platform.ts +24 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/003-seed-device-id.ts +3 -4
- package/src/workspace/migrations/006-services-config.ts +5 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
- package/src/workspace/migrations/{002-backfill-installation-id.ts → 011-backfill-installation-id.ts} +24 -13
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
- package/src/workspace/migrations/registry.ts +11 -1
- package/src/workspace/top-level-renderer.ts +12 -0
- package/src/__tests__/asset-materialize-tool.test.ts +0 -523
- package/src/__tests__/asset-search-tool.test.ts +0 -536
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
- package/src/__tests__/media-visibility-policy.test.ts +0 -190
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
- package/src/daemon/media-visibility-policy.ts +0 -59
- package/src/tools/assets/materialize.ts +0 -248
- package/src/tools/assets/search.ts +0 -400
package/src/daemon/lifecycle.ts
CHANGED
|
@@ -142,7 +142,6 @@ export async function runDaemon(): Promise<void> {
|
|
|
142
142
|
await initLogfire();
|
|
143
143
|
|
|
144
144
|
ensureDataDir();
|
|
145
|
-
await runWorkspaceMigrations(getWorkspaceDir(), WORKSPACE_MIGRATIONS);
|
|
146
145
|
|
|
147
146
|
// Load (or generate + persist) the auth signing key so tokens survive
|
|
148
147
|
// daemon restarts. Must happen after ensureDataDir() creates the
|
|
@@ -150,14 +149,16 @@ export async function runDaemon(): Promise<void> {
|
|
|
150
149
|
const signingKey = loadOrCreateSigningKey();
|
|
151
150
|
initAuthSigningKey(signingKey);
|
|
152
151
|
|
|
153
|
-
log.info("Daemon startup: migrations complete");
|
|
154
|
-
|
|
155
152
|
seedInterfaceFiles();
|
|
156
153
|
|
|
157
154
|
log.info("Daemon startup: installing templates and initializing DB");
|
|
158
155
|
installTemplates();
|
|
159
156
|
ensurePromptFiles();
|
|
160
157
|
|
|
158
|
+
// DB must be initialized before workspace migrations because some
|
|
159
|
+
// workspace migrations (e.g. 009-backfill-conversation-disk-view)
|
|
160
|
+
// depend on DB migrations having run (e.g. the inline-attachment-to-disk
|
|
161
|
+
// backfill that populates attachment filePaths).
|
|
161
162
|
initializeDb();
|
|
162
163
|
// Seed well-known OAuth provider configurations (insert-if-not-exists)
|
|
163
164
|
seedOAuthProviders();
|
|
@@ -174,6 +175,9 @@ export async function runDaemon(): Promise<void> {
|
|
|
174
175
|
}
|
|
175
176
|
log.info("Daemon startup: DB initialized");
|
|
176
177
|
|
|
178
|
+
await runWorkspaceMigrations(getWorkspaceDir(), WORKSPACE_MIGRATIONS);
|
|
179
|
+
log.info("Daemon startup: workspace migrations complete");
|
|
180
|
+
|
|
177
181
|
// Purge private (temporary) conversations from the previous daemon run.
|
|
178
182
|
// These are ephemeral by design and should not survive daemon restarts.
|
|
179
183
|
const { count: purgedCount, deletedMemory } = purgePrivateConversations();
|
|
@@ -196,31 +200,43 @@ export async function runDaemon(): Promise<void> {
|
|
|
196
200
|
targetId: itemId,
|
|
197
201
|
});
|
|
198
202
|
}
|
|
203
|
+
for (const summaryId of deletedMemory.deletedSummaryIds) {
|
|
204
|
+
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
205
|
+
targetType: "summary",
|
|
206
|
+
targetId: summaryId,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
199
209
|
if (
|
|
200
210
|
deletedMemory.segmentIds.length > 0 ||
|
|
201
|
-
deletedMemory.orphanedItemIds.length > 0
|
|
211
|
+
deletedMemory.orphanedItemIds.length > 0 ||
|
|
212
|
+
deletedMemory.deletedSummaryIds.length > 0
|
|
202
213
|
) {
|
|
203
214
|
log.info(
|
|
204
215
|
{
|
|
205
216
|
segments: deletedMemory.segmentIds.length,
|
|
206
217
|
orphanedItems: deletedMemory.orphanedItemIds.length,
|
|
218
|
+
deletedSummaries: deletedMemory.deletedSummaryIds.length,
|
|
207
219
|
},
|
|
208
220
|
"Enqueued Qdrant vector cleanup jobs for purged private conversations",
|
|
209
221
|
);
|
|
210
222
|
}
|
|
211
223
|
}
|
|
212
224
|
|
|
213
|
-
// Expire pending
|
|
214
|
-
//
|
|
215
|
-
//
|
|
216
|
-
//
|
|
217
|
-
//
|
|
218
|
-
//
|
|
225
|
+
// Expire stale pending canonical guardian requests left over from before
|
|
226
|
+
// this process started. Two categories are cleaned up:
|
|
227
|
+
//
|
|
228
|
+
// 1. Interaction-bound kinds (tool_approval, pending_question) — their
|
|
229
|
+
// in-memory pending-interaction session references are gone, so they
|
|
230
|
+
// can never be completed.
|
|
231
|
+
// 2. Any pending request whose expiresAt has already passed — persistent
|
|
232
|
+
// kinds (access_request, tool_grant_request) that expired while the
|
|
233
|
+
// daemon was stopped are transitioned so dedup logic doesn't return
|
|
234
|
+
// stale rows.
|
|
219
235
|
const expiredCount = expireAllPendingCanonicalRequests();
|
|
220
236
|
if (expiredCount > 0) {
|
|
221
237
|
log.info(
|
|
222
238
|
{ event: "startup_expired_stale_requests", expiredCount },
|
|
223
|
-
`Expired ${expiredCount} stale
|
|
239
|
+
`Expired ${expiredCount} stale canonical request(s) from previous process`,
|
|
224
240
|
);
|
|
225
241
|
}
|
|
226
242
|
|
|
@@ -329,56 +345,74 @@ export async function runDaemon(): Promise<void> {
|
|
|
329
345
|
await server.start();
|
|
330
346
|
log.info("Daemon startup: DaemonServer started");
|
|
331
347
|
|
|
332
|
-
//
|
|
333
|
-
//
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
348
|
+
// Mutable refs for Qdrant and memory worker so background init can assign
|
|
349
|
+
// them and the shutdown handler always sees the latest value.
|
|
350
|
+
const bgRefs: {
|
|
351
|
+
qdrantManager: QdrantManager | null;
|
|
352
|
+
memoryWorker: { stop(): void } | null;
|
|
353
|
+
} = { qdrantManager: null, memoryWorker: null };
|
|
354
|
+
|
|
355
|
+
// Initialize Qdrant vector store and memory worker in the background so the
|
|
356
|
+
// RuntimeHttpServer can start accepting requests without waiting for Qdrant.
|
|
357
|
+
async function initializeQdrantAndMemory(): Promise<void> {
|
|
358
|
+
// Prefer QDRANT_HTTP_PORT (locally-spawned Qdrant on a specific port) over
|
|
359
|
+
// QDRANT_URL (external Qdrant instance) so the CLI can set the port without
|
|
360
|
+
// triggering QdrantManager's external mode which skips local process spawn.
|
|
361
|
+
const qdrantHttpPort = getQdrantHttpPortEnv();
|
|
362
|
+
const qdrantUrl = qdrantHttpPort
|
|
363
|
+
? `http://127.0.0.1:${qdrantHttpPort}`
|
|
364
|
+
: getQdrantUrlEnv() || config.memory.qdrant.url;
|
|
365
|
+
log.info({ qdrantUrl }, "Daemon startup: initializing Qdrant");
|
|
366
|
+
const manager = new QdrantManager({ url: qdrantUrl });
|
|
367
|
+
bgRefs.qdrantManager = manager;
|
|
368
|
+
try {
|
|
369
|
+
await manager.start();
|
|
370
|
+
const embeddingSelection = await selectEmbeddingBackend(config);
|
|
371
|
+
const embeddingModel = embeddingSelection.backend
|
|
372
|
+
? `${embeddingSelection.backend.provider}:${embeddingSelection.backend.model}:sparse-v${SPARSE_EMBEDDING_VERSION}`
|
|
373
|
+
: undefined;
|
|
374
|
+
const qdrantClient = initQdrantClient({
|
|
375
|
+
url: qdrantUrl,
|
|
376
|
+
collection: config.memory.qdrant.collection,
|
|
377
|
+
vectorSize: config.memory.qdrant.vectorSize,
|
|
378
|
+
onDisk: config.memory.qdrant.onDisk,
|
|
379
|
+
quantization: config.memory.qdrant.quantization,
|
|
380
|
+
embeddingModel,
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Eagerly ensure the collection exists so we detect migrations
|
|
384
|
+
// (unnamed→named vectors, dimension/model changes) at startup.
|
|
385
|
+
// If a destructive migration occurred, enqueue a rebuild_index job
|
|
386
|
+
// to re-embed all memory items from the SQLite cache.
|
|
387
|
+
const { migrated } = await qdrantClient.ensureCollection();
|
|
388
|
+
if (migrated) {
|
|
389
|
+
enqueueMemoryJob("rebuild_index", {});
|
|
390
|
+
log.info(
|
|
391
|
+
"Qdrant collection was migrated — enqueued rebuild_index job",
|
|
392
|
+
);
|
|
393
|
+
}
|
|
356
394
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
enqueueMemoryJob("rebuild_index", {});
|
|
364
|
-
log.info("Qdrant collection was migrated — enqueued rebuild_index job");
|
|
395
|
+
log.info("Qdrant vector store initialized");
|
|
396
|
+
} catch (err) {
|
|
397
|
+
log.warn(
|
|
398
|
+
{ err },
|
|
399
|
+
"Qdrant failed to start — memory features will be unavailable",
|
|
400
|
+
);
|
|
365
401
|
}
|
|
366
402
|
|
|
367
|
-
log.info("
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
403
|
+
log.info("Daemon startup: starting memory worker");
|
|
404
|
+
bgRefs.memoryWorker = startMemoryJobsWorker();
|
|
405
|
+
|
|
406
|
+
// Seed capability memories for first-party catalog skills so the memory
|
|
407
|
+
// pipeline can surface relevant skills via semantic search.
|
|
408
|
+
void seedCatalogSkillMemories().catch((err) =>
|
|
409
|
+
log.warn({ err }, "Catalog skill memory seeding failed — continuing"),
|
|
372
410
|
);
|
|
373
411
|
}
|
|
374
412
|
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
// Seed capability memories for first-party catalog skills so the memory
|
|
379
|
-
// pipeline can surface relevant skills via semantic search.
|
|
380
|
-
void seedCatalogSkillMemories().catch((err) =>
|
|
381
|
-
log.warn({ err }, "Catalog skill memory seeding failed — continuing"),
|
|
413
|
+
// Fire-and-forget: Qdrant init runs concurrently with the rest of startup
|
|
414
|
+
void initializeQdrantAndMemory().catch((err) =>
|
|
415
|
+
log.warn({ err }, "Background Qdrant init failed"),
|
|
382
416
|
);
|
|
383
417
|
|
|
384
418
|
registerWatcherProviders();
|
|
@@ -459,7 +493,7 @@ export async function runDaemon(): Promise<void> {
|
|
|
459
493
|
title: notification.title,
|
|
460
494
|
body: notification.body,
|
|
461
495
|
},
|
|
462
|
-
dedupeKey: `watcher:notification:${
|
|
496
|
+
dedupeKey: `watcher:notification:${crypto.randomUUID()}`,
|
|
463
497
|
});
|
|
464
498
|
},
|
|
465
499
|
(params) => {
|
|
@@ -477,7 +511,7 @@ export async function runDaemon(): Promise<void> {
|
|
|
477
511
|
title: params.title,
|
|
478
512
|
body: params.body,
|
|
479
513
|
},
|
|
480
|
-
dedupeKey: `watcher:escalation:${
|
|
514
|
+
dedupeKey: `watcher:escalation:${crypto.randomUUID()}`,
|
|
481
515
|
});
|
|
482
516
|
},
|
|
483
517
|
(info) => {
|
|
@@ -532,13 +566,22 @@ export async function runDaemon(): Promise<void> {
|
|
|
532
566
|
getOrCreateConversation: (conversationId) =>
|
|
533
567
|
server.getConversationForMessages(conversationId),
|
|
534
568
|
assistantEventHub,
|
|
535
|
-
resolveAttachments: (attachmentIds) =>
|
|
536
|
-
attachmentsStore.getAttachmentsByIds(attachmentIds
|
|
569
|
+
resolveAttachments: (attachmentIds) => {
|
|
570
|
+
const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds, {
|
|
571
|
+
hydrateFileData: true,
|
|
572
|
+
});
|
|
573
|
+
const sourcePaths =
|
|
574
|
+
attachmentsStore.getSourcePathsForAttachments(attachmentIds);
|
|
575
|
+
return resolved.map((a) => ({
|
|
537
576
|
id: a.id,
|
|
538
577
|
filename: a.originalFilename,
|
|
539
578
|
mimeType: a.mimeType,
|
|
540
579
|
data: a.dataBase64,
|
|
541
|
-
|
|
580
|
+
...(sourcePaths.has(a.id)
|
|
581
|
+
? { filePath: sourcePaths.get(a.id) }
|
|
582
|
+
: {}),
|
|
583
|
+
}));
|
|
584
|
+
},
|
|
542
585
|
},
|
|
543
586
|
findConversation: (conversationId) =>
|
|
544
587
|
server.findConversation(conversationId),
|
|
@@ -623,13 +666,20 @@ export async function runDaemon(): Promise<void> {
|
|
|
623
666
|
setVoiceBridgeDeps({
|
|
624
667
|
getOrCreateConversation: (conversationId, _transport) =>
|
|
625
668
|
server.getConversationForMessages(conversationId),
|
|
626
|
-
resolveAttachments: (attachmentIds) =>
|
|
627
|
-
attachmentsStore.getAttachmentsByIds(attachmentIds
|
|
669
|
+
resolveAttachments: (attachmentIds) => {
|
|
670
|
+
const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds, {
|
|
671
|
+
hydrateFileData: true,
|
|
672
|
+
});
|
|
673
|
+
const sourcePaths =
|
|
674
|
+
attachmentsStore.getSourcePathsForAttachments(attachmentIds);
|
|
675
|
+
return resolved.map((a) => ({
|
|
628
676
|
id: a.id,
|
|
629
677
|
filename: a.originalFilename,
|
|
630
678
|
mimeType: a.mimeType,
|
|
631
679
|
data: a.dataBase64,
|
|
632
|
-
|
|
680
|
+
...(sourcePaths.has(a.id) ? { filePath: sourcePaths.get(a.id) } : {}),
|
|
681
|
+
}));
|
|
682
|
+
},
|
|
633
683
|
deriveDefaultStrictSideEffects: (conversationId) => {
|
|
634
684
|
const conversationType = getConversationType(conversationId);
|
|
635
685
|
return conversationType === "private";
|
|
@@ -881,8 +931,8 @@ export async function runDaemon(): Promise<void> {
|
|
|
881
931
|
hookManager,
|
|
882
932
|
runtimeHttp,
|
|
883
933
|
scheduler,
|
|
884
|
-
memoryWorker,
|
|
885
|
-
qdrantManager,
|
|
934
|
+
getMemoryWorker: () => bgRefs.memoryWorker,
|
|
935
|
+
getQdrantManager: () => bgRefs.qdrantManager,
|
|
886
936
|
mcpManager,
|
|
887
937
|
telemetryReporter,
|
|
888
938
|
cleanupPidFile,
|
|
@@ -38,6 +38,7 @@ export * from "./message-types/skills.js";
|
|
|
38
38
|
export * from "./message-types/subagents.js";
|
|
39
39
|
export * from "./message-types/surfaces.js";
|
|
40
40
|
export * from "./message-types/trust.js";
|
|
41
|
+
export * from "./message-types/upgrades.js";
|
|
41
42
|
export * from "./message-types/work-items.js";
|
|
42
43
|
export * from "./message-types/workspace.js";
|
|
43
44
|
|
|
@@ -123,6 +124,7 @@ import type {
|
|
|
123
124
|
_TrustClientMessages,
|
|
124
125
|
_TrustServerMessages,
|
|
125
126
|
} from "./message-types/trust.js";
|
|
127
|
+
import type { _UpgradesServerMessages } from "./message-types/upgrades.js";
|
|
126
128
|
import type {
|
|
127
129
|
_WorkItemsClientMessages,
|
|
128
130
|
_WorkItemsServerMessages,
|
|
@@ -194,6 +196,7 @@ export type ServerMessage =
|
|
|
194
196
|
| _InboxServerMessages
|
|
195
197
|
| _PairingServerMessages
|
|
196
198
|
| _NotificationsServerMessages
|
|
199
|
+
| _UpgradesServerMessages
|
|
197
200
|
| _AcpServerMessages
|
|
198
201
|
| SubagentEvent;
|
|
199
202
|
|
|
@@ -80,6 +80,7 @@ export interface ModelGetRequest {
|
|
|
80
80
|
export interface ModelSetRequest {
|
|
81
81
|
type: "model_set";
|
|
82
82
|
model: string;
|
|
83
|
+
provider?: string;
|
|
83
84
|
}
|
|
84
85
|
|
|
85
86
|
export interface ImageGenModelSetRequest {
|
|
@@ -177,6 +178,12 @@ export interface AssistantAttention {
|
|
|
177
178
|
lastSeenSignalType?: string;
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
export interface ConversationForkParent {
|
|
182
|
+
conversationId: string;
|
|
183
|
+
messageId: string;
|
|
184
|
+
title: string;
|
|
185
|
+
}
|
|
186
|
+
|
|
180
187
|
export interface ConversationListResponse {
|
|
181
188
|
type: "conversation_list_response";
|
|
182
189
|
conversations: Array<{
|
|
@@ -193,6 +200,7 @@ export interface ConversationListResponse {
|
|
|
193
200
|
assistantAttention?: AssistantAttention;
|
|
194
201
|
displayOrder?: number;
|
|
195
202
|
isPinned?: boolean;
|
|
203
|
+
forkParent?: ConversationForkParent;
|
|
196
204
|
}>;
|
|
197
205
|
/** Whether more conversations exist beyond the returned page. */
|
|
198
206
|
hasMore?: boolean;
|
|
@@ -231,6 +239,7 @@ export interface GenerationHandoff {
|
|
|
231
239
|
requestId?: string;
|
|
232
240
|
queuedCount: number;
|
|
233
241
|
attachments?: UserMessageAttachment[];
|
|
242
|
+
attachmentWarnings?: string[];
|
|
234
243
|
/** Database ID of the persisted assistant message, if any. */
|
|
235
244
|
messageId?: string;
|
|
236
245
|
}
|
|
@@ -240,6 +249,15 @@ export interface ModelInfo {
|
|
|
240
249
|
model: string;
|
|
241
250
|
provider: string;
|
|
242
251
|
configuredProviders?: string[];
|
|
252
|
+
availableModels?: Array<{ id: string; displayName: string }>;
|
|
253
|
+
allProviders?: Array<{
|
|
254
|
+
id: string;
|
|
255
|
+
displayName: string;
|
|
256
|
+
models: Array<{ id: string; displayName: string }>;
|
|
257
|
+
defaultModel: string;
|
|
258
|
+
apiKeyUrl?: string;
|
|
259
|
+
apiKeyPlaceholder?: string;
|
|
260
|
+
}>;
|
|
243
261
|
}
|
|
244
262
|
|
|
245
263
|
export interface HistoryResponseToolCall {
|
|
@@ -183,6 +183,7 @@ export interface MessageComplete {
|
|
|
183
183
|
type: "message_complete";
|
|
184
184
|
conversationId?: string;
|
|
185
185
|
attachments?: UserMessageAttachment[];
|
|
186
|
+
attachmentWarnings?: string[];
|
|
186
187
|
/** Database ID of the persisted assistant message, if any. */
|
|
187
188
|
messageId?: string;
|
|
188
189
|
}
|
|
@@ -34,6 +34,8 @@ export interface UserMessageAttachment {
|
|
|
34
34
|
filename: string;
|
|
35
35
|
mimeType: string;
|
|
36
36
|
data: string;
|
|
37
|
+
/** Origin of the attachment on the daemon side, when known. */
|
|
38
|
+
sourceType?: "sandbox_file" | "host_file" | "tool_block";
|
|
37
39
|
extractedText?: string;
|
|
38
40
|
/** Original file size in bytes. Present when data was omitted from history_response to reduce payload size. */
|
|
39
41
|
sizeBytes?: number;
|
|
@@ -100,6 +100,8 @@ export interface DynamicPageSurfaceData {
|
|
|
100
100
|
width?: number;
|
|
101
101
|
height?: number;
|
|
102
102
|
appId?: string;
|
|
103
|
+
/** Filesystem directory name for this app (may differ from `appId`). */
|
|
104
|
+
dirName?: string;
|
|
103
105
|
reloadGeneration?: number;
|
|
104
106
|
status?: string;
|
|
105
107
|
preview?: DynamicPagePreview;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** Broadcast to connected clients when a service group update is about to begin. */
|
|
2
|
+
export interface ServiceGroupUpdateStarting {
|
|
3
|
+
type: "service_group_update_starting";
|
|
4
|
+
/** The version being upgraded to. */
|
|
5
|
+
targetVersion: string;
|
|
6
|
+
/** Estimated seconds of downtime. */
|
|
7
|
+
expectedDowntimeSeconds: number;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/** Broadcast to connected clients when a service group update has completed. */
|
|
11
|
+
export interface ServiceGroupUpdateComplete {
|
|
12
|
+
type: "service_group_update_complete";
|
|
13
|
+
/** The version that was installed (may differ from target if rolled back). */
|
|
14
|
+
installedVersion: string;
|
|
15
|
+
/** Whether the update succeeded or rolled back. */
|
|
16
|
+
success: boolean;
|
|
17
|
+
/** If rolled back, the version reverted to. */
|
|
18
|
+
rolledBackToVersion?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export type _UpgradesServerMessages =
|
|
22
|
+
| ServiceGroupUpdateStarting
|
|
23
|
+
| ServiceGroupUpdateComplete;
|
package/src/daemon/server.ts
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
getAcpSessionManager,
|
|
7
7
|
setBroadcastToAllClients,
|
|
8
8
|
} from "../acp/index.js";
|
|
9
|
+
import { enrichMessageWithSourcePaths } from "../agent/attachments.js";
|
|
9
10
|
import {
|
|
10
11
|
createAssistantMessage,
|
|
11
12
|
createUserMessage,
|
|
@@ -34,12 +35,14 @@ import {
|
|
|
34
35
|
} from "../memory/canonical-guardian-store.js";
|
|
35
36
|
import {
|
|
36
37
|
addMessage,
|
|
38
|
+
getConversation,
|
|
37
39
|
getConversationMemoryScopeId,
|
|
38
40
|
getConversationType,
|
|
39
41
|
provenanceFromTrustContext,
|
|
40
42
|
setConversationOriginChannelIfUnset,
|
|
41
43
|
setConversationOriginInterfaceIfUnset,
|
|
42
44
|
} from "../memory/conversation-crud.js";
|
|
45
|
+
import { updateMetaFile } from "../memory/conversation-disk-view.js";
|
|
43
46
|
import { getOrCreateConversation } from "../memory/conversation-key-store.js";
|
|
44
47
|
import { buildSystemPrompt } from "../prompts/system-prompt.js";
|
|
45
48
|
import { resolveManagedProxyContext } from "../providers/managed-proxy/context.js";
|
|
@@ -75,7 +78,7 @@ import {
|
|
|
75
78
|
} from "./conversation.js";
|
|
76
79
|
import { ConversationEvictor } from "./conversation-evictor.js";
|
|
77
80
|
import { resolveChannelCapabilities } from "./conversation-runtime-assembly.js";
|
|
78
|
-
import { resolveSlash } from "./conversation-slash.js";
|
|
81
|
+
import { resolveSlash, type SlashContext } from "./conversation-slash.js";
|
|
79
82
|
import { undoLastMessage } from "./handlers/conversations.js";
|
|
80
83
|
import { parseIdentityFields } from "./handlers/identity.js";
|
|
81
84
|
import type {
|
|
@@ -878,6 +881,7 @@ export class DaemonServer {
|
|
|
878
881
|
filename: string;
|
|
879
882
|
mimeType: string;
|
|
880
883
|
data: string;
|
|
884
|
+
filePath?: string;
|
|
881
885
|
}[];
|
|
882
886
|
}> {
|
|
883
887
|
const ingressCheck = checkIngressForSecrets(content);
|
|
@@ -960,12 +964,22 @@ export class DaemonServer {
|
|
|
960
964
|
});
|
|
961
965
|
|
|
962
966
|
const attachments = attachmentIds
|
|
963
|
-
?
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
967
|
+
? (() => {
|
|
968
|
+
const resolved = attachmentsStore.getAttachmentsByIds(attachmentIds, {
|
|
969
|
+
hydrateFileData: true,
|
|
970
|
+
});
|
|
971
|
+
const sourcePaths =
|
|
972
|
+
attachmentsStore.getSourcePathsForAttachments(attachmentIds);
|
|
973
|
+
return resolved.map((a) => ({
|
|
974
|
+
id: a.id,
|
|
975
|
+
filename: a.originalFilename,
|
|
976
|
+
mimeType: a.mimeType,
|
|
977
|
+
data: a.dataBase64,
|
|
978
|
+
...(sourcePaths.has(a.id)
|
|
979
|
+
? { filePath: sourcePaths.get(a.id) }
|
|
980
|
+
: {}),
|
|
981
|
+
}));
|
|
982
|
+
})()
|
|
969
983
|
: [];
|
|
970
984
|
|
|
971
985
|
return { conversation, attachments };
|
|
@@ -1057,14 +1071,32 @@ export class DaemonServer {
|
|
|
1057
1071
|
sourceInterface,
|
|
1058
1072
|
);
|
|
1059
1073
|
|
|
1060
|
-
const
|
|
1074
|
+
const config = getConfig();
|
|
1075
|
+
const serverInterfaceCtx = conversation.getTurnInterfaceContext();
|
|
1076
|
+
const slashContext: SlashContext = {
|
|
1077
|
+
messageCount: conversation.getMessages().length,
|
|
1078
|
+
inputTokens: conversation.usageStats.inputTokens,
|
|
1079
|
+
outputTokens: conversation.usageStats.outputTokens,
|
|
1080
|
+
maxInputTokens: config.contextWindow.maxInputTokens,
|
|
1081
|
+
model: config.services.inference.model,
|
|
1082
|
+
provider: config.services.inference.provider,
|
|
1083
|
+
estimatedCost: conversation.usageStats.estimatedCost,
|
|
1084
|
+
userMessageInterface: serverInterfaceCtx?.userMessageInterface,
|
|
1085
|
+
};
|
|
1086
|
+
const slashResult = await resolveSlash(content, slashContext);
|
|
1061
1087
|
|
|
1062
1088
|
if (slashResult.kind === "unknown") {
|
|
1063
1089
|
const serverTurnCtx = conversation.getTurnChannelContext();
|
|
1064
|
-
const serverInterfaceCtx = conversation.getTurnInterfaceContext();
|
|
1065
1090
|
const serverProvenance = provenanceFromTrustContext(
|
|
1066
1091
|
conversation.trustContext,
|
|
1067
1092
|
);
|
|
1093
|
+
const imageSourcePaths: Record<string, string> = {};
|
|
1094
|
+
for (let i = 0; i < attachments.length; i++) {
|
|
1095
|
+
const a = attachments[i];
|
|
1096
|
+
if (a.filePath && a.mimeType.toLowerCase().startsWith("image/")) {
|
|
1097
|
+
imageSourcePaths[`${i}:${a.filename}`] = a.filePath;
|
|
1098
|
+
}
|
|
1099
|
+
}
|
|
1068
1100
|
const serverChannelMeta = {
|
|
1069
1101
|
...serverProvenance,
|
|
1070
1102
|
...(serverTurnCtx
|
|
@@ -1080,15 +1112,19 @@ export class DaemonServer {
|
|
|
1080
1112
|
serverInterfaceCtx.assistantMessageInterface,
|
|
1081
1113
|
}
|
|
1082
1114
|
: {}),
|
|
1115
|
+
...(Object.keys(imageSourcePaths).length > 0
|
|
1116
|
+
? { imageSourcePaths }
|
|
1117
|
+
: {}),
|
|
1083
1118
|
};
|
|
1084
|
-
const
|
|
1119
|
+
const cleanMsg = createUserMessage(content, attachments);
|
|
1120
|
+
const llmMsg = enrichMessageWithSourcePaths(cleanMsg, attachments);
|
|
1085
1121
|
const persisted = await addMessage(
|
|
1086
1122
|
conversationId,
|
|
1087
1123
|
"user",
|
|
1088
|
-
JSON.stringify(
|
|
1124
|
+
JSON.stringify(cleanMsg.content),
|
|
1089
1125
|
serverChannelMeta,
|
|
1090
1126
|
);
|
|
1091
|
-
conversation.getMessages().push(
|
|
1127
|
+
conversation.getMessages().push(llmMsg);
|
|
1092
1128
|
|
|
1093
1129
|
if (serverTurnCtx) {
|
|
1094
1130
|
try {
|
|
@@ -1117,6 +1153,21 @@ export class DaemonServer {
|
|
|
1117
1153
|
}
|
|
1118
1154
|
}
|
|
1119
1155
|
|
|
1156
|
+
// Rewrite meta.json so the on-disk metadata reflects the origin channel
|
|
1157
|
+
if (serverTurnCtx || serverInterfaceCtx) {
|
|
1158
|
+
try {
|
|
1159
|
+
const convForMeta = getConversation(conversationId);
|
|
1160
|
+
if (convForMeta) {
|
|
1161
|
+
updateMetaFile(convForMeta);
|
|
1162
|
+
}
|
|
1163
|
+
} catch (err) {
|
|
1164
|
+
log.warn(
|
|
1165
|
+
{ err, conversationId },
|
|
1166
|
+
"Failed to update disk meta (best-effort)",
|
|
1167
|
+
);
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1120
1171
|
const assistantMsg = createAssistantMessage(slashResult.message);
|
|
1121
1172
|
await addMessage(
|
|
1122
1173
|
conversationId,
|
|
@@ -1198,9 +1249,29 @@ export class DaemonServer {
|
|
|
1198
1249
|
* Look up an active conversation that owns a given surfaceId.
|
|
1199
1250
|
*/
|
|
1200
1251
|
findConversationBySurfaceId(surfaceId: string): Conversation | undefined {
|
|
1252
|
+
// Fast path: exact surfaceId match in surfaceState
|
|
1201
1253
|
for (const c of this.conversations.values()) {
|
|
1202
1254
|
if (c.surfaceState.has(surfaceId)) return c;
|
|
1203
1255
|
}
|
|
1256
|
+
|
|
1257
|
+
// Fallback: standalone app surfaces use "app-open-{appId}" IDs that
|
|
1258
|
+
// were never part of any conversation. Extract the appId and find
|
|
1259
|
+
// a conversation whose surfaceState has a surface for that app.
|
|
1260
|
+
const appOpenPrefix = "app-open-";
|
|
1261
|
+
if (surfaceId.startsWith(appOpenPrefix)) {
|
|
1262
|
+
const appId = surfaceId.slice(appOpenPrefix.length);
|
|
1263
|
+
for (const c of this.conversations.values()) {
|
|
1264
|
+
for (const [, state] of c.surfaceState.entries()) {
|
|
1265
|
+
const data = state.data as unknown as Record<string, unknown>;
|
|
1266
|
+
if (data?.appId === appId) {
|
|
1267
|
+
// Register this surfaceId so subsequent lookups are O(1)
|
|
1268
|
+
c.surfaceState.set(surfaceId, state);
|
|
1269
|
+
return c;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1204
1275
|
return undefined;
|
|
1205
1276
|
}
|
|
1206
1277
|
|
|
@@ -21,8 +21,8 @@ export interface ShutdownDeps {
|
|
|
21
21
|
hookManager: HookManager;
|
|
22
22
|
runtimeHttp: RuntimeHttpServer | null;
|
|
23
23
|
scheduler: { stop(): void };
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
getMemoryWorker: () => { stop(): void } | null;
|
|
25
|
+
getQdrantManager: () => QdrantManager | null;
|
|
26
26
|
mcpManager: McpServerManager | null;
|
|
27
27
|
telemetryReporter: { stop(): Promise<void> } | null;
|
|
28
28
|
cleanupPidFile: () => void;
|
|
@@ -106,7 +106,7 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
106
106
|
if (deps.runtimeHttp) await deps.runtimeHttp.stop();
|
|
107
107
|
await browserManager.closeAllPages();
|
|
108
108
|
deps.scheduler.stop();
|
|
109
|
-
deps.
|
|
109
|
+
deps.getMemoryWorker()?.stop();
|
|
110
110
|
|
|
111
111
|
if (deps.mcpManager) {
|
|
112
112
|
try {
|
|
@@ -116,7 +116,7 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
|
|
119
|
-
await deps.
|
|
119
|
+
await deps.getQdrantManager()?.stop();
|
|
120
120
|
|
|
121
121
|
// Checkpoint WAL and close SQLite so no writes are lost on exit.
|
|
122
122
|
// Checkpoint and close are in separate try blocks so that close()
|
|
@@ -143,7 +143,10 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
|
|
|
143
143
|
process.on("SIGHUP", shutdown);
|
|
144
144
|
|
|
145
145
|
process.on("unhandledRejection", (reason) => {
|
|
146
|
-
log.error(
|
|
146
|
+
log.error(
|
|
147
|
+
{ err: reason },
|
|
148
|
+
"Unhandled promise rejection — initiating shutdown",
|
|
149
|
+
);
|
|
147
150
|
Sentry.captureException(reason);
|
|
148
151
|
exitCode = 1;
|
|
149
152
|
void shutdown();
|
|
@@ -27,6 +27,14 @@ const DAEMON_ERROR_PREFIX = "DAEMON_ERROR:";
|
|
|
27
27
|
* Inspect an error and return a categorized {@link DaemonStartupError}.
|
|
28
28
|
*/
|
|
29
29
|
export function categorizeDaemonError(err: unknown): DaemonStartupError {
|
|
30
|
+
if (err == null) {
|
|
31
|
+
return {
|
|
32
|
+
error: "UNKNOWN",
|
|
33
|
+
message: String(err),
|
|
34
|
+
detail: "An unexpected error occurred during startup.",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
const code = (err as { code?: string }).code ?? "";
|
|
31
39
|
const name = (err as { name?: string }).name ?? "";
|
|
32
40
|
const message =
|
|
@@ -96,6 +104,7 @@ export function categorizeDaemonError(err: unknown): DaemonStartupError {
|
|
|
96
104
|
message.startsWith("Invalid RUNTIME_HTTP_PORT") ||
|
|
97
105
|
message.startsWith("Invalid integer for GATEWAY_PORT") ||
|
|
98
106
|
message.startsWith("Invalid integer for RUNTIME_HTTP_PORT") ||
|
|
107
|
+
message.startsWith("Invalid integer for QDRANT_HTTP_PORT") ||
|
|
99
108
|
/\benv\b.*\bvalidat/i.test(message) ||
|
|
100
109
|
/\bvalidat.*\benv\b/i.test(message)
|
|
101
110
|
) {
|