@vellumai/assistant 0.5.1 → 0.5.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +163 -54
- package/docs/architecture/integrations.md +62 -67
- package/docs/credential-execution-service.md +3 -3
- package/docs/skills.md +100 -0
- package/package.json +1 -1
- package/src/__tests__/agent-loop.test.ts +111 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +3 -4
- package/src/__tests__/app-builder-tool-scripts.test.ts +13 -151
- package/src/__tests__/app-dir-path-guard.test.ts +78 -0
- package/src/__tests__/app-executors.test.ts +1 -291
- package/src/__tests__/app-git-history.test.ts +4 -4
- package/src/__tests__/app-routes-csp.test.ts +1 -0
- package/src/__tests__/app-store-dir-names.test.ts +426 -0
- package/src/__tests__/attachments-store.test.ts +169 -21
- package/src/__tests__/attachments.test.ts +115 -1
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/canonical-guardian-store.test.ts +38 -0
- package/src/__tests__/channel-reply-delivery.test.ts +55 -0
- package/src/__tests__/checker.test.ts +54 -0
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -0
- package/src/__tests__/claude-code-tool-profiles.test.ts +2 -0
- package/src/__tests__/compaction.benchmark.test.ts +2 -1
- package/src/__tests__/config-schema-cmd.test.ts +68 -21
- package/src/__tests__/config-schema.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +156 -5
- package/src/__tests__/conversation-agent-loop.test.ts +297 -2
- package/src/__tests__/conversation-attachments.test.ts +17 -19
- package/src/__tests__/conversation-disk-view-integration.test.ts +277 -0
- package/src/__tests__/conversation-disk-view.test.ts +810 -0
- package/src/__tests__/conversation-error.test.ts +1 -1
- package/src/__tests__/conversation-fork-crud.test.ts +551 -0
- package/src/__tests__/conversation-fork-route.test.ts +386 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +130 -0
- package/src/__tests__/conversation-media-retry.test.ts +8 -2
- package/src/__tests__/conversation-memory-dirty-tail.test.ts +150 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +7 -0
- package/src/__tests__/conversation-queue.test.ts +36 -1
- package/src/__tests__/conversation-routes-disk-view.test.ts +439 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +2 -2
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -7
- package/src/__tests__/conversation-runtime-assembly.test.ts +17 -2
- package/src/__tests__/conversation-skill-tools.test.ts +4 -9
- package/src/__tests__/conversation-slash-commands.test.ts +149 -0
- package/src/__tests__/conversation-store.test.ts +24 -21
- package/src/__tests__/conversation-surfaces-state-update.test.ts +246 -0
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +1 -0
- package/src/__tests__/conversation-title-service.test.ts +137 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +25 -315
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +1 -0
- package/src/__tests__/conversation-wipe.test.ts +226 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +44 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +11 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-vault-unit.test.ts +5 -10
- package/src/__tests__/cu-unified-flow.test.ts +1 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +241 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +214 -0
- package/src/__tests__/db-memory-archive-migration.test.ts +372 -0
- package/src/__tests__/db-memory-brief-state-migration.test.ts +213 -0
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +273 -0
- package/src/__tests__/diagnostics-export.test.ts +70 -1
- package/src/__tests__/first-greeting.test.ts +80 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +3 -7
- package/src/__tests__/history-repair.test.ts +32 -10
- package/src/__tests__/http-conversation-lineage.test.ts +251 -0
- package/src/__tests__/image-source-path-reinject.test.ts +136 -0
- package/src/__tests__/inline-command-runner.test.ts +311 -0
- package/src/__tests__/inline-skill-authoring-guard.test.ts +220 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +435 -0
- package/src/__tests__/list-messages-attachments.test.ts +96 -0
- package/src/__tests__/llm-context-normalization.test.ts +1116 -0
- package/src/__tests__/llm-context-route-provider.test.ts +217 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +270 -0
- package/src/__tests__/media-generate-image.test.ts +47 -94
- package/src/__tests__/memory-brief-open-loops.test.ts +530 -0
- package/src/__tests__/memory-brief-time.test.ts +285 -0
- package/src/__tests__/memory-brief-wrapper.test.ts +311 -0
- package/src/__tests__/memory-chunk-archive.test.ts +400 -0
- package/src/__tests__/memory-chunk-dual-write.test.ts +453 -0
- package/src/__tests__/memory-episode-archive.test.ts +370 -0
- package/src/__tests__/memory-episode-dual-write.test.ts +626 -0
- package/src/__tests__/memory-lifecycle-e2e.test.ts +3 -1
- package/src/__tests__/memory-observation-archive.test.ts +375 -0
- package/src/__tests__/memory-observation-dual-write.test.ts +318 -0
- package/src/__tests__/memory-recall-quality.test.ts +7 -7
- package/src/__tests__/memory-reducer-store.test.ts +728 -0
- package/src/__tests__/memory-reducer-types.test.ts +699 -0
- package/src/__tests__/memory-reducer.test.ts +698 -0
- package/src/__tests__/memory-regressions.test.ts +6 -4
- package/src/__tests__/memory-simplified-config.test.ts +281 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +4 -1
- package/src/__tests__/migration-export-http.test.ts +3 -1
- package/src/__tests__/migration-import-commit-http.test.ts +18 -4
- package/src/__tests__/migration-import-preflight-http.test.ts +1 -3
- package/src/__tests__/mime-builder.test.ts +3 -2
- package/src/__tests__/non-member-access-request.test.ts +12 -1
- package/src/__tests__/notification-decision-identity.test.ts +52 -0
- package/src/__tests__/oauth-apps-routes.test.ts +103 -0
- package/src/__tests__/oauth-store.test.ts +115 -0
- package/src/__tests__/parse-identity-fields.test.ts +129 -0
- package/src/__tests__/provider-error-scenarios.test.ts +1 -3
- package/src/__tests__/provider-failover-actual-provider.test.ts +66 -0
- package/src/__tests__/recording-handler.test.ts +17 -0
- package/src/__tests__/registry.test.ts +3 -8
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +7 -3
- package/src/__tests__/schema-transforms.test.ts +165 -5
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/skill-load-inline-command.test.ts +598 -0
- package/src/__tests__/skill-load-inline-includes.test.ts +644 -0
- package/src/__tests__/skills-inline-command-expansions.test.ts +301 -0
- package/src/__tests__/skills-transitive-hash.test.ts +333 -0
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -2
- package/src/__tests__/starter-task-flow.test.ts +1 -0
- package/src/__tests__/suggestion-routes.test.ts +443 -0
- package/src/__tests__/swarm-conversation-integration.test.ts +1 -0
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -5
- package/src/__tests__/top-level-renderer.test.ts +22 -0
- package/src/__tests__/turn-boundary-resolution.test.ts +243 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +320 -0
- package/src/__tests__/web-fetch.test.ts +6 -2
- package/src/__tests__/workspace-migration-006-services-config.test.ts +335 -0
- package/src/__tests__/workspace-migration-007-web-search-provider-rename.test.ts +312 -0
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +278 -0
- package/src/__tests__/workspace-migration-010-app-dir-rename.test.ts +275 -0
- package/src/__tests__/workspace-migration-012-rename-conversation-disk-view-dirs.test.ts +77 -0
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +401 -0
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +328 -0
- package/src/__tests__/workspace-migration-seed-device-id.test.ts +6 -10
- package/src/agent/attachments.ts +27 -1
- package/src/agent/loop.ts +29 -1
- package/src/avatar/traits-png-sync.ts +80 -25
- package/src/bundler/app-bundler.ts +4 -4
- package/src/calls/call-domain.ts +1 -0
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/commands/auth.ts +92 -0
- package/src/cli/commands/avatar.ts +7 -6
- package/src/cli/commands/config.ts +2 -0
- package/src/cli/commands/oauth/providers.ts +29 -0
- package/src/cli/program.ts +12 -0
- package/src/cli.ts +15 -48
- package/src/config/bundled-skills/app-builder/SKILL.md +103 -28
- package/src/config/bundled-skills/app-builder/TOOLS.json +5 -199
- package/src/config/bundled-skills/app-builder/tools/{app-query.ts → app-refresh.ts} +2 -2
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +6 -9
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +4 -6
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +2 -3
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +2 -3
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -2
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +45 -72
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -3
- package/src/config/bundled-skills/skill-management/SKILL.md +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +2 -2
- package/src/config/bundled-skills/slack/tools/shared.ts +19 -4
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +2 -3
- package/src/config/bundled-skills/transcribe/SKILL.md +1 -1
- package/src/config/bundled-skills/transcribe/TOOLS.json +2 -6
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +19 -83
- package/src/config/bundled-tool-registry.ts +2 -14
- package/src/config/feature-flag-registry.json +24 -0
- package/src/config/loader.ts +65 -0
- package/src/config/raw-config-utils.ts +58 -0
- package/src/config/schema-utils.ts +28 -7
- package/src/config/schema.ts +20 -0
- package/src/config/schemas/elevenlabs.ts +18 -0
- package/src/config/schemas/memory-lifecycle.ts +4 -2
- package/src/config/schemas/memory-simplified.ts +101 -0
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +8 -6
- package/src/config/skills.ts +50 -4
- package/src/contacts/contact-store.ts +13 -6
- package/src/contacts/contacts-write.ts +0 -1
- package/src/context/window-manager.ts +13 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +54 -8
- package/src/daemon/conversation-agent-loop.ts +127 -20
- package/src/daemon/conversation-attachments.ts +18 -36
- package/src/daemon/conversation-error.ts +2 -1
- package/src/daemon/conversation-history.ts +18 -4
- package/src/daemon/conversation-lifecycle.ts +50 -16
- package/src/daemon/conversation-messaging.ts +70 -26
- package/src/daemon/conversation-process.ts +58 -34
- package/src/daemon/conversation-runtime-assembly.ts +22 -38
- package/src/daemon/conversation-slash.ts +121 -256
- package/src/daemon/conversation-surfaces.ts +170 -24
- package/src/daemon/conversation-tool-setup.ts +0 -6
- package/src/daemon/conversation-workspace.ts +21 -1
- package/src/daemon/conversation.ts +69 -30
- package/src/daemon/first-greeting.ts +35 -0
- package/src/daemon/handlers/config-embeddings.ts +156 -0
- package/src/daemon/handlers/config-model.ts +62 -26
- package/src/daemon/handlers/conversations.ts +0 -23
- package/src/daemon/handlers/identity.ts +12 -1
- package/src/daemon/handlers/recording.ts +26 -21
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/lifecycle.ts +115 -65
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +18 -0
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/shared.ts +2 -0
- package/src/daemon/message-types/surfaces.ts +2 -0
- package/src/daemon/message-types/upgrades.ts +23 -0
- package/src/daemon/server.ts +83 -12
- package/src/daemon/shutdown-handlers.ts +8 -5
- package/src/daemon/startup-error.ts +9 -0
- package/src/daemon/tool-side-effects.ts +11 -28
- package/src/events/tool-permission-telemetry-listener.ts +1 -3
- package/src/followups/followup-store.ts +47 -1
- package/src/instrument.ts +0 -4
- package/src/media/app-icon-generator.ts +2 -2
- package/src/memory/app-git-service.ts +28 -16
- package/src/memory/app-store.ts +230 -41
- package/src/memory/archive-store.ts +400 -0
- package/src/memory/attachments-store.ts +558 -130
- package/src/memory/brief-formatting.ts +33 -0
- package/src/memory/brief-open-loops.ts +266 -0
- package/src/memory/brief-time.ts +161 -0
- package/src/memory/brief.ts +75 -0
- package/src/memory/conversation-attention-store.ts +70 -0
- package/src/memory/conversation-crud.ts +591 -8
- package/src/memory/conversation-directories.ts +125 -0
- package/src/memory/conversation-disk-view.ts +390 -0
- package/src/memory/conversation-key-store.ts +17 -5
- package/src/memory/conversation-queries.ts +5 -1
- package/src/memory/conversation-title-service.ts +21 -49
- package/src/memory/db-init.ts +40 -0
- package/src/memory/embedding-backend.ts +42 -53
- package/src/memory/embedding-gemini.test.ts +4 -4
- package/src/memory/embedding-local.ts +1 -3
- package/src/memory/embedding-ollama.ts +1 -3
- package/src/memory/embedding-openai.ts +1 -3
- package/src/memory/indexer.ts +114 -21
- package/src/memory/items-extractor.ts +42 -13
- package/src/memory/job-handlers/conversation-starters.ts +6 -1
- package/src/memory/job-handlers/embedding.test.ts +2 -4
- package/src/memory/job-handlers/embedding.ts +83 -0
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +6 -0
- package/src/memory/jobs-worker.ts +12 -0
- package/src/memory/llm-request-log-store.ts +100 -1
- package/src/memory/migrations/102-alter-table-columns.ts +5 -0
- package/src/memory/migrations/146-schedule-oneshot-routing.ts +3 -3
- package/src/memory/migrations/147-migrate-reminders-to-schedules.ts +66 -70
- package/src/memory/migrations/148-drop-reminders-table.ts +5 -9
- package/src/memory/migrations/160-drop-loopback-port-column.ts +1 -3
- package/src/memory/migrations/174-rename-thread-starters-table.ts +0 -7
- package/src/memory/migrations/178-oauth-providers-managed-service-config-key.ts +15 -0
- package/src/memory/migrations/179-llm-request-log-message-id.ts +16 -0
- package/src/memory/migrations/180-backfill-inline-attachments-to-disk.ts +66 -0
- package/src/memory/migrations/181-rename-thread-starters-checkpoints.ts +46 -0
- package/src/memory/migrations/182-oauth-providers-display-metadata.ts +20 -0
- package/src/memory/migrations/183-add-conversation-fork-lineage.ts +22 -0
- package/src/memory/migrations/184-llm-request-log-provider.ts +12 -0
- package/src/memory/migrations/185-memory-brief-state.ts +52 -0
- package/src/memory/migrations/186-memory-archive.ts +109 -0
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +19 -0
- package/src/memory/migrations/index.ts +10 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/qdrant-client.ts +23 -4
- package/src/memory/reducer-store.ts +271 -0
- package/src/memory/reducer-types.ts +99 -0
- package/src/memory/reducer.ts +453 -0
- package/src/memory/retriever.test.ts +601 -2
- package/src/memory/retriever.ts +85 -9
- package/src/memory/schema/conversations.ts +9 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/infrastructure.ts +13 -7
- package/src/memory/schema/memory-archive.ts +121 -0
- package/src/memory/schema/memory-brief.ts +55 -0
- package/src/memory/schema/oauth.ts +6 -0
- package/src/memory/search/semantic.ts +17 -4
- package/src/messaging/providers/gmail/mime-builder.ts +3 -1
- package/src/notifications/copy-composer.ts +26 -0
- package/src/notifications/decision-engine.ts +14 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +36 -0
- package/src/oauth/byo-connection.test.ts +1 -45
- package/src/oauth/byo-connection.ts +2 -8
- package/src/oauth/connect-orchestrator.ts +15 -11
- package/src/oauth/connection-resolver.test.ts +191 -0
- package/src/oauth/connection-resolver.ts +66 -38
- package/src/oauth/connection.ts +0 -1
- package/src/oauth/oauth-store.ts +99 -47
- package/src/oauth/platform-connection.test.ts +0 -1
- package/src/oauth/platform-connection.ts +11 -3
- package/src/oauth/seed-providers.ts +78 -3
- package/src/oauth/token-persistence.ts +16 -10
- package/src/permissions/checker.ts +160 -14
- package/src/permissions/defaults.ts +14 -0
- package/src/prompts/templates/BOOTSTRAP.md +2 -0
- package/src/providers/anthropic/client.ts +8 -1
- package/src/providers/failover.ts +4 -1
- package/src/providers/gemini/client.ts +50 -0
- package/src/providers/model-catalog.ts +92 -0
- package/src/providers/model-intents.ts +29 -20
- package/src/providers/openai/client.ts +49 -0
- package/src/providers/types.ts +2 -0
- package/src/runtime/access-request-helper.ts +16 -7
- package/src/runtime/auth/credential-service.ts +3 -1
- package/src/runtime/auth/route-policy.ts +14 -1
- package/src/runtime/btw-sidechain.ts +101 -0
- package/src/runtime/channel-reply-delivery.ts +17 -1
- package/src/runtime/http-router.ts +3 -1
- package/src/runtime/http-server.ts +196 -141
- package/src/runtime/http-types.ts +1 -0
- package/src/runtime/migrations/vbundle-builder.ts +5 -1
- package/src/runtime/routes/access-request-decision.ts +41 -0
- package/src/runtime/routes/app-management-routes.ts +6 -3
- package/src/runtime/routes/app-routes.ts +7 -3
- package/src/runtime/routes/approval-routes.ts +1 -0
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +34 -2
- package/src/runtime/routes/attachment-routes.ts +45 -15
- package/src/runtime/routes/btw-routes.ts +21 -61
- package/src/runtime/routes/conversation-management-routes.ts +74 -0
- package/src/runtime/routes/conversation-query-routes.ts +187 -10
- package/src/runtime/routes/conversation-routes.ts +269 -28
- package/src/runtime/routes/conversation-starter-routes.ts +9 -11
- package/src/runtime/routes/diagnostics-routes.ts +1 -0
- package/src/runtime/routes/identity-routes.ts +2 -35
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -2
- package/src/runtime/routes/llm-context-normalization.ts +1212 -0
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/memory-item-routes.test.ts +34 -0
- package/src/runtime/routes/memory-item-routes.ts +94 -5
- package/src/runtime/routes/migration-routes.ts +4 -1
- package/src/runtime/routes/oauth-apps.ts +291 -0
- package/src/runtime/routes/secret-routes.ts +30 -1
- package/src/runtime/routes/settings-routes.ts +14 -0
- package/src/runtime/routes/surface-action-routes.ts +68 -1
- package/src/runtime/routes/trace-event-routes.ts +4 -1
- package/src/schedule/schedule-store.ts +30 -21
- package/src/security/secure-keys.ts +21 -0
- package/src/signals/bash.ts +1 -1
- package/src/skills/inline-command-expansions.ts +204 -0
- package/src/skills/inline-command-render.ts +127 -0
- package/src/skills/inline-command-runner.ts +242 -0
- package/src/skills/transitive-version-hash.ts +88 -0
- package/src/swarm/backend-claude-code.ts +3 -6
- package/src/tasks/task-store.ts +43 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -2
- package/src/telemetry/usage-telemetry-reporter.ts +3 -1
- package/src/tools/AGENTS.md +6 -10
- package/src/tools/apps/executors.ts +17 -232
- package/src/tools/claude-code/claude-code.ts +2 -3
- package/src/tools/credentials/vault.ts +7 -12
- package/src/tools/host-filesystem/read.ts +13 -10
- package/src/tools/network/__tests__/web-search.test.ts +4 -2
- package/src/tools/permission-checker.ts +8 -1
- package/src/tools/schedule/list.ts +2 -7
- package/src/tools/schema-transforms.ts +5 -0
- package/src/tools/shared/filesystem/format-diff.ts +2 -7
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +140 -6
- package/src/tools/tool-manifest.ts +0 -6
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/device-id.ts +28 -5
- package/src/util/platform.ts +24 -0
- package/src/util/pricing.ts +1 -0
- package/src/util/retry.ts +1 -3
- package/src/workspace/migrations/003-seed-device-id.ts +3 -4
- package/src/workspace/migrations/006-services-config.ts +5 -0
- package/src/workspace/migrations/008-voice-timeout-and-max-steps.ts +12 -0
- package/src/workspace/migrations/009-backfill-conversation-disk-view.ts +10 -0
- package/src/workspace/migrations/010-app-dir-rename.ts +223 -0
- package/src/workspace/migrations/{002-backfill-installation-id.ts → 011-backfill-installation-id.ts} +24 -13
- package/src/workspace/migrations/012-rename-conversation-disk-view-dirs.ts +64 -0
- package/src/workspace/migrations/013-repair-conversation-disk-view.ts +11 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +186 -0
- package/src/workspace/migrations/registry.ts +11 -1
- package/src/workspace/top-level-renderer.ts +12 -0
- package/src/__tests__/asset-materialize-tool.test.ts +0 -523
- package/src/__tests__/asset-search-tool.test.ts +0 -536
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +0 -56
- package/src/__tests__/media-reuse-story.e2e.test.ts +0 -762
- package/src/__tests__/media-visibility-policy.test.ts +0 -190
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +0 -21
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +0 -14
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +0 -13
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +0 -23
- package/src/daemon/media-visibility-policy.ts +0 -59
- package/src/tools/assets/materialize.ts +0 -248
- package/src/tools/assets/search.ts +0 -400
package/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
|
|
|
@@ -1261,6 +1261,115 @@ graph TB
|
|
|
1261
1261
|
TRUST -->|"Deny rule matches"| DENY["Blocked"]
|
|
1262
1262
|
```
|
|
1263
1263
|
|
|
1264
|
+
### Inline Skill Command Expansion
|
|
1265
|
+
|
|
1266
|
+
Skills can embed dynamic shell output in their SKILL.md body using `!`command``tokens. When`skill_load` processes a skill containing these tokens, the commands are executed at load time through a sandboxed runner and their output is substituted inline. This enables externally authored skills to include project-specific context (e.g., directory listings, config values) without requiring manual edits.
|
|
1267
|
+
|
|
1268
|
+
**Feature flag:** `feature_flags.inline-skill-commands.enabled` (default: enabled). When disabled, loading a skill that contains `!`command`` tokens fails closed with an error rather than leaving raw tokens in the prompt.
|
|
1269
|
+
|
|
1270
|
+
#### Syntax and Parsing
|
|
1271
|
+
|
|
1272
|
+
The `!`command``syntax is parsed by`parseInlineCommandExpansions()` from the SKILL.md body after frontmatter extraction. The parser:
|
|
1273
|
+
|
|
1274
|
+
- Extracts all `!`command`` tokens outside fenced code blocks (documentation examples in fenced blocks are ignored)
|
|
1275
|
+
- Assigns each token a stable `placeholderId` (0-indexed encounter order)
|
|
1276
|
+
- Rejects malformed tokens fail-closed: empty commands, nested backticks, and unmatched opening backticks produce `InlineCommandExpansionError` entries rather than best-effort expansions
|
|
1277
|
+
|
|
1278
|
+
#### Transitive Version Hash
|
|
1279
|
+
|
|
1280
|
+
When a skill contains inline command expansions, the permission system computes a **transitive version hash** (`tv1:<sha256>`) that covers the root skill and all its included children (DFS pre-order). The hash folds:
|
|
1281
|
+
|
|
1282
|
+
1. Each visited skill ID (graph structure)
|
|
1283
|
+
2. Each visited skill's directory content hash (file changes)
|
|
1284
|
+
|
|
1285
|
+
Editing any file in the root skill or any included child invalidates the transitive hash, which forces re-approval. The hash is computed by `computeTransitiveSkillVersionHash()` and fails closed (`TransitiveHashError`) on missing children or cycles in the include graph.
|
|
1286
|
+
|
|
1287
|
+
#### Permission Gating (`skill_load_dynamic:*`)
|
|
1288
|
+
|
|
1289
|
+
Skills containing inline command expansions use a separate permission candidate namespace (`skill_load_dynamic:*`) instead of the normal `skill_load:*` namespace. This prevents them from falling through to the permissive default `skill_load:*` allow rule. The permission checker emits candidates in specificity order:
|
|
1290
|
+
|
|
1291
|
+
1. `skill_load_dynamic:<skill-id>@<transitive-hash>` — version-pinned approval (most specific)
|
|
1292
|
+
2. `skill_load_dynamic:<skill-id>` — any-version approval
|
|
1293
|
+
|
|
1294
|
+
A default ask rule at priority 200 (`default:ask-skill_load_dynamic-global`) catches these candidates, ensuring the guardian is always prompted before inline commands execute. The user can create a pinned trust rule for a specific transitive hash to auto-approve known-good versions. Non-interactive sessions (no human present) deny dynamic skill loads rather than silently auto-approving.
|
|
1295
|
+
|
|
1296
|
+
```mermaid
|
|
1297
|
+
graph TB
|
|
1298
|
+
LOAD["skill_load(selector)"] --> PARSE["Parse SKILL.md body"]
|
|
1299
|
+
PARSE --> CHECK{"Has !\x60command\x60<br/>tokens?"}
|
|
1300
|
+
CHECK -->|"No"| NORMAL["Normal skill_load:* candidate<br/>(auto-allowed)"]
|
|
1301
|
+
CHECK -->|"Yes"| FLAG{"inline-skill-commands<br/>flag enabled?"}
|
|
1302
|
+
FLAG -->|"No"| FAIL_FLAG["Fail closed:<br/>error returned"]
|
|
1303
|
+
FLAG -->|"Yes"| SOURCE{"Eligible source?<br/>(bundled/managed/workspace)"}
|
|
1304
|
+
SOURCE -->|"No (extra)"| FAIL_SOURCE["Fail closed:<br/>source not eligible"]
|
|
1305
|
+
SOURCE -->|"Yes"| HASH["Compute transitive hash"]
|
|
1306
|
+
HASH --> DYN["skill_load_dynamic:id@hash<br/>candidate emitted"]
|
|
1307
|
+
DYN --> PERM["PermissionChecker"]
|
|
1308
|
+
PERM --> RULE{"Trust rule?"}
|
|
1309
|
+
RULE -->|"Pinned allow"| RENDER["Execute + render"]
|
|
1310
|
+
RULE -->|"No rule"| PROMPT["Prompt guardian"]
|
|
1311
|
+
RULE -->|"Deny"| DENY["Blocked"]
|
|
1312
|
+
```
|
|
1313
|
+
|
|
1314
|
+
#### Sandbox-Only Execution
|
|
1315
|
+
|
|
1316
|
+
Inline commands are executed through `runInlineCommand()`, a purpose-built sandbox runner with strict security constraints:
|
|
1317
|
+
|
|
1318
|
+
- **Sandbox enforced**: The sandbox is always enabled with `networkMode: "off"` — no outbound network connections
|
|
1319
|
+
- **Sanitized environment**: Uses `buildSanitizedEnv()` — no API keys, tokens, credentials, gateway URLs, or workspace paths in the environment
|
|
1320
|
+
- **No host fallback**: Unlike the general `bash` tool, there is no fallback to host execution when the sandbox is unavailable
|
|
1321
|
+
- **No credential proxy**: No CES client, no credential materialization
|
|
1322
|
+
- **Timeout**: 10-second wall-clock limit (killed with SIGKILL on timeout)
|
|
1323
|
+
- **Output cap**: 20,000 characters maximum (truncated with `[output truncated]` marker)
|
|
1324
|
+
- **Binary rejection**: Output with >10% non-printable characters (after ANSI stripping) is rejected
|
|
1325
|
+
- **Stdout only**: stderr is discarded; ANSI escape sequences are stripped from stdout
|
|
1326
|
+
|
|
1327
|
+
The runner returns a deterministic `InlineCommandResult` with machine-readable failure reasons (`timeout`, `non_zero_exit`, `binary_output`, `spawn_failure`) — raw stderr is never surfaced.
|
|
1328
|
+
|
|
1329
|
+
#### Rendering Flow
|
|
1330
|
+
|
|
1331
|
+
The `renderInlineCommands()` function processes expansions sequentially (not in parallel) to maintain deterministic order. Each `!`command`` token is replaced with an XML-wrapped result:
|
|
1332
|
+
|
|
1333
|
+
- **Success**: `<inline_skill_command index="N">...output...</inline_skill_command>`
|
|
1334
|
+
- **Failure**: `<inline_skill_command index="N">[inline command unavailable: <reason>]</inline_skill_command>`
|
|
1335
|
+
|
|
1336
|
+
Rendering applies at two levels during `skill_load`:
|
|
1337
|
+
|
|
1338
|
+
1. **Root skill**: If the loaded skill has inline expansions, they are rendered before the skill body is emitted. A root skill with inline commands that fail the feature-flag or source-eligibility check returns an error (fail closed, no `<loaded_skill>` marker).
|
|
1339
|
+
2. **Included children**: Each included child skill's body is rendered independently. A render failure in one child does not prevent sibling rendering — the failed child's body falls back to raw (unexpanded) text with a warning log.
|
|
1340
|
+
|
|
1341
|
+
#### v1 Source Restriction
|
|
1342
|
+
|
|
1343
|
+
In the initial release, only skills from **bundled**, **managed**, and **workspace** sources are eligible for inline command expansion. Skills from **extra** (third-party) roots are explicitly rejected with an error message. The `INLINE_COMMAND_ELIGIBLE_SOURCES` set in `load.ts` enforces this restriction. Unknown or future source types also fail closed.
|
|
1344
|
+
|
|
1345
|
+
#### Fail-Closed Behavior Summary
|
|
1346
|
+
|
|
1347
|
+
Every layer in the pipeline defaults to rejection rather than silent degradation:
|
|
1348
|
+
|
|
1349
|
+
| Layer | Failure mode | Behavior |
|
|
1350
|
+
| ---------------- | ---------------------------------------------------- | ------------------------------------------------------ |
|
|
1351
|
+
| Parser | Malformed token (empty, nested backtick, unmatched) | Logged as error, not expanded |
|
|
1352
|
+
| Feature flag | Flag disabled | `skill_load` returns error, no `<loaded_skill>` marker |
|
|
1353
|
+
| Source check | `extra` or unknown source | `skill_load` returns error, no `<loaded_skill>` marker |
|
|
1354
|
+
| Transitive hash | Missing child or cycle in include graph | `TransitiveHashError` thrown, permission check fails |
|
|
1355
|
+
| Permission | No trust rule and non-interactive | Denied (never silently auto-approved) |
|
|
1356
|
+
| Sandbox runner | Timeout, non-zero exit, binary output, spawn failure | Deterministic stub rendered, no raw stderr |
|
|
1357
|
+
| Renderer (root) | Feature flag off or ineligible source | Error returned from `skill_load` |
|
|
1358
|
+
| Renderer (child) | Exception during render | Raw body used, sibling rendering continues |
|
|
1359
|
+
|
|
1360
|
+
#### Key Source Files
|
|
1361
|
+
|
|
1362
|
+
| File | Role |
|
|
1363
|
+
| --------------------------------------------------- | -------------------------------------------------------------------------------- |
|
|
1364
|
+
| `assistant/src/skills/inline-command-expansions.ts` | `parseInlineCommandExpansions()` — parser for `!`command`` tokens |
|
|
1365
|
+
| `assistant/src/skills/inline-command-runner.ts` | `runInlineCommand()` — sandbox-only command executor |
|
|
1366
|
+
| `assistant/src/skills/inline-command-render.ts` | `renderInlineCommands()` — token replacement and XML wrapping |
|
|
1367
|
+
| `assistant/src/skills/transitive-version-hash.ts` | `computeTransitiveSkillVersionHash()` — hash covering root + included children |
|
|
1368
|
+
| `assistant/src/tools/skills/load.ts` | `skill_load` execute path — feature flag check, source check, render integration |
|
|
1369
|
+
| `assistant/src/permissions/checker.ts` | `skill_load_dynamic:*` candidate emission and allowlist options |
|
|
1370
|
+
| `assistant/src/permissions/defaults.ts` | `default:ask-skill_load_dynamic-global` rule (priority 200) |
|
|
1371
|
+
| `meta/feature-flags/feature-flag-registry.json` | `inline-skill-commands` flag definition |
|
|
1372
|
+
|
|
1264
1373
|
### Key Source Files
|
|
1265
1374
|
|
|
1266
1375
|
| File | Role |
|
|
@@ -1525,7 +1634,7 @@ sequenceDiagram
|
|
|
1525
1634
|
|
|
1526
1635
|
### Key design decisions
|
|
1527
1636
|
|
|
1528
|
-
- **Recursion guard**: A module-level `Set<
|
|
1637
|
+
- **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
1638
|
- **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
1639
|
- **DAG scheduling**: Tasks with dependencies are topologically ordered. Independent tasks run in parallel up to `maxWorkers`.
|
|
1531
1640
|
- **Per-task retries**: Failed tasks retry up to `maxRetriesPerTask` before being marked failed. Dependents are transitively blocked.
|
|
@@ -1568,7 +1677,7 @@ sequenceDiagram
|
|
|
1568
1677
|
|
|
1569
1678
|
Note over Daemon: Processing previous request...<br/>Reaches safe tool-loop checkpoint
|
|
1570
1679
|
|
|
1571
|
-
Daemon-->>DC: generation_handoff (
|
|
1680
|
+
Daemon-->>DC: generation_handoff (conversationId, queuedCount)
|
|
1572
1681
|
Note over Daemon: Daemon yields current generation
|
|
1573
1682
|
|
|
1574
1683
|
Daemon-->>DC: message_dequeued
|
|
@@ -1585,7 +1694,7 @@ sequenceDiagram
|
|
|
1585
1694
|
|
|
1586
1695
|
## Trace System — Debug Panel Data Flow
|
|
1587
1696
|
|
|
1588
|
-
The trace system provides real-time observability of daemon
|
|
1697
|
+
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
1698
|
|
|
1590
1699
|
```mermaid
|
|
1591
1700
|
sequenceDiagram
|
|
@@ -1636,41 +1745,41 @@ sequenceDiagram
|
|
|
1636
1745
|
TE-->>DC: trace_event (message_complete)
|
|
1637
1746
|
DC-->>TS: ingest()
|
|
1638
1747
|
|
|
1639
|
-
Note over TS: Events deduplicated by eventId,<br/>ordered by sequence + timestampMs,<br/>grouped by
|
|
1748
|
+
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
1749
|
|
|
1641
|
-
TS-->>DP: @Published
|
|
1750
|
+
TS-->>DP: @Published eventsByConversation
|
|
1642
1751
|
Note over DP: Metrics strip: requests, LLM calls,<br/>tokens (in/out), avg latency, failures<br/>Timeline: events grouped by requestId
|
|
1643
1752
|
```
|
|
1644
1753
|
|
|
1645
1754
|
### Trace Event Kinds
|
|
1646
1755
|
|
|
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 /
|
|
1756
|
+
Events emitted during a conversation lifecycle:
|
|
1757
|
+
|
|
1758
|
+
| Kind | Emitted by | When |
|
|
1759
|
+
| --------------------------- | ----------------------- | ----------------------------------------------------------------------------------------------- |
|
|
1760
|
+
| `request_received` | Handlers / Conversation | User message or surface action arrives |
|
|
1761
|
+
| `request_queued` | Handlers / Conversation | Message queued while conversation is busy |
|
|
1762
|
+
| `request_dequeued` | Conversation | Queued message begins processing |
|
|
1763
|
+
| `llm_call_started` | Conversation | LLM API call initiated |
|
|
1764
|
+
| `llm_call_finished` | Conversation | LLM API call completed (carries `inputTokens`, `outputTokens`, `latencyMs`) |
|
|
1765
|
+
| `assistant_message` | Conversation | Assistant response assembled (carries `toolUseCount`) |
|
|
1766
|
+
| `tool_started` | ToolTraceListener | Tool execution begins |
|
|
1767
|
+
| `tool_permission_requested` | ToolTraceListener | Permission check needed (carries `riskLevel`) |
|
|
1768
|
+
| `tool_permission_decided` | ToolTraceListener | Permission granted or denied (carries `decision`) |
|
|
1769
|
+
| `tool_finished` | ToolTraceListener | Tool execution completed (carries `durationMs`) |
|
|
1770
|
+
| `tool_failed` | ToolTraceListener | Tool execution failed (carries `durationMs`) |
|
|
1771
|
+
| `secret_detected` | ToolTraceListener | Secret found in tool output |
|
|
1772
|
+
| `generation_handoff` | Conversation | Yielding to next queued message |
|
|
1773
|
+
| `message_complete` | Conversation | Full request processing finished |
|
|
1774
|
+
| `generation_cancelled` | Conversation | User cancelled the generation |
|
|
1775
|
+
| `request_error` | Handlers / Conversation | Unrecoverable error during processing (includes queue-full rejection and persist-failure paths) |
|
|
1667
1776
|
|
|
1668
1777
|
### Architecture
|
|
1669
1778
|
|
|
1670
|
-
- **TraceEmitter** (daemon, per-
|
|
1671
|
-
- **ToolTraceListener** (daemon): Subscribes to the
|
|
1779
|
+
- **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.
|
|
1780
|
+
- **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
1781
|
- **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
|
|
1782
|
+
- **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
1783
|
- **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
1784
|
|
|
1676
1785
|
---
|
|
@@ -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
|