@vellumai/assistant 0.5.16 → 0.6.1
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 +69 -16
- package/Dockerfile +2 -5
- package/bun.lock +6 -2
- package/docker-entrypoint.sh +32 -1
- package/docs/architecture/integrations.md +1 -1
- package/docs/architecture/memory.md +21 -24
- package/knip.json +2 -1
- package/openapi.yaml +1198 -83
- package/package.json +5 -1
- package/src/__tests__/actor-token-service.test.ts +68 -0
- package/src/__tests__/agent-loop.test.ts +0 -32
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/anthropic-provider.test.ts +217 -98
- package/src/__tests__/app-compiler.test.ts +120 -0
- 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-feature-flags-integration.test.ts +2 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -6
- package/src/__tests__/call-domain.test.ts +2 -6
- package/src/__tests__/call-pointer-messages.test.ts +2 -14
- package/src/__tests__/call-recovery.test.ts +2 -6
- package/src/__tests__/call-routes-http.test.ts +2 -6
- package/src/__tests__/call-store.test.ts +2 -6
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +2 -6
- package/src/__tests__/canonical-guardian-store.test.ts +2 -6
- package/src/__tests__/channel-delivery-store.test.ts +2 -6
- package/src/__tests__/channel-retry-sweep.test.ts +2 -6
- package/src/__tests__/checker.test.ts +63 -9
- package/src/__tests__/clawhub.test.ts +54 -24
- package/src/__tests__/cli-command-risk-guard.test.ts +14 -0
- package/src/__tests__/config-schema.test.ts +6 -1
- package/src/__tests__/config-set-platform-guard.test.ts +302 -0
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +2 -6
- package/src/__tests__/contacts-tools.test.ts +31 -0
- package/src/__tests__/context-overflow-reducer.test.ts +86 -0
- package/src/__tests__/context-token-estimator.test.ts +175 -10
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +13 -6
- package/src/__tests__/conversation-agent-loop.test.ts +13 -51
- package/src/__tests__/conversation-attachments.test.ts +2 -6
- package/src/__tests__/conversation-attention-store.test.ts +2 -6
- package/src/__tests__/conversation-clear-safety.test.ts +2 -6
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +4 -10
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -6
- package/src/__tests__/conversation-disk-view.test.ts +2 -6
- package/src/__tests__/conversation-error.test.ts +33 -2
- package/src/__tests__/conversation-fork-crud.test.ts +2 -6
- package/src/__tests__/conversation-history-web-search.test.ts +6 -1
- package/src/__tests__/conversation-load-history-repair.test.ts +5 -1
- package/src/__tests__/conversation-media-retry.test.ts +91 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +653 -832
- package/src/__tests__/conversation-runtime-workspace.test.ts +1 -93
- package/src/__tests__/conversation-starter-routes.test.ts +20 -11
- package/src/__tests__/conversation-store.test.ts +2 -6
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +17 -4
- package/src/__tests__/conversation-usage.test.ts +2 -6
- package/src/__tests__/conversation-wipe.test.ts +13 -414
- 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-feature-gates.test.ts +3 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +2 -2
- package/src/__tests__/credential-security-e2e.test.ts +2 -0
- 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__/followup-tools.test.ts +2 -6
- package/src/__tests__/graph-extraction-event-date.test.ts +186 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -6
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -6
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +2 -6
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -6
- package/src/__tests__/guardian-action-store.test.ts +2 -6
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -6
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +8 -8
- package/src/__tests__/guardian-dispatch.test.ts +2 -6
- package/src/__tests__/guardian-grant-minting.test.ts +2 -14
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -6
- package/src/__tests__/guardian-routing-invariants.test.ts +192 -6
- package/src/__tests__/guardian-routing-state.test.ts +2 -6
- package/src/__tests__/guardian-verification-voice-binding.test.ts +2 -6
- package/src/__tests__/heartbeat-service.test.ts +180 -3
- package/src/__tests__/identity-routes.test.ts +328 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +2 -6
- package/src/__tests__/injection-block.test.ts +178 -0
- package/src/__tests__/install-meta.test.ts +506 -0
- package/src/__tests__/install-skill-routing.test.ts +293 -0
- package/src/__tests__/invite-redemption-service.test.ts +2 -6
- package/src/__tests__/invite-routes-http.test.ts +2 -6
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +17 -28
- package/src/__tests__/list-messages-attachments.test.ts +2 -6
- 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 +103 -6
- package/src/__tests__/llm-request-log-turn-query.test.ts +164 -6
- package/src/__tests__/llm-usage-store.test.ts +2 -6
- package/src/__tests__/log-export-workspace.test.ts +74 -111
- package/src/__tests__/managed-store.test.ts +38 -11
- package/src/__tests__/mcp-abort-signal.test.ts +5 -0
- package/src/__tests__/mcp-client-auth.test.ts +5 -0
- package/src/__tests__/memory-jobs-worker-backoff.test.ts +2 -8
- package/src/__tests__/memory-recall-log-store.test.ts +134 -6
- package/src/__tests__/memory-upsert-concurrency.test.ts +4 -112
- 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__/non-member-access-request.test.ts +2 -6
- package/src/__tests__/notification-decision-recipient-context.test.ts +282 -0
- package/src/__tests__/notification-guardian-path.test.ts +2 -6
- package/src/__tests__/oauth-cli.test.ts +364 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +18 -3
- package/src/__tests__/onboarding-template-contract.test.ts +62 -14
- package/src/__tests__/outlook-attachments.test.ts +301 -0
- package/src/__tests__/outlook-automation-tools.test.ts +425 -0
- package/src/__tests__/outlook-categories.test.ts +212 -0
- package/src/__tests__/outlook-client-automation.test.ts +246 -0
- package/src/__tests__/outlook-compose-tools.test.ts +325 -0
- package/src/__tests__/outlook-declutter-tools.test.ts +585 -0
- package/src/__tests__/outlook-email-watcher.test.ts +322 -0
- package/src/__tests__/outlook-follow-up.test.ts +196 -0
- package/src/__tests__/outlook-messaging-provider.test.ts +498 -3
- package/src/__tests__/outlook-trash.test.ts +77 -0
- package/src/__tests__/outlook-unsubscribe.test.ts +250 -0
- 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__/platform-bash-auto-approve.test.ts +359 -0
- package/src/__tests__/platform-callback-registration.test.ts +4 -4
- package/src/__tests__/playbook-execution.test.ts +76 -80
- package/src/__tests__/playbook-tools.test.ts +5 -7
- package/src/__tests__/profiler-routes.test.ts +502 -0
- package/src/__tests__/profiler-run-store.test.ts +441 -0
- package/src/__tests__/provider-error-scenarios.test.ts +21 -0
- package/src/__tests__/proxy-approval-callback.test.ts +4 -75
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +273 -0
- package/src/__tests__/registry.test.ts +3 -3
- package/src/__tests__/require-fresh-approval.test.ts +64 -2
- package/src/__tests__/runtime-events-sse-parity.test.ts +2 -6
- package/src/__tests__/runtime-events-sse.test.ts +2 -6
- package/src/__tests__/sandbox-host-parity.test.ts +5 -4
- package/src/__tests__/schedule-store.test.ts +2 -6
- package/src/__tests__/schedule-tools.test.ts +2 -6
- package/src/__tests__/scheduler-recurrence.test.ts +1 -5
- package/src/__tests__/scheduler-reuse-conversation.test.ts +368 -0
- package/src/__tests__/scoped-approval-grants.test.ts +2 -6
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -6
- package/src/__tests__/scrub-corrupted-image-attachments.test.ts +278 -0
- package/src/__tests__/search-skills-unified.test.ts +422 -0
- package/src/__tests__/secret-onetime-send.test.ts +2 -0
- package/src/__tests__/send-endpoint-busy.test.ts +44 -9
- package/src/__tests__/sequence-store.test.ts +2 -6
- package/src/__tests__/server-history-render.test.ts +2 -6
- package/src/__tests__/set-permission-mode.test.ts +274 -0
- package/src/__tests__/skill-feature-flags-integration.test.ts +38 -31
- package/src/__tests__/skill-feature-flags.test.ts +6 -6
- package/src/__tests__/skill-load-feature-flag.test.ts +23 -11
- package/src/__tests__/skill-memory.test.ts +2 -741
- package/src/__tests__/skills-uninstall.test.ts +2 -2
- package/src/__tests__/skills.test.ts +1 -1
- package/src/__tests__/slack-inbound-verification.test.ts +2 -6
- 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-compiler.test.ts +2 -6
- package/src/__tests__/task-management-tools.test.ts +2 -6
- package/src/__tests__/task-memory-cleanup.test.ts +185 -241
- package/src/__tests__/task-runner.test.ts +2 -6
- package/src/__tests__/task-scheduler.test.ts +2 -6
- package/src/__tests__/terminal-tools.test.ts +17 -27
- package/src/__tests__/test-preload.ts +7 -0
- package/src/__tests__/tool-approval-handler.test.ts +2 -6
- package/src/__tests__/tool-executor.test.ts +4 -26
- package/src/__tests__/tool-grant-request-escalation.test.ts +2 -6
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +277 -0
- package/src/__tests__/top-level-renderer.test.ts +10 -13
- package/src/__tests__/trust-store.test.ts +1 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +2 -6
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +118 -8
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -6
- package/src/__tests__/trusted-contact-verification.test.ts +2 -6
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -6
- package/src/__tests__/usage-cache-backfill-migration.test.ts +1 -6
- package/src/__tests__/usage-routes.test.ts +2 -6
- package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
- package/src/__tests__/voice-invite-redemption.test.ts +2 -6
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -6
- package/src/__tests__/voice-session-bridge.test.ts +2 -6
- package/src/__tests__/volume-security-guard.test.ts +2 -0
- package/src/__tests__/workspace-lifecycle.test.ts +29 -1
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +2 -6
- package/src/__tests__/workspace-migration-026-backfill-install-meta.test.ts +558 -0
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +387 -0
- package/src/__tests__/workspace-policy.test.ts +1 -1
- package/src/agent/attachments.ts +7 -2
- package/src/agent/image-optimize.ts +165 -0
- package/src/agent/loop.ts +7 -15
- package/src/approvals/guardian-request-resolvers.ts +24 -0
- package/src/avatar/traits-png-sync.ts +3 -3
- package/src/bundler/app-compiler.ts +179 -2
- package/src/bundler/package-resolver.ts +3 -5
- package/src/cli/__tests__/notifications.test.ts +1 -2
- package/src/cli/__tests__/run-assistant-command.ts +29 -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/avatar.ts +3 -3
- package/src/cli/commands/config.ts +26 -13
- package/src/cli/commands/conversations.ts +1 -8
- package/src/cli/commands/doctor.ts +2 -2
- package/src/cli/commands/email.ts +584 -835
- package/src/cli/commands/memory.ts +37 -84
- package/src/cli/commands/notifications.ts +7 -2
- package/src/cli/commands/oauth/__tests__/connect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +2 -2
- package/src/cli/commands/oauth/__tests__/mode.test.ts +8 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +2 -2
- package/src/cli/commands/oauth/connect.ts +25 -11
- package/src/cli/commands/oauth/mode.ts +7 -0
- package/src/cli/commands/oauth/shared.ts +39 -3
- 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 +5 -5
- package/src/cli/commands/platform/index.ts +16 -16
- package/src/cli/commands/routes.ts +396 -0
- package/src/cli/commands/skills.ts +218 -36
- package/src/cli/commands/trust.ts +2 -2
- package/src/cli/lib/daemon-credential-client.ts +2 -3
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +1 -120
- package/src/config/bundled-skills/acp/TOOLS.json +1 -1
- package/src/config/bundled-skills/app-builder/SKILL.md +4 -1
- package/src/config/bundled-skills/contacts/SKILL.md +0 -1
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -8
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -4
- package/src/config/bundled-skills/gmail/SKILL.md +4 -12
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -9
- package/src/config/bundled-skills/messaging/SKILL.md +17 -18
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +40 -33
- package/src/config/bundled-skills/outlook/SKILL.md +189 -0
- package/src/config/bundled-skills/outlook/TOOLS.json +530 -0
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +85 -0
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +77 -0
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +84 -0
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +94 -0
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +49 -0
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +237 -0
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +161 -0
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +32 -0
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +272 -0
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +29 -0
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +129 -0
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +87 -0
- package/src/config/bundled-skills/outlook/tools/shared.ts +20 -0
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +51 -0
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +221 -0
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +252 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +53 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +74 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +18 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +46 -0
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +36 -0
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +17 -0
- package/src/config/bundled-skills/outlook-calendar/types.ts +120 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +47 -40
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +16 -29
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +16 -18
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +39 -47
- 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/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/slack/SKILL.md +3 -7
- package/src/config/bundled-skills/subagent/SKILL.md +43 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +29 -4
- package/src/config/bundled-tool-registry.ts +56 -4
- package/src/config/env-registry.ts +78 -8
- package/src/config/feature-flag-registry.json +38 -125
- 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/platform.ts +8 -0
- package/src/config/schemas/security.ts +14 -0
- package/src/config/schemas/timeouts.ts +1 -1
- package/src/config/skills.ts +18 -7
- package/src/context/token-estimator.ts +25 -18
- package/src/context/window-manager.ts +6 -2
- package/src/credential-execution/process-manager.ts +3 -1
- package/src/daemon/app-source-watcher.ts +93 -0
- package/src/daemon/config-watcher.ts +79 -1
- package/src/daemon/context-overflow-reducer.ts +46 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +143 -82
- package/src/daemon/conversation-agent-loop.ts +236 -108
- package/src/daemon/conversation-error.ts +31 -8
- package/src/daemon/conversation-history.ts +4 -19
- package/src/daemon/conversation-lifecycle.ts +36 -9
- package/src/daemon/conversation-media-retry.ts +85 -7
- package/src/daemon/conversation-notifiers.ts +4 -1
- package/src/daemon/conversation-process.ts +13 -7
- package/src/daemon/conversation-runtime-assembly.ts +305 -306
- package/src/daemon/conversation-tool-setup.ts +44 -14
- package/src/daemon/conversation-workspace.ts +1 -2
- package/src/daemon/conversation.ts +59 -2
- package/src/daemon/daemon-control.ts +8 -2
- package/src/daemon/date-context.ts +26 -53
- package/src/daemon/first-greeting.ts +1 -1
- package/src/daemon/handlers/conversations.ts +4 -7
- package/src/daemon/handlers/shared.test.ts +143 -0
- package/src/daemon/handlers/shared.ts +85 -17
- package/src/daemon/handlers/skills.ts +416 -209
- package/src/daemon/lifecycle.ts +212 -131
- package/src/daemon/main.ts +5 -1
- package/src/daemon/message-types/conversations.ts +29 -7
- package/src/daemon/message-types/messages.ts +12 -2
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +6 -0
- package/src/daemon/message-types/skills.ts +97 -36
- package/src/daemon/profiler-run-store.ts +557 -0
- package/src/daemon/providers-setup.ts +5 -0
- package/src/daemon/server.ts +100 -11
- package/src/daemon/shutdown-handlers.ts +5 -0
- package/src/daemon/tool-side-effects.ts +50 -8
- package/src/export/transcript-formatter.ts +148 -0
- package/src/filing/filing-service.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +97 -7
- package/src/hooks/cli.ts +2 -2
- package/src/hooks/runner.ts +15 -38
- package/src/inbound/platform-callback-registration.ts +14 -14
- package/src/mcp/client.ts +6 -0
- package/src/mcp/mcp-oauth-provider.ts +149 -27
- package/src/memory/admin.ts +42 -75
- package/src/memory/app-store.ts +69 -0
- package/src/memory/conversation-bootstrap.ts +3 -1
- package/src/memory/conversation-crud.ts +211 -288
- package/src/memory/conversation-group-migration.ts +157 -0
- package/src/memory/conversation-queries.ts +61 -13
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/db-init.ts +194 -361
- package/src/memory/embed.ts +73 -0
- package/src/memory/embedding-backend.ts +8 -14
- package/src/memory/embedding-runtime-manager.ts +12 -114
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/graph/bootstrap.ts +521 -0
- package/src/memory/graph/capability-seed.ts +449 -0
- package/src/memory/graph/consolidation.ts +725 -0
- package/src/memory/graph/conversation-graph-memory.ts +659 -0
- package/src/memory/graph/decay.test.ts +208 -0
- package/src/memory/graph/decay.ts +195 -0
- package/src/memory/graph/extraction-job.ts +74 -0
- package/src/memory/graph/extraction.test.ts +936 -0
- package/src/memory/graph/extraction.ts +1297 -0
- package/src/memory/graph/graph-memory-state-store.ts +37 -0
- package/src/memory/graph/graph-search.ts +280 -0
- package/src/memory/graph/image-ref-utils.ts +29 -0
- package/src/memory/graph/injection.test.ts +513 -0
- package/src/memory/graph/injection.ts +469 -0
- package/src/memory/graph/inspect.ts +543 -0
- package/src/memory/graph/narrative.ts +267 -0
- package/src/memory/graph/pattern-scan.ts +269 -0
- package/src/memory/graph/retriever.ts +1111 -0
- package/src/memory/graph/scoring.test.ts +548 -0
- package/src/memory/graph/scoring.ts +232 -0
- package/src/memory/graph/serendipity.ts +65 -0
- package/src/memory/graph/store.test.ts +1098 -0
- package/src/memory/graph/store.ts +838 -0
- package/src/memory/graph/tool-handlers.ts +301 -0
- package/src/memory/graph/tools.ts +97 -0
- package/src/memory/graph/triggers.test.ts +487 -0
- package/src/memory/graph/triggers.ts +223 -0
- package/src/memory/graph/types.ts +295 -0
- package/src/memory/group-crud.ts +191 -0
- package/src/memory/indexer.ts +37 -19
- package/src/memory/job-handlers/cleanup.ts +32 -42
- package/src/memory/job-handlers/conversation-starters.ts +91 -53
- package/src/memory/job-handlers/embedding.ts +5 -31
- package/src/memory/job-handlers/index-maintenance.ts +23 -11
- package/src/memory/job-handlers/summarization.ts +32 -17
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +21 -31
- package/src/memory/jobs-worker.ts +180 -129
- package/src/memory/llm-request-log-store.ts +96 -12
- package/src/memory/memory-recall-log-store.ts +49 -5
- package/src/memory/message-content.ts +1 -0
- package/src/memory/migrations/202-memory-graph-tables.ts +130 -0
- package/src/memory/migrations/203-drop-memory-items-tables.ts +55 -0
- package/src/memory/migrations/204-rename-memory-graph-type-values.ts +46 -0
- package/src/memory/migrations/205-memory-graph-image-refs.ts +11 -0
- 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 +12 -0
- package/src/memory/migrations/registry.ts +16 -0
- package/src/memory/qdrant-client.ts +44 -17
- package/src/memory/schema/conversations.ts +14 -0
- package/src/memory/schema/index.ts +1 -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 +154 -0
- package/src/memory/search/semantic.ts +47 -91
- package/src/memory/task-memory-cleanup.ts +58 -61
- package/src/messaging/providers/outlook/adapter.ts +8 -1
- package/src/messaging/providers/outlook/client.ts +299 -0
- package/src/messaging/providers/outlook/types.ts +118 -0
- package/src/notifications/adapters/macos.ts +1 -0
- package/src/notifications/copy-composer.ts +95 -0
- package/src/notifications/decision-engine.ts +35 -0
- package/src/notifications/signal.ts +16 -0
- package/src/oauth/seed-providers.ts +2 -1
- package/src/permissions/checker.ts +36 -4
- package/src/permissions/defaults.ts +4 -4
- package/src/permissions/permission-mode-store.ts +180 -0
- package/src/permissions/permission-mode.ts +31 -0
- package/src/permissions/workspace-policy.ts +10 -1
- package/src/playbooks/playbook-compiler.ts +19 -18
- package/src/playbooks/types.ts +4 -3
- package/src/prompts/system-prompt.ts +62 -36
- package/src/prompts/templates/BOOTSTRAP-REFERENCE.md +100 -0
- package/src/prompts/templates/BOOTSTRAP.md +70 -165
- package/src/prompts/templates/HEARTBEAT.md +3 -1
- package/src/prompts/templates/SOUL.md +25 -4
- package/src/prompts/templates/UPDATES.md +8 -0
- package/src/providers/anthropic/client.ts +136 -220
- package/src/providers/gemini/client.ts +1 -1
- package/src/providers/openai/client.ts +1 -1
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +19 -3
- package/src/runtime/actor-trust-resolver.ts +5 -1
- package/src/runtime/auth/route-policy.ts +30 -0
- package/src/runtime/guardian-reply-router.ts +5 -1
- package/src/runtime/http-server.ts +55 -5
- package/src/runtime/http-types.ts +12 -1
- package/src/runtime/middleware/auth.ts +20 -0
- 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/attachment-routes.test.ts +106 -0
- package/src/runtime/routes/attachment-routes.ts +106 -16
- package/src/runtime/routes/avatar-routes.ts +2 -9
- package/src/runtime/routes/brain-graph-routes.ts +21 -22
- package/src/runtime/routes/btw-routes.ts +22 -1
- package/src/runtime/routes/conversation-analysis-routes.ts +173 -0
- package/src/runtime/routes/conversation-management-routes.ts +3 -14
- package/src/runtime/routes/conversation-query-routes.ts +49 -3
- package/src/runtime/routes/conversation-routes.ts +264 -44
- package/src/runtime/routes/conversation-starter-routes.ts +2 -2
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/global-search-routes.ts +21 -19
- package/src/runtime/routes/group-routes.ts +207 -0
- package/src/runtime/routes/guardian-action-routes.ts +21 -10
- package/src/runtime/routes/guardian-bootstrap-routes.ts +23 -19
- package/src/runtime/routes/heartbeat-routes.ts +4 -10
- package/src/runtime/routes/identity-routes.ts +53 -18
- package/src/runtime/routes/inbound-message-handler.ts +19 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +292 -0
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +207 -0
- package/src/runtime/routes/llm-context-normalization.ts +14 -10
- package/src/runtime/routes/log-export-routes.ts +23 -275
- package/src/runtime/routes/memory-item-routes.test.ts +170 -247
- package/src/runtime/routes/memory-item-routes.ts +341 -388
- 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 +28 -11
- package/src/runtime/routes/settings-routes.ts +95 -8
- package/src/runtime/routes/skills-routes.ts +103 -37
- 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/work-items-routes.test.ts +2 -6
- package/src/runtime/routes/workspace-routes.ts +0 -1
- package/src/schedule/schedule-store.ts +30 -0
- package/src/schedule/scheduler.ts +52 -18
- package/src/security/oauth2.ts +1 -1
- package/src/security/secure-keys.ts +4 -8
- package/src/shared/provider-env-vars.ts +19 -0
- package/src/skills/catalog-cache.ts +5 -0
- package/src/skills/catalog-install.ts +25 -16
- package/src/skills/clawhub.ts +134 -154
- package/src/skills/install-meta.ts +208 -0
- package/src/skills/managed-store.ts +29 -18
- package/src/skills/skill-memory.ts +12 -229
- package/src/skills/skillssh-registry.ts +19 -17
- 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 +7 -5
- package/src/telemetry/usage-telemetry-reporter.test.ts +3 -5
- package/src/tools/apps/executors.ts +29 -4
- package/src/tools/browser/runtime-check.ts +3 -1
- package/src/tools/filesystem/list.ts +93 -0
- package/src/tools/memory/register.ts +63 -46
- package/src/tools/permission-checker.ts +85 -1
- 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/shared/filesystem/errors.ts +5 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +90 -2
- package/src/tools/shared/filesystem/image-read.ts +22 -85
- package/src/tools/shared/filesystem/types.ts +17 -0
- package/src/tools/shared/shell-output.ts +31 -2
- 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 +17 -1
- package/src/tools/tool-manifest.ts +9 -3
- package/src/tools/types.ts +2 -0
- package/src/util/browser.ts +25 -10
- package/src/util/bun-runtime.ts +172 -0
- package/src/util/logger.ts +1 -1
- package/src/util/platform.ts +50 -17
- package/src/watcher/providers/outlook-calendar.ts +343 -0
- package/src/watcher/providers/outlook.ts +198 -0
- 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/025-remove-oauth-app-setup-skills.ts +76 -0
- package/src/workspace/migrations/026-backfill-install-meta.ts +325 -0
- package/src/workspace/migrations/027-remove-orphaned-optimized-images-cache.ts +42 -0
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +270 -0
- package/src/workspace/migrations/029-seed-pkb.ts +84 -0
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/top-level-renderer.ts +5 -9
- package/src/__tests__/cli-memory.test.ts +0 -372
- package/src/__tests__/clipboard.test.ts +0 -88
- package/src/__tests__/context-memory-e2e.test.ts +0 -415
- package/src/__tests__/journal-context.test.ts +0 -268
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -297
- package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -459
- package/src/__tests__/memory-query-builder.test.ts +0 -59
- package/src/__tests__/memory-recall-quality.test.ts +0 -1046
- package/src/__tests__/memory-regressions.experimental.test.ts +0 -629
- package/src/__tests__/memory-regressions.test.ts +0 -3696
- package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -295
- package/src/cli/cli-memory.ts +0 -176
- package/src/daemon/conversation-memory.ts +0 -207
- package/src/memory/conversation-starters-cadence.ts +0 -74
- package/src/memory/items-extractor.ts +0 -860
- package/src/memory/job-handlers/batch-extraction.ts +0 -753
- package/src/memory/job-handlers/extraction.ts +0 -40
- package/src/memory/job-handlers/journal-carry-forward.test.ts +0 -355
- package/src/memory/job-handlers/journal-carry-forward.ts +0 -255
- package/src/memory/journal-memory.ts +0 -224
- package/src/memory/query-builder.ts +0 -47
- package/src/memory/query-expansion.ts +0 -83
- package/src/memory/retriever.test.ts +0 -1592
- package/src/memory/retriever.ts +0 -1331
- package/src/memory/search/formatting.test.ts +0 -140
- package/src/memory/search/formatting.ts +0 -262
- package/src/memory/search/mmr.ts +0 -139
- package/src/memory/search/ranking.ts +0 -15
- package/src/memory/search/staleness.ts +0 -40
- package/src/memory/search/tier-classifier.ts +0 -18
- package/src/memory/search/types.ts +0 -121
- package/src/prompts/journal-context.ts +0 -154
- package/src/tools/memory/definitions.ts +0 -69
- package/src/tools/memory/handlers.test.ts +0 -562
- package/src/tools/memory/handlers.ts +0 -434
- package/src/util/clipboard.ts +0 -34
|
@@ -353,6 +353,15 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
353
353
|
};
|
|
354
354
|
},
|
|
355
355
|
|
|
356
|
+
"guardian.channel_activation": (payload) => {
|
|
357
|
+
const code = str(payload.verificationCode, "------");
|
|
358
|
+
const channel = str(payload.sourceChannel, "a channel");
|
|
359
|
+
return {
|
|
360
|
+
title: "Guardian Verification Code",
|
|
361
|
+
body: `Your ${channel} verification code is: ${code}\n\nEnter this code in your ${channel} chat to verify your identity as guardian.`,
|
|
362
|
+
};
|
|
363
|
+
},
|
|
364
|
+
|
|
356
365
|
"ingress.access_request": (payload) => ({
|
|
357
366
|
title: "Access Request",
|
|
358
367
|
body: buildAccessRequestContractText(payload),
|
|
@@ -399,6 +408,92 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
399
408
|
};
|
|
400
409
|
},
|
|
401
410
|
|
|
411
|
+
"ingress.trusted_contact.guardian_decision": (payload) => {
|
|
412
|
+
const decision = str(payload.decision, "decided on");
|
|
413
|
+
const sourceChannel =
|
|
414
|
+
typeof payload.sourceChannel === "string"
|
|
415
|
+
? payload.sourceChannel
|
|
416
|
+
: undefined;
|
|
417
|
+
|
|
418
|
+
const requesterDisplayName =
|
|
419
|
+
typeof payload.requesterDisplayName === "string" &&
|
|
420
|
+
payload.requesterDisplayName.length > 0
|
|
421
|
+
? payload.requesterDisplayName
|
|
422
|
+
: undefined;
|
|
423
|
+
const requesterExternalUserId =
|
|
424
|
+
typeof payload.requesterExternalUserId === "string" &&
|
|
425
|
+
payload.requesterExternalUserId.length > 0
|
|
426
|
+
? payload.requesterExternalUserId
|
|
427
|
+
: undefined;
|
|
428
|
+
const requesterLabel = sanitizeIdentityField(
|
|
429
|
+
requesterDisplayName ??
|
|
430
|
+
(sourceChannel === "slack" &&
|
|
431
|
+
requesterExternalUserId &&
|
|
432
|
+
/^U[A-Z0-9]+$/i.test(requesterExternalUserId)
|
|
433
|
+
? `<@${requesterExternalUserId}>`
|
|
434
|
+
: requesterExternalUserId) ??
|
|
435
|
+
"Someone",
|
|
436
|
+
);
|
|
437
|
+
|
|
438
|
+
const decidedByDisplayName =
|
|
439
|
+
typeof payload.decidedByDisplayName === "string" &&
|
|
440
|
+
payload.decidedByDisplayName.length > 0
|
|
441
|
+
? payload.decidedByDisplayName
|
|
442
|
+
: undefined;
|
|
443
|
+
const decidedByExternalUserId =
|
|
444
|
+
typeof payload.decidedByExternalUserId === "string" &&
|
|
445
|
+
payload.decidedByExternalUserId.length > 0
|
|
446
|
+
? payload.decidedByExternalUserId
|
|
447
|
+
: undefined;
|
|
448
|
+
const decidedByLabel = sanitizeIdentityField(
|
|
449
|
+
decidedByDisplayName ??
|
|
450
|
+
(sourceChannel === "slack" &&
|
|
451
|
+
decidedByExternalUserId &&
|
|
452
|
+
/^U[A-Z0-9]+$/i.test(decidedByExternalUserId)
|
|
453
|
+
? `<@${decidedByExternalUserId}>`
|
|
454
|
+
: decidedByExternalUserId) ??
|
|
455
|
+
"a guardian",
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
const verb = decision === "approved" ? "approved" : "denied";
|
|
459
|
+
return {
|
|
460
|
+
title: "Trusted Contact Decision",
|
|
461
|
+
body: `${requesterLabel}'s access request has been ${verb} by ${decidedByLabel}.`,
|
|
462
|
+
};
|
|
463
|
+
},
|
|
464
|
+
|
|
465
|
+
"ingress.trusted_contact.denied": (payload) => {
|
|
466
|
+
const sourceChannel =
|
|
467
|
+
typeof payload.sourceChannel === "string"
|
|
468
|
+
? payload.sourceChannel
|
|
469
|
+
: undefined;
|
|
470
|
+
|
|
471
|
+
const requesterDisplayName =
|
|
472
|
+
typeof payload.requesterDisplayName === "string" &&
|
|
473
|
+
payload.requesterDisplayName.length > 0
|
|
474
|
+
? payload.requesterDisplayName
|
|
475
|
+
: undefined;
|
|
476
|
+
const requesterExternalUserId =
|
|
477
|
+
typeof payload.requesterExternalUserId === "string" &&
|
|
478
|
+
payload.requesterExternalUserId.length > 0
|
|
479
|
+
? payload.requesterExternalUserId
|
|
480
|
+
: undefined;
|
|
481
|
+
const requesterLabel = sanitizeIdentityField(
|
|
482
|
+
requesterDisplayName ??
|
|
483
|
+
(sourceChannel === "slack" &&
|
|
484
|
+
requesterExternalUserId &&
|
|
485
|
+
/^U[A-Z0-9]+$/i.test(requesterExternalUserId)
|
|
486
|
+
? `<@${requesterExternalUserId}>`
|
|
487
|
+
: requesterExternalUserId) ??
|
|
488
|
+
"Someone",
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
return {
|
|
492
|
+
title: "Trusted Contact Denied",
|
|
493
|
+
body: `A trusted contact request from ${requesterLabel} has been denied.`,
|
|
494
|
+
};
|
|
495
|
+
},
|
|
496
|
+
|
|
402
497
|
"ingress.escalation": (payload) => ({
|
|
403
498
|
title: "Escalation",
|
|
404
499
|
body:
|
|
@@ -13,6 +13,7 @@ import { v4 as uuid } from "uuid";
|
|
|
13
13
|
|
|
14
14
|
import { getDeliverableChannels } from "../channels/config.js";
|
|
15
15
|
import { getConfig } from "../config/loader.js";
|
|
16
|
+
import { listGuardianChannels } from "../contacts/contact-store.js";
|
|
16
17
|
import { resolveGuardianPersona } from "../prompts/persona-resolver.js";
|
|
17
18
|
import { buildCoreIdentityContext } from "../prompts/system-prompt.js";
|
|
18
19
|
import {
|
|
@@ -73,6 +74,7 @@ function buildSystemPrompt(
|
|
|
73
74
|
preferenceContext?: string,
|
|
74
75
|
candidateContext?: string,
|
|
75
76
|
identityContext?: string,
|
|
77
|
+
recipientNotes?: string,
|
|
76
78
|
): string {
|
|
77
79
|
const sections: string[] = [
|
|
78
80
|
`You are a notification routing engine. Given a signal describing an event, decide whether the user should be notified, on which channel(s), and compose the notification copy.`,
|
|
@@ -89,6 +91,16 @@ function buildSystemPrompt(
|
|
|
89
91
|
);
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
if (recipientNotes) {
|
|
95
|
+
sections.push(
|
|
96
|
+
``,
|
|
97
|
+
`<recipient-context>`,
|
|
98
|
+
`The following are notes about the notification recipient. Use this context to tailor notification tone, formality, and content to the recipient's preferences.`,
|
|
99
|
+
recipientNotes,
|
|
100
|
+
`</recipient-context>`,
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
|
|
92
104
|
if (identityContext) {
|
|
93
105
|
sections.push(
|
|
94
106
|
``,
|
|
@@ -807,11 +819,34 @@ async function classifyWithLLM(
|
|
|
807
819
|
const identityContext = rawIdentityContext
|
|
808
820
|
? truncate(rawIdentityContext, MAX_IDENTITY_CONTEXT_CHARS, "\n…[truncated]")
|
|
809
821
|
: undefined;
|
|
822
|
+
|
|
823
|
+
// Resolve guardian contact notes for recipient context. Use the channel-
|
|
824
|
+
// agnostic guardian lookup so notes are available even when the only
|
|
825
|
+
// deliverable channel is "vellum" (which has no contact channel type).
|
|
826
|
+
let recipientNotes: string | undefined;
|
|
827
|
+
try {
|
|
828
|
+
const guardianResult = listGuardianChannels();
|
|
829
|
+
if (guardianResult?.contact.notes) {
|
|
830
|
+
recipientNotes = truncate(
|
|
831
|
+
guardianResult.contact.notes,
|
|
832
|
+
MAX_IDENTITY_CONTEXT_CHARS,
|
|
833
|
+
"\n…[truncated]",
|
|
834
|
+
);
|
|
835
|
+
}
|
|
836
|
+
} catch (err) {
|
|
837
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
838
|
+
log.warn(
|
|
839
|
+
{ err: errMsg },
|
|
840
|
+
"Failed to resolve guardian contact notes, proceeding without recipient context",
|
|
841
|
+
);
|
|
842
|
+
}
|
|
843
|
+
|
|
810
844
|
const systemPrompt = buildSystemPrompt(
|
|
811
845
|
availableChannels,
|
|
812
846
|
preferenceContext,
|
|
813
847
|
candidateContext,
|
|
814
848
|
identityContext,
|
|
849
|
+
recipientNotes,
|
|
815
850
|
);
|
|
816
851
|
const prompt = buildUserPrompt(signal);
|
|
817
852
|
const tool = buildDecisionTool(availableChannels);
|
|
@@ -46,6 +46,11 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
|
|
|
46
46
|
id: "guardian.question",
|
|
47
47
|
description: "Guardian approval question requiring response",
|
|
48
48
|
},
|
|
49
|
+
{
|
|
50
|
+
id: "guardian.channel_activation",
|
|
51
|
+
description:
|
|
52
|
+
"Guardian channel activation code delivered for /start verification",
|
|
53
|
+
},
|
|
49
54
|
{ id: "ingress.access_request", description: "Non-member requesting access" },
|
|
50
55
|
{
|
|
51
56
|
id: "ingress.access_request.callback_handoff",
|
|
@@ -155,9 +160,20 @@ export interface AccessRequestContextPayload {
|
|
|
155
160
|
messagePreview: string | null;
|
|
156
161
|
}
|
|
157
162
|
|
|
163
|
+
export interface GuardianChannelActivationPayload {
|
|
164
|
+
verificationCode: string;
|
|
165
|
+
sourceChannel: string;
|
|
166
|
+
actorExternalId: string;
|
|
167
|
+
actorDisplayName: string | null;
|
|
168
|
+
actorUsername: string | null;
|
|
169
|
+
sessionId: string;
|
|
170
|
+
expiresAt: number;
|
|
171
|
+
}
|
|
172
|
+
|
|
158
173
|
export interface NotificationEventContextPayloadMap {
|
|
159
174
|
"guardian.question": GuardianQuestionPayload;
|
|
160
175
|
"ingress.access_request": AccessRequestContextPayload;
|
|
176
|
+
"guardian.channel_activation": GuardianChannelActivationPayload;
|
|
161
177
|
}
|
|
162
178
|
|
|
163
179
|
export type NotificationContextPayload<TEventName extends string = string> =
|
|
@@ -90,6 +90,7 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
90
90
|
forbiddenScopes: [],
|
|
91
91
|
},
|
|
92
92
|
extraParams: { access_type: "offline", prompt: "consent" },
|
|
93
|
+
loopbackPort: 17321,
|
|
93
94
|
managedServiceConfigKey: "google-oauth",
|
|
94
95
|
injectionTemplates: [
|
|
95
96
|
{
|
|
@@ -619,6 +620,7 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
619
620
|
"Mail.Send",
|
|
620
621
|
"Calendars.Read",
|
|
621
622
|
"Calendars.ReadWrite",
|
|
623
|
+
"MailboxSettings.ReadWrite",
|
|
622
624
|
],
|
|
623
625
|
scopePolicy: {
|
|
624
626
|
allowAdditionalScopes: true,
|
|
@@ -640,7 +642,6 @@ const PROVIDER_SEED_DATA: Record<
|
|
|
640
642
|
appType: "App registration",
|
|
641
643
|
identityUrl: "https://graph.microsoft.com/v1.0/me",
|
|
642
644
|
identityResponsePaths: ["mail", "userPrincipalName"],
|
|
643
|
-
featureFlag: "outlook-oauth-integration",
|
|
644
645
|
},
|
|
645
646
|
|
|
646
647
|
// Manual-token providers: these don't use OAuth2 flows but need provider
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
|
-
import { dirname, resolve } from "node:path";
|
|
3
|
+
import { dirname, join, resolve } from "node:path";
|
|
4
4
|
|
|
5
5
|
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
6
6
|
import { getConfig } from "../config/loader.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
looksLikePathOnlyInput,
|
|
20
20
|
} from "../tools/network/url-safety.js";
|
|
21
21
|
import { getTool } from "../tools/registry.js";
|
|
22
|
-
import { getWorkspaceHooksDir } from "../util/platform.js";
|
|
22
|
+
import { getDeprecatedDir, getWorkspaceHooksDir } from "../util/platform.js";
|
|
23
23
|
import {
|
|
24
24
|
buildShellAllowlistOptions,
|
|
25
25
|
buildShellCommandCandidates,
|
|
@@ -677,7 +677,7 @@ export async function classifyRisk(
|
|
|
677
677
|
}
|
|
678
678
|
}
|
|
679
679
|
|
|
680
|
-
|
|
680
|
+
let result = await classifyRiskUncached(
|
|
681
681
|
toolName,
|
|
682
682
|
input,
|
|
683
683
|
workingDir,
|
|
@@ -685,6 +685,17 @@ export async function classifyRisk(
|
|
|
685
685
|
manifestOverride,
|
|
686
686
|
);
|
|
687
687
|
|
|
688
|
+
// Proxied bash commands route through the credential proxy which handles
|
|
689
|
+
// per-request approval separately. Cap the bash tool's own risk at Medium
|
|
690
|
+
// so trust rules can auto-allow the command execution.
|
|
691
|
+
if (
|
|
692
|
+
toolName === "bash" &&
|
|
693
|
+
input.network_mode === "proxied" &&
|
|
694
|
+
result === RiskLevel.High
|
|
695
|
+
) {
|
|
696
|
+
result = RiskLevel.Medium;
|
|
697
|
+
}
|
|
698
|
+
|
|
688
699
|
if (cacheKey) {
|
|
689
700
|
if (riskCache.size >= RISK_CACHE_MAX) {
|
|
690
701
|
const oldest = riskCache.keys().next().value;
|
|
@@ -703,7 +714,13 @@ async function classifyRiskUncached(
|
|
|
703
714
|
preParsed?: ParsedCommand,
|
|
704
715
|
manifestOverride?: ManifestOverride,
|
|
705
716
|
): Promise<RiskLevel> {
|
|
706
|
-
if (toolName === "file_read")
|
|
717
|
+
if (toolName === "file_read") {
|
|
718
|
+
const filePath = getStringField(input, "path", "file_path");
|
|
719
|
+
if (isActorTokenSigningKeyPath(filePath, workingDir)) {
|
|
720
|
+
return RiskLevel.High;
|
|
721
|
+
}
|
|
722
|
+
return RiskLevel.Low;
|
|
723
|
+
}
|
|
707
724
|
if (toolName === "file_write" || toolName === "file_edit") {
|
|
708
725
|
const filePath = getStringField(input, "path", "file_path");
|
|
709
726
|
if (
|
|
@@ -937,6 +954,21 @@ async function classifyRiskUncached(
|
|
|
937
954
|
return RiskLevel.Medium;
|
|
938
955
|
}
|
|
939
956
|
|
|
957
|
+
function isActorTokenSigningKeyPath(
|
|
958
|
+
filePath: string | undefined,
|
|
959
|
+
workingDir?: string,
|
|
960
|
+
): boolean {
|
|
961
|
+
if (!filePath) return false;
|
|
962
|
+
const cwd = workingDir ?? process.cwd();
|
|
963
|
+
const resolvedPath = resolve(cwd, filePath);
|
|
964
|
+
const signingKeyPaths = [
|
|
965
|
+
join(homedir(), ".vellum", "protected", "actor-token-signing-key"),
|
|
966
|
+
join(getDeprecatedDir(), "actor-token-signing-key"),
|
|
967
|
+
resolve(cwd, "deprecated", "actor-token-signing-key"),
|
|
968
|
+
];
|
|
969
|
+
return signingKeyPaths.includes(resolvedPath);
|
|
970
|
+
}
|
|
971
|
+
|
|
940
972
|
export async function check(
|
|
941
973
|
toolName: string,
|
|
942
974
|
input: Record<string, unknown>,
|
|
@@ -287,11 +287,11 @@ export function getDefaultRuleTemplates(): DefaultRuleTemplate[] {
|
|
|
287
287
|
}),
|
|
288
288
|
);
|
|
289
289
|
|
|
290
|
-
//
|
|
290
|
+
// recall is a read-only tool — always allow without prompting.
|
|
291
291
|
const memoryRecallRule: DefaultRuleTemplate = {
|
|
292
|
-
id: "default:allow-
|
|
293
|
-
tool: "
|
|
294
|
-
pattern: "
|
|
292
|
+
id: "default:allow-recall-global",
|
|
293
|
+
tool: "recall",
|
|
294
|
+
pattern: "recall:*",
|
|
295
295
|
scope: "everywhere",
|
|
296
296
|
decision: "allow",
|
|
297
297
|
priority: 100,
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Singleton runtime store for the two-axis permission mode.
|
|
3
|
+
*
|
|
4
|
+
* Reads initial state from the `permissions` section of config.json on
|
|
5
|
+
* initialization and persists mutations back to the config file via the
|
|
6
|
+
* raw-config read/write helpers so env-var–derived keys are never leaked
|
|
7
|
+
* to disk.
|
|
8
|
+
*
|
|
9
|
+
* Downstream consumers (e.g. SSE broadcast) register change listeners
|
|
10
|
+
* via `onModeChanged()`.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
invalidateConfigCache,
|
|
15
|
+
loadConfig,
|
|
16
|
+
loadRawConfig,
|
|
17
|
+
saveRawConfig,
|
|
18
|
+
} from "../config/loader.js";
|
|
19
|
+
import { getLogger } from "../util/logger.js";
|
|
20
|
+
import type { PermissionMode } from "./permission-mode.js";
|
|
21
|
+
import { DEFAULT_PERMISSION_MODE } from "./permission-mode.js";
|
|
22
|
+
|
|
23
|
+
const log = getLogger("permission-mode-store");
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Types
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
export type ModeChangeListener = (mode: PermissionMode) => void;
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Module-level state
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
|
|
35
|
+
let currentMode: PermissionMode = { ...DEFAULT_PERMISSION_MODE };
|
|
36
|
+
let initialized = false;
|
|
37
|
+
const listeners: ModeChangeListener[] = [];
|
|
38
|
+
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Internal helpers
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
|
|
43
|
+
function notifyListeners(): void {
|
|
44
|
+
const snapshot = { ...currentMode };
|
|
45
|
+
for (const listener of listeners) {
|
|
46
|
+
try {
|
|
47
|
+
listener(snapshot);
|
|
48
|
+
} catch (err) {
|
|
49
|
+
log.error({ err }, "Error in permission mode change listener");
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Persist the current in-memory permission mode to config.json.
|
|
56
|
+
*
|
|
57
|
+
* Uses the raw-config pattern (loadRawConfig → mutate → saveRawConfig) so
|
|
58
|
+
* that env-var–derived fields (API keys, dataDir) are never written to disk.
|
|
59
|
+
*/
|
|
60
|
+
function persistToConfig(): void {
|
|
61
|
+
try {
|
|
62
|
+
const raw = loadRawConfig();
|
|
63
|
+
|
|
64
|
+
// Ensure the permissions object exists
|
|
65
|
+
if (
|
|
66
|
+
raw.permissions == null ||
|
|
67
|
+
typeof raw.permissions !== "object" ||
|
|
68
|
+
Array.isArray(raw.permissions)
|
|
69
|
+
) {
|
|
70
|
+
raw.permissions = {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const permissions = raw.permissions as Record<string, unknown>;
|
|
74
|
+
permissions.askBeforeActing = currentMode.askBeforeActing;
|
|
75
|
+
permissions.hostAccess = currentMode.hostAccess;
|
|
76
|
+
|
|
77
|
+
saveRawConfig(raw);
|
|
78
|
+
|
|
79
|
+
// Invalidate the cached config so the next loadConfig() picks up the
|
|
80
|
+
// persisted values rather than returning stale in-memory state.
|
|
81
|
+
invalidateConfigCache();
|
|
82
|
+
} catch (err) {
|
|
83
|
+
log.error({ err }, "Failed to persist permission mode to config");
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// ---------------------------------------------------------------------------
|
|
88
|
+
// Public API
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Initialize the store from the current config. Safe to call multiple times;
|
|
93
|
+
* subsequent calls are no-ops unless `resetForTesting()` has been called.
|
|
94
|
+
*/
|
|
95
|
+
export function initPermissionModeStore(): void {
|
|
96
|
+
if (initialized) return;
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const config = loadConfig();
|
|
100
|
+
currentMode = {
|
|
101
|
+
askBeforeActing: config.permissions.askBeforeActing,
|
|
102
|
+
hostAccess: config.permissions.hostAccess,
|
|
103
|
+
};
|
|
104
|
+
} catch (err) {
|
|
105
|
+
log.warn(
|
|
106
|
+
{ err },
|
|
107
|
+
"Failed to load permission mode from config; using defaults",
|
|
108
|
+
);
|
|
109
|
+
currentMode = { ...DEFAULT_PERMISSION_MODE };
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
initialized = true;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Return the current permission mode. Initializes from config on first call
|
|
117
|
+
* if `initPermissionModeStore()` hasn't been called yet.
|
|
118
|
+
*/
|
|
119
|
+
export function getMode(): PermissionMode {
|
|
120
|
+
if (!initialized) {
|
|
121
|
+
initPermissionModeStore();
|
|
122
|
+
}
|
|
123
|
+
return { ...currentMode };
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Update the `askBeforeActing` axis. Persists to config.json and notifies
|
|
128
|
+
* change listeners.
|
|
129
|
+
*/
|
|
130
|
+
export function setAskBeforeActing(value: boolean): void {
|
|
131
|
+
if (!initialized) {
|
|
132
|
+
initPermissionModeStore();
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
if (currentMode.askBeforeActing === value) return;
|
|
136
|
+
|
|
137
|
+
currentMode.askBeforeActing = value;
|
|
138
|
+
persistToConfig();
|
|
139
|
+
notifyListeners();
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Update the `hostAccess` axis. Persists to config.json and notifies
|
|
144
|
+
* change listeners.
|
|
145
|
+
*/
|
|
146
|
+
export function setHostAccess(value: boolean): void {
|
|
147
|
+
if (!initialized) {
|
|
148
|
+
initPermissionModeStore();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (currentMode.hostAccess === value) return;
|
|
152
|
+
|
|
153
|
+
currentMode.hostAccess = value;
|
|
154
|
+
persistToConfig();
|
|
155
|
+
notifyListeners();
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Register a callback that fires whenever the permission mode changes.
|
|
160
|
+
* Returns an unsubscribe function.
|
|
161
|
+
*/
|
|
162
|
+
export function onModeChanged(callback: ModeChangeListener): () => void {
|
|
163
|
+
listeners.push(callback);
|
|
164
|
+
return () => {
|
|
165
|
+
const idx = listeners.indexOf(callback);
|
|
166
|
+
if (idx >= 0) {
|
|
167
|
+
listeners.splice(idx, 1);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Reset the store to uninitialized state. **Test-only** — production code
|
|
174
|
+
* should never call this.
|
|
175
|
+
*/
|
|
176
|
+
export function resetForTesting(): void {
|
|
177
|
+
currentMode = { ...DEFAULT_PERMISSION_MODE };
|
|
178
|
+
initialized = false;
|
|
179
|
+
listeners.length = 0;
|
|
180
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Two-axis permission model:
|
|
5
|
+
* - `askBeforeActing` — LLM behavior toggle: when true the assistant checks in
|
|
6
|
+
* with the user before taking actions.
|
|
7
|
+
* - `hostAccess` — System-enforced gate: when true the assistant can execute
|
|
8
|
+
* commands on the host machine without prompting.
|
|
9
|
+
*/
|
|
10
|
+
export type PermissionMode = {
|
|
11
|
+
askBeforeActing: boolean;
|
|
12
|
+
hostAccess: boolean;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const DEFAULT_PERMISSION_MODE: PermissionMode = {
|
|
16
|
+
askBeforeActing: true,
|
|
17
|
+
hostAccess: false,
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const PermissionModeSchema = z.object({
|
|
21
|
+
askBeforeActing: z
|
|
22
|
+
.boolean({ error: "permissionMode.askBeforeActing must be a boolean" })
|
|
23
|
+
.default(true)
|
|
24
|
+
.describe("Whether the assistant should check in before taking actions"),
|
|
25
|
+
hostAccess: z
|
|
26
|
+
.boolean({ error: "permissionMode.hostAccess must be a boolean" })
|
|
27
|
+
.default(false)
|
|
28
|
+
.describe(
|
|
29
|
+
"Whether the assistant can execute commands on the host machine without prompting",
|
|
30
|
+
),
|
|
31
|
+
});
|
|
@@ -74,12 +74,21 @@ const HOST_TOOLS = new Set([
|
|
|
74
74
|
"host_file_write",
|
|
75
75
|
"host_file_edit",
|
|
76
76
|
"host_bash",
|
|
77
|
+
"computer_use_run_applescript",
|
|
77
78
|
]);
|
|
78
79
|
|
|
80
|
+
/**
|
|
81
|
+
* Check whether a tool name is a host-level tool that requires the
|
|
82
|
+
* `hostAccess` permission to execute.
|
|
83
|
+
*/
|
|
84
|
+
export function isHostTool(toolName: string): boolean {
|
|
85
|
+
return HOST_TOOLS.has(toolName);
|
|
86
|
+
}
|
|
87
|
+
|
|
79
88
|
/** Safe local-only tools that are always workspace-scoped. */
|
|
80
89
|
const ALWAYS_SCOPED_TOOLS = new Set([
|
|
81
90
|
"skill_load",
|
|
82
|
-
"
|
|
91
|
+
"recall",
|
|
83
92
|
"ui_update",
|
|
84
93
|
"ui_dismiss",
|
|
85
94
|
]);
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Compile all active playbook
|
|
2
|
+
* Compile all active playbook graph nodes into a triage context block
|
|
3
3
|
* that can be injected into the system prompt alongside the contact
|
|
4
4
|
* graph.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { and,
|
|
7
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
8
8
|
|
|
9
9
|
import { getDb } from "../memory/db.js";
|
|
10
|
-
import {
|
|
10
|
+
import { memoryGraphNodes } from "../memory/schema.js";
|
|
11
11
|
import type { Playbook } from "./types.js";
|
|
12
12
|
import { parsePlaybookStatement } from "./types.js";
|
|
13
13
|
|
|
14
14
|
export interface CompiledPlaybooks {
|
|
15
15
|
/** Formatted text block ready for system prompt injection. */
|
|
16
16
|
text: string;
|
|
17
|
-
/** Total number of active playbook
|
|
17
|
+
/** Total number of active playbook nodes found. */
|
|
18
18
|
totalCount: number;
|
|
19
19
|
/** Number of playbooks successfully parsed and included. */
|
|
20
20
|
includedCount: number;
|
|
@@ -26,8 +26,7 @@ export interface CompilePlaybooksOptions {
|
|
|
26
26
|
|
|
27
27
|
interface PlaybookRow {
|
|
28
28
|
id: string;
|
|
29
|
-
|
|
30
|
-
statement: string;
|
|
29
|
+
content: string;
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
export function compilePlaybooks(
|
|
@@ -38,31 +37,33 @@ export function compilePlaybooks(
|
|
|
38
37
|
|
|
39
38
|
const rows: PlaybookRow[] = db
|
|
40
39
|
.select({
|
|
41
|
-
id:
|
|
42
|
-
|
|
43
|
-
statement: memoryItems.statement,
|
|
40
|
+
id: memoryGraphNodes.id,
|
|
41
|
+
content: memoryGraphNodes.content,
|
|
44
42
|
})
|
|
45
|
-
.from(
|
|
43
|
+
.from(memoryGraphNodes)
|
|
46
44
|
.where(
|
|
47
45
|
and(
|
|
48
|
-
eq(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
isNull(memoryItems.invalidAt),
|
|
46
|
+
eq(memoryGraphNodes.scopeId, scopeId),
|
|
47
|
+
sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'`,
|
|
48
|
+
sql`${memoryGraphNodes.fidelity} != 'gone'`,
|
|
52
49
|
),
|
|
53
50
|
)
|
|
54
|
-
.orderBy(
|
|
51
|
+
.orderBy(sql`${memoryGraphNodes.significance} DESC`)
|
|
55
52
|
.all();
|
|
56
53
|
|
|
57
54
|
if (rows.length === 0) {
|
|
58
55
|
return { text: "", totalCount: 0, includedCount: 0 };
|
|
59
56
|
}
|
|
60
57
|
|
|
61
|
-
const parsed: Array<{ id: string;
|
|
58
|
+
const parsed: Array<{ id: string; playbook: Playbook }> = [];
|
|
62
59
|
for (const row of rows) {
|
|
63
|
-
|
|
60
|
+
// Content format: "Playbook: <trigger>\n<json statement>"
|
|
61
|
+
const newlineIdx = row.content.indexOf("\n");
|
|
62
|
+
if (newlineIdx === -1) continue;
|
|
63
|
+
const statement = row.content.slice(newlineIdx + 1);
|
|
64
|
+
const playbook = parsePlaybookStatement(statement);
|
|
64
65
|
if (playbook) {
|
|
65
|
-
parsed.push({ id: row.id,
|
|
66
|
+
parsed.push({ id: row.id, playbook });
|
|
66
67
|
}
|
|
67
68
|
}
|
|
68
69
|
|
package/src/playbooks/types.ts
CHANGED
|
@@ -2,9 +2,10 @@
|
|
|
2
2
|
* Action Playbook — a structured trigger→action rule that tells the
|
|
3
3
|
* triage engine how to handle incoming messages matching a pattern.
|
|
4
4
|
*
|
|
5
|
-
* Playbooks are stored as
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Playbooks are stored as memory_graph_nodes with
|
|
6
|
+
* sourceConversations containing a "playbook:{nodeId}" entry. The
|
|
7
|
+
* content column holds "Playbook: <trigger>\n<json>" where the JSON
|
|
8
|
+
* encodes the structured fields below.
|
|
8
9
|
*/
|
|
9
10
|
|
|
10
11
|
export interface Playbook {
|