@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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Route handlers for attachment upload, download, and deletion.
|
|
3
3
|
*/
|
|
4
|
-
import { existsSync } from "node:fs";
|
|
4
|
+
import { existsSync, statSync } from "node:fs";
|
|
5
5
|
|
|
6
6
|
import * as attachmentsStore from "../../memory/attachments-store.js";
|
|
7
7
|
import {
|
|
@@ -29,9 +29,10 @@ export async function handleUploadAttachment(req: Request): Promise<Response> {
|
|
|
29
29
|
filename?: string;
|
|
30
30
|
mimeType?: string;
|
|
31
31
|
data?: string;
|
|
32
|
+
filePath?: string;
|
|
32
33
|
};
|
|
33
34
|
|
|
34
|
-
const { filename, mimeType, data } = body;
|
|
35
|
+
const { filename, mimeType, data, filePath } = body;
|
|
35
36
|
|
|
36
37
|
if (!filename || typeof filename !== "string") {
|
|
37
38
|
return httpError("BAD_REQUEST", "filename is required", 400);
|
|
@@ -41,24 +42,49 @@ export async function handleUploadAttachment(req: Request): Promise<Response> {
|
|
|
41
42
|
return httpError("BAD_REQUEST", "mimeType is required", 400);
|
|
42
43
|
}
|
|
43
44
|
|
|
44
|
-
if (!data || typeof data !== "string") {
|
|
45
|
-
return httpError("BAD_REQUEST", "data (base64) is required", 400);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
45
|
const validation = validateAttachmentUpload(filename, mimeType);
|
|
49
46
|
if (!validation.ok) {
|
|
50
47
|
return httpError("UNPROCESSABLE_ENTITY", validation.error, 415);
|
|
51
48
|
}
|
|
52
49
|
|
|
53
50
|
let attachment: attachmentsStore.StoredAttachment;
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
51
|
+
|
|
52
|
+
// File-backed upload: when filePath is provided and data is empty/missing,
|
|
53
|
+
// register the attachment by path reference instead of requiring base64 data.
|
|
54
|
+
// This supports retry of file-backed attachments (e.g. recordings) where the
|
|
55
|
+
// client no longer holds the inline data but the file still exists on disk.
|
|
56
|
+
if (filePath && typeof filePath === "string" && (!data || data === "")) {
|
|
57
|
+
if (!existsSync(filePath)) {
|
|
58
|
+
return httpError("BAD_REQUEST", "filePath does not exist on disk", 400);
|
|
59
|
+
}
|
|
60
|
+
const sizeBytes = statSync(filePath).size;
|
|
61
|
+
attachment = attachmentsStore.uploadFileBackedAttachment(
|
|
62
|
+
filename,
|
|
63
|
+
mimeType,
|
|
64
|
+
filePath,
|
|
65
|
+
sizeBytes,
|
|
66
|
+
);
|
|
67
|
+
} else {
|
|
68
|
+
if (!data || typeof data !== "string") {
|
|
69
|
+
return httpError("BAD_REQUEST", "data (base64) is required", 400);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
try {
|
|
73
|
+
attachment = attachmentsStore.uploadAttachment(
|
|
74
|
+
filename,
|
|
75
|
+
mimeType,
|
|
76
|
+
data,
|
|
77
|
+
filePath ?? undefined,
|
|
78
|
+
);
|
|
79
|
+
} catch (err) {
|
|
80
|
+
if (err instanceof AttachmentUploadError) {
|
|
81
|
+
const status = err.message.startsWith("Attachment too large")
|
|
82
|
+
? 413
|
|
83
|
+
: 400;
|
|
84
|
+
return httpError("BAD_REQUEST", err.message, status);
|
|
85
|
+
}
|
|
86
|
+
throw err;
|
|
60
87
|
}
|
|
61
|
-
throw err;
|
|
62
88
|
}
|
|
63
89
|
|
|
64
90
|
return Response.json({
|
|
@@ -102,7 +128,9 @@ export async function handleDeleteAttachment(req: Request): Promise<Response> {
|
|
|
102
128
|
}
|
|
103
129
|
|
|
104
130
|
function handleGetAttachment(attachmentId: string): Response {
|
|
105
|
-
const attachment = attachmentsStore.getAttachmentById(attachmentId
|
|
131
|
+
const attachment = attachmentsStore.getAttachmentById(attachmentId, {
|
|
132
|
+
hydrateFileData: true,
|
|
133
|
+
});
|
|
106
134
|
if (!attachment) {
|
|
107
135
|
return httpError("NOT_FOUND", "Attachment not found", 404);
|
|
108
136
|
}
|
|
@@ -132,7 +160,9 @@ export function handleGetAttachmentContent(
|
|
|
132
160
|
attachmentId: string,
|
|
133
161
|
req: Request,
|
|
134
162
|
): Response {
|
|
135
|
-
const attachment = attachmentsStore.getAttachmentById(attachmentId
|
|
163
|
+
const attachment = attachmentsStore.getAttachmentById(attachmentId, {
|
|
164
|
+
hydrateFileData: true,
|
|
165
|
+
});
|
|
136
166
|
if (!attachment) {
|
|
137
167
|
return httpError("NOT_FOUND", "Attachment not found", 404);
|
|
138
168
|
}
|
|
@@ -14,17 +14,12 @@
|
|
|
14
14
|
|
|
15
15
|
import { existsSync, readFileSync } from "node:fs";
|
|
16
16
|
|
|
17
|
-
import { buildToolDefinitions } from "../../daemon/conversation-tool-setup.js";
|
|
18
17
|
import { getConversationByKey } from "../../memory/conversation-key-store.js";
|
|
19
|
-
import { buildSystemPrompt } from "../../prompts/system-prompt.js";
|
|
20
|
-
import {
|
|
21
|
-
createTimeout,
|
|
22
|
-
userMessage,
|
|
23
|
-
} from "../../providers/provider-send-message.js";
|
|
24
18
|
import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
25
19
|
import { getLogger } from "../../util/logger.js";
|
|
26
20
|
import { getWorkspacePromptPath } from "../../util/platform.js";
|
|
27
21
|
import type { AuthContext } from "../auth/types.js";
|
|
22
|
+
import { runBtwSidechain } from "../btw-sidechain.js";
|
|
28
23
|
import { httpError } from "../http-errors.js";
|
|
29
24
|
import type { RouteDefinition } from "../http-router.js";
|
|
30
25
|
import type { SendMessageDeps } from "../http-types.js";
|
|
@@ -159,73 +154,42 @@ async function handleBtw(
|
|
|
159
154
|
const conversation =
|
|
160
155
|
await deps.sendMessageDeps.getOrCreateConversation(conversationId);
|
|
161
156
|
|
|
162
|
-
const messages = [...conversation.getMessages(), userMessage(trimmedContent)];
|
|
163
|
-
const tools = buildToolDefinitions();
|
|
164
|
-
const { signal: timeoutSignal, cleanup: cleanupTimeout } =
|
|
165
|
-
createTimeout(30_000);
|
|
166
|
-
|
|
167
|
-
// Combine the timeout signal with the request's abort signal so that
|
|
168
|
-
// disconnection or timeout both cancel the provider call.
|
|
169
|
-
const combinedController = new AbortController();
|
|
170
|
-
const onTimeoutAbort = () => combinedController.abort();
|
|
171
|
-
const onRequestAbort = () => combinedController.abort();
|
|
172
|
-
timeoutSignal.addEventListener("abort", onTimeoutAbort, { once: true });
|
|
173
|
-
req.signal.addEventListener("abort", onRequestAbort, { once: true });
|
|
174
|
-
const combinedSignal = combinedController.signal;
|
|
175
|
-
|
|
176
157
|
const encoder = new TextEncoder();
|
|
177
158
|
|
|
178
159
|
const stream = new ReadableStream({
|
|
179
160
|
start(controller) {
|
|
180
161
|
(async () => {
|
|
181
162
|
try {
|
|
182
|
-
// Preserve any conversation-specific systemPromptOverride so
|
|
183
|
-
// side-chain responses match the active conversation contract. Only
|
|
184
|
-
// fall back to a fresh prompt (excluding BOOTSTRAP.md) for
|
|
185
|
-
// default conversations where no override was provided.
|
|
186
|
-
const systemPrompt = conversation.hasSystemPromptOverride
|
|
187
|
-
? conversation.systemPrompt
|
|
188
|
-
: buildSystemPrompt({ excludeBootstrap: true });
|
|
189
|
-
|
|
190
163
|
const isIntroRequest = conversationKey === IDENTITY_INTRO_KEY;
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
}
|
|
203
|
-
onEvent: (event) => {
|
|
204
|
-
if (event.type === "text_delta") {
|
|
205
|
-
textDeltaCount++;
|
|
206
|
-
if (isIntroRequest) collectedText += event.text;
|
|
207
|
-
controller.enqueue(
|
|
208
|
-
encoder.encode(
|
|
209
|
-
`event: btw_text_delta\ndata: ${JSON.stringify({ text: event.text })}\n\n`,
|
|
210
|
-
),
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
signal: combinedSignal,
|
|
164
|
+
const result = await runBtwSidechain({
|
|
165
|
+
content: trimmedContent,
|
|
166
|
+
conversation,
|
|
167
|
+
signal: req.signal,
|
|
168
|
+
onEvent: (event) => {
|
|
169
|
+
if (event.type === "text_delta") {
|
|
170
|
+
controller.enqueue(
|
|
171
|
+
encoder.encode(
|
|
172
|
+
`event: btw_text_delta\ndata: ${JSON.stringify({ text: event.text })}\n\n`,
|
|
173
|
+
),
|
|
174
|
+
);
|
|
175
|
+
}
|
|
215
176
|
},
|
|
216
|
-
);
|
|
177
|
+
});
|
|
217
178
|
|
|
218
|
-
if (
|
|
179
|
+
if (!result.hadTextDeltas) {
|
|
219
180
|
log.warn(
|
|
220
|
-
{
|
|
181
|
+
{
|
|
182
|
+
conversationKey,
|
|
183
|
+
messageCount: conversation.getMessages().length + 1,
|
|
184
|
+
},
|
|
221
185
|
"btw side-chain completed with no text deltas",
|
|
222
186
|
);
|
|
223
187
|
}
|
|
224
188
|
|
|
225
189
|
// Cache the generated identity intro for subsequent requests.
|
|
226
|
-
if (isIntroRequest &&
|
|
190
|
+
if (isIntroRequest && result.text) {
|
|
227
191
|
try {
|
|
228
|
-
setCachedIntro(
|
|
192
|
+
setCachedIntro(result.text);
|
|
229
193
|
log.debug("Cached identity intro text");
|
|
230
194
|
} catch {
|
|
231
195
|
// Non-fatal — next request will regenerate.
|
|
@@ -249,10 +213,6 @@ async function handleBtw(
|
|
|
249
213
|
} catch {
|
|
250
214
|
/* stream already closed */
|
|
251
215
|
}
|
|
252
|
-
} finally {
|
|
253
|
-
cleanupTimeout();
|
|
254
|
-
timeoutSignal.removeEventListener("abort", onTimeoutAbort);
|
|
255
|
-
req.signal.removeEventListener("abort", onRequestAbort);
|
|
256
216
|
}
|
|
257
217
|
})();
|
|
258
218
|
},
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* Route handlers for conversation management operations.
|
|
3
3
|
*
|
|
4
4
|
* POST /v1/conversations/switch — switch to an existing conversation
|
|
5
|
+
* POST /v1/conversations/fork — fork an existing conversation
|
|
5
6
|
* PATCH /v1/conversations/:id/name — rename a conversation
|
|
6
7
|
* DELETE /v1/conversations — clear all conversations
|
|
7
8
|
* POST /v1/conversations/:id/wipe — wipe conversation and revert memory
|
|
@@ -15,6 +16,7 @@
|
|
|
15
16
|
import {
|
|
16
17
|
batchSetDisplayOrders,
|
|
17
18
|
deleteConversation,
|
|
19
|
+
PRIVATE_CONVERSATION_FORK_ERROR,
|
|
18
20
|
wipeConversation,
|
|
19
21
|
} from "../../memory/conversation-crud.js";
|
|
20
22
|
import {
|
|
@@ -22,6 +24,7 @@ import {
|
|
|
22
24
|
setConversationKeyIfAbsent,
|
|
23
25
|
} from "../../memory/conversation-key-store.js";
|
|
24
26
|
import { enqueueMemoryJob } from "../../memory/jobs-store.js";
|
|
27
|
+
import { UserError } from "../../util/errors.js";
|
|
25
28
|
import { getLogger } from "../../util/logger.js";
|
|
26
29
|
import { httpError } from "../http-errors.js";
|
|
27
30
|
import type { RouteDefinition } from "../http-router.js";
|
|
@@ -33,6 +36,10 @@ const log = getLogger("conversation-management-routes");
|
|
|
33
36
|
// ---------------------------------------------------------------------------
|
|
34
37
|
|
|
35
38
|
export interface ConversationManagementDeps {
|
|
39
|
+
forkConversation?: (params: {
|
|
40
|
+
conversationId: string;
|
|
41
|
+
throughMessageId?: string;
|
|
42
|
+
}) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
36
43
|
switchConversation: (conversationId: string) => Promise<{
|
|
37
44
|
conversationId: string;
|
|
38
45
|
title: string;
|
|
@@ -59,6 +66,67 @@ export function conversationManagementRouteDefinitions(
|
|
|
59
66
|
deps: ConversationManagementDeps,
|
|
60
67
|
): RouteDefinition[] {
|
|
61
68
|
return [
|
|
69
|
+
{
|
|
70
|
+
endpoint: "conversations/fork",
|
|
71
|
+
method: "POST",
|
|
72
|
+
policyKey: "conversations/fork",
|
|
73
|
+
handler: async ({ req }) => {
|
|
74
|
+
if (!deps.forkConversation) {
|
|
75
|
+
return httpError(
|
|
76
|
+
"INTERNAL_ERROR",
|
|
77
|
+
"Conversation forking not available",
|
|
78
|
+
500,
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const rawBody = (await req.json()) as unknown;
|
|
83
|
+
if (
|
|
84
|
+
rawBody == null ||
|
|
85
|
+
typeof rawBody !== "object" ||
|
|
86
|
+
Array.isArray(rawBody)
|
|
87
|
+
) {
|
|
88
|
+
return httpError("BAD_REQUEST", "Invalid request body", 400);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const body = rawBody as {
|
|
92
|
+
conversationId?: string;
|
|
93
|
+
throughMessageId?: string;
|
|
94
|
+
};
|
|
95
|
+
const conversationId = body.conversationId;
|
|
96
|
+
if (!conversationId || typeof conversationId !== "string") {
|
|
97
|
+
return httpError("BAD_REQUEST", "Missing conversationId", 400);
|
|
98
|
+
}
|
|
99
|
+
if (
|
|
100
|
+
body.throughMessageId !== undefined &&
|
|
101
|
+
typeof body.throughMessageId !== "string"
|
|
102
|
+
) {
|
|
103
|
+
return httpError(
|
|
104
|
+
"BAD_REQUEST",
|
|
105
|
+
"throughMessageId must be a string",
|
|
106
|
+
400,
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const resolvedConversationId =
|
|
111
|
+
resolveConversationId(conversationId) ?? conversationId;
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const conversation = await deps.forkConversation({
|
|
115
|
+
conversationId: resolvedConversationId,
|
|
116
|
+
throughMessageId: body.throughMessageId,
|
|
117
|
+
});
|
|
118
|
+
return Response.json({ conversation });
|
|
119
|
+
} catch (err) {
|
|
120
|
+
if (err instanceof UserError) {
|
|
121
|
+
if (err.message === PRIVATE_CONVERSATION_FORK_ERROR) {
|
|
122
|
+
return httpError("FORBIDDEN", err.message, 403);
|
|
123
|
+
}
|
|
124
|
+
return httpError("NOT_FOUND", err.message, 404);
|
|
125
|
+
}
|
|
126
|
+
throw err;
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
},
|
|
62
130
|
{
|
|
63
131
|
endpoint: "conversations/switch",
|
|
64
132
|
method: "POST",
|
|
@@ -207,6 +275,12 @@ export function conversationManagementRouteDefinitions(
|
|
|
207
275
|
targetId: itemId,
|
|
208
276
|
});
|
|
209
277
|
}
|
|
278
|
+
for (const summaryId of deleted.deletedSummaryIds) {
|
|
279
|
+
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
280
|
+
targetType: "summary",
|
|
281
|
+
targetId: summaryId,
|
|
282
|
+
});
|
|
283
|
+
}
|
|
210
284
|
log.info({ conversationId: resolvedId }, "Deleted conversation");
|
|
211
285
|
return new Response(null, { status: 204 });
|
|
212
286
|
},
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* HTTP route definitions for model configuration,
|
|
3
|
-
* message content, and queued
|
|
2
|
+
* HTTP route definitions for model configuration, embedding configuration,
|
|
3
|
+
* conversation search, message content, LLM context inspection, and queued
|
|
4
|
+
* message deletion.
|
|
4
5
|
*
|
|
5
6
|
* These routes expose conversation query functionality over the HTTP API.
|
|
6
7
|
*
|
|
7
|
-
* GET /v1/model
|
|
8
|
-
* PUT /v1/model
|
|
9
|
-
* PUT /v1/model/image-gen
|
|
10
|
-
* GET /v1/
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* GET /v1/model — current model info
|
|
9
|
+
* PUT /v1/model — set model
|
|
10
|
+
* PUT /v1/model/image-gen — set image-gen model
|
|
11
|
+
* GET /v1/config/embeddings — current embedding config
|
|
12
|
+
* PUT /v1/config/embeddings — set embedding provider/model
|
|
13
|
+
* GET /v1/conversations/search — search conversations
|
|
14
|
+
* GET /v1/messages/:id/content — full message content
|
|
15
|
+
* GET /v1/messages/:id/llm-context — LLM request logs for a message
|
|
16
|
+
* DELETE /v1/messages/queued/:id — delete queued message
|
|
13
17
|
*/
|
|
14
18
|
|
|
19
|
+
import { VALID_MEMORY_EMBEDDING_PROVIDERS } from "../../config/schemas/memory-storage.js";
|
|
20
|
+
import { VALID_INFERENCE_PROVIDERS } from "../../config/schemas/services.js";
|
|
21
|
+
import {
|
|
22
|
+
getEmbeddingConfigInfo,
|
|
23
|
+
setEmbeddingConfig,
|
|
24
|
+
} from "../../daemon/handlers/config-embeddings.js";
|
|
15
25
|
import {
|
|
16
26
|
getModelInfo,
|
|
17
27
|
type ModelSetContext,
|
|
@@ -23,8 +33,45 @@ import {
|
|
|
23
33
|
performConversationSearch,
|
|
24
34
|
} from "../../daemon/handlers/conversation-history.js";
|
|
25
35
|
import { deleteQueuedMessage } from "../../daemon/handlers/conversations.js";
|
|
36
|
+
import { getRequestLogsByMessageId } from "../../memory/llm-request-log-store.js";
|
|
26
37
|
import { httpError } from "../http-errors.js";
|
|
27
38
|
import type { RouteDefinition } from "../http-router.js";
|
|
39
|
+
import { normalizeLlmContextPayloads } from "./llm-context-normalization.js";
|
|
40
|
+
|
|
41
|
+
const validProviderSet = new Set<string>(VALID_INFERENCE_PROVIDERS);
|
|
42
|
+
const validEmbeddingProviderSet = new Set<string>(
|
|
43
|
+
VALID_MEMORY_EMBEDDING_PROVIDERS,
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
type LlmContextNormalizationResult = ReturnType<
|
|
47
|
+
typeof normalizeLlmContextPayloads
|
|
48
|
+
>;
|
|
49
|
+
|
|
50
|
+
type LlmContextSummaryResponse = NonNullable<
|
|
51
|
+
Omit<NonNullable<LlmContextNormalizationResult["summary"]>, "provider">
|
|
52
|
+
> & {
|
|
53
|
+
provider: string;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
type LlmContextRouteResult = Omit<LlmContextNormalizationResult, "summary"> & {
|
|
57
|
+
summary?: LlmContextSummaryResponse;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
function applyStoredProviderToLlmContextResult(
|
|
61
|
+
normalized: LlmContextNormalizationResult,
|
|
62
|
+
provider: string | null,
|
|
63
|
+
): LlmContextRouteResult {
|
|
64
|
+
if (!provider) {
|
|
65
|
+
return normalized as LlmContextRouteResult;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return {
|
|
69
|
+
...normalized,
|
|
70
|
+
summary: normalized.summary
|
|
71
|
+
? { ...normalized.summary, provider }
|
|
72
|
+
: { provider },
|
|
73
|
+
};
|
|
74
|
+
}
|
|
28
75
|
|
|
29
76
|
// ---------------------------------------------------------------------------
|
|
30
77
|
// Dependency interfaces
|
|
@@ -65,7 +112,10 @@ export function conversationQueryRouteDefinitions(
|
|
|
65
112
|
if (!deps.getModelSetContext) {
|
|
66
113
|
return httpError("INTERNAL_ERROR", "Model set not available", 500);
|
|
67
114
|
}
|
|
68
|
-
const body = (await req.json()) as {
|
|
115
|
+
const body = (await req.json()) as {
|
|
116
|
+
modelId?: string;
|
|
117
|
+
provider?: string;
|
|
118
|
+
};
|
|
69
119
|
if (!body.modelId || typeof body.modelId !== "string") {
|
|
70
120
|
return httpError(
|
|
71
121
|
"BAD_REQUEST",
|
|
@@ -73,8 +123,23 @@ export function conversationQueryRouteDefinitions(
|
|
|
73
123
|
400,
|
|
74
124
|
);
|
|
75
125
|
}
|
|
126
|
+
if (
|
|
127
|
+
body.provider !== undefined &&
|
|
128
|
+
(typeof body.provider !== "string" ||
|
|
129
|
+
!validProviderSet.has(body.provider))
|
|
130
|
+
) {
|
|
131
|
+
return httpError(
|
|
132
|
+
"BAD_REQUEST",
|
|
133
|
+
`Invalid provider "${body.provider}". Valid providers: ${[...validProviderSet].join(", ")}`,
|
|
134
|
+
400,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
76
137
|
try {
|
|
77
|
-
const info = await setModel(
|
|
138
|
+
const info = await setModel(
|
|
139
|
+
body.modelId,
|
|
140
|
+
deps.getModelSetContext(),
|
|
141
|
+
body.provider,
|
|
142
|
+
);
|
|
78
143
|
return Response.json(info);
|
|
79
144
|
} catch (err) {
|
|
80
145
|
const message = err instanceof Error ? err.message : String(err);
|
|
@@ -120,6 +185,71 @@ export function conversationQueryRouteDefinitions(
|
|
|
120
185
|
},
|
|
121
186
|
},
|
|
122
187
|
|
|
188
|
+
// ── Embedding config ─────────────────────────────────────────────
|
|
189
|
+
{
|
|
190
|
+
endpoint: "config/embeddings",
|
|
191
|
+
method: "GET",
|
|
192
|
+
policyKey: "config/embeddings",
|
|
193
|
+
handler: async () => {
|
|
194
|
+
const info = await getEmbeddingConfigInfo();
|
|
195
|
+
return Response.json(info);
|
|
196
|
+
},
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
endpoint: "config/embeddings",
|
|
200
|
+
method: "PUT",
|
|
201
|
+
policyKey: "config/embeddings",
|
|
202
|
+
handler: async ({ req }) => {
|
|
203
|
+
if (!deps.getModelSetContext) {
|
|
204
|
+
return httpError(
|
|
205
|
+
"INTERNAL_ERROR",
|
|
206
|
+
"Embedding config not available",
|
|
207
|
+
500,
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
const body = (await req.json()) as {
|
|
211
|
+
provider?: string;
|
|
212
|
+
model?: string;
|
|
213
|
+
};
|
|
214
|
+
if (!body.provider || typeof body.provider !== "string") {
|
|
215
|
+
return httpError(
|
|
216
|
+
"BAD_REQUEST",
|
|
217
|
+
"Missing required field: provider",
|
|
218
|
+
400,
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
if (!validEmbeddingProviderSet.has(body.provider)) {
|
|
222
|
+
return httpError(
|
|
223
|
+
"BAD_REQUEST",
|
|
224
|
+
`Invalid provider "${body.provider}". Valid providers: ${[...validEmbeddingProviderSet].join(", ")}`,
|
|
225
|
+
400,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
if (body.model !== undefined && typeof body.model !== "string") {
|
|
229
|
+
return httpError(
|
|
230
|
+
"BAD_REQUEST",
|
|
231
|
+
"Field 'model' must be a string",
|
|
232
|
+
400,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
try {
|
|
236
|
+
const info = await setEmbeddingConfig(
|
|
237
|
+
body.provider,
|
|
238
|
+
body.model,
|
|
239
|
+
deps.getModelSetContext(),
|
|
240
|
+
);
|
|
241
|
+
return Response.json(info);
|
|
242
|
+
} catch (err) {
|
|
243
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
244
|
+
return httpError(
|
|
245
|
+
"INTERNAL_ERROR",
|
|
246
|
+
`Failed to set embedding config: ${message}`,
|
|
247
|
+
500,
|
|
248
|
+
);
|
|
249
|
+
}
|
|
250
|
+
},
|
|
251
|
+
},
|
|
252
|
+
|
|
123
253
|
// ── Conversation search ───────────────────────────────────────────
|
|
124
254
|
{
|
|
125
255
|
endpoint: "conversations/search",
|
|
@@ -167,6 +297,53 @@ export function conversationQueryRouteDefinitions(
|
|
|
167
297
|
},
|
|
168
298
|
},
|
|
169
299
|
|
|
300
|
+
// ── LLM context (request logs) for a message ───────────────────────
|
|
301
|
+
{
|
|
302
|
+
endpoint: "messages/:id/llm-context",
|
|
303
|
+
method: "GET",
|
|
304
|
+
policyKey: "messages/llm-context",
|
|
305
|
+
handler: ({ params }) => {
|
|
306
|
+
const messageId = params.id;
|
|
307
|
+
if (!messageId) {
|
|
308
|
+
return httpError("BAD_REQUEST", "message id is required", 400);
|
|
309
|
+
}
|
|
310
|
+
const logs = getRequestLogsByMessageId(messageId);
|
|
311
|
+
return Response.json({
|
|
312
|
+
messageId,
|
|
313
|
+
logs: logs.map((log) => {
|
|
314
|
+
let requestPayload: unknown;
|
|
315
|
+
try {
|
|
316
|
+
requestPayload = JSON.parse(log.requestPayload);
|
|
317
|
+
} catch {
|
|
318
|
+
requestPayload = log.requestPayload;
|
|
319
|
+
}
|
|
320
|
+
let responsePayload: unknown;
|
|
321
|
+
try {
|
|
322
|
+
responsePayload = JSON.parse(log.responsePayload);
|
|
323
|
+
} catch {
|
|
324
|
+
responsePayload = log.responsePayload;
|
|
325
|
+
}
|
|
326
|
+
const normalized = normalizeLlmContextPayloads({
|
|
327
|
+
requestPayload,
|
|
328
|
+
responsePayload,
|
|
329
|
+
createdAt: log.createdAt,
|
|
330
|
+
});
|
|
331
|
+
const result = applyStoredProviderToLlmContextResult(
|
|
332
|
+
normalized,
|
|
333
|
+
log.provider,
|
|
334
|
+
);
|
|
335
|
+
return {
|
|
336
|
+
id: log.id,
|
|
337
|
+
requestPayload,
|
|
338
|
+
responsePayload,
|
|
339
|
+
createdAt: log.createdAt,
|
|
340
|
+
...result,
|
|
341
|
+
};
|
|
342
|
+
}),
|
|
343
|
+
});
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
|
|
170
347
|
// ── Delete queued message ─────────────────────────────────────────
|
|
171
348
|
{
|
|
172
349
|
endpoint: "messages/queued/:id",
|