@vellumai/assistant 0.6.0 → 0.6.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/AGENTS.md +4 -0
- package/ARCHITECTURE.md +68 -15
- package/Dockerfile +2 -2
- package/bun.lock +6 -2
- package/docker-entrypoint.sh +42 -1
- package/docs/architecture/integrations.md +1 -1
- package/docs/architecture/memory.md +21 -24
- package/node_modules/@vellumai/ces-contracts/src/handles.ts +7 -9
- package/openapi.yaml +539 -4
- package/package.json +5 -1
- package/src/__tests__/anthropic-provider.test.ts +160 -95
- package/src/__tests__/app-dir-path-guard.test.ts +1 -0
- package/src/__tests__/app-executors.test.ts +47 -1
- package/src/__tests__/app-source-watcher.test.ts +159 -0
- package/src/__tests__/assistant-event-hub.test.ts +30 -0
- package/src/__tests__/checker.test.ts +138 -172
- package/src/__tests__/cli-command-risk-guard.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +5 -0
- package/src/__tests__/context-overflow-approval.test.ts +5 -5
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +4 -6
- package/src/__tests__/conversation-agent-loop.test.ts +4 -51
- package/src/__tests__/conversation-analysis-routes.test.ts +169 -0
- package/src/__tests__/conversation-directories-parse.test.ts +105 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
- package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
- package/src/__tests__/conversation-wipe.test.ts +2 -6
- package/src/__tests__/conversation-workspace-cache-state.test.ts +6 -12
- package/src/__tests__/conversation-workspace-injection.test.ts +25 -26
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/copy-composer-tc-templates.test.ts +335 -0
- package/src/__tests__/credential-execution-approval-bridge.test.ts +0 -2
- package/src/__tests__/date-context.test.ts +76 -210
- package/src/__tests__/db-schedule-syntax-migration.test.ts +16 -1
- package/src/__tests__/file-list-tool.test.ts +219 -0
- package/src/__tests__/first-greeting.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +180 -3
- package/src/__tests__/identity-routes.test.ts +328 -0
- package/src/__tests__/init-feature-flag-overrides.test.ts +167 -0
- package/src/__tests__/injection-block.test.ts +24 -0
- package/src/__tests__/inline-command-runner.test.ts +7 -5
- package/src/__tests__/install-skill-routing.test.ts +7 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +15 -14
- package/src/__tests__/list-messages-tool-merge.test.ts +300 -0
- package/src/__tests__/llm-context-normalization.test.ts +18 -18
- package/src/__tests__/llm-context-route-provider.test.ts +101 -0
- package/src/__tests__/llm-request-log-turn-query.test.ts +162 -0
- package/src/__tests__/log-export-workspace.test.ts +257 -100
- package/src/__tests__/managed-credential-catalog-cli.test.ts +12 -14
- package/src/__tests__/mcp-abort-signal.test.ts +5 -0
- package/src/__tests__/mcp-client-auth.test.ts +5 -0
- package/src/__tests__/memory-recall-log-store.test.ts +132 -0
- package/src/__tests__/migration-export-streaming.test.ts +304 -0
- package/src/__tests__/migration-import-commit-http.test.ts +11 -10
- package/src/__tests__/mock-fetch.ts +87 -0
- package/src/__tests__/navigate-settings-tab.test.ts +14 -1
- package/src/__tests__/notification-broadcaster.test.ts +65 -0
- package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
- package/src/__tests__/onboarding-template-contract.test.ts +63 -14
- package/src/__tests__/parser.test.ts +32 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +452 -0
- package/src/__tests__/permission-controls-v2-flag.test.ts +55 -0
- package/src/__tests__/permission-mode-sse.test.ts +418 -0
- package/src/__tests__/permission-mode-store.test.ts +277 -0
- package/src/__tests__/permission-mode.test.ts +101 -0
- package/src/__tests__/pkb-autoinject.test.ts +96 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +359 -0
- package/src/__tests__/profiler-routes.test.ts +502 -0
- package/src/__tests__/profiler-run-store.test.ts +441 -0
- package/src/__tests__/proxy-approval-callback.test.ts +4 -75
- package/src/__tests__/registry.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +0 -2
- package/src/__tests__/sandbox-diagnostics.test.ts +1 -32
- package/src/__tests__/sandbox-host-parity.test.ts +5 -4
- package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
- package/src/__tests__/search-skills-unified.test.ts +4 -3
- package/src/__tests__/send-endpoint-busy.test.ts +42 -3
- package/src/__tests__/set-permission-mode.test.ts +274 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +12 -0
- package/src/__tests__/skill-memory.test.ts +2 -783
- package/src/__tests__/strip-memory-injections.test.ts +187 -0
- package/src/__tests__/subagent-detail.test.ts +84 -0
- package/src/__tests__/subagent-disposal.test.ts +308 -0
- package/src/__tests__/subagent-manager-notify.test.ts +19 -10
- package/src/__tests__/subagent-notify-parent.test.ts +390 -0
- package/src/__tests__/subagent-role-registry.test.ts +108 -0
- package/src/__tests__/subagent-tool-filtering.test.ts +71 -0
- package/src/__tests__/subagent-tools.test.ts +464 -4
- package/src/__tests__/system-prompt-ask-mode.test.ts +139 -0
- package/src/__tests__/task-memory-cleanup.test.ts +12 -12
- package/src/__tests__/terminal-sandbox.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +16 -29
- package/src/__tests__/test-preload.ts +18 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -8
- package/src/__tests__/tool-executor.test.ts +4 -27
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/top-level-renderer.test.ts +10 -13
- package/src/__tests__/transport-hints-queue.test.ts +77 -0
- package/src/__tests__/trust-store.test.ts +4 -4
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +116 -2
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
- package/src/__tests__/workspace-migration-030-seed-pkb-autoinject.test.ts +168 -0
- package/src/__tests__/workspace-policy.test.ts +2 -7
- package/src/agent/loop.ts +6 -29
- package/src/approvals/guardian-request-resolvers.ts +24 -0
- package/src/avatar/traits-png-sync.ts +3 -3
- package/src/channels/types.ts +5 -0
- package/src/cli/__tests__/run-assistant-command.ts +56 -0
- package/src/cli/__tests__/unknown-command.test.ts +33 -0
- package/src/cli/commands/__tests__/email-download.test.ts +245 -0
- package/src/cli/commands/__tests__/email-list.test.ts +192 -0
- package/src/cli/commands/__tests__/email-register.test.ts +186 -0
- package/src/cli/commands/__tests__/email-send.test.ts +291 -0
- package/src/cli/commands/__tests__/email-status.test.ts +181 -0
- package/src/cli/commands/__tests__/email-unregister.test.ts +139 -0
- package/src/cli/commands/__tests__/routes.test.ts +562 -0
- package/src/cli/commands/conversations.ts +1 -8
- package/src/cli/commands/default-action.ts +68 -1
- package/src/cli/commands/email.ts +584 -835
- package/src/cli/commands/memory.ts +1 -34
- package/src/cli/commands/notifications.ts +7 -2
- package/src/cli/commands/oauth/__tests__/connect.test.ts +27 -0
- package/src/cli/commands/oauth/connect.ts +25 -5
- package/src/cli/commands/platform/__tests__/connect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +1 -1
- package/src/cli/commands/routes.ts +396 -0
- package/src/cli/commands/skills.ts +130 -20
- package/src/cli/program.ts +11 -2
- package/src/cli.ts +1 -120
- package/src/config/assistant-feature-flags.ts +59 -55
- package/src/config/bundled-skills/app-builder/SKILL.md +91 -5
- package/src/config/bundled-skills/gmail/SKILL.md +13 -8
- package/src/config/bundled-skills/gmail/TOOLS.json +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +2 -1
- package/src/config/bundled-skills/messaging/SKILL.md +7 -0
- package/src/config/bundled-skills/schedule/SKILL.md +22 -2
- package/src/config/bundled-skills/schedule/TOOLS.json +8 -0
- package/src/config/bundled-skills/settings/TOOLS.json +1 -1
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +3 -13
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +2 -4
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +5 -2
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +8 -3
- package/src/config/bundled-skills/slack/SKILL.md +2 -0
- package/src/config/bundled-skills/subagent/SKILL.md +43 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
- package/src/config/env-registry.ts +63 -0
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +8 -0
- package/src/config/schemas/filing.ts +51 -0
- package/src/config/schemas/heartbeat.ts +15 -12
- package/src/config/schemas/memory-lifecycle.ts +12 -0
- package/src/config/schemas/security.ts +14 -0
- package/src/config/schemas/services.ts +8 -0
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/managed-catalog.ts +3 -7
- package/src/daemon/app-source-watcher.ts +93 -0
- package/src/daemon/config-watcher.ts +85 -3
- package/src/daemon/context-overflow-approval.ts +0 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +20 -0
- package/src/daemon/conversation-agent-loop.ts +179 -65
- package/src/daemon/conversation-attachments.ts +0 -1
- package/src/daemon/conversation-history.ts +4 -19
- package/src/daemon/conversation-lifecycle.ts +8 -14
- package/src/daemon/conversation-messaging.ts +3 -0
- package/src/daemon/conversation-process.ts +30 -8
- package/src/daemon/conversation-queue-manager.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +359 -308
- package/src/daemon/conversation-surfaces.ts +65 -0
- package/src/daemon/conversation-tool-setup.ts +44 -17
- package/src/daemon/conversation-workspace.ts +1 -2
- package/src/daemon/conversation.ts +19 -3
- package/src/daemon/date-context.ts +26 -53
- package/src/daemon/first-greeting.ts +1 -1
- package/src/daemon/handlers/conversations.ts +5 -7
- package/src/daemon/handlers/shared.test.ts +143 -0
- package/src/daemon/handlers/shared.ts +70 -5
- package/src/daemon/handlers/skills.ts +11 -18
- package/src/daemon/lifecycle.ts +220 -158
- package/src/daemon/message-types/conversations.ts +29 -6
- package/src/daemon/message-types/messages.ts +9 -2
- package/src/daemon/message-types/notifications.ts +12 -0
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +18 -0
- package/src/daemon/profiler-run-store.ts +557 -0
- package/src/daemon/server.ts +87 -10
- package/src/daemon/shutdown-handlers.ts +5 -0
- package/src/daemon/tool-side-effects.ts +23 -3
- package/src/daemon/transport-hints.ts +33 -0
- package/src/export/transcript-formatter.ts +148 -0
- package/src/filing/filing-service.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +96 -7
- package/src/index.ts +1 -1
- package/src/mcp/client.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +149 -27
- package/src/memory/admin.ts +33 -32
- package/src/memory/app-store.ts +69 -0
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +151 -117
- package/src/memory/conversation-directories.ts +39 -0
- package/src/memory/conversation-group-migration.ts +66 -6
- package/src/memory/conversation-queries.ts +58 -12
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/db-init.ts +182 -376
- package/src/memory/embedding-local.ts +1 -1
- package/src/memory/graph/bootstrap.ts +75 -66
- package/src/memory/graph/capability-seed.ts +167 -17
- package/src/memory/graph/consolidation.ts +38 -4
- package/src/memory/graph/conversation-graph-memory.ts +133 -104
- package/src/memory/graph/extraction-job.ts +9 -4
- package/src/memory/graph/extraction.ts +66 -23
- package/src/memory/graph/graph-memory-state-store.ts +37 -0
- package/src/memory/graph/graph-search.ts +29 -15
- package/src/memory/graph/injection.ts +38 -8
- package/src/memory/graph/inspect.ts +12 -3
- package/src/memory/graph/retriever.ts +365 -262
- package/src/memory/graph/store.test.ts +48 -0
- package/src/memory/graph/store.ts +150 -11
- package/src/memory/graph/tool-handlers.ts +84 -209
- package/src/memory/graph/tools.ts +8 -52
- package/src/memory/graph/types.ts +24 -0
- package/src/memory/group-crud.ts +25 -9
- package/src/memory/job-handlers/cleanup.ts +44 -1
- package/src/memory/jobs-store.ts +70 -60
- package/src/memory/jobs-worker.ts +44 -28
- package/src/memory/llm-request-log-store.ts +96 -12
- package/src/memory/memory-recall-log-store.ts +49 -5
- package/src/memory/migrations/203-drop-memory-items-tables.ts +33 -1
- package/src/memory/migrations/206-memory-graph-node-edits.ts +19 -0
- package/src/memory/migrations/206-scrub-corrupted-image-attachments.ts +131 -0
- package/src/memory/migrations/207-conversation-graph-memory-state.ts +20 -0
- package/src/memory/migrations/208-conversations-last-message-at.ts +35 -0
- package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +85 -0
- package/src/memory/migrations/210-schedule-reuse-conversation.ts +13 -0
- package/src/memory/migrations/211-memory-recall-logs-query-context.ts +21 -0
- package/src/memory/migrations/212-llm-request-logs-created-at-index.ts +19 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/schema/conversations.ts +14 -0
- package/src/memory/schema/infrastructure.ts +8 -1
- package/src/memory/schema/memory-core.ts +0 -51
- package/src/memory/schema/memory-graph.ts +15 -0
- package/src/memory/task-memory-cleanup.ts +30 -11
- package/src/messaging/provider.ts +1 -1
- package/src/notifications/broadcaster.ts +6 -0
- package/src/notifications/conversation-pairing.ts +12 -4
- package/src/notifications/copy-composer.ts +86 -0
- package/src/notifications/decision-engine.ts +35 -0
- package/src/notifications/emit-signal.ts +14 -0
- package/src/notifications/signal.ts +11 -0
- package/src/oauth/platform-connection.test.ts +2 -2
- package/src/oauth/seed-providers.ts +1 -0
- package/src/permissions/checker.ts +15 -4
- package/src/permissions/defaults.ts +7 -8
- package/src/permissions/permission-mode-store.ts +180 -0
- package/src/permissions/permission-mode.ts +31 -0
- package/src/permissions/prompter.ts +0 -2
- package/src/permissions/workspace-policy.ts +9 -0
- package/src/platform/client.ts +1 -1
- package/src/prompts/system-prompt.ts +59 -7
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
- package/src/prompts/templates/BOOTSTRAP.md +76 -162
- package/src/prompts/templates/HEARTBEAT.md +3 -1
- package/src/prompts/templates/SOUL.md +30 -9
- package/src/prompts/templates/UPDATES.md +8 -0
- package/src/providers/anthropic/client.ts +107 -219
- package/src/runtime/assistant-event-hub.ts +22 -0
- package/src/runtime/auth/route-policy.ts +23 -0
- package/src/runtime/auth/token-service.ts +8 -0
- package/src/runtime/http-server.ts +32 -2
- package/src/runtime/http-types.ts +12 -1
- package/src/runtime/migrations/vbundle-builder.ts +389 -3
- package/src/runtime/migrations/vbundle-importer.ts +8 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +378 -0
- package/src/runtime/routes/app-management-routes.ts +1 -11
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +26 -0
- package/src/runtime/routes/archive-utils.ts +29 -0
- package/src/runtime/routes/avatar-routes.ts +2 -9
- package/src/runtime/routes/btw-routes.ts +14 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +185 -0
- package/src/runtime/routes/conversation-management-routes.ts +1 -14
- package/src/runtime/routes/conversation-query-routes.ts +49 -3
- package/src/runtime/routes/conversation-routes.ts +270 -44
- package/src/runtime/routes/group-routes.ts +22 -8
- package/src/runtime/routes/heartbeat-routes.ts +4 -10
- package/src/runtime/routes/identity-routes.ts +53 -18
- package/src/runtime/routes/llm-context-normalization.ts +14 -10
- package/src/runtime/routes/log-export/AGENTS.md +104 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +103 -0
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +716 -0
- package/src/runtime/routes/log-export/workspace-allowlist.ts +458 -0
- package/src/runtime/routes/log-export-routes.ts +41 -278
- package/src/runtime/routes/memory-item-routes.test.ts +168 -233
- package/src/runtime/routes/migration-routes.ts +18 -7
- package/src/runtime/routes/profiler-routes.ts +350 -0
- package/src/runtime/routes/schedule-routes.ts +27 -12
- package/src/runtime/routes/settings-routes.ts +95 -8
- package/src/runtime/routes/subagents-routes.ts +28 -7
- package/src/runtime/routes/user-route-dispatcher.ts +223 -0
- package/src/runtime/routes/user-routes.ts +41 -0
- package/src/runtime/routes/workspace-routes.ts +0 -1
- package/src/schedule/schedule-store.ts +30 -0
- package/src/schedule/scheduler.ts +45 -18
- package/src/skills/catalog-install.ts +10 -2
- package/src/skills/inline-command-runner.ts +12 -14
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/skill-memory.ts +1 -293
- package/src/subagent/index.ts +13 -3
- package/src/subagent/manager.ts +308 -29
- package/src/subagent/types.ts +68 -0
- package/src/tasks/task-runner.ts +4 -4
- package/src/tools/apps/executors.ts +29 -4
- package/src/tools/filesystem/list.ts +93 -0
- package/src/tools/permission-checker.ts +78 -18
- package/src/tools/registry.ts +4 -0
- package/src/tools/schedule/create.ts +3 -0
- package/src/tools/schedule/list.ts +1 -0
- package/src/tools/schedule/update.ts +6 -0
- package/src/tools/secret-detection-handler.ts +0 -1
- package/src/tools/shared/filesystem/errors.ts +5 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
- package/src/tools/shared/filesystem/types.ts +17 -0
- package/src/tools/shared/shell-output.ts +31 -2
- package/src/tools/skills/sandbox-runner.ts +3 -6
- package/src/tools/subagent/abort.ts +12 -2
- package/src/tools/subagent/message.ts +9 -2
- package/src/tools/subagent/notify-parent.ts +79 -0
- package/src/tools/subagent/read.ts +29 -8
- package/src/tools/subagent/resolve.ts +21 -0
- package/src/tools/subagent/spawn.ts +2 -0
- package/src/tools/subagent/status.ts +11 -1
- package/src/tools/system/avatar-generator.ts +3 -3
- package/src/tools/system/register.ts +23 -0
- package/src/tools/system/set-permission-mode.ts +103 -0
- package/src/tools/terminal/parser.ts +30 -5
- package/src/tools/terminal/safe-env.ts +16 -1
- package/src/tools/terminal/sandbox-diagnostics.ts +4 -4
- package/src/tools/terminal/sandbox.ts +4 -1
- package/src/tools/terminal/shell.ts +3 -5
- package/src/tools/tool-manifest.ts +6 -0
- package/src/tools/types.ts +2 -3
- package/src/util/logger.ts +1 -1
- package/src/util/platform.ts +50 -17
- package/src/watcher/provider-types.ts +1 -1
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +2 -2
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
- package/src/workspace/migrations/029-seed-pkb.ts +85 -0
- package/src/workspace/migrations/030-seed-pkb-autoinject.ts +73 -0
- package/src/workspace/migrations/registry.ts +6 -0
- package/src/workspace/top-level-renderer.ts +5 -9
- package/src/__tests__/cli-memory.test.ts +0 -377
- package/src/__tests__/clipboard.test.ts +0 -88
- package/src/cli/cli-memory.ts +0 -179
- package/src/util/clipboard.ts +0 -34
|
@@ -570,16 +570,8 @@ function anthropicMessageSections(
|
|
|
570
570
|
const role = asString(message.role) ?? "unknown";
|
|
571
571
|
const content = message.content;
|
|
572
572
|
const sections: LlmContextSection[] = [];
|
|
573
|
-
const text = collectAnthropicMessageText(content);
|
|
574
|
-
if (text) {
|
|
575
|
-
sections.push({
|
|
576
|
-
kind: "message",
|
|
577
|
-
label,
|
|
578
|
-
role,
|
|
579
|
-
text,
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
573
|
|
|
574
|
+
// Collect reasoning sections first so they appear before the message text.
|
|
583
575
|
for (const block of asRecordArray(content) ?? []) {
|
|
584
576
|
const type = asString(block.type);
|
|
585
577
|
if (type === "thinking" || type === "redacted_thinking") {
|
|
@@ -589,9 +581,21 @@ function anthropicMessageSections(
|
|
|
589
581
|
role,
|
|
590
582
|
text: collectAnthropicReasoningText(block),
|
|
591
583
|
});
|
|
592
|
-
continue;
|
|
593
584
|
}
|
|
585
|
+
}
|
|
594
586
|
|
|
587
|
+
const text = collectAnthropicMessageText(content);
|
|
588
|
+
if (text) {
|
|
589
|
+
sections.push({
|
|
590
|
+
kind: "message",
|
|
591
|
+
label,
|
|
592
|
+
role,
|
|
593
|
+
text,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
for (const block of asRecordArray(content) ?? []) {
|
|
598
|
+
const type = asString(block.type);
|
|
595
599
|
if (isAnthropicToolUseType(type)) {
|
|
596
600
|
sections.push({
|
|
597
601
|
kind: "tool_use",
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# Log Export — Workspace Allowlist Rules
|
|
2
|
+
|
|
3
|
+
`POST /v1/export` (handled by `log-export-routes.ts`) builds a tar.gz archive
|
|
4
|
+
from audit DB rows, daemon logs under `<workspace>/data/logs/`, and a
|
|
5
|
+
sanitized `config.json` snapshot. This directory
|
|
6
|
+
(`assistant/src/runtime/routes/log-export/`) houses the allowlist module
|
|
7
|
+
that governs which subpaths of the user's workspace directory
|
|
8
|
+
(`~/.vellum/workspace/`) are permitted to flow into that archive.
|
|
9
|
+
|
|
10
|
+
Workspace contents are **opt-in (allowlist), not opt-out**. The workspace
|
|
11
|
+
contains arbitrary user files — skills, hooks, routes, conversations,
|
|
12
|
+
credentials scaffolding, and other material the user has authored or
|
|
13
|
+
installed locally. Accidentally bundling any of that into a support
|
|
14
|
+
archive would exfiltrate data the user never intended to share. The
|
|
15
|
+
default must therefore be "nothing from the workspace ships" and each
|
|
16
|
+
individual entry that _does_ ship must be justified against the rules
|
|
17
|
+
below.
|
|
18
|
+
|
|
19
|
+
## Rule 1 — Prefer time-filterable data
|
|
20
|
+
|
|
21
|
+
Only allowlist a workspace subpath if its contents can be narrowed to the
|
|
22
|
+
`[startTime, endTime]` window carried on the export request.
|
|
23
|
+
|
|
24
|
+
- When the data is organized as per-record files or per-record
|
|
25
|
+
directories whose **names encode a timestamp**, filter by parsing the
|
|
26
|
+
name. The canonical example is the per-conversation directory layout
|
|
27
|
+
where each directory is named `<ISO-with-dashes>_<conversationId>`
|
|
28
|
+
(the ISO date comes first so ordinary lexicographic comparison yields
|
|
29
|
+
chronological order, and colons in the ISO string are replaced with
|
|
30
|
+
`-` so the name is filesystem-safe). A time filter can be implemented
|
|
31
|
+
by parsing the prefix and comparing it to `startTime` / `endTime`
|
|
32
|
+
without reading file contents.
|
|
33
|
+
- When the relevant time information lives **only inside files**, the
|
|
34
|
+
allowlist entry should err on the side of **not** being included —
|
|
35
|
+
unless the file is small, rarely changes, and its full contents are
|
|
36
|
+
acceptable to ship regardless of the requested window.
|
|
37
|
+
|
|
38
|
+
## Rule 2 — Prefer conversation-filterable data
|
|
39
|
+
|
|
40
|
+
When the export request carries a `conversationId`, every allowlisted
|
|
41
|
+
subpath should narrow itself to that conversation **if at all possible**.
|
|
42
|
+
|
|
43
|
+
- Data that is intrinsically global (i.e. not associated with a single
|
|
44
|
+
conversation) is acceptable to include **only** when Rule 1 alone is
|
|
45
|
+
sufficient and the request has no `conversationId` filter.
|
|
46
|
+
- When a `conversationId` _is_ set and an entry cannot be scoped to it,
|
|
47
|
+
prefer omitting the entry for that particular export rather than
|
|
48
|
+
shipping unrelated conversation data.
|
|
49
|
+
|
|
50
|
+
The `<ISO-with-dashes>_<conversationId>` directory naming is again the
|
|
51
|
+
motivating example: the suffix lets us select exactly one
|
|
52
|
+
per-conversation directory without scanning file contents.
|
|
53
|
+
|
|
54
|
+
## Rule 3 — Default deny
|
|
55
|
+
|
|
56
|
+
Anything in the workspace that is not explicitly added to the allowlist
|
|
57
|
+
module must remain excluded from the export archive. Adding a new entry
|
|
58
|
+
requires, in the same PR:
|
|
59
|
+
|
|
60
|
+
1. Updating the allowlist module in this directory to teach it about the
|
|
61
|
+
new subpath (including its time filter, conversation filter, and
|
|
62
|
+
size cap).
|
|
63
|
+
2. Updating this `AGENTS.md` to record the entry name, which filters it
|
|
64
|
+
honors, and its size cap under `## Allowlisted entries`.
|
|
65
|
+
|
|
66
|
+
Review must confirm both updates landed together. A workspace subpath
|
|
67
|
+
that is not mentioned in the registry below is, by definition, not
|
|
68
|
+
allowed in the export archive.
|
|
69
|
+
|
|
70
|
+
## Rule 4 — Bounded size
|
|
71
|
+
|
|
72
|
+
Every allowlisted entry must enforce a byte cap so that a misbehaving
|
|
73
|
+
workspace (e.g. a runaway log, a giant attachment, a pathological skill)
|
|
74
|
+
cannot blow up the archive and defeat the export endpoint.
|
|
75
|
+
|
|
76
|
+
The current convention is **10 MB** across the workspace allowlist,
|
|
77
|
+
mirroring `MAX_LOG_PAYLOAD_BYTES` in `log-export-routes.ts`. Entries
|
|
78
|
+
should track the number of bytes already consumed and stop adding files
|
|
79
|
+
once the cap would be exceeded, preferring to include the newest /
|
|
80
|
+
most-relevant records first.
|
|
81
|
+
|
|
82
|
+
## Allowlisted entries
|
|
83
|
+
|
|
84
|
+
- **`conversations/`**
|
|
85
|
+
- **Path**: `<workspace>/conversations/<ISO-with-dashes>_<conversationId>/`
|
|
86
|
+
- **Honors filters**: time (union of parsed `createdAt` prefix _and_
|
|
87
|
+
per-message `ts` inside `messages.jsonl`) and `conversationId`
|
|
88
|
+
(exact match on the directory-name suffix — no substring matching).
|
|
89
|
+
- **Time semantics**: A conversation directory is included if EITHER
|
|
90
|
+
its `createdAt` (parsed from the directory name) falls in the
|
|
91
|
+
requested window OR `messages.jsonl` contains at least one message
|
|
92
|
+
whose `ts` falls in the window. The cheap directory-name check runs
|
|
93
|
+
first; the per-message scan only runs as a fallback when the cheap
|
|
94
|
+
check failed, so the common in-window case stays IO-free. This is
|
|
95
|
+
the "support bundle" union — false positives are cheaper than false
|
|
96
|
+
negatives because the user almost always wants the conversations
|
|
97
|
+
they were _active in_ during the window, not just the ones they
|
|
98
|
+
_started_ during it.
|
|
99
|
+
- **Cap**: shares the 10 MB workspace cap defined by
|
|
100
|
+
`MAX_WORKSPACE_PAYLOAD_BYTES` in `workspace-allowlist.ts`.
|
|
101
|
+
- **Notes**: Directory names that don't match the canonical
|
|
102
|
+
`<ISO-with-dashes>_<conversationId>` format are silently skipped
|
|
103
|
+
(Rule 3 — default deny). Legacy `<id>_<ISO>` directories are
|
|
104
|
+
intentionally excluded until they migrate to the canonical format.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Regression test for the `result.entries` contract on `collectWorkspaceData`.
|
|
3
|
+
*
|
|
4
|
+
* Consumers and telemetry rely on `collectWorkspaceData` always returning at
|
|
5
|
+
* least one entry summary for the `conversations` allowlist entry — even when
|
|
6
|
+
* something throws partway through the candidate loop. This file pins that
|
|
7
|
+
* contract by mocking `parseConversationDirName` to return a malicious object
|
|
8
|
+
* whose `createdAtMs` getter throws. That throw escapes the inner per-iteration
|
|
9
|
+
* try/catch (it happens during sort + filter expression evaluation, not inside
|
|
10
|
+
* the wrapped parser call), bubbles up to the outer try/catch in
|
|
11
|
+
* `collectWorkspaceData`, and verifies that `result.entries` still contains
|
|
12
|
+
* exactly one `conversations` entry summary.
|
|
13
|
+
*
|
|
14
|
+
* Lives in its own file because `mock.module` is a global module override and
|
|
15
|
+
* we don't want it bleeding into the rest of the workspace-allowlist tests.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
19
|
+
import { join } from "node:path";
|
|
20
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
21
|
+
|
|
22
|
+
mock.module("../../../../memory/conversation-directories.js", () => ({
|
|
23
|
+
parseConversationDirName: (_name: string) => {
|
|
24
|
+
// Return an object whose `createdAtMs` accessor throws. This bypasses the
|
|
25
|
+
// inner try/catch wrapping `parseConversationDirName(name)` (which only
|
|
26
|
+
// catches synchronous throws from the call itself, not from later property
|
|
27
|
+
// accesses) and triggers the unwrapped sort/filter comparisons further
|
|
28
|
+
// down in `collectConversations`.
|
|
29
|
+
return {
|
|
30
|
+
conversationId: "evil",
|
|
31
|
+
get createdAtMs(): number {
|
|
32
|
+
throw new Error("simulated parser corruption");
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
}));
|
|
37
|
+
|
|
38
|
+
import { getConversationsDir } from "../../../../util/platform.js";
|
|
39
|
+
import { collectWorkspaceData } from "../workspace-allowlist.js";
|
|
40
|
+
|
|
41
|
+
let staging: string;
|
|
42
|
+
|
|
43
|
+
beforeEach(() => {
|
|
44
|
+
// Fresh staging directory for each test.
|
|
45
|
+
const conversationsDir = getConversationsDir();
|
|
46
|
+
rmSync(conversationsDir, { recursive: true, force: true });
|
|
47
|
+
mkdirSync(conversationsDir, { recursive: true });
|
|
48
|
+
|
|
49
|
+
staging = join(
|
|
50
|
+
process.env.VELLUM_WORKSPACE_DIR ?? "/tmp",
|
|
51
|
+
"ws-allowlist-error-staging",
|
|
52
|
+
);
|
|
53
|
+
rmSync(staging, { recursive: true, force: true });
|
|
54
|
+
mkdirSync(staging, { recursive: true });
|
|
55
|
+
|
|
56
|
+
// Seed a single canonical-looking dir so the loop has something to chew on.
|
|
57
|
+
const dirName = "2025-01-15T00-00-00.000Z_conv-jan15";
|
|
58
|
+
const dir = join(conversationsDir, dirName);
|
|
59
|
+
mkdirSync(dir, { recursive: true });
|
|
60
|
+
writeFileSync(
|
|
61
|
+
join(dir, "meta.json"),
|
|
62
|
+
JSON.stringify({ name: dirName }),
|
|
63
|
+
"utf-8",
|
|
64
|
+
);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
afterEach(() => {
|
|
68
|
+
try {
|
|
69
|
+
rmSync(staging, { recursive: true, force: true });
|
|
70
|
+
} catch {
|
|
71
|
+
/* best-effort cleanup */
|
|
72
|
+
}
|
|
73
|
+
try {
|
|
74
|
+
rmSync(getConversationsDir(), { recursive: true, force: true });
|
|
75
|
+
} catch {
|
|
76
|
+
/* best-effort cleanup */
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe("collectWorkspaceData — entry contract on unexpected error", () => {
|
|
81
|
+
test("synthesizes a conversations entry summary even when the loop throws", () => {
|
|
82
|
+
// The mocked parser returns a poisoned object whose `createdAtMs` accessor
|
|
83
|
+
// throws. The first read happens inside the time-filter checks in the
|
|
84
|
+
// candidate-collection loop, which is NOT wrapped in a per-iteration
|
|
85
|
+
// try/catch. The throw should propagate up to the outer try/catch in
|
|
86
|
+
// `collectWorkspaceData`, where it must be swallowed without dropping
|
|
87
|
+
// the entry summary.
|
|
88
|
+
const result = collectWorkspaceData({
|
|
89
|
+
staging,
|
|
90
|
+
// Force the time-filter branch to read `createdAtMs`.
|
|
91
|
+
startTime: 0,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Contract: exactly one entry, named "conversations", regardless of error.
|
|
95
|
+
expect(result.entries).toHaveLength(1);
|
|
96
|
+
const [entry] = result.entries;
|
|
97
|
+
expect(entry.entry).toBe("conversations");
|
|
98
|
+
expect(entry.itemCount).toBe(0);
|
|
99
|
+
expect(entry.bytes).toBe(0);
|
|
100
|
+
expect(entry.skippedDueToCap).toBe(0);
|
|
101
|
+
expect(result.totalBytes).toBe(0);
|
|
102
|
+
});
|
|
103
|
+
});
|