@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
|
@@ -39,6 +39,85 @@ export interface SkillRouteDeps {
|
|
|
39
39
|
getSkillContext: () => SkillOperationContext;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
const slimSkillBase = {
|
|
43
|
+
id: z.string(),
|
|
44
|
+
name: z.string(),
|
|
45
|
+
description: z.string(),
|
|
46
|
+
emoji: z.string().optional(),
|
|
47
|
+
kind: z.enum(["bundled", "installed", "catalog"]),
|
|
48
|
+
status: z.enum(["enabled", "disabled", "available"]),
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const slimSkillSchema = z.discriminatedUnion("origin", [
|
|
52
|
+
z.object({ ...slimSkillBase, origin: z.literal("vellum") }),
|
|
53
|
+
z.object({
|
|
54
|
+
...slimSkillBase,
|
|
55
|
+
origin: z.literal("clawhub"),
|
|
56
|
+
slug: z.string(),
|
|
57
|
+
author: z.string(),
|
|
58
|
+
stars: z.number(),
|
|
59
|
+
installs: z.number(),
|
|
60
|
+
reports: z.number(),
|
|
61
|
+
publishedAt: z.string().optional(),
|
|
62
|
+
}),
|
|
63
|
+
z.object({
|
|
64
|
+
...slimSkillBase,
|
|
65
|
+
origin: z.literal("skillssh"),
|
|
66
|
+
slug: z.string(),
|
|
67
|
+
sourceRepo: z.string(),
|
|
68
|
+
installs: z.number(),
|
|
69
|
+
}),
|
|
70
|
+
z.object({ ...slimSkillBase, origin: z.literal("custom") }),
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
const skillDetailSchema = z.discriminatedUnion("origin", [
|
|
74
|
+
z.object({ ...slimSkillBase, origin: z.literal("vellum") }),
|
|
75
|
+
z.object({
|
|
76
|
+
...slimSkillBase,
|
|
77
|
+
origin: z.literal("clawhub"),
|
|
78
|
+
slug: z.string(),
|
|
79
|
+
author: z.string(),
|
|
80
|
+
stars: z.number(),
|
|
81
|
+
installs: z.number(),
|
|
82
|
+
reports: z.number(),
|
|
83
|
+
publishedAt: z.string().optional(),
|
|
84
|
+
owner: z
|
|
85
|
+
.object({
|
|
86
|
+
handle: z.string(),
|
|
87
|
+
displayName: z.string(),
|
|
88
|
+
image: z.string().optional(),
|
|
89
|
+
})
|
|
90
|
+
.nullable()
|
|
91
|
+
.optional(),
|
|
92
|
+
stats: z
|
|
93
|
+
.object({
|
|
94
|
+
stars: z.number(),
|
|
95
|
+
installs: z.number(),
|
|
96
|
+
downloads: z.number(),
|
|
97
|
+
versions: z.number(),
|
|
98
|
+
})
|
|
99
|
+
.nullable()
|
|
100
|
+
.optional(),
|
|
101
|
+
latestVersion: z
|
|
102
|
+
.object({
|
|
103
|
+
version: z.string(),
|
|
104
|
+
changelog: z.string().optional(),
|
|
105
|
+
})
|
|
106
|
+
.nullable()
|
|
107
|
+
.optional(),
|
|
108
|
+
createdAt: z.number().nullable().optional(),
|
|
109
|
+
updatedAt: z.number().nullable().optional(),
|
|
110
|
+
}),
|
|
111
|
+
z.object({
|
|
112
|
+
...slimSkillBase,
|
|
113
|
+
origin: z.literal("skillssh"),
|
|
114
|
+
slug: z.string(),
|
|
115
|
+
sourceRepo: z.string(),
|
|
116
|
+
installs: z.number(),
|
|
117
|
+
}),
|
|
118
|
+
z.object({ ...slimSkillBase, origin: z.literal("custom") }),
|
|
119
|
+
]);
|
|
120
|
+
|
|
42
121
|
export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
43
122
|
const ctx = () => deps.getSkillContext();
|
|
44
123
|
|
|
@@ -60,34 +139,7 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
60
139
|
},
|
|
61
140
|
],
|
|
62
141
|
responseBody: z.object({
|
|
63
|
-
skills: z
|
|
64
|
-
.array(
|
|
65
|
-
z.object({
|
|
66
|
-
id: z.string(),
|
|
67
|
-
name: z.string(),
|
|
68
|
-
description: z.string(),
|
|
69
|
-
emoji: z.string().optional(),
|
|
70
|
-
homepage: z.string().optional(),
|
|
71
|
-
source: z.enum([
|
|
72
|
-
"bundled",
|
|
73
|
-
"managed",
|
|
74
|
-
"workspace",
|
|
75
|
-
"clawhub",
|
|
76
|
-
"extra",
|
|
77
|
-
"catalog",
|
|
78
|
-
]),
|
|
79
|
-
state: z.enum(["enabled", "disabled"]),
|
|
80
|
-
installStatus: z.enum(["bundled", "installed", "available"]),
|
|
81
|
-
updateAvailable: z.boolean(),
|
|
82
|
-
provenance: z.object({
|
|
83
|
-
kind: z.enum(["first-party", "third-party", "local"]),
|
|
84
|
-
provider: z.string().optional(),
|
|
85
|
-
originId: z.string().optional(),
|
|
86
|
-
sourceUrl: z.string().optional(),
|
|
87
|
-
}),
|
|
88
|
-
}),
|
|
89
|
-
)
|
|
90
|
-
.describe("Skill objects"),
|
|
142
|
+
skills: z.array(slimSkillSchema).describe("Skill objects"),
|
|
91
143
|
}),
|
|
92
144
|
handler: async ({ url }) => {
|
|
93
145
|
const include = url.searchParams.get("include");
|
|
@@ -201,16 +253,23 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
201
253
|
url: z.string().describe("Skill URL"),
|
|
202
254
|
spec: z.string().describe("Skill spec"),
|
|
203
255
|
version: z.string(),
|
|
256
|
+
origin: z
|
|
257
|
+
.enum(["clawhub", "skillssh"])
|
|
258
|
+
.optional()
|
|
259
|
+
.describe(
|
|
260
|
+
"Which registry to install from. When omitted, the install flow auto-detects based on slug format.",
|
|
261
|
+
),
|
|
204
262
|
}),
|
|
205
263
|
responseBody: z.object({
|
|
206
264
|
ok: z.boolean(),
|
|
207
265
|
}),
|
|
208
|
-
handler: async ({ req }) => {
|
|
266
|
+
handler: async ({ req, authContext }) => {
|
|
209
267
|
const body = (await req.json()) as {
|
|
210
268
|
slug?: string;
|
|
211
269
|
url?: string;
|
|
212
270
|
spec?: string;
|
|
213
271
|
version?: string;
|
|
272
|
+
origin?: "clawhub" | "skillssh";
|
|
214
273
|
};
|
|
215
274
|
const slug = body.slug ?? body.url ?? body.spec;
|
|
216
275
|
if (!slug || typeof slug !== "string") {
|
|
@@ -220,8 +279,9 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
220
279
|
400,
|
|
221
280
|
);
|
|
222
281
|
}
|
|
282
|
+
const contactId = authContext.actorPrincipalId ?? undefined;
|
|
223
283
|
const result = await installSkill(
|
|
224
|
-
{ slug, version: body.version },
|
|
284
|
+
{ slug, version: body.version, origin: body.origin, contactId },
|
|
225
285
|
ctx(),
|
|
226
286
|
);
|
|
227
287
|
if (!result.success) {
|
|
@@ -265,7 +325,9 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
265
325
|
},
|
|
266
326
|
],
|
|
267
327
|
responseBody: z.object({
|
|
268
|
-
|
|
328
|
+
skills: z
|
|
329
|
+
.array(slimSkillSchema)
|
|
330
|
+
.describe("Skill objects matching the search query"),
|
|
269
331
|
}),
|
|
270
332
|
handler: async ({ url }) => {
|
|
271
333
|
const query = url.searchParams.get("q") ?? "";
|
|
@@ -276,7 +338,7 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
276
338
|
if (!result.success) {
|
|
277
339
|
return httpError("INTERNAL_ERROR", result.error, 500);
|
|
278
340
|
}
|
|
279
|
-
return Response.json({
|
|
341
|
+
return Response.json({ skills: result.skills });
|
|
280
342
|
},
|
|
281
343
|
},
|
|
282
344
|
|
|
@@ -323,7 +385,7 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
323
385
|
responseBody: z.object({
|
|
324
386
|
ok: z.boolean(),
|
|
325
387
|
}),
|
|
326
|
-
handler: async ({ req }) => {
|
|
388
|
+
handler: async ({ req, authContext }) => {
|
|
327
389
|
const body = (await req.json()) as CreateSkillParams;
|
|
328
390
|
if (
|
|
329
391
|
!body.skillId ||
|
|
@@ -337,7 +399,8 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
337
399
|
400,
|
|
338
400
|
);
|
|
339
401
|
}
|
|
340
|
-
const
|
|
402
|
+
const contactId = authContext.actorPrincipalId ?? undefined;
|
|
403
|
+
const result = await createSkill({ ...body, contactId }, ctx());
|
|
341
404
|
if (!result.success) {
|
|
342
405
|
return httpError("INTERNAL_ERROR", result.error, 500);
|
|
343
406
|
}
|
|
@@ -395,10 +458,13 @@ export function skillRouteDefinitions(deps: SkillRouteDeps): RouteDefinition[] {
|
|
|
395
458
|
method: "GET",
|
|
396
459
|
policyKey: "skills",
|
|
397
460
|
summary: "Get skill",
|
|
398
|
-
description: "Return a single skill by ID.",
|
|
461
|
+
description: "Return a single skill by ID with enriched detail fields.",
|
|
399
462
|
tags: ["skills"],
|
|
400
|
-
|
|
401
|
-
|
|
463
|
+
responseBody: z.object({
|
|
464
|
+
skill: skillDetailSchema.describe("Skill detail object"),
|
|
465
|
+
}),
|
|
466
|
+
handler: async ({ params }) => {
|
|
467
|
+
const result = await getSkill(params.id, ctx());
|
|
402
468
|
if ("error" in result) {
|
|
403
469
|
if (result.status === 404) {
|
|
404
470
|
return httpError("NOT_FOUND", result.error, 404);
|
|
@@ -34,15 +34,17 @@ export interface SubagentDetailResult {
|
|
|
34
34
|
}>;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
/**
|
|
38
|
+
* Parse raw message rows into subagent detail events. Extracted as a pure
|
|
39
|
+
* function so it can be unit-tested without a database.
|
|
40
|
+
*/
|
|
41
|
+
export function parseSubagentMessages(
|
|
38
42
|
subagentId: string,
|
|
39
|
-
|
|
43
|
+
messages: Array<{ role: string; content: string }>,
|
|
40
44
|
): SubagentDetailResult {
|
|
41
|
-
const subagentMsgs = getMessages(conversationId);
|
|
42
|
-
|
|
43
45
|
// Extract objective from the first user message
|
|
44
46
|
let objective: string | undefined;
|
|
45
|
-
const firstUser =
|
|
47
|
+
const firstUser = messages.find((m) => m.role === "user");
|
|
46
48
|
if (firstUser) {
|
|
47
49
|
try {
|
|
48
50
|
const parsed = JSON.parse(firstUser.content);
|
|
@@ -67,7 +69,7 @@ export function getSubagentDetail(
|
|
|
67
69
|
isError?: boolean;
|
|
68
70
|
}> = [];
|
|
69
71
|
const pendingTools = new Map<string, string>();
|
|
70
|
-
for (const m of
|
|
72
|
+
for (const m of messages) {
|
|
71
73
|
if (m.role !== "assistant" && m.role !== "user") continue;
|
|
72
74
|
let content: unknown[];
|
|
73
75
|
try {
|
|
@@ -101,7 +103,19 @@ export function getSubagentDetail(
|
|
|
101
103
|
const toolUseId =
|
|
102
104
|
typeof block.tool_use_id === "string" ? block.tool_use_id : "";
|
|
103
105
|
const resultContent =
|
|
104
|
-
typeof block.content === "string"
|
|
106
|
+
typeof block.content === "string"
|
|
107
|
+
? block.content
|
|
108
|
+
: Array.isArray(block.content)
|
|
109
|
+
? (block.content as unknown[])
|
|
110
|
+
.filter(
|
|
111
|
+
(b): b is Record<string, unknown> =>
|
|
112
|
+
isRecord(b) &&
|
|
113
|
+
(b as Record<string, unknown>).type === "text" &&
|
|
114
|
+
typeof (b as Record<string, unknown>).text === "string",
|
|
115
|
+
)
|
|
116
|
+
.map((b) => b.text as string)
|
|
117
|
+
.join("\n")
|
|
118
|
+
: "";
|
|
105
119
|
const isError = block.is_error === true;
|
|
106
120
|
const toolName = toolUseId ? pendingTools.get(toolUseId) : undefined;
|
|
107
121
|
events.push({
|
|
@@ -117,6 +131,13 @@ export function getSubagentDetail(
|
|
|
117
131
|
return { subagentId, objective, events };
|
|
118
132
|
}
|
|
119
133
|
|
|
134
|
+
export function getSubagentDetail(
|
|
135
|
+
subagentId: string,
|
|
136
|
+
conversationId: string,
|
|
137
|
+
): SubagentDetailResult {
|
|
138
|
+
return parseSubagentMessages(subagentId, getMessages(conversationId));
|
|
139
|
+
}
|
|
140
|
+
|
|
120
141
|
// ---------------------------------------------------------------------------
|
|
121
142
|
// Route definitions
|
|
122
143
|
// ---------------------------------------------------------------------------
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File-based route dispatcher for user-defined HTTP endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Maps requests under the `/x/*` path prefix to handler modules in the
|
|
5
|
+
* workspace routes directory (`$VELLUM_WORKSPACE_DIR/routes/`). Each handler file
|
|
6
|
+
* exports named functions for HTTP methods (GET, POST, PUT, etc.) using
|
|
7
|
+
* the standard Web API Request/Response signature.
|
|
8
|
+
*
|
|
9
|
+
* Modules are lazily loaded on first request and cached by file path +
|
|
10
|
+
* mtime. When a file changes on disk, the next request reloads it via
|
|
11
|
+
* Bun's dynamic `import()` with a cache-busting query parameter.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { existsSync, statSync } from "node:fs";
|
|
15
|
+
import { join, resolve } from "node:path";
|
|
16
|
+
|
|
17
|
+
import { getLogger } from "../../util/logger.js";
|
|
18
|
+
import { getWorkspaceRoutesDir } from "../../util/platform.js";
|
|
19
|
+
import { httpError } from "../http-errors.js";
|
|
20
|
+
|
|
21
|
+
const log = getLogger("user-routes");
|
|
22
|
+
|
|
23
|
+
/** HTTP methods that can be exported from a handler module. */
|
|
24
|
+
const HTTP_METHODS = [
|
|
25
|
+
"GET",
|
|
26
|
+
"POST",
|
|
27
|
+
"PUT",
|
|
28
|
+
"PATCH",
|
|
29
|
+
"DELETE",
|
|
30
|
+
"HEAD",
|
|
31
|
+
"OPTIONS",
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
type HttpMethod = (typeof HTTP_METHODS)[number];
|
|
35
|
+
|
|
36
|
+
/** The function signature that user-defined route handlers must follow. */
|
|
37
|
+
type RouteHandler = (request: Request) => Response | Promise<Response>;
|
|
38
|
+
|
|
39
|
+
/** A loaded handler module with its cached metadata. */
|
|
40
|
+
interface CachedModule {
|
|
41
|
+
/** The module's exports (keyed by HTTP method name). */
|
|
42
|
+
handlers: Partial<Record<HttpMethod, RouteHandler>>;
|
|
43
|
+
/** Optional description exported by the module for display in CLI. */
|
|
44
|
+
description?: string;
|
|
45
|
+
/** The file's mtime at the time of loading, in milliseconds. */
|
|
46
|
+
mtimeMs: number;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Default per-request timeout for user-defined route handlers (30 seconds). */
|
|
50
|
+
const DEFAULT_HANDLER_TIMEOUT_MS = 30_000;
|
|
51
|
+
|
|
52
|
+
/** Supported file extensions for handler modules. */
|
|
53
|
+
const HANDLER_EXTENSIONS = [".ts", ".js"] as const;
|
|
54
|
+
|
|
55
|
+
export class UserRouteDispatcher {
|
|
56
|
+
private moduleCache = new Map<string, CachedModule>();
|
|
57
|
+
private handlerTimeoutMs: number;
|
|
58
|
+
|
|
59
|
+
constructor(options?: { handlerTimeoutMs?: number }) {
|
|
60
|
+
this.handlerTimeoutMs =
|
|
61
|
+
options?.handlerTimeoutMs ?? DEFAULT_HANDLER_TIMEOUT_MS;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Dispatch a request to the appropriate user-defined handler file.
|
|
66
|
+
*
|
|
67
|
+
* @param routePath The path after the `x/` prefix (e.g. `my-app/status`).
|
|
68
|
+
* @param request The original HTTP request.
|
|
69
|
+
* @returns A Response from the handler, or an error response (404, 405, 500).
|
|
70
|
+
*/
|
|
71
|
+
async dispatch(routePath: string, request: Request): Promise<Response> {
|
|
72
|
+
if (routePath.includes("..")) {
|
|
73
|
+
return httpError("BAD_REQUEST", "Path traversal is not allowed", 400);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const routesDir = getWorkspaceRoutesDir();
|
|
77
|
+
const filePath = this.resolveHandlerFile(routesDir, routePath);
|
|
78
|
+
|
|
79
|
+
if (!filePath) {
|
|
80
|
+
return httpError(
|
|
81
|
+
"NOT_FOUND",
|
|
82
|
+
`No route handler found for /x/${routePath}`,
|
|
83
|
+
404,
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const mod = await this.loadModule(filePath);
|
|
88
|
+
const method = request.method as HttpMethod;
|
|
89
|
+
const handler = mod.handlers[method];
|
|
90
|
+
|
|
91
|
+
if (!handler) {
|
|
92
|
+
const allowed = HTTP_METHODS.filter((m) => m in mod.handlers);
|
|
93
|
+
return new Response(null, {
|
|
94
|
+
status: 405,
|
|
95
|
+
headers: { Allow: allowed.join(", ") },
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return this.executeHandler(handler, request, routePath);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Resolve a route path to a handler file on disk.
|
|
104
|
+
*
|
|
105
|
+
* Checks for direct file matches first (`<path>.ts`, `<path>.js`),
|
|
106
|
+
* then falls back to index files (`<path>/index.ts`, `<path>/index.js`).
|
|
107
|
+
*
|
|
108
|
+
* Returns the absolute path to the handler file, or null if not found.
|
|
109
|
+
*/
|
|
110
|
+
private resolveHandlerFile(
|
|
111
|
+
routesDir: string,
|
|
112
|
+
routePath: string,
|
|
113
|
+
): string | null {
|
|
114
|
+
const basePath = join(routesDir, routePath);
|
|
115
|
+
const resolved = resolve(basePath);
|
|
116
|
+
|
|
117
|
+
// Ensure the resolved path is within the routes directory to prevent
|
|
118
|
+
// any path traversal that slipped through the initial check.
|
|
119
|
+
if (!resolved.startsWith(resolve(routesDir))) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Direct file match: routes/<path>.ts or routes/<path>.js
|
|
124
|
+
for (const ext of HANDLER_EXTENSIONS) {
|
|
125
|
+
const candidate = `${resolved}${ext}`;
|
|
126
|
+
if (existsSync(candidate)) {
|
|
127
|
+
return candidate;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Index file convention: routes/<path>/index.ts or routes/<path>/index.js
|
|
132
|
+
for (const ext of HANDLER_EXTENSIONS) {
|
|
133
|
+
const candidate = join(resolved, `index${ext}`);
|
|
134
|
+
if (existsSync(candidate)) {
|
|
135
|
+
return candidate;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Load a handler module, using the mtime-based cache when possible.
|
|
144
|
+
*
|
|
145
|
+
* On cache miss or stale mtime, the module is re-imported via Bun's
|
|
146
|
+
* dynamic `import()` with a cache-busting query parameter derived
|
|
147
|
+
* from the file's current mtime.
|
|
148
|
+
*/
|
|
149
|
+
private async loadModule(filePath: string): Promise<CachedModule> {
|
|
150
|
+
const stat = statSync(filePath);
|
|
151
|
+
const mtimeMs = stat.mtimeMs;
|
|
152
|
+
|
|
153
|
+
const cached = this.moduleCache.get(filePath);
|
|
154
|
+
if (cached && cached.mtimeMs === mtimeMs) {
|
|
155
|
+
return cached;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Cache-bust Bun's module cache by appending mtime as a query param.
|
|
159
|
+
const mod = (await import(`${filePath}?t=${mtimeMs}`)) as Record<
|
|
160
|
+
string,
|
|
161
|
+
unknown
|
|
162
|
+
>;
|
|
163
|
+
|
|
164
|
+
const handlers: Partial<Record<HttpMethod, RouteHandler>> = {};
|
|
165
|
+
for (const method of HTTP_METHODS) {
|
|
166
|
+
if (typeof mod[method] === "function") {
|
|
167
|
+
handlers[method] = mod[method] as RouteHandler;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const description =
|
|
172
|
+
typeof mod.description === "string" ? mod.description : undefined;
|
|
173
|
+
|
|
174
|
+
const entry: CachedModule = { handlers, description, mtimeMs };
|
|
175
|
+
this.moduleCache.set(filePath, entry);
|
|
176
|
+
|
|
177
|
+
log.info(
|
|
178
|
+
{ filePath, methods: Object.keys(handlers), description },
|
|
179
|
+
"Loaded user route handler",
|
|
180
|
+
);
|
|
181
|
+
|
|
182
|
+
return entry;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Execute a handler function with a per-request timeout and error boundary.
|
|
187
|
+
*/
|
|
188
|
+
private async executeHandler(
|
|
189
|
+
handler: RouteHandler,
|
|
190
|
+
request: Request,
|
|
191
|
+
routePath: string,
|
|
192
|
+
): Promise<Response> {
|
|
193
|
+
try {
|
|
194
|
+
const result = await Promise.race([
|
|
195
|
+
Promise.resolve(handler(request)),
|
|
196
|
+
new Promise<never>((_, reject) =>
|
|
197
|
+
setTimeout(
|
|
198
|
+
() => reject(new Error("Handler timed out")),
|
|
199
|
+
this.handlerTimeoutMs,
|
|
200
|
+
),
|
|
201
|
+
),
|
|
202
|
+
]);
|
|
203
|
+
return result;
|
|
204
|
+
} catch (err) {
|
|
205
|
+
if (err instanceof Error && err.message === "Handler timed out") {
|
|
206
|
+
log.error(
|
|
207
|
+
{ routePath, timeoutMs: this.handlerTimeoutMs },
|
|
208
|
+
"User route handler timed out",
|
|
209
|
+
);
|
|
210
|
+
return httpError(
|
|
211
|
+
"SERVICE_UNAVAILABLE",
|
|
212
|
+
`Route handler for /x/${routePath} timed out after ${this.handlerTimeoutMs}ms`,
|
|
213
|
+
504,
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
log.error({ err, routePath }, "User route handler threw an error");
|
|
218
|
+
const message =
|
|
219
|
+
err instanceof Error ? err.message : "Internal server error";
|
|
220
|
+
return httpError("INTERNAL_ERROR", message, 500);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Route definitions for user-defined endpoints under `/x/*`.
|
|
3
|
+
*
|
|
4
|
+
* Registers a single catch-all route that delegates to the
|
|
5
|
+
* UserRouteDispatcher for file-based dispatch from
|
|
6
|
+
* `$VELLUM_WORKSPACE_DIR/routes/`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { RouteDefinition } from "../http-router.js";
|
|
10
|
+
import { UserRouteDispatcher } from "./user-route-dispatcher.js";
|
|
11
|
+
|
|
12
|
+
const dispatcher = new UserRouteDispatcher();
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* HTTP methods supported by user-defined route handlers.
|
|
16
|
+
*
|
|
17
|
+
* Each method gets its own route definition so the HttpRouter can match
|
|
18
|
+
* on method before dispatching. The catch-all `x/:path*` pattern ensures
|
|
19
|
+
* all sub-paths are captured regardless of depth.
|
|
20
|
+
*/
|
|
21
|
+
const METHODS = [
|
|
22
|
+
"GET",
|
|
23
|
+
"POST",
|
|
24
|
+
"PUT",
|
|
25
|
+
"PATCH",
|
|
26
|
+
"DELETE",
|
|
27
|
+
"HEAD",
|
|
28
|
+
"OPTIONS",
|
|
29
|
+
] as const;
|
|
30
|
+
|
|
31
|
+
export function userRouteDefinitions(): RouteDefinition[] {
|
|
32
|
+
return METHODS.map((method) => ({
|
|
33
|
+
endpoint: "x/:path*",
|
|
34
|
+
method,
|
|
35
|
+
policyKey: "x",
|
|
36
|
+
summary: `User-defined ${method} route`,
|
|
37
|
+
description: `Dispatches ${method} requests to user-defined handler files in the workspace routes directory.`,
|
|
38
|
+
tags: ["user-routes"],
|
|
39
|
+
handler: ({ params, req }) => dispatcher.dispatch(params.path, req),
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* item falls back to the task-level required tools instead of silently
|
|
6
6
|
* skipping permission checks.
|
|
7
7
|
*/
|
|
8
|
-
import {
|
|
8
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
9
9
|
|
|
10
10
|
mock.module("../../util/logger.js", () => ({
|
|
11
11
|
getLogger: () =>
|
|
@@ -19,7 +19,7 @@ mock.module("../../permissions/checker.js", () => ({
|
|
|
19
19
|
classifyRisk: async () => "high",
|
|
20
20
|
}));
|
|
21
21
|
|
|
22
|
-
import { initializeDb
|
|
22
|
+
import { initializeDb } from "../../memory/db.js";
|
|
23
23
|
import { createTask } from "../../tasks/task-store.js";
|
|
24
24
|
import { createWorkItem } from "../../work-items/work-item-store.js";
|
|
25
25
|
import type { RouteContext } from "../http-router.js";
|
|
@@ -30,10 +30,6 @@ import {
|
|
|
30
30
|
|
|
31
31
|
initializeDb();
|
|
32
32
|
|
|
33
|
-
afterAll(() => {
|
|
34
|
-
resetDb();
|
|
35
|
-
});
|
|
36
|
-
|
|
37
33
|
describe("empty required_tools snapshot bypass", () => {
|
|
38
34
|
test("falls back to task required tools when snapshot requiredTools is empty", async () => {
|
|
39
35
|
const task = createTask({
|
|
@@ -36,6 +36,7 @@ export interface ScheduleJob {
|
|
|
36
36
|
routingIntent: RoutingIntent;
|
|
37
37
|
routingHints: Record<string, unknown>;
|
|
38
38
|
quiet: boolean;
|
|
39
|
+
reuseConversation: boolean;
|
|
39
40
|
status: ScheduleStatus;
|
|
40
41
|
createdAt: number;
|
|
41
42
|
updatedAt: number;
|
|
@@ -93,6 +94,7 @@ export function createSchedule(params: {
|
|
|
93
94
|
routingIntent?: RoutingIntent;
|
|
94
95
|
routingHints?: Record<string, unknown>;
|
|
95
96
|
quiet?: boolean;
|
|
97
|
+
reuseConversation?: boolean;
|
|
96
98
|
}): ScheduleJob {
|
|
97
99
|
const expression = params.expression ?? params.cronExpression ?? null;
|
|
98
100
|
const isOneShot = expression == null;
|
|
@@ -121,6 +123,7 @@ export function createSchedule(params: {
|
|
|
121
123
|
const routingIntent = params.routingIntent ?? "all_channels";
|
|
122
124
|
const routingHints = params.routingHints ?? {};
|
|
123
125
|
const quiet = params.quiet ?? false;
|
|
126
|
+
const reuseConversation = params.reuseConversation ?? false;
|
|
124
127
|
|
|
125
128
|
let nextRunAt: number;
|
|
126
129
|
if (isOneShot) {
|
|
@@ -148,6 +151,7 @@ export function createSchedule(params: {
|
|
|
148
151
|
routingIntent,
|
|
149
152
|
routingHintsJson: JSON.stringify(routingHints),
|
|
150
153
|
quiet,
|
|
154
|
+
reuseConversation,
|
|
151
155
|
status: "active" as ScheduleStatus,
|
|
152
156
|
createdAt: now,
|
|
153
157
|
updatedAt: now,
|
|
@@ -220,6 +224,7 @@ export function updateSchedule(
|
|
|
220
224
|
routingIntent?: RoutingIntent;
|
|
221
225
|
routingHints?: Record<string, unknown>;
|
|
222
226
|
quiet?: boolean;
|
|
227
|
+
reuseConversation?: boolean;
|
|
223
228
|
},
|
|
224
229
|
): ScheduleJob | null {
|
|
225
230
|
const db = getDb();
|
|
@@ -275,6 +280,8 @@ export function updateSchedule(
|
|
|
275
280
|
if (updates.routingHints !== undefined)
|
|
276
281
|
set.routingHintsJson = JSON.stringify(updates.routingHints);
|
|
277
282
|
if (updates.quiet !== undefined) set.quiet = updates.quiet;
|
|
283
|
+
if (updates.reuseConversation !== undefined)
|
|
284
|
+
set.reuseConversation = updates.reuseConversation;
|
|
278
285
|
|
|
279
286
|
// Recompute nextRunAt if schedule timing may have changed (only for recurring)
|
|
280
287
|
if (
|
|
@@ -563,6 +570,28 @@ export function completeScheduleRun(
|
|
|
563
570
|
}
|
|
564
571
|
}
|
|
565
572
|
|
|
573
|
+
/**
|
|
574
|
+
* Return the conversation ID from the most recent successful run
|
|
575
|
+
* for a given schedule, or null if none exists.
|
|
576
|
+
*/
|
|
577
|
+
export function getLastScheduleConversationId(jobId: string): string | null {
|
|
578
|
+
const db = getDb();
|
|
579
|
+
const row = db
|
|
580
|
+
.select({ conversationId: scheduleRuns.conversationId })
|
|
581
|
+
.from(scheduleRuns)
|
|
582
|
+
.where(
|
|
583
|
+
and(
|
|
584
|
+
eq(scheduleRuns.jobId, jobId),
|
|
585
|
+
eq(scheduleRuns.status, "ok"),
|
|
586
|
+
sql`${scheduleRuns.conversationId} IS NOT NULL`,
|
|
587
|
+
),
|
|
588
|
+
)
|
|
589
|
+
.orderBy(desc(scheduleRuns.createdAt))
|
|
590
|
+
.limit(1)
|
|
591
|
+
.get();
|
|
592
|
+
return row?.conversationId ?? null;
|
|
593
|
+
}
|
|
594
|
+
|
|
566
595
|
export function getScheduleRuns(jobId: string, limit?: number): ScheduleRun[] {
|
|
567
596
|
const db = getDb();
|
|
568
597
|
const rows = db
|
|
@@ -757,6 +786,7 @@ function parseJobRow(row: typeof scheduleJobs.$inferSelect): ScheduleJob {
|
|
|
757
786
|
routingIntent: (row.routingIntent ?? "all_channels") as RoutingIntent,
|
|
758
787
|
routingHints: safeParseJson(row.routingHintsJson),
|
|
759
788
|
quiet: row.quiet ?? false,
|
|
789
|
+
reuseConversation: row.reuseConversation ?? false,
|
|
760
790
|
status: (row.status ?? "active") as ScheduleStatus,
|
|
761
791
|
createdAt: row.createdAt,
|
|
762
792
|
updatedAt: row.updatedAt,
|