@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
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
ToolContext,
|
|
3
|
+
ToolExecutionResult,
|
|
4
|
+
} from "../../../../tools/types.js";
|
|
5
|
+
import * as calendar from "../calendar-client.js";
|
|
6
|
+
import { getCalendarConnection, ok } from "./shared.js";
|
|
7
|
+
|
|
8
|
+
export async function run(
|
|
9
|
+
input: Record<string, unknown>,
|
|
10
|
+
_context: ToolContext,
|
|
11
|
+
): Promise<ToolExecutionResult> {
|
|
12
|
+
const account = input.account as string | undefined;
|
|
13
|
+
const eventId = input.event_id as string;
|
|
14
|
+
const response = input.response as "accepted" | "declined" | "tentative";
|
|
15
|
+
|
|
16
|
+
const connection = await getCalendarConnection(account);
|
|
17
|
+
|
|
18
|
+
// Fetch the event to get context for the response message
|
|
19
|
+
const event = await calendar.getEvent(connection, eventId);
|
|
20
|
+
|
|
21
|
+
// If the user is the organizer, no RSVP is needed
|
|
22
|
+
if (event.responseStatus?.response === "organizer") {
|
|
23
|
+
return ok("You are the organizer of this event. No RSVP needed.");
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
// Send RSVP via the dedicated Microsoft Graph endpoint, notifying the organizer
|
|
27
|
+
await calendar.rsvpEvent(connection, eventId, response, true);
|
|
28
|
+
|
|
29
|
+
const responseLabel =
|
|
30
|
+
response === "accepted"
|
|
31
|
+
? "Accepted"
|
|
32
|
+
: response === "declined"
|
|
33
|
+
? "Declined"
|
|
34
|
+
: "Tentatively accepted";
|
|
35
|
+
return ok(`${responseLabel} the event "${event.subject ?? eventId}".`);
|
|
36
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OAuthConnection } from "../../../../oauth/connection.js";
|
|
2
|
+
import { resolveOAuthConnection } from "../../../../oauth/connection-resolver.js";
|
|
3
|
+
import type { ToolExecutionResult } from "../../../../tools/types.js";
|
|
4
|
+
|
|
5
|
+
export function ok(content: string): ToolExecutionResult {
|
|
6
|
+
return { content, isError: false };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function err(message: string): ToolExecutionResult {
|
|
10
|
+
return { content: message, isError: true };
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export async function getCalendarConnection(
|
|
14
|
+
account?: string,
|
|
15
|
+
): Promise<OAuthConnection> {
|
|
16
|
+
return resolveOAuthConnection("outlook", { account });
|
|
17
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/** Microsoft Graph date+time pair. timeZone may be omitted when dateTime carries an offset. */
|
|
2
|
+
export interface OutlookDateTimeZone {
|
|
3
|
+
dateTime: string;
|
|
4
|
+
timeZone?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/** Attendee on a calendar event. */
|
|
8
|
+
export interface OutlookCalendarAttendee {
|
|
9
|
+
emailAddress: { address: string; name?: string };
|
|
10
|
+
type: "required" | "optional" | "resource";
|
|
11
|
+
status?: {
|
|
12
|
+
response:
|
|
13
|
+
| "none"
|
|
14
|
+
| "organizer"
|
|
15
|
+
| "tentativelyAccepted"
|
|
16
|
+
| "accepted"
|
|
17
|
+
| "declined"
|
|
18
|
+
| "notResponded";
|
|
19
|
+
time?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** Physical or virtual location for a calendar event. */
|
|
24
|
+
export interface OutlookLocation {
|
|
25
|
+
displayName?: string;
|
|
26
|
+
locationType?: string;
|
|
27
|
+
address?: Record<string, unknown>;
|
|
28
|
+
coordinates?: Record<string, unknown>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Rich-text body of a calendar item. */
|
|
32
|
+
export interface OutlookItemBody {
|
|
33
|
+
contentType: "text" | "html";
|
|
34
|
+
content: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A single calendar event from Microsoft Graph. */
|
|
38
|
+
export interface OutlookCalendarEvent {
|
|
39
|
+
id: string;
|
|
40
|
+
subject?: string;
|
|
41
|
+
bodyPreview?: string;
|
|
42
|
+
body?: OutlookItemBody;
|
|
43
|
+
start?: OutlookDateTimeZone;
|
|
44
|
+
end?: OutlookDateTimeZone;
|
|
45
|
+
location?: OutlookLocation;
|
|
46
|
+
locations?: OutlookLocation[];
|
|
47
|
+
attendees?: OutlookCalendarAttendee[];
|
|
48
|
+
organizer?: { emailAddress: { address: string; name?: string } };
|
|
49
|
+
isAllDay?: boolean;
|
|
50
|
+
isCancelled?: boolean;
|
|
51
|
+
showAs?:
|
|
52
|
+
| "free"
|
|
53
|
+
| "tentative"
|
|
54
|
+
| "busy"
|
|
55
|
+
| "oof"
|
|
56
|
+
| "workingElsewhere"
|
|
57
|
+
| "unknown";
|
|
58
|
+
importance?: "low" | "normal" | "high";
|
|
59
|
+
sensitivity?: "normal" | "personal" | "private" | "confidential";
|
|
60
|
+
webLink?: string;
|
|
61
|
+
onlineMeetingUrl?: string;
|
|
62
|
+
createdDateTime?: string;
|
|
63
|
+
lastModifiedDateTime?: string;
|
|
64
|
+
seriesMasterId?: string;
|
|
65
|
+
type?: "singleInstance" | "occurrence" | "exception" | "seriesMaster";
|
|
66
|
+
categories?: string[];
|
|
67
|
+
responseStatus?: { response: string; time?: string };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Paginated list of calendar events. */
|
|
71
|
+
export interface OutlookCalendarEventListResponse {
|
|
72
|
+
value?: OutlookCalendarEvent[];
|
|
73
|
+
"@odata.nextLink"?: string;
|
|
74
|
+
"@odata.deltaLink"?: string;
|
|
75
|
+
"@odata.count"?: number;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** A single schedule item (free/busy block). */
|
|
79
|
+
export interface OutlookScheduleItem {
|
|
80
|
+
status:
|
|
81
|
+
| "free"
|
|
82
|
+
| "tentative"
|
|
83
|
+
| "busy"
|
|
84
|
+
| "oof"
|
|
85
|
+
| "workingElsewhere"
|
|
86
|
+
| "unknown";
|
|
87
|
+
start: OutlookDateTimeZone;
|
|
88
|
+
end: OutlookDateTimeZone;
|
|
89
|
+
subject?: string;
|
|
90
|
+
location?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/** Schedule information for one user. */
|
|
94
|
+
export interface OutlookScheduleInformation {
|
|
95
|
+
scheduleId: string;
|
|
96
|
+
availabilityView: string;
|
|
97
|
+
scheduleItems: OutlookScheduleItem[];
|
|
98
|
+
error?: Record<string, unknown>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Response from the getSchedule endpoint. */
|
|
102
|
+
export interface OutlookScheduleResponse {
|
|
103
|
+
value?: OutlookScheduleInformation[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** A calendar in the user's mailbox. */
|
|
107
|
+
export interface OutlookCalendar {
|
|
108
|
+
id: string;
|
|
109
|
+
name?: string;
|
|
110
|
+
color?: string;
|
|
111
|
+
isDefaultCalendar?: boolean;
|
|
112
|
+
canEdit?: boolean;
|
|
113
|
+
owner?: { name: string; address: string };
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Paginated list of calendars. */
|
|
117
|
+
export interface OutlookCalendarListResponse {
|
|
118
|
+
value?: OutlookCalendar[];
|
|
119
|
+
"@odata.nextLink"?: string;
|
|
120
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { v4 as uuid } from "uuid";
|
|
1
|
+
import { sql } from "drizzle-orm";
|
|
3
2
|
|
|
4
3
|
import { getDb } from "../../../../memory/db.js";
|
|
5
|
-
import {
|
|
4
|
+
import { createNode, updateNode } from "../../../../memory/graph/store.js";
|
|
5
|
+
import type { NewNode } from "../../../../memory/graph/types.js";
|
|
6
6
|
import { enqueueMemoryJob } from "../../../../memory/jobs-store.js";
|
|
7
|
-
import {
|
|
7
|
+
import { memoryGraphNodes } from "../../../../memory/schema.js";
|
|
8
8
|
import type {
|
|
9
9
|
Playbook,
|
|
10
10
|
PlaybookAutonomyLevel,
|
|
@@ -13,7 +13,6 @@ import type {
|
|
|
13
13
|
ToolContext,
|
|
14
14
|
ToolExecutionResult,
|
|
15
15
|
} from "../../../../tools/types.js";
|
|
16
|
-
import { truncate } from "../../../../util/truncate.js";
|
|
17
16
|
|
|
18
17
|
const VALID_AUTONOMY_LEVELS = new Set<string>(["auto", "draft", "notify"]);
|
|
19
18
|
|
|
@@ -56,27 +55,23 @@ export async function executePlaybookCreate(
|
|
|
56
55
|
priority,
|
|
57
56
|
};
|
|
58
57
|
const statement = JSON.stringify(playbook);
|
|
59
|
-
const
|
|
58
|
+
const sanitizedTrigger = trigger.replace(/[\r\n]+/g, " ");
|
|
59
|
+
const subject = `Playbook: ${sanitizedTrigger}`.slice(0, 80);
|
|
60
|
+
const content = `${subject}\n${statement}`;
|
|
60
61
|
const scopeId = context.memoryScopeId ?? "default";
|
|
61
62
|
|
|
62
|
-
const fingerprint = computeMemoryFingerprint(
|
|
63
|
-
scopeId,
|
|
64
|
-
"playbook",
|
|
65
|
-
subject,
|
|
66
|
-
statement,
|
|
67
|
-
);
|
|
68
|
-
|
|
69
63
|
try {
|
|
70
64
|
const db = getDb();
|
|
71
65
|
|
|
66
|
+
// Check for duplicate by matching content in playbook-prefixed graph nodes
|
|
72
67
|
const existing = db
|
|
73
|
-
.select()
|
|
74
|
-
.from(
|
|
68
|
+
.select({ id: memoryGraphNodes.id })
|
|
69
|
+
.from(memoryGraphNodes)
|
|
75
70
|
.where(
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
71
|
+
sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'
|
|
72
|
+
AND ${memoryGraphNodes.content} = ${content}
|
|
73
|
+
AND ${memoryGraphNodes.scopeId} = ${scopeId}
|
|
74
|
+
AND ${memoryGraphNodes.fidelity} != 'gone'`,
|
|
80
75
|
)
|
|
81
76
|
.get();
|
|
82
77
|
|
|
@@ -87,29 +82,41 @@ export async function executePlaybookCreate(
|
|
|
87
82
|
};
|
|
88
83
|
}
|
|
89
84
|
|
|
90
|
-
const id = uuid();
|
|
91
85
|
const now = Date.now();
|
|
86
|
+
const newNode: NewNode = {
|
|
87
|
+
content,
|
|
88
|
+
type: "semantic",
|
|
89
|
+
created: now,
|
|
90
|
+
lastAccessed: now,
|
|
91
|
+
lastConsolidated: now,
|
|
92
|
+
eventDate: null,
|
|
93
|
+
emotionalCharge: {
|
|
94
|
+
valence: 0,
|
|
95
|
+
intensity: 0.1,
|
|
96
|
+
decayCurve: "linear",
|
|
97
|
+
decayRate: 0.05,
|
|
98
|
+
originalIntensity: 0.1,
|
|
99
|
+
},
|
|
100
|
+
fidelity: "vivid",
|
|
101
|
+
confidence: 0.95,
|
|
102
|
+
significance: 0.8,
|
|
103
|
+
stability: 14,
|
|
104
|
+
reinforcementCount: 0,
|
|
105
|
+
lastReinforced: now,
|
|
106
|
+
sourceConversations: [],
|
|
107
|
+
sourceType: "direct",
|
|
108
|
+
narrativeRole: null,
|
|
109
|
+
partOfStory: null,
|
|
110
|
+
imageRefs: null,
|
|
111
|
+
scopeId,
|
|
112
|
+
};
|
|
92
113
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
subject,
|
|
98
|
-
statement,
|
|
99
|
-
status: "active",
|
|
100
|
-
confidence: 0.95,
|
|
101
|
-
importance: 0.8,
|
|
102
|
-
fingerprint,
|
|
103
|
-
sourceType: "tool",
|
|
104
|
-
verificationState: "user_confirmed",
|
|
105
|
-
scopeId,
|
|
106
|
-
firstSeenAt: now,
|
|
107
|
-
lastSeenAt: now,
|
|
108
|
-
lastUsedAt: null,
|
|
109
|
-
})
|
|
110
|
-
.run();
|
|
114
|
+
const node = createNode(newNode);
|
|
115
|
+
updateNode(node.id, {
|
|
116
|
+
sourceConversations: [`playbook:${node.id}`],
|
|
117
|
+
});
|
|
111
118
|
|
|
112
|
-
enqueueMemoryJob("
|
|
119
|
+
enqueueMemoryJob("embed_graph_node", { nodeId: node.id });
|
|
113
120
|
|
|
114
121
|
const autonomyLabel =
|
|
115
122
|
autonomyLevel === "auto"
|
|
@@ -121,7 +128,7 @@ export async function executePlaybookCreate(
|
|
|
121
128
|
return {
|
|
122
129
|
content: [
|
|
123
130
|
"Playbook created successfully.",
|
|
124
|
-
` ID: ${id}`,
|
|
131
|
+
` ID: ${node.id}`,
|
|
125
132
|
` Trigger: ${trigger}`,
|
|
126
133
|
` Channel: ${channel}`,
|
|
127
134
|
` Category: ${category}`,
|
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import { getDb } from "../../../../memory/db.js";
|
|
4
|
-
import { memoryItems } from "../../../../memory/schema.js";
|
|
1
|
+
import { getNode, updateNode } from "../../../../memory/graph/store.js";
|
|
5
2
|
import { parsePlaybookStatement } from "../../../../playbooks/types.js";
|
|
6
3
|
import type {
|
|
7
4
|
ToolContext,
|
|
@@ -23,38 +20,28 @@ export async function executePlaybookDelete(
|
|
|
23
20
|
const scopeId = context.memoryScopeId ?? "default";
|
|
24
21
|
|
|
25
22
|
try {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.
|
|
30
|
-
.
|
|
31
|
-
.
|
|
32
|
-
|
|
33
|
-
eq(memoryItems.id, playbookId),
|
|
34
|
-
eq(memoryItems.kind, "playbook"),
|
|
35
|
-
eq(memoryItems.scopeId, scopeId),
|
|
36
|
-
),
|
|
37
|
-
)
|
|
38
|
-
.get();
|
|
39
|
-
|
|
40
|
-
if (!existing) {
|
|
23
|
+
const existing = getNode(playbookId);
|
|
24
|
+
if (
|
|
25
|
+
!existing ||
|
|
26
|
+
existing.scopeId !== scopeId ||
|
|
27
|
+
!existing.sourceConversations.some((s) => s.startsWith("playbook:")) ||
|
|
28
|
+
existing.fidelity === "gone"
|
|
29
|
+
) {
|
|
41
30
|
return {
|
|
42
31
|
content: `Error: Playbook with ID "${playbookId}" not found`,
|
|
43
32
|
isError: true,
|
|
44
33
|
};
|
|
45
34
|
}
|
|
46
35
|
|
|
47
|
-
|
|
48
|
-
const
|
|
36
|
+
// Extract trigger label from content
|
|
37
|
+
const newlineIdx = existing.content.indexOf("\n");
|
|
38
|
+
const statement =
|
|
39
|
+
newlineIdx !== -1 ? existing.content.slice(newlineIdx + 1) : "";
|
|
40
|
+
const playbook = parsePlaybookStatement(statement);
|
|
41
|
+
const triggerLabel = playbook?.trigger ?? existing.content.split("\n")[0];
|
|
49
42
|
|
|
50
|
-
// Soft-delete by
|
|
51
|
-
|
|
52
|
-
// Setting invalidAt so the cleanup job can eventually hard-delete it.
|
|
53
|
-
const now = Date.now();
|
|
54
|
-
db.update(memoryItems)
|
|
55
|
-
.set({ status: "superseded", invalidAt: now })
|
|
56
|
-
.where(eq(memoryItems.id, existing.id))
|
|
57
|
-
.run();
|
|
43
|
+
// Soft-delete by setting fidelity to "gone"
|
|
44
|
+
updateNode(existing.id, { fidelity: "gone" });
|
|
58
45
|
|
|
59
46
|
return {
|
|
60
47
|
content: `Playbook deleted (ID: ${existing.id}, trigger: "${triggerLabel}").`,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { and,
|
|
1
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
2
2
|
|
|
3
3
|
import { getDb } from "../../../../memory/db.js";
|
|
4
|
-
import {
|
|
4
|
+
import { memoryGraphNodes } from "../../../../memory/schema.js";
|
|
5
5
|
import { parsePlaybookStatement } from "../../../../playbooks/types.js";
|
|
6
6
|
import type {
|
|
7
7
|
ToolContext,
|
|
@@ -23,22 +23,20 @@ export async function executePlaybookList(
|
|
|
23
23
|
|
|
24
24
|
const rows = db
|
|
25
25
|
.select({
|
|
26
|
-
id:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
lastSeenAt: memoryItems.lastSeenAt,
|
|
26
|
+
id: memoryGraphNodes.id,
|
|
27
|
+
content: memoryGraphNodes.content,
|
|
28
|
+
significance: memoryGraphNodes.significance,
|
|
29
|
+
lastAccessed: memoryGraphNodes.lastAccessed,
|
|
31
30
|
})
|
|
32
|
-
.from(
|
|
31
|
+
.from(memoryGraphNodes)
|
|
33
32
|
.where(
|
|
34
33
|
and(
|
|
35
|
-
eq(
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
isNull(memoryItems.invalidAt),
|
|
34
|
+
eq(memoryGraphNodes.scopeId, scopeId),
|
|
35
|
+
sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'`,
|
|
36
|
+
sql`${memoryGraphNodes.fidelity} != 'gone'`,
|
|
39
37
|
),
|
|
40
38
|
)
|
|
41
|
-
.orderBy(
|
|
39
|
+
.orderBy(sql`${memoryGraphNodes.significance} DESC`)
|
|
42
40
|
.all();
|
|
43
41
|
|
|
44
42
|
if (rows.length === 0) {
|
|
@@ -47,12 +45,14 @@ export async function executePlaybookList(
|
|
|
47
45
|
|
|
48
46
|
const entries: Array<{
|
|
49
47
|
id: string;
|
|
50
|
-
subject: string;
|
|
51
|
-
statement: string;
|
|
52
48
|
playbook: NonNullable<ReturnType<typeof parsePlaybookStatement>>;
|
|
53
49
|
}> = [];
|
|
54
50
|
for (const row of rows) {
|
|
55
|
-
|
|
51
|
+
// Content format: "Playbook: <trigger>\n<json statement>"
|
|
52
|
+
const newlineIdx = row.content.indexOf("\n");
|
|
53
|
+
if (newlineIdx === -1) continue;
|
|
54
|
+
const statement = row.content.slice(newlineIdx + 1);
|
|
55
|
+
const playbook = parsePlaybookStatement(statement);
|
|
56
56
|
if (!playbook) continue;
|
|
57
57
|
|
|
58
58
|
// Apply filters
|
|
@@ -66,8 +66,6 @@ export async function executePlaybookList(
|
|
|
66
66
|
|
|
67
67
|
entries.push({
|
|
68
68
|
id: row.id,
|
|
69
|
-
subject: row.subject,
|
|
70
|
-
statement: row.statement,
|
|
71
69
|
playbook,
|
|
72
70
|
});
|
|
73
71
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { and, eq } from "drizzle-orm";
|
|
1
|
+
import { and, eq, sql } from "drizzle-orm";
|
|
2
2
|
|
|
3
3
|
import { getDb } from "../../../../memory/db.js";
|
|
4
|
-
import {
|
|
4
|
+
import { getNode, updateNode } from "../../../../memory/graph/store.js";
|
|
5
5
|
import { enqueueMemoryJob } from "../../../../memory/jobs-store.js";
|
|
6
|
-
import {
|
|
6
|
+
import { memoryGraphNodes } from "../../../../memory/schema.js";
|
|
7
7
|
import type {
|
|
8
8
|
Playbook,
|
|
9
9
|
PlaybookAutonomyLevel,
|
|
@@ -13,7 +13,6 @@ import type {
|
|
|
13
13
|
ToolContext,
|
|
14
14
|
ToolExecutionResult,
|
|
15
15
|
} from "../../../../tools/types.js";
|
|
16
|
-
import { truncate } from "../../../../util/truncate.js";
|
|
17
16
|
|
|
18
17
|
const VALID_AUTONOMY_LEVELS = new Set<string>(["auto", "draft", "notify"]);
|
|
19
18
|
|
|
@@ -32,28 +31,29 @@ export async function executePlaybookUpdate(
|
|
|
32
31
|
const scopeId = context.memoryScopeId ?? "default";
|
|
33
32
|
|
|
34
33
|
try {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
.
|
|
39
|
-
.
|
|
40
|
-
.
|
|
41
|
-
|
|
42
|
-
eq(memoryItems.id, playbookId),
|
|
43
|
-
eq(memoryItems.kind, "playbook"),
|
|
44
|
-
eq(memoryItems.scopeId, scopeId),
|
|
45
|
-
),
|
|
46
|
-
)
|
|
47
|
-
.get();
|
|
48
|
-
|
|
49
|
-
if (!existing) {
|
|
34
|
+
const existing = getNode(playbookId);
|
|
35
|
+
if (
|
|
36
|
+
!existing ||
|
|
37
|
+
existing.scopeId !== scopeId ||
|
|
38
|
+
!existing.sourceConversations.some((s) => s.startsWith("playbook:")) ||
|
|
39
|
+
existing.fidelity === "gone"
|
|
40
|
+
) {
|
|
50
41
|
return {
|
|
51
42
|
content: `Error: Playbook with ID "${playbookId}" not found`,
|
|
52
43
|
isError: true,
|
|
53
44
|
};
|
|
54
45
|
}
|
|
55
46
|
|
|
56
|
-
|
|
47
|
+
// Extract the JSON statement from the content (after the first newline)
|
|
48
|
+
const newlineIdx = existing.content.indexOf("\n");
|
|
49
|
+
if (newlineIdx === -1) {
|
|
50
|
+
return {
|
|
51
|
+
content: `Error: Playbook data is corrupted for ID "${playbookId}"`,
|
|
52
|
+
isError: true,
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
const currentStatement = existing.content.slice(newlineIdx + 1);
|
|
56
|
+
const currentPlaybook = parsePlaybookStatement(currentStatement);
|
|
57
57
|
if (!currentPlaybook) {
|
|
58
58
|
return {
|
|
59
59
|
content: `Error: Playbook data is corrupted for ID "${playbookId}"`,
|
|
@@ -91,47 +91,39 @@ export async function executePlaybookUpdate(
|
|
|
91
91
|
};
|
|
92
92
|
|
|
93
93
|
const statement = JSON.stringify(updated);
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
const fingerprint = computeMemoryFingerprint(
|
|
98
|
-
scopeId,
|
|
99
|
-
"playbook",
|
|
100
|
-
subject,
|
|
101
|
-
statement,
|
|
102
|
-
);
|
|
94
|
+
const sanitizedTrigger = updated.trigger.replace(/[\r\n]+/g, " ");
|
|
95
|
+
const subject = `Playbook: ${sanitizedTrigger}`.slice(0, 80);
|
|
96
|
+
const content = `${subject}\n${statement}`;
|
|
103
97
|
|
|
104
|
-
// Check
|
|
98
|
+
// Check for duplicate content among other playbook nodes
|
|
99
|
+
const db = getDb();
|
|
105
100
|
const collision = db
|
|
106
|
-
.select({ id:
|
|
107
|
-
.from(
|
|
101
|
+
.select({ id: memoryGraphNodes.id })
|
|
102
|
+
.from(memoryGraphNodes)
|
|
108
103
|
.where(
|
|
109
104
|
and(
|
|
110
|
-
eq(
|
|
111
|
-
|
|
105
|
+
eq(memoryGraphNodes.scopeId, scopeId),
|
|
106
|
+
sql`${memoryGraphNodes.sourceConversations} LIKE '%playbook:%'`,
|
|
107
|
+
eq(memoryGraphNodes.content, content),
|
|
108
|
+
sql`${memoryGraphNodes.fidelity} != 'gone'`,
|
|
109
|
+
sql`${memoryGraphNodes.id} != ${existing.id}`,
|
|
112
110
|
),
|
|
113
111
|
)
|
|
114
112
|
.get();
|
|
115
|
-
|
|
113
|
+
|
|
114
|
+
if (collision) {
|
|
116
115
|
return {
|
|
117
116
|
content: `Error: Another playbook with this exact configuration already exists (ID: ${collision.id}).`,
|
|
118
117
|
isError: true,
|
|
119
118
|
};
|
|
120
119
|
}
|
|
121
120
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
fingerprint,
|
|
127
|
-
lastSeenAt: now,
|
|
128
|
-
sourceType: "tool",
|
|
129
|
-
verificationState: "user_confirmed",
|
|
130
|
-
})
|
|
131
|
-
.where(eq(memoryItems.id, existing.id))
|
|
132
|
-
.run();
|
|
121
|
+
updateNode(existing.id, {
|
|
122
|
+
content,
|
|
123
|
+
lastAccessed: Date.now(),
|
|
124
|
+
});
|
|
133
125
|
|
|
134
|
-
enqueueMemoryJob("
|
|
126
|
+
enqueueMemoryJob("embed_graph_node", { nodeId: existing.id });
|
|
135
127
|
|
|
136
128
|
const autonomyLabel =
|
|
137
129
|
updated.autonomyLevel === "auto"
|
|
@@ -87,6 +87,14 @@ The `mode` parameter controls what happens when a schedule fires:
|
|
|
87
87
|
|
|
88
88
|
Use `notify` for simple reminders ("remind me to take medicine at 9am") and `execute` for tasks that need assistant action ("check my calendar at 8am and send me a digest").
|
|
89
89
|
|
|
90
|
+
## Conversation Reuse
|
|
91
|
+
|
|
92
|
+
By default, each schedule run creates a new conversation. For recurring schedules that benefit from accumulating context across runs (e.g. polling-style jobs, daily digests that reference prior results), set `reuse_conversation: true`. When enabled, subsequent runs reuse the conversation from the last successful run instead of creating a new one.
|
|
93
|
+
|
|
94
|
+
- Only applies to **recurring** schedules; ignored for one-shot schedules.
|
|
95
|
+
- If the prior conversation has been deleted, a new one is created automatically.
|
|
96
|
+
- On the first run (no prior conversation), a new conversation is created as usual.
|
|
97
|
+
|
|
90
98
|
## Routing (notify mode)
|
|
91
99
|
|
|
92
100
|
Control how notify-mode schedules are delivered at trigger time with `routing_intent`:
|
|
@@ -101,9 +109,20 @@ Optionally pass `routing_hints` (a JSON object) to influence routing decisions (
|
|
|
101
109
|
|
|
102
110
|
- **Default to `all_channels`** for most notifications. Users usually want to be notified wherever they are.
|
|
103
111
|
- **Use `single_channel`** only when the user explicitly specifies a single channel (e.g. "remind me on Telegram").
|
|
104
|
-
- **
|
|
112
|
+
- **Determine the originating channel** for routing hints using this priority:
|
|
113
|
+
1. **`source_channel`** from `<turn_context>` — use directly if present. This is the authoritative channel name.
|
|
114
|
+
2. **`interface` fallback** — if `source_channel` is absent (common for guardian/direct users), map the `interface` value to a channel name:
|
|
115
|
+
| `interface` value | Channel name |
|
|
116
|
+
| --- | --- |
|
|
117
|
+
| `macos`, `ios` | `vellum` |
|
|
118
|
+
| `telegram` | `telegram` |
|
|
119
|
+
| `slack` | `slack` |
|
|
120
|
+
| `cli` | _(omit — no routable channel)_ |
|
|
121
|
+
3. If neither field is present or the interface is `cli`, omit `preferred_channels`.
|
|
122
|
+
|
|
123
|
+
When a channel is determined, include it as a routing hint:
|
|
105
124
|
```
|
|
106
|
-
routing_hints: { preferred_channels: ["
|
|
125
|
+
routing_hints: { preferred_channels: ["<resolved channel>"] }
|
|
107
126
|
routing_intent: "all_channels"
|
|
108
127
|
```
|
|
109
128
|
|
|
@@ -119,6 +138,7 @@ Use `syntax` + `expression` to specify the schedule type explicitly, or just `ex
|
|
|
119
138
|
|
|
120
139
|
## Tips
|
|
121
140
|
|
|
141
|
+
- **When the user specifies a name for the schedule, use it exactly as given.** Do not paraphrase, embellish, or generate a descriptive name.
|
|
122
142
|
- Use `schedule_create` for both recurring automation ("every day at 9am") and one-time reminders ("remind me at 3pm").
|
|
123
143
|
- For task tracking ("add to my tasks", "add to my queue"), use task_list_add instead.
|
|
124
144
|
- `fire_at` must be a strict ISO 8601 timestamp with timezone offset or Z (e.g. `2025-03-15T09:00:00-05:00`).
|
|
@@ -56,6 +56,10 @@
|
|
|
56
56
|
"type": "boolean",
|
|
57
57
|
"description": "When true, suppress completion notifications for this schedule. The job still runs and produces output, but no notification or conversation message is sent on completion. Useful for high-frequency recurring jobs that report findings separately. Defaults to false."
|
|
58
58
|
},
|
|
59
|
+
"reuse_conversation": {
|
|
60
|
+
"type": "boolean",
|
|
61
|
+
"description": "When true, reuse the same conversation across recurring schedule runs instead of creating a new one each time. Useful for polling-style schedules that accumulate context over time. Ignored for one-shot schedules. Defaults to false."
|
|
62
|
+
},
|
|
59
63
|
"activity": {
|
|
60
64
|
"type": "string",
|
|
61
65
|
"description": "Brief non-technical explanation of why this tool is being called"
|
|
@@ -147,6 +151,10 @@
|
|
|
147
151
|
"type": "boolean",
|
|
148
152
|
"description": "When true, suppress completion notifications for this schedule. Useful for high-frequency jobs that report findings separately."
|
|
149
153
|
},
|
|
154
|
+
"reuse_conversation": {
|
|
155
|
+
"type": "boolean",
|
|
156
|
+
"description": "When true, reuse the same conversation across recurring schedule runs instead of creating a new one each time. Useful for polling-style schedules that accumulate context over time. Ignored for one-shot schedules."
|
|
157
|
+
},
|
|
150
158
|
"activity": {
|
|
151
159
|
"type": "string",
|
|
152
160
|
"description": "Brief non-technical explanation of why this tool is being called"
|
|
@@ -7,27 +7,17 @@ import type {
|
|
|
7
7
|
ToolContext,
|
|
8
8
|
ToolExecutionResult,
|
|
9
9
|
} from "../../../../tools/types.js";
|
|
10
|
-
import {
|
|
10
|
+
import { getAvatarDir, getAvatarImagePath } from "../../../../util/platform.js";
|
|
11
11
|
|
|
12
12
|
export async function run(
|
|
13
13
|
_input: Record<string, unknown>,
|
|
14
14
|
_context: ToolContext,
|
|
15
15
|
): Promise<ToolExecutionResult> {
|
|
16
|
-
const avatarPath =
|
|
17
|
-
getWorkspaceDir(),
|
|
18
|
-
"data",
|
|
19
|
-
"avatar",
|
|
20
|
-
"avatar-image.png",
|
|
21
|
-
);
|
|
16
|
+
const avatarPath = getAvatarImagePath();
|
|
22
17
|
|
|
23
18
|
if (!existsSync(avatarPath)) {
|
|
24
19
|
// Check for native character traits and regenerate the static PNG
|
|
25
|
-
const traitsPath = join(
|
|
26
|
-
getWorkspaceDir(),
|
|
27
|
-
"data",
|
|
28
|
-
"avatar",
|
|
29
|
-
"character-traits.json",
|
|
30
|
-
);
|
|
20
|
+
const traitsPath = join(getAvatarDir(), "character-traits.json");
|
|
31
21
|
if (existsSync(traitsPath)) {
|
|
32
22
|
try {
|
|
33
23
|
const traits = JSON.parse(readFileSync(traitsPath, "utf-8"));
|