@vellumai/assistant 0.5.0 → 0.5.2
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 +54 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- 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__/assistant-feature-flags-integration.test.ts +7 -9
- 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 +149 -5
- package/src/__tests__/conversation-agent-loop.test.ts +290 -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-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-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +3 -3
- 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__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/filesystem-tools.test.ts +4 -2
- 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 +103 -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__/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-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-recall-quality.test.ts +5 -5
- 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__/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-feature-flags-integration.test.ts +18 -17
- package/src/__tests__/skill-feature-flags.test.ts +13 -13
- package/src/__tests__/skill-load-feature-flag.test.ts +4 -4
- 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__/system-prompt.test.ts +8 -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__/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/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 +16 -0
- package/src/config/loader.ts +64 -0
- package/src/config/raw-config-utils.ts +30 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/services.ts +8 -6
- 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 +46 -42
- package/src/daemon/conversation-agent-loop.ts +56 -19
- 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 +39 -15
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +21 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +143 -20
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +51 -29
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +148 -0
- package/src/daemon/handlers/config-model.ts +71 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/history-repair.ts +28 -8
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +106 -64
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +19 -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/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/attachments-store.ts +558 -130
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +442 -3
- 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 +28 -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 +9 -7
- 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 +1 -4
- 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/index.ts +7 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +6 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/oauth.ts +6 -0
- 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 +97 -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 +62 -19
- package/src/prompts/system-prompt.ts +2 -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 +68 -0
- package/src/runtime/routes/conversation-query-routes.ts +180 -10
- package/src/runtime/routes/conversation-routes.ts +222 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1199 -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 +4 -0
- 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 +28 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +9 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/swarm/backend-claude-code.ts +3 -6
- 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/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +4 -21
- package/src/tools/skills/execute.ts +1 -1
- 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 +6 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/002-backfill-installation-id.ts +23 -12
- 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/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 +10 -0
- 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/ARCHITECTURE.md
CHANGED
|
@@ -783,26 +783,26 @@ All client-server communication uses HTTP for request/response operations and Se
|
|
|
783
783
|
|
|
784
784
|
The daemon emits two distinct error message types via SSE:
|
|
785
785
|
|
|
786
|
-
| Message type | Scope | Purpose | Payload
|
|
787
|
-
| -------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
788
|
-
| `conversation_error` | Conversation-scoped | Typed, actionable failures during conversation runtime (e.g., provider network error, rate limit, API failure) | `
|
|
789
|
-
| `error` | Global | Generic, non-
|
|
790
|
-
|
|
791
|
-
**Design rationale:** `conversation_error` carries structured metadata (error code, retryable flag, debug details) so the client can present actionable UI — a toast with retry/dismiss buttons — rather than a generic error banner. The older `error` type is retained for backward compatibility with non-
|
|
792
|
-
|
|
793
|
-
###
|
|
794
|
-
|
|
795
|
-
| Code
|
|
796
|
-
|
|
|
797
|
-
| `PROVIDER_NETWORK`
|
|
798
|
-
| `PROVIDER_RATE_LIMIT`
|
|
799
|
-
| `PROVIDER_API`
|
|
800
|
-
| `PROVIDER_BILLING`
|
|
801
|
-
| `CONTEXT_TOO_LARGE`
|
|
802
|
-
| `
|
|
803
|
-
| `
|
|
804
|
-
| `REGENERATE_FAILED`
|
|
805
|
-
| `UNKNOWN`
|
|
786
|
+
| Message type | Scope | Purpose | Payload |
|
|
787
|
+
| -------------------- | ------------------- | -------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
|
|
788
|
+
| `conversation_error` | Conversation-scoped | Typed, actionable failures during conversation runtime (e.g., provider network error, rate limit, API failure) | `conversationId`, `code` (typed enum), `userMessage`, `retryable`, `debugDetails?` |
|
|
789
|
+
| `error` | Global | Generic, non-conversation failures (e.g., daemon startup errors, unknown message types) | `message` (string) |
|
|
790
|
+
|
|
791
|
+
**Design rationale:** `conversation_error` carries structured metadata (error code, retryable flag, debug details) so the client can present actionable UI — a toast with retry/dismiss buttons — rather than a generic error banner. The older `error` type is retained for backward compatibility with non-conversation contexts.
|
|
792
|
+
|
|
793
|
+
### Conversation Error Codes
|
|
794
|
+
|
|
795
|
+
| Code | Meaning | Retryable |
|
|
796
|
+
| -------------------------------- | ----------------------------------------------------------------------- | --------- |
|
|
797
|
+
| `PROVIDER_NETWORK` | Unable to reach the LLM provider (connection refused, timeout, DNS) | Yes |
|
|
798
|
+
| `PROVIDER_RATE_LIMIT` | LLM provider rate-limited the request (HTTP 429) | Yes |
|
|
799
|
+
| `PROVIDER_API` | Provider returned a server error (5xx) or retryable 4xx | Yes |
|
|
800
|
+
| `PROVIDER_BILLING` | Invalid/expired API key or insufficient credits (HTTP 401, billing 4xx) | No |
|
|
801
|
+
| `CONTEXT_TOO_LARGE` | Request exceeds the model's context window (HTTP 413, token limit) | No |
|
|
802
|
+
| `CONVERSATION_ABORTED` | Non-user abort interrupted the request | Yes |
|
|
803
|
+
| `CONVERSATION_PROCESSING_FAILED` | Catch-all for unexpected processing failures | No |
|
|
804
|
+
| `REGENERATE_FAILED` | Failed to regenerate a previous response | Yes |
|
|
805
|
+
| `UNKNOWN` | Unrecognized error that does not match any specific category | No |
|
|
806
806
|
|
|
807
807
|
### Error Classification
|
|
808
808
|
|
|
@@ -826,7 +826,7 @@ sequenceDiagram
|
|
|
826
826
|
|
|
827
827
|
Note over Daemon: LLM call fails or<br/>processing error occurs
|
|
828
828
|
Daemon->>Daemon: classifyConversationError(error, ctx)
|
|
829
|
-
Daemon->>DC: conversation_error {
|
|
829
|
+
Daemon->>DC: conversation_error {conversationId, code,<br/>userMessage, retryable, debugDetails?}
|
|
830
830
|
DC->>DC: broadcast to all subscribers
|
|
831
831
|
DC->>VM: subscribe() stream delivers message
|
|
832
832
|
VM->>VM: set conversationError property<br/>clear isThinking / isCancelling
|
|
@@ -837,7 +837,7 @@ sequenceDiagram
|
|
|
837
837
|
alt User taps Retry (retryable == true)
|
|
838
838
|
UI->>VM: retryAfterConversationError()
|
|
839
839
|
VM->>VM: dismissConversationError()<br/>+ regenerateLastMessage()
|
|
840
|
-
VM->>DC: regenerate {
|
|
840
|
+
VM->>DC: regenerate {conversationId}
|
|
841
841
|
DC->>Daemon: HTTP POST /v1/messages
|
|
842
842
|
else User taps Dismiss
|
|
843
843
|
UI->>VM: dismissConversationError()
|
|
@@ -939,7 +939,7 @@ graph TB
|
|
|
939
939
|
end
|
|
940
940
|
|
|
941
941
|
SUBMIT --> SLASH_CHECK
|
|
942
|
-
SLASH_CHECK -->|"Yes (/
|
|
942
|
+
SLASH_CHECK -->|"Yes (/models, /status, etc.)"| QA_ROUTE
|
|
943
943
|
SLASH_CHECK -->|"No"| VOICE_CHECK
|
|
944
944
|
VOICE_CHECK -->|"Yes"| QA_ROUTE
|
|
945
945
|
VOICE_CHECK -->|"No"| CLASSIFIER
|
|
@@ -1017,12 +1017,12 @@ graph TB
|
|
|
1017
1017
|
|
|
1018
1018
|
INPUT --> RESOLVE
|
|
1019
1019
|
RESOLVE -->|"kind: passthrough"| PASSTHROUGH
|
|
1020
|
-
RESOLVE -->|"kind: unknown<br/>(/
|
|
1020
|
+
RESOLVE -->|"kind: unknown<br/>(/models, /status, /commands, /pair)"| HANDLED
|
|
1021
1021
|
```
|
|
1022
1022
|
|
|
1023
1023
|
Key behaviors:
|
|
1024
1024
|
|
|
1025
|
-
- **Built-in commands**: `/
|
|
1025
|
+
- **Built-in commands**: `/models`, `/status`, `/commands`, and `/pair` are handled directly by `resolveSlash()`. A deterministic `assistant_text_delta` + `message_complete` is emitted. No message persistence or model call occurs.
|
|
1026
1026
|
- **Passthrough**: Any input that does not match a built-in command passes through to the normal agent loop, including slash-like tokens that are not recognized.
|
|
1027
1027
|
- **Queue**: Queued messages receive the same slash resolution.
|
|
1028
1028
|
|
|
@@ -1183,7 +1183,7 @@ The following capabilities ship as bundled skills in `assistant/src/config/bundl
|
|
|
1183
1183
|
| `claude-code` | Claude Code tool | Delegate coding tasks to Claude Code subprocess |
|
|
1184
1184
|
| `computer-use` | `computer_use_observe`, `computer_use_click`, `computer_use_type_text`, `computer_use_key`, `computer_use_scroll`, `computer_use_drag`, `computer_use_wait`, `computer_use_open_app`, `computer_use_run_applescript`, `computer_use_done`, `computer_use_respond` | Computer-use proxy tools — preactivated via `preactivatedSkillIds` in desktop sessions. Each tool forwards actions to the connected macOS client via `HostCuProxy`, which handles request/resolve proxying, step counting, loop detection, and observation formatting within the unified agent loop. |
|
|
1185
1185
|
| `weather` | `get-weather` | Fetch current weather data |
|
|
1186
|
-
| `app-builder` | `app_create`, `
|
|
1186
|
+
| `app-builder` | `app_create`, `app_delete`, `app_refresh`, `app_generate_icon` | Dynamic app authoring — create and manage persistent apps; file editing uses generic file tools plus `app_refresh` (activated via `skill_load app-builder`; `app_open` remains a core proxy tool) |
|
|
1187
1187
|
| `self-upgrade` | (instruction-only) | Self-improvement workflow |
|
|
1188
1188
|
| `start-the-day` | (instruction-only) | Morning briefing routine |
|
|
1189
1189
|
|
|
@@ -1525,7 +1525,7 @@ sequenceDiagram
|
|
|
1525
1525
|
|
|
1526
1526
|
### Key design decisions
|
|
1527
1527
|
|
|
1528
|
-
- **Recursion guard**: A module-level `Set<
|
|
1528
|
+
- **Recursion guard**: A module-level `Set<conversationId>` prevents concurrent swarms within the same conversation while allowing independent conversations to run their own swarms in parallel.
|
|
1529
1529
|
- **Abort signal**: The tool checks `context.signal?.aborted` before planning and before execution. The signal is also forwarded into `executeSwarm` and the worker backend, enabling cooperative cancellation of in-flight workers.
|
|
1530
1530
|
- **DAG scheduling**: Tasks with dependencies are topologically ordered. Independent tasks run in parallel up to `maxWorkers`.
|
|
1531
1531
|
- **Per-task retries**: Failed tasks retry up to `maxRetriesPerTask` before being marked failed. Dependents are transitively blocked.
|
|
@@ -1568,7 +1568,7 @@ sequenceDiagram
|
|
|
1568
1568
|
|
|
1569
1569
|
Note over Daemon: Processing previous request...<br/>Reaches safe tool-loop checkpoint
|
|
1570
1570
|
|
|
1571
|
-
Daemon-->>DC: generation_handoff (
|
|
1571
|
+
Daemon-->>DC: generation_handoff (conversationId, queuedCount)
|
|
1572
1572
|
Note over Daemon: Daemon yields current generation
|
|
1573
1573
|
|
|
1574
1574
|
Daemon-->>DC: message_dequeued
|
|
@@ -1585,7 +1585,7 @@ sequenceDiagram
|
|
|
1585
1585
|
|
|
1586
1586
|
## Trace System — Debug Panel Data Flow
|
|
1587
1587
|
|
|
1588
|
-
The trace system provides real-time observability of daemon
|
|
1588
|
+
The trace system provides real-time observability of daemon conversation internals. Each conversation creates a `TraceEmitter` that emits structured `trace_event` SSE events as the conversation processes requests, makes LLM calls, and executes tools.
|
|
1589
1589
|
|
|
1590
1590
|
```mermaid
|
|
1591
1591
|
sequenceDiagram
|
|
@@ -1636,41 +1636,41 @@ sequenceDiagram
|
|
|
1636
1636
|
TE-->>DC: trace_event (message_complete)
|
|
1637
1637
|
DC-->>TS: ingest()
|
|
1638
1638
|
|
|
1639
|
-
Note over TS: Events deduplicated by eventId,<br/>ordered by sequence + timestampMs,<br/>grouped by
|
|
1639
|
+
Note over TS: Events deduplicated by eventId,<br/>ordered by sequence + timestampMs,<br/>grouped by conversation and requestId,<br/>capped at 5000 per conversation
|
|
1640
1640
|
|
|
1641
|
-
TS-->>DP: @Published
|
|
1641
|
+
TS-->>DP: @Published eventsByConversation
|
|
1642
1642
|
Note over DP: Metrics strip: requests, LLM calls,<br/>tokens (in/out), avg latency, failures<br/>Timeline: events grouped by requestId
|
|
1643
1643
|
```
|
|
1644
1644
|
|
|
1645
1645
|
### Trace Event Kinds
|
|
1646
1646
|
|
|
1647
|
-
Events emitted during a
|
|
1648
|
-
|
|
1649
|
-
| Kind | Emitted by
|
|
1650
|
-
| --------------------------- |
|
|
1651
|
-
| `request_received` | Handlers /
|
|
1652
|
-
| `request_queued` | Handlers /
|
|
1653
|
-
| `request_dequeued` |
|
|
1654
|
-
| `llm_call_started` |
|
|
1655
|
-
| `llm_call_finished` |
|
|
1656
|
-
| `assistant_message` |
|
|
1657
|
-
| `tool_started` | ToolTraceListener
|
|
1658
|
-
| `tool_permission_requested` | ToolTraceListener
|
|
1659
|
-
| `tool_permission_decided` | ToolTraceListener
|
|
1660
|
-
| `tool_finished` | ToolTraceListener
|
|
1661
|
-
| `tool_failed` | ToolTraceListener
|
|
1662
|
-
| `secret_detected` | ToolTraceListener
|
|
1663
|
-
| `generation_handoff` |
|
|
1664
|
-
| `message_complete` |
|
|
1665
|
-
| `generation_cancelled` |
|
|
1666
|
-
| `request_error` | Handlers /
|
|
1647
|
+
Events emitted during a conversation lifecycle:
|
|
1648
|
+
|
|
1649
|
+
| Kind | Emitted by | When |
|
|
1650
|
+
| --------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------- |
|
|
1651
|
+
| `request_received` | Handlers / Conversation | User message or surface action arrives |
|
|
1652
|
+
| `request_queued` | Handlers / Conversation | Message queued while conversation is busy |
|
|
1653
|
+
| `request_dequeued` | Conversation | Queued message begins processing |
|
|
1654
|
+
| `llm_call_started` | Conversation | LLM API call initiated |
|
|
1655
|
+
| `llm_call_finished` | Conversation | LLM API call completed (carries `inputTokens`, `outputTokens`, `latencyMs`) |
|
|
1656
|
+
| `assistant_message` | Conversation | Assistant response assembled (carries `toolUseCount`) |
|
|
1657
|
+
| `tool_started` | ToolTraceListener | Tool execution begins |
|
|
1658
|
+
| `tool_permission_requested` | ToolTraceListener | Permission check needed (carries `riskLevel`) |
|
|
1659
|
+
| `tool_permission_decided` | ToolTraceListener | Permission granted or denied (carries `decision`) |
|
|
1660
|
+
| `tool_finished` | ToolTraceListener | Tool execution completed (carries `durationMs`) |
|
|
1661
|
+
| `tool_failed` | ToolTraceListener | Tool execution failed (carries `durationMs`) |
|
|
1662
|
+
| `secret_detected` | ToolTraceListener | Secret found in tool output |
|
|
1663
|
+
| `generation_handoff` | Conversation | Yielding to next queued message |
|
|
1664
|
+
| `message_complete` | Conversation | Full request processing finished |
|
|
1665
|
+
| `generation_cancelled` | Conversation | User cancelled the generation |
|
|
1666
|
+
| `request_error` | Handlers / Conversation | Unrecoverable error during processing (includes queue-full rejection and persist-failure paths) |
|
|
1667
1667
|
|
|
1668
1668
|
### Architecture
|
|
1669
1669
|
|
|
1670
|
-
- **TraceEmitter** (daemon, per-
|
|
1671
|
-
- **ToolTraceListener** (daemon): Subscribes to the
|
|
1670
|
+
- **TraceEmitter** (daemon, per-conversation): Constructed with a `conversationId` and a `sendToClient` callback. Maintains a monotonic sequence counter for stable ordering. Truncates summaries to 200 chars and attribute values to 500 chars. Each call to `emit()` sends a `trace_event` SSE event to connected clients.
|
|
1671
|
+
- **ToolTraceListener** (daemon): Subscribes to the conversation's `EventBus` via `onAny()` and translates tool domain events (`tool.execution.started`, `tool.execution.finished`, `tool.execution.failed`, `tool.permission.requested`, `tool.permission.decided`, `tool.secret.detected`) into trace events through the `TraceEmitter`.
|
|
1672
1672
|
- **DaemonClient** (Swift, shared): Decodes `trace_event` SSE events into `TraceEventMessage` structs and invokes the `onTraceEvent` callback.
|
|
1673
|
-
- **TraceStore** (Swift, macOS): `@MainActor ObservableObject` that ingests `TraceEventMessage` structs. Deduplicates by `eventId`, maintains stable sort order (sequence, then timestampMs, then insertion order), groups events by
|
|
1673
|
+
- **TraceStore** (Swift, macOS): `@MainActor ObservableObject` that ingests `TraceEventMessage` structs. Deduplicates by `eventId`, maintains stable sort order (sequence, then timestampMs, then insertion order), groups events by conversation and requestId, and enforces a retention cap of 5,000 events per conversation. Each request group is classified with a terminal status: `completed` (via `message_complete`), `cancelled` (via `generation_cancelled`), `handedOff` (via `generation_handoff`), `error` (via `request_error` or any event with `status == "error"`), or `active` (no terminal event yet).
|
|
1674
1674
|
- **DebugPanel** (Swift, macOS): SwiftUI view that observes `TraceStore`. Displays a metrics strip (request count, LLM calls, total tokens, average latency, tool failures) and a `TraceTimelineView` showing events grouped by requestId with color-coded status indicators. The timeline auto-scrolls to new events while the user is at the bottom; scrolling up pauses auto-scroll and shows a "Jump to bottom" button that resumes it.
|
|
1675
1675
|
|
|
1676
1676
|
---
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Integrations Architecture
|
|
2
2
|
|
|
3
|
-
OAuth, messaging adapters, script proxy, and
|
|
3
|
+
OAuth, messaging adapters, script proxy, and conversation disk view architecture.
|
|
4
4
|
|
|
5
5
|
## Integrations — OAuth2 + Unified Messaging
|
|
6
6
|
|
|
@@ -514,90 +514,85 @@ The proxy subsystem is fully wired, including credential injection. The session
|
|
|
514
514
|
|
|
515
515
|
---
|
|
516
516
|
|
|
517
|
-
##
|
|
517
|
+
## Conversation Disk View — Filesystem-Based Conversation Access
|
|
518
518
|
|
|
519
|
-
The
|
|
519
|
+
The conversation disk view projects conversation metadata, messages, and attachments to a browsable filesystem layout under `~/.vellum/workspace/conversations/`. This enables the assistant to search, read, and manipulate conversation data (including media attachments) using standard file tools (`read_file`, `glob`, `grep`) rather than dedicated asset search tools.
|
|
520
520
|
|
|
521
|
-
###
|
|
521
|
+
### Directory Layout
|
|
522
522
|
|
|
523
|
-
|
|
524
|
-
sequenceDiagram
|
|
525
|
-
participant Model as LLM
|
|
526
|
-
participant Search as asset_search tool
|
|
527
|
-
participant DB as SQLite (attachments)
|
|
528
|
-
participant Visibility as media-visibility-policy
|
|
529
|
-
participant Materialize as asset_materialize tool
|
|
530
|
-
participant Sandbox as Sandbox filesystem
|
|
531
|
-
|
|
532
|
-
Model->>Search: search(mime_type: "image/*", recency: "last_7_days")
|
|
533
|
-
Search->>DB: query attachments (filters)
|
|
534
|
-
DB-->>Search: matching rows (metadata only, no base64)
|
|
535
|
-
Search->>Visibility: filterVisibleAttachments(results, currentContext)
|
|
536
|
-
Note over Visibility: Private-conversation attachments filtered out<br/>unless viewer is in the same conversation
|
|
537
|
-
Visibility-->>Search: visible results
|
|
538
|
-
Search-->>Model: metadata list (IDs, filenames, types, sizes)
|
|
539
|
-
|
|
540
|
-
Model->>Materialize: materialize(attachment_id, destination_path)
|
|
541
|
-
Materialize->>Materialize: sandboxPolicy(destination_path)
|
|
542
|
-
Materialize->>DB: load attachment (including base64 data)
|
|
543
|
-
Materialize->>Visibility: isAttachmentVisible(attachmentCtx, currentCtx)
|
|
544
|
-
Note over Visibility: Second visibility check at materialize time<br/>prevents TOCTOU between search and materialize
|
|
545
|
-
Materialize->>Materialize: size check (max 100 MB)
|
|
546
|
-
Materialize->>Sandbox: write decoded bytes to destination
|
|
547
|
-
Materialize-->>Model: "Materialized 'photo.jpg' to /workspace/media/photo.jpg"
|
|
548
|
-
```
|
|
523
|
+
Each conversation is projected to a directory named `{isoDate}_{id}`:
|
|
549
524
|
|
|
550
|
-
|
|
525
|
+
```
|
|
526
|
+
~/.vellum/workspace/conversations/
|
|
527
|
+
2025-01-15T10-30-00.000Z_abc123/
|
|
528
|
+
meta.json # Conversation metadata (id, title, type, channel, timestamps)
|
|
529
|
+
messages.jsonl # Flattened message log (one JSON object per line)
|
|
530
|
+
attachments/ # Decoded attachment files (original filenames, collision-safe)
|
|
531
|
+
photo.png
|
|
532
|
+
document.pdf
|
|
533
|
+
```
|
|
551
534
|
|
|
552
|
-
|
|
535
|
+
### Write-Through Sync
|
|
553
536
|
|
|
554
|
-
|
|
555
|
-
graph TB
|
|
556
|
-
subgraph "Visibility Rules"
|
|
557
|
-
ATT_STD["Attachment from<br/>standard conversation"]
|
|
558
|
-
ATT_PVT["Attachment from<br/>private conversation"]
|
|
537
|
+
The disk view is updated at the daemon level, not automatically by the DB CRUD layer. Conversation creation, metadata updates, and deletion are synced from `conversation-crud.ts`, but message sync (`syncMessageToDisk`) is only called from daemon-level code paths (e.g. `conversation-messaging.ts`) — not from the CRUD `addMessage()` function. This means `messages.jsonl` reflects messages processed through the daemon's messaging pipeline, not every message write. All disk writes are best-effort; failures are logged but never thrown, so the disk view cannot break DB operations.
|
|
559
538
|
|
|
560
|
-
|
|
561
|
-
VIEWER_SAME["Same private conversation<br/>(matching conversationId)"]
|
|
562
|
-
VIEWER_OTHER["Different private conversation<br/>or standard conversation"]
|
|
563
|
-
end
|
|
539
|
+
> **Privacy note:** Conversation disk-view files live under `~/.vellum/workspace/conversations/` and are **excluded** from diagnostic log exports ("Send logs to Vellum") via the `WORKSPACE_SKIP_DIRS` filter in `log-export-routes.ts`. However, the SQLite database (`assistant.db`) is included in exports as a SQL dump, and it contains conversation messages and attachment data in its tables. The disk-view exclusion prevents the raw conversation files and decoded attachments from being exported, but conversation content stored in the database may still be present in the export.
|
|
564
540
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
541
|
+
```mermaid
|
|
542
|
+
sequenceDiagram
|
|
543
|
+
participant CRUD as conversation-crud.ts
|
|
544
|
+
participant Daemon as conversation-messaging.ts
|
|
545
|
+
participant DiskView as conversation-disk-view.ts
|
|
546
|
+
participant FS as Filesystem
|
|
547
|
+
|
|
548
|
+
Note over CRUD,FS: Conversation creation (CRUD layer)
|
|
549
|
+
CRUD->>CRUD: INSERT conversation row
|
|
550
|
+
CRUD->>DiskView: initConversationDir(conv)
|
|
551
|
+
DiskView->>FS: mkdir + write meta.json
|
|
552
|
+
|
|
553
|
+
Note over Daemon,FS: Message insertion (daemon layer)
|
|
554
|
+
Daemon->>CRUD: addMessage(convId, role, content)
|
|
555
|
+
CRUD->>CRUD: INSERT message row
|
|
556
|
+
Daemon->>DiskView: syncMessageToDisk(convId, msgId, createdAtMs)
|
|
557
|
+
DiskView->>DiskView: flattenContentBlocks(content)
|
|
558
|
+
DiskView->>FS: append JSONL record to messages.jsonl
|
|
559
|
+
DiskView->>FS: reference files already materialized in attachments/
|
|
560
|
+
|
|
561
|
+
Note over CRUD,FS: Conversation update (CRUD layer)
|
|
562
|
+
CRUD->>CRUD: UPDATE conversation row
|
|
563
|
+
CRUD->>DiskView: updateMetaFile(conv)
|
|
564
|
+
DiskView->>FS: rewrite meta.json
|
|
565
|
+
|
|
566
|
+
Note over CRUD,FS: Conversation deletion (CRUD layer)
|
|
567
|
+
CRUD->>CRUD: DELETE conversation row
|
|
568
|
+
CRUD->>DiskView: removeConversationDir(id, createdAtMs)
|
|
569
|
+
DiskView->>FS: rm -rf conversation directory
|
|
568
570
|
```
|
|
569
571
|
|
|
570
|
-
|
|
572
|
+
### Content Flattening
|
|
571
573
|
|
|
572
|
-
|
|
574
|
+
Message content (stored as JSON `ContentBlock[]` in the DB) is flattened for the JSONL log:
|
|
573
575
|
|
|
574
|
-
**
|
|
576
|
+
- **Text blocks** are concatenated into a single `content` string.
|
|
577
|
+
- **Tool use blocks** are extracted into a `toolCalls` array (`{ name, input }`).
|
|
578
|
+
- **Tool result blocks** are extracted into a `toolResults` array.
|
|
579
|
+
- **Image/file blocks** are skipped — they are represented via the `attachments/` subdirectory instead.
|
|
575
580
|
|
|
576
|
-
###
|
|
581
|
+
### Attachment Projection
|
|
577
582
|
|
|
578
|
-
|
|
579
|
-
| ----------------- | ------ | ---------------------------------------------------------------------------------------------- |
|
|
580
|
-
| `mime_type` | string | MIME type filter with wildcard support (`image/*`, `application/pdf`) |
|
|
581
|
-
| `filename` | string | Case-insensitive substring match on original filename |
|
|
582
|
-
| `recency` | enum | Time-based filter: `last_hour`, `last_24_hours`, `last_7_days`, `last_30_days`, `last_90_days` |
|
|
583
|
-
| `conversation_id` | string | Scope results to attachments in a specific conversation |
|
|
584
|
-
| `limit` | number | Maximum results (default 20, max 100) |
|
|
583
|
+
Attachments are materialized into `conversations/<conversation>/attachments/` as soon as they are linked to a message. During disk-view sync, the JSONL record reuses those filenames directly and only falls back to materializing legacy rows that have not been projected yet. Filename collisions are still resolved by appending a numeric suffix (e.g., `photo-2.png`, `photo-3.png`).
|
|
585
584
|
|
|
586
|
-
###
|
|
585
|
+
### Backfill Migration
|
|
587
586
|
|
|
588
|
-
-
|
|
589
|
-
- **Size limit**: 100 MB ceiling prevents materializing excessively large attachments
|
|
590
|
-
- **Double visibility check**: Both `asset_search` and `asset_materialize` independently verify visibility, preventing TOCTOU races between search and use
|
|
591
|
-
- **Risk level**: Both tools are `RiskLevel.Low` since they read existing data and write only within the sandbox
|
|
587
|
+
Existing conversations created before the disk view was introduced are backfilled by workspace migration `009-backfill-conversation-disk-view`, which replays all conversations and their messages through the disk-view sync functions.
|
|
592
588
|
|
|
593
589
|
### Key Source Files
|
|
594
590
|
|
|
595
|
-
| File
|
|
596
|
-
|
|
|
597
|
-
| `assistant/src/
|
|
598
|
-
| `assistant/src/
|
|
599
|
-
| `assistant/src/daemon/
|
|
600
|
-
| `assistant/src/
|
|
601
|
-
| `assistant/src/memory/conversation-crud.ts` | `getConversationType()` — conversation type lookup for visibility context |
|
|
591
|
+
| File | Role |
|
|
592
|
+
| --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
593
|
+
| `assistant/src/memory/conversation-disk-view.ts` | Disk view module — init, update, sync, remove, content flattening |
|
|
594
|
+
| `assistant/src/memory/conversation-crud.ts` | DB CRUD layer — calls init, update, and remove disk-view functions (not message sync) |
|
|
595
|
+
| `assistant/src/daemon/conversation-messaging.ts` | Daemon messaging pipeline — calls `syncMessageToDisk` after message insertion |
|
|
596
|
+
| `assistant/src/workspace/migrations/009-backfill-conversation-disk-view.ts` | Backfill migration for pre-existing conversations |
|
|
602
597
|
|
|
603
598
|
---
|
|
@@ -46,7 +46,7 @@ CES exposes exactly three tools to the assistant, registered as a **deliberate e
|
|
|
46
46
|
|
|
47
47
|
### Tool registration
|
|
48
48
|
|
|
49
|
-
CES tools use the standard `class ... implements Tool` registration pattern.
|
|
49
|
+
CES tools use the standard `class ... implements Tool` registration pattern. These are justified exceptions to the general preference for skills because:
|
|
50
50
|
|
|
51
51
|
- The security boundary requires that credential materialization happens in a separate process
|
|
52
52
|
- Skill scripts run inside the assistant process and cannot enforce the hard isolation invariant
|
|
@@ -223,7 +223,7 @@ These invariants are enforced by guard tests and code review:
|
|
|
223
223
|
|
|
224
224
|
1. **No cross-package source imports**: `assistant/` must not import from `credential-executor/` and vice versa. Communication is RPC only. Shared types flow through `packages/` only.
|
|
225
225
|
2. **No credential values in assistant process memory**: The assistant sends credential handles (not values) to CES. CES materializes and uses them internally.
|
|
226
|
-
3. **CES tools
|
|
226
|
+
3. **CES tools justify tool registrations over skills** for credential-bearing execution because of the hard process-boundary isolation requirement. All other credential use continues through the existing broker for local deployments.
|
|
227
227
|
4. **Grants and audit logs are CES-internal**: The assistant cannot read CES grant tables or audit logs directly. CES exposes grant status and audit summaries via RPC responses.
|
|
228
228
|
5. **No generic authenticated HTTP clients in secure commands**: `curl`, `wget`, `httpie`, interpreters, and shell trampolines are structurally denied as secure command entrypoints. This is checked at manifest validation and re-checked at execution time.
|
|
229
229
|
6. **Managed CES container runs as non-root**: The CES Docker image runs as `uid 1001` (user `ces`). The CES data volume is owned by this user.
|
|
@@ -400,5 +400,5 @@ The following capabilities are intentionally deferred beyond v1:
|
|
|
400
400
|
|
|
401
401
|
- [Security architecture](architecture/security.md) — existing credential broker and permission model
|
|
402
402
|
- [AGENTS.md](../../AGENTS.md) — tooling direction and CES exception
|
|
403
|
-
- [Tools AGENTS.md](../src/tools/AGENTS.md) —
|
|
403
|
+
- [Tools AGENTS.md](../src/tools/AGENTS.md) — tooling direction and CES exception
|
|
404
404
|
- [Network traffic matrix](../../../vellum-assistant-platform/docs/network-traffic-matrix.md) — managed pod network policies
|
package/package.json
CHANGED
|
@@ -1629,4 +1629,115 @@ describe("AgentLoop", () => {
|
|
|
1629
1629
|
);
|
|
1630
1630
|
expect(textBlock!.text).toBe("Normal response with no placeholders.");
|
|
1631
1631
|
});
|
|
1632
|
+
|
|
1633
|
+
// Tool error retry nudge — when a tool returns isError: true, the loop
|
|
1634
|
+
// should inject a system_notice nudging the LLM to retry instead of ending.
|
|
1635
|
+
test("injects retry nudge system_notice when tool returns an error", async () => {
|
|
1636
|
+
const { provider, calls } = createMockProvider([
|
|
1637
|
+
// First turn: LLM calls a tool that errors
|
|
1638
|
+
toolUseResponse("t1", "read_file", { path: "/missing.txt" }),
|
|
1639
|
+
// Second turn: LLM retries after seeing the error + nudge
|
|
1640
|
+
toolUseResponse("t2", "read_file", { path: "/existing.txt" }),
|
|
1641
|
+
// Third turn: LLM responds with success
|
|
1642
|
+
textResponse("Got the file."),
|
|
1643
|
+
]);
|
|
1644
|
+
|
|
1645
|
+
let callCount = 0;
|
|
1646
|
+
const toolExecutor = async (
|
|
1647
|
+
_name: string,
|
|
1648
|
+
_input: Record<string, unknown>,
|
|
1649
|
+
) => {
|
|
1650
|
+
callCount++;
|
|
1651
|
+
if (callCount === 1) {
|
|
1652
|
+
return {
|
|
1653
|
+
content:
|
|
1654
|
+
'{"error":"name is required and must be a non-empty string"}',
|
|
1655
|
+
isError: true,
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
return { content: "file contents", isError: false };
|
|
1659
|
+
};
|
|
1660
|
+
|
|
1661
|
+
const loop = new AgentLoop(
|
|
1662
|
+
provider,
|
|
1663
|
+
"system",
|
|
1664
|
+
{},
|
|
1665
|
+
dummyTools,
|
|
1666
|
+
toolExecutor,
|
|
1667
|
+
);
|
|
1668
|
+
await loop.run([userMessage], () => {});
|
|
1669
|
+
|
|
1670
|
+
// Provider should have been called 3 times (error -> retry -> final text)
|
|
1671
|
+
expect(calls).toHaveLength(3);
|
|
1672
|
+
|
|
1673
|
+
// The second call's messages should contain the retry nudge system_notice
|
|
1674
|
+
const secondCallMessages = calls[1].messages;
|
|
1675
|
+
const toolResultMessage = secondCallMessages[secondCallMessages.length - 1];
|
|
1676
|
+
expect(toolResultMessage.role).toBe("user");
|
|
1677
|
+
|
|
1678
|
+
const retryNudge = toolResultMessage.content.find(
|
|
1679
|
+
(b): b is Extract<ContentBlock, { type: "text" }> =>
|
|
1680
|
+
b.type === "text" && b.text.includes("looks recoverable"),
|
|
1681
|
+
);
|
|
1682
|
+
expect(retryNudge).toBeDefined();
|
|
1683
|
+
|
|
1684
|
+
// The third call should NOT have the retry nudge (successful tool result)
|
|
1685
|
+
const thirdCallMessages = calls[2].messages;
|
|
1686
|
+
const thirdToolResultMessage =
|
|
1687
|
+
thirdCallMessages[thirdCallMessages.length - 1];
|
|
1688
|
+
const noRetryNudge = thirdToolResultMessage.content.find(
|
|
1689
|
+
(b): b is Extract<ContentBlock, { type: "text" }> =>
|
|
1690
|
+
b.type === "text" && b.text.includes("looks recoverable"),
|
|
1691
|
+
);
|
|
1692
|
+
expect(noRetryNudge).toBeUndefined();
|
|
1693
|
+
});
|
|
1694
|
+
|
|
1695
|
+
// Retry nudge stops after MAX_CONSECUTIVE_ERROR_NUDGES (3) consecutive errors
|
|
1696
|
+
test("stops injecting retry nudge after 3 consecutive error turns", async () => {
|
|
1697
|
+
const { provider, calls } = createMockProvider([
|
|
1698
|
+
// 4 consecutive error turns, then final text
|
|
1699
|
+
toolUseResponse("t1", "read_file", { path: "/a" }),
|
|
1700
|
+
toolUseResponse("t2", "read_file", { path: "/b" }),
|
|
1701
|
+
toolUseResponse("t3", "read_file", { path: "/c" }),
|
|
1702
|
+
toolUseResponse("t4", "read_file", { path: "/d" }),
|
|
1703
|
+
textResponse("Giving up."),
|
|
1704
|
+
]);
|
|
1705
|
+
|
|
1706
|
+
const toolExecutor = async (
|
|
1707
|
+
_name: string,
|
|
1708
|
+
_input: Record<string, unknown>,
|
|
1709
|
+
) => {
|
|
1710
|
+
return { content: "service unavailable", isError: true };
|
|
1711
|
+
};
|
|
1712
|
+
|
|
1713
|
+
const loop = new AgentLoop(
|
|
1714
|
+
provider,
|
|
1715
|
+
"system",
|
|
1716
|
+
{},
|
|
1717
|
+
dummyTools,
|
|
1718
|
+
toolExecutor,
|
|
1719
|
+
);
|
|
1720
|
+
await loop.run([userMessage], () => {});
|
|
1721
|
+
|
|
1722
|
+
expect(calls).toHaveLength(5);
|
|
1723
|
+
|
|
1724
|
+
// Helper to check if a call's last user message has the retry nudge
|
|
1725
|
+
const hasRetryNudge = (callIndex: number): boolean => {
|
|
1726
|
+
const msgs = calls[callIndex].messages;
|
|
1727
|
+
const lastMsg = msgs[msgs.length - 1];
|
|
1728
|
+
return lastMsg.content.some(
|
|
1729
|
+
(b) =>
|
|
1730
|
+
b.type === "text" &&
|
|
1731
|
+
"text" in b &&
|
|
1732
|
+
(b as { text: string }).text.includes("looks recoverable"),
|
|
1733
|
+
);
|
|
1734
|
+
};
|
|
1735
|
+
|
|
1736
|
+
// Turns 1-3 should have the nudge
|
|
1737
|
+
expect(hasRetryNudge(1)).toBe(true);
|
|
1738
|
+
expect(hasRetryNudge(2)).toBe(true);
|
|
1739
|
+
expect(hasRetryNudge(3)).toBe(true);
|
|
1740
|
+
// Turn 4 should NOT have the nudge (exceeded limit)
|
|
1741
|
+
expect(hasRetryNudge(4)).toBe(false);
|
|
1742
|
+
});
|
|
1632
1743
|
});
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* Guard test: always-loaded tool count
|
|
3
3
|
*
|
|
4
4
|
* This test asserts the exact set of tools that are active when no client is
|
|
5
|
-
* connected, no host proxy is available, no
|
|
6
|
-
*
|
|
5
|
+
* connected, no host proxy is available, and no special channel capabilities
|
|
6
|
+
* exist. This represents the minimal "always-loaded"
|
|
7
7
|
* baseline that is sent to the LLM on every turn.
|
|
8
8
|
*
|
|
9
9
|
* Adding a tool to this set increases token cost for every request. If this test
|
|
@@ -32,14 +32,13 @@ describe("always-loaded tool count", () => {
|
|
|
32
32
|
await initializeTools();
|
|
33
33
|
const allDefs = buildToolDefinitions();
|
|
34
34
|
|
|
35
|
-
// Minimal context: no client, no
|
|
35
|
+
// Minimal context: no client, no capabilities
|
|
36
36
|
const minimalContext: SkillProjectionContext = {
|
|
37
37
|
skillProjectionState: new Map(),
|
|
38
38
|
skillProjectionCache: {},
|
|
39
39
|
coreToolNames: new Set(),
|
|
40
40
|
toolsDisabledDepth: 0,
|
|
41
41
|
hasNoClient: true,
|
|
42
|
-
hasAttachments: false,
|
|
43
42
|
channelCapabilities: undefined,
|
|
44
43
|
};
|
|
45
44
|
|