@vellumai/assistant 0.8.5 → 0.8.6
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 +33 -1
- package/ARCHITECTURE.md +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +1900 -166
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +5 -4
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- package/src/__tests__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/auth/route-policy.ts +10 -0
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
createScheduleRun,
|
|
23
23
|
failOneShotPermanently,
|
|
24
24
|
getLastScheduleConversationId,
|
|
25
|
+
listSchedules,
|
|
25
26
|
resetRetryCount,
|
|
26
27
|
retryOneShot,
|
|
27
28
|
type RoutingIntent,
|
|
@@ -48,9 +49,27 @@ type ScheduleConversationCreatedNotifier = (info: {
|
|
|
48
49
|
|
|
49
50
|
export interface SchedulerHandle {
|
|
50
51
|
runOnce(): Promise<number>;
|
|
52
|
+
runDueWorkOnce(
|
|
53
|
+
options?: SchedulerRunDueWorkOptions,
|
|
54
|
+
): Promise<SchedulerDueWorkResult>;
|
|
51
55
|
stop(): void;
|
|
52
56
|
}
|
|
53
57
|
|
|
58
|
+
export interface SchedulerRunDueWorkOptions {
|
|
59
|
+
now?: number;
|
|
60
|
+
deadlineAt?: number;
|
|
61
|
+
minStartBudgetMs?: number;
|
|
62
|
+
includeStillPending?: boolean;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export interface SchedulerDueWorkResult {
|
|
66
|
+
claimed: number;
|
|
67
|
+
completed: number;
|
|
68
|
+
failed: number;
|
|
69
|
+
skipped: number;
|
|
70
|
+
stillPending: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
54
73
|
const TICK_INTERVAL_MS = 15_000;
|
|
55
74
|
|
|
56
75
|
/**
|
|
@@ -140,6 +159,17 @@ export function startScheduler(
|
|
|
140
159
|
onScheduleConversationCreated,
|
|
141
160
|
);
|
|
142
161
|
},
|
|
162
|
+
async runDueWorkOnce(
|
|
163
|
+
options?: SchedulerRunDueWorkOptions,
|
|
164
|
+
): Promise<SchedulerDueWorkResult> {
|
|
165
|
+
return runScheduleDueWorkOnce(
|
|
166
|
+
processMessage,
|
|
167
|
+
notifyScheduleOneShot,
|
|
168
|
+
watcherNotifier,
|
|
169
|
+
onScheduleConversationCreated,
|
|
170
|
+
options,
|
|
171
|
+
);
|
|
172
|
+
},
|
|
143
173
|
stop(): void {
|
|
144
174
|
stopped = true;
|
|
145
175
|
clearInterval(timer);
|
|
@@ -153,8 +183,45 @@ export async function runScheduleOnce(
|
|
|
153
183
|
watcherNotifier?: WatcherNotifier,
|
|
154
184
|
onScheduleConversationCreated?: ScheduleConversationCreatedNotifier,
|
|
155
185
|
): Promise<number> {
|
|
156
|
-
const
|
|
157
|
-
|
|
186
|
+
const result = await runScheduleDueWorkOnce(
|
|
187
|
+
processMessage,
|
|
188
|
+
notifyScheduleOneShot,
|
|
189
|
+
watcherNotifier,
|
|
190
|
+
onScheduleConversationCreated,
|
|
191
|
+
);
|
|
192
|
+
return result.completed + result.failed + result.skipped;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
export async function runScheduleDueWorkOnce(
|
|
196
|
+
processMessage: ScheduleMessageProcessor,
|
|
197
|
+
notifyScheduleOneShot: ScheduleNotifyModeNotifier,
|
|
198
|
+
watcherNotifier?: WatcherNotifier,
|
|
199
|
+
onScheduleConversationCreated?: ScheduleConversationCreatedNotifier,
|
|
200
|
+
options: SchedulerRunDueWorkOptions = {},
|
|
201
|
+
): Promise<SchedulerDueWorkResult> {
|
|
202
|
+
const now = options.now ?? Date.now();
|
|
203
|
+
const minStartBudgetMs = options.minStartBudgetMs ?? 0;
|
|
204
|
+
const result: SchedulerDueWorkResult = {
|
|
205
|
+
claimed: 0,
|
|
206
|
+
completed: 0,
|
|
207
|
+
failed: 0,
|
|
208
|
+
skipped: 0,
|
|
209
|
+
stillPending: 0,
|
|
210
|
+
};
|
|
211
|
+
const mark = (status: "completed" | "failed" | "skipped") => {
|
|
212
|
+
result[status] += 1;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
if (
|
|
216
|
+
options.deadlineAt != null &&
|
|
217
|
+
options.deadlineAt - Date.now() < minStartBudgetMs
|
|
218
|
+
) {
|
|
219
|
+
result.stillPending = options.includeStillPending
|
|
220
|
+
? countDueScheduleJobs(now)
|
|
221
|
+
: 0;
|
|
222
|
+
result.skipped = result.stillPending;
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
158
225
|
|
|
159
226
|
const diskPressureGate = checkDiskPressureBackgroundGate("background-work");
|
|
160
227
|
if (diskPressureGate.action === "skip") {
|
|
@@ -167,16 +234,21 @@ export async function runScheduleOnce(
|
|
|
167
234
|
"Schedule tick skipped during disk pressure cleanup mode",
|
|
168
235
|
);
|
|
169
236
|
}
|
|
170
|
-
|
|
237
|
+
result.stillPending = options.includeStillPending
|
|
238
|
+
? countDueScheduleJobs(now)
|
|
239
|
+
: 0;
|
|
240
|
+
return result;
|
|
171
241
|
}
|
|
172
242
|
|
|
173
243
|
// ── Schedules (recurring cron/RRULE + one-shot) ─────────────────────
|
|
174
244
|
const jobs = claimDueSchedules(now);
|
|
245
|
+
result.claimed = jobs.length;
|
|
175
246
|
for (const job of jobs) {
|
|
176
247
|
const isOneShot = job.expression == null;
|
|
177
248
|
|
|
178
249
|
// ── Notify mode (one-shot or recurring) ─────────────────────────
|
|
179
250
|
if (job.mode === "notify") {
|
|
251
|
+
let failed = false;
|
|
180
252
|
try {
|
|
181
253
|
log.info(
|
|
182
254
|
{ jobId: job.id, name: job.name, isOneShot },
|
|
@@ -208,8 +280,9 @@ export async function runScheduleOnce(
|
|
|
208
280
|
const errorRunId = createScheduleRun(job.id, `notify-error:${job.id}`);
|
|
209
281
|
completeScheduleRun(errorRunId, { status: "error", error: errorMsg });
|
|
210
282
|
handleExecutionFailure({ job, errorMsg, isOneShot });
|
|
283
|
+
failed = true;
|
|
211
284
|
}
|
|
212
|
-
|
|
285
|
+
mark(failed ? "failed" : "completed");
|
|
213
286
|
continue;
|
|
214
287
|
}
|
|
215
288
|
|
|
@@ -220,10 +293,11 @@ export async function runScheduleOnce(
|
|
|
220
293
|
{ jobId: job.id, name: job.name },
|
|
221
294
|
"Script schedule has no script command — skipping",
|
|
222
295
|
);
|
|
223
|
-
|
|
296
|
+
mark("skipped");
|
|
224
297
|
continue;
|
|
225
298
|
}
|
|
226
299
|
const runId = createScheduleRun(job.id, `script:${job.id}`);
|
|
300
|
+
let failed = false;
|
|
227
301
|
try {
|
|
228
302
|
log.info(
|
|
229
303
|
{ jobId: job.id, name: job.name, isOneShot },
|
|
@@ -241,6 +315,7 @@ export async function runScheduleOnce(
|
|
|
241
315
|
const errorMsg =
|
|
242
316
|
result.stderr || "Script exited with non-zero status";
|
|
243
317
|
handleExecutionFailure({ job, errorMsg, isOneShot });
|
|
318
|
+
failed = true;
|
|
244
319
|
}
|
|
245
320
|
} catch (err) {
|
|
246
321
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -250,8 +325,9 @@ export async function runScheduleOnce(
|
|
|
250
325
|
);
|
|
251
326
|
completeScheduleRun(runId, { status: "error", error: errorMsg });
|
|
252
327
|
handleExecutionFailure({ job, errorMsg, isOneShot });
|
|
328
|
+
failed = true;
|
|
253
329
|
}
|
|
254
|
-
|
|
330
|
+
mark(failed ? "failed" : "completed");
|
|
255
331
|
continue;
|
|
256
332
|
}
|
|
257
333
|
|
|
@@ -264,10 +340,11 @@ export async function runScheduleOnce(
|
|
|
264
340
|
"Wake schedule missing wakeConversationId — completing as no-op",
|
|
265
341
|
);
|
|
266
342
|
if (isOneShot) completeOneShot(job.id);
|
|
267
|
-
|
|
343
|
+
mark("skipped");
|
|
268
344
|
continue;
|
|
269
345
|
}
|
|
270
346
|
|
|
347
|
+
let failed = false;
|
|
271
348
|
try {
|
|
272
349
|
log.info(
|
|
273
350
|
{ jobId: job.id, name: job.name, wakeConversationId, isOneShot },
|
|
@@ -305,7 +382,7 @@ export async function runScheduleOnce(
|
|
|
305
382
|
);
|
|
306
383
|
retryOneShot(job.id);
|
|
307
384
|
}
|
|
308
|
-
|
|
385
|
+
mark("skipped");
|
|
309
386
|
continue;
|
|
310
387
|
}
|
|
311
388
|
|
|
@@ -323,7 +400,7 @@ export async function runScheduleOnce(
|
|
|
323
400
|
"Wake not invoked; skipping feed event",
|
|
324
401
|
);
|
|
325
402
|
if (isOneShot) completeOneShot(job.id);
|
|
326
|
-
|
|
403
|
+
mark("skipped");
|
|
327
404
|
continue;
|
|
328
405
|
}
|
|
329
406
|
|
|
@@ -347,8 +424,9 @@ export async function runScheduleOnce(
|
|
|
347
424
|
error: errorMsg,
|
|
348
425
|
});
|
|
349
426
|
handleExecutionFailure({ job, errorMsg, isOneShot });
|
|
427
|
+
failed = true;
|
|
350
428
|
}
|
|
351
|
-
|
|
429
|
+
mark(failed ? "failed" : "completed");
|
|
352
430
|
continue;
|
|
353
431
|
}
|
|
354
432
|
|
|
@@ -362,6 +440,7 @@ export async function runScheduleOnce(
|
|
|
362
440
|
job.syntax === "rrule" &&
|
|
363
441
|
job.expression != null &&
|
|
364
442
|
hasSetConstructs(job.expression);
|
|
443
|
+
let failed = false;
|
|
365
444
|
try {
|
|
366
445
|
log.info(
|
|
367
446
|
{
|
|
@@ -415,11 +494,11 @@ export async function runScheduleOnce(
|
|
|
415
494
|
errorMsg: errorMessage,
|
|
416
495
|
isOneShot,
|
|
417
496
|
});
|
|
497
|
+
failed = true;
|
|
418
498
|
} else {
|
|
419
499
|
completeScheduleRun(runId, { status: "ok" });
|
|
420
500
|
if (isOneShot) completeOneShot(job.id);
|
|
421
501
|
}
|
|
422
|
-
processed += 1;
|
|
423
502
|
} catch (err) {
|
|
424
503
|
const message = err instanceof Error ? err.message : String(err);
|
|
425
504
|
log.warn(
|
|
@@ -461,7 +540,9 @@ export async function runScheduleOnce(
|
|
|
461
540
|
errorMsg: message,
|
|
462
541
|
isOneShot,
|
|
463
542
|
});
|
|
543
|
+
failed = true;
|
|
464
544
|
}
|
|
545
|
+
mark(failed ? "failed" : "completed");
|
|
465
546
|
continue;
|
|
466
547
|
}
|
|
467
548
|
|
|
@@ -567,7 +648,7 @@ export async function runScheduleOnce(
|
|
|
567
648
|
if (ok) {
|
|
568
649
|
completeScheduleRun(runId, { status: "ok" });
|
|
569
650
|
if (isOneShot) completeOneShot(job.id);
|
|
570
|
-
|
|
651
|
+
mark("completed");
|
|
571
652
|
} else {
|
|
572
653
|
log.warn(
|
|
573
654
|
{
|
|
@@ -605,6 +686,7 @@ export async function runScheduleOnce(
|
|
|
605
686
|
);
|
|
606
687
|
}
|
|
607
688
|
}
|
|
689
|
+
mark("failed");
|
|
608
690
|
}
|
|
609
691
|
}
|
|
610
692
|
|
|
@@ -612,7 +694,7 @@ export async function runScheduleOnce(
|
|
|
612
694
|
if (watcherNotifier) {
|
|
613
695
|
try {
|
|
614
696
|
const watcherProcessed = await runWatchersOnce(watcherNotifier);
|
|
615
|
-
|
|
697
|
+
result.completed += watcherProcessed;
|
|
616
698
|
} catch (err) {
|
|
617
699
|
log.error({ err }, "Watcher tick failed");
|
|
618
700
|
}
|
|
@@ -621,15 +703,29 @@ export async function runScheduleOnce(
|
|
|
621
703
|
// ── Sequences (multi-step outreach) ──────────────────────────────
|
|
622
704
|
try {
|
|
623
705
|
const sequenceProcessed = await runSequencesOnce();
|
|
624
|
-
|
|
706
|
+
result.completed += sequenceProcessed;
|
|
625
707
|
} catch (err) {
|
|
626
708
|
log.error({ err }, "Sequence engine tick failed");
|
|
627
709
|
}
|
|
628
710
|
|
|
711
|
+
if (options.includeStillPending) {
|
|
712
|
+
result.stillPending = countDueScheduleJobs(Date.now());
|
|
713
|
+
}
|
|
714
|
+
const processed = result.completed + result.failed + result.skipped;
|
|
629
715
|
if (processed > 0) {
|
|
630
716
|
log.info({ processed }, "Schedule tick complete");
|
|
631
717
|
}
|
|
632
|
-
return
|
|
718
|
+
return result;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
function countDueScheduleJobs(now: number): number {
|
|
722
|
+
return listSchedules({ enabledOnly: true }).filter(
|
|
723
|
+
(job) =>
|
|
724
|
+
job.status === "active" &&
|
|
725
|
+
Number.isFinite(job.nextRunAt) &&
|
|
726
|
+
job.nextRunAt > 0 &&
|
|
727
|
+
job.nextRunAt <= now,
|
|
728
|
+
).length;
|
|
633
729
|
}
|
|
634
730
|
|
|
635
731
|
/**
|
|
@@ -27,7 +27,7 @@ mock.module("../../util/logger.js", () => ({
|
|
|
27
27
|
// Imports under test
|
|
28
28
|
// ---------------------------------------------------------------------------
|
|
29
29
|
|
|
30
|
-
import {
|
|
30
|
+
import { setStorePathForTesting } from "../../__tests__/encrypted-store-test-helpers.js";
|
|
31
31
|
import { _resetBackend, getProviderKeyAsync } from "../secure-keys.js";
|
|
32
32
|
|
|
33
33
|
const TEST_DIR = join(
|
|
@@ -61,7 +61,7 @@ describe("getProviderKeyAsync env-var fallback (regression #27126)", () => {
|
|
|
61
61
|
// Fresh encrypted store (no saved credentials → forces env-var fallback).
|
|
62
62
|
if (existsSync(TEST_DIR)) rmSync(TEST_DIR, { recursive: true });
|
|
63
63
|
mkdirSync(TEST_DIR, { recursive: true });
|
|
64
|
-
|
|
64
|
+
setStorePathForTesting(STORE_PATH);
|
|
65
65
|
_resetBackend();
|
|
66
66
|
|
|
67
67
|
// Snapshot env so each test starts clean.
|
|
@@ -72,7 +72,7 @@ describe("getProviderKeyAsync env-var fallback (regression #27126)", () => {
|
|
|
72
72
|
});
|
|
73
73
|
|
|
74
74
|
afterEach(() => {
|
|
75
|
-
|
|
75
|
+
setStorePathForTesting(null);
|
|
76
76
|
_resetBackend();
|
|
77
77
|
for (const name of MANAGED_VARS) {
|
|
78
78
|
const saved = SAVED_ENV[name];
|
|
@@ -31,6 +31,10 @@ import { getIsContainerized } from "../config/env-registry.js";
|
|
|
31
31
|
import { ensureDir, pathExists } from "../util/fs.js";
|
|
32
32
|
import { getLogger } from "../util/logger.js";
|
|
33
33
|
import { getPlatformName, getProtectedDir } from "../util/platform.js";
|
|
34
|
+
import {
|
|
35
|
+
getStoreKeyPathOverride,
|
|
36
|
+
getStorePathOverride,
|
|
37
|
+
} from "./store-path-override.js";
|
|
34
38
|
|
|
35
39
|
const log = getLogger("encrypted-store");
|
|
36
40
|
|
|
@@ -77,15 +81,8 @@ interface EncryptedEntry {
|
|
|
77
81
|
// Paths
|
|
78
82
|
// ---------------------------------------------------------------------------
|
|
79
83
|
|
|
80
|
-
let storePathOverride: string | null = null;
|
|
81
|
-
|
|
82
84
|
function getStorePath(): string {
|
|
83
|
-
return
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/** @internal Test-only: override the store file path. Pass `null` to reset. */
|
|
87
|
-
export function _setStorePath(path: string | null): void {
|
|
88
|
-
storePathOverride = path;
|
|
85
|
+
return getStorePathOverride() ?? join(getProtectedDir(), "keys.enc");
|
|
89
86
|
}
|
|
90
87
|
|
|
91
88
|
// ---------------------------------------------------------------------------
|
|
@@ -95,16 +92,10 @@ export function _setStorePath(path: string | null): void {
|
|
|
95
92
|
const STORE_KEY_FILENAME = "store.key";
|
|
96
93
|
const STORE_KEY_LENGTH = 32; // bytes
|
|
97
94
|
|
|
98
|
-
let storeKeyPathOverride: string | null = null;
|
|
99
|
-
|
|
100
|
-
/** @internal Test-only: override the store key file path. Pass `null` to reset. */
|
|
101
|
-
export function _setStoreKeyPath(path: string | null): void {
|
|
102
|
-
storeKeyPathOverride = path;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
95
|
function getStoreKeyPath(): string {
|
|
106
96
|
return (
|
|
107
|
-
|
|
97
|
+
getStoreKeyPathOverride() ??
|
|
98
|
+
join(dirname(getStorePath()), STORE_KEY_FILENAME)
|
|
108
99
|
);
|
|
109
100
|
}
|
|
110
101
|
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Holds optional path overrides for the encrypted credential store.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own module (rather than alongside the crypto code in
|
|
5
|
+
* `encrypted-store.ts`) so test code can install/clear overrides without
|
|
6
|
+
* importing `encrypted-store.ts` — which transitively pulls
|
|
7
|
+
* `util/logger.js` (pino). Stdlib-only by design: this file must remain
|
|
8
|
+
* safe to import from the test preload's load-time chain, where a broken
|
|
9
|
+
* `node_modules` symlink has historically tripped the env override
|
|
10
|
+
* (see DB ghost #3, /workspace/journal/2026-05-25-db-ghost-3-recovery.md).
|
|
11
|
+
*
|
|
12
|
+
* State is held on `globalThis.vellumAssistant.storePathOverride` so
|
|
13
|
+
* test helpers in `__tests__/` can read/write it WITHOUT importing this
|
|
14
|
+
* module — they declare the same slot shape locally and access the
|
|
15
|
+
* globalThis namespace directly. See
|
|
16
|
+
* `__tests__/encrypted-store-test-helpers.ts` for the test-side mirror;
|
|
17
|
+
* the slot shape MUST stay in sync between the two.
|
|
18
|
+
*
|
|
19
|
+
* Note: the new test preload places `VELLUM_WORKSPACE_DIR` at
|
|
20
|
+
* `<tmpRoot>/workspace`, so `getProtectedDir()` resolves to
|
|
21
|
+
* `<tmpRoot>/protected` naturally — most tests no longer need an explicit
|
|
22
|
+
* override. The setters here exist for the small set of tests that
|
|
23
|
+
* exercise specific path scenarios (env-var fallbacks, migration, etc.).
|
|
24
|
+
*
|
|
25
|
+
* Consumers:
|
|
26
|
+
* - `encrypted-store.ts` (reads the override when computing paths)
|
|
27
|
+
* - `__tests__/encrypted-store-test-helpers.ts` (writes for tests, via globalThis)
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
type PathSlot = {
|
|
31
|
+
storePath: string | null;
|
|
32
|
+
storeKeyPath: string | null;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
type VellumAssistantNamespace = {
|
|
36
|
+
storePathOverride?: PathSlot;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
function slot(): PathSlot {
|
|
40
|
+
const g = globalThis as { vellumAssistant?: VellumAssistantNamespace };
|
|
41
|
+
const ns = (g.vellumAssistant ??= {});
|
|
42
|
+
return (ns.storePathOverride ??= { storePath: null, storeKeyPath: null });
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getStorePathOverride(): string | null {
|
|
46
|
+
return slot().storePath;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** Pass `null` to reset to the default (`<protectedDir>/keys.enc`). */
|
|
50
|
+
export function setStorePathOverride(path: string | null): void {
|
|
51
|
+
slot().storePath = path;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getStoreKeyPathOverride(): string | null {
|
|
55
|
+
return slot().storeKeyPath;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Pass `null` to reset to the default (`<dirname(storePath)>/store.key`). */
|
|
59
|
+
export function setStoreKeyPathOverride(path: string | null): void {
|
|
60
|
+
slot().storeKeyPath = path;
|
|
61
|
+
}
|
|
@@ -120,20 +120,17 @@ async function dispatchUserMessage(params: {
|
|
|
120
120
|
const requestId = crypto.randomUUID();
|
|
121
121
|
const resolvedChannel = resolveTurnChannel(params.sourceChannel);
|
|
122
122
|
const resolvedInterface = resolveTurnInterface(params.sourceInterface);
|
|
123
|
-
const result = conversation.enqueueMessage(
|
|
124
|
-
params.content,
|
|
125
|
-
resolvedAttachments,
|
|
126
|
-
undefined,
|
|
123
|
+
const result = conversation.enqueueMessage({
|
|
124
|
+
content: params.content,
|
|
125
|
+
attachments: resolvedAttachments,
|
|
127
126
|
requestId,
|
|
128
|
-
|
|
129
|
-
undefined,
|
|
130
|
-
{
|
|
127
|
+
metadata: {
|
|
131
128
|
userMessageChannel: resolvedChannel,
|
|
132
129
|
assistantMessageChannel: resolvedChannel,
|
|
133
130
|
userMessageInterface: resolvedInterface,
|
|
134
131
|
assistantMessageInterface: resolvedInterface,
|
|
135
132
|
},
|
|
136
|
-
);
|
|
133
|
+
});
|
|
137
134
|
return { accepted: !result.rejected };
|
|
138
135
|
}
|
|
139
136
|
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure JSON-schema input validator for skill tool calls.
|
|
3
|
+
*
|
|
4
|
+
* Deliberate strict subset of JSON Schema: it covers only the keywords
|
|
5
|
+
* actually used by `assistant/src/config/bundled-skills/**\/TOOLS.json`
|
|
6
|
+
* (required / type / enum / items.type) plus unknown-key detection. Anything
|
|
7
|
+
* else (`$ref`, `oneOf`, `anyOf`, `allOf`, `format`, `pattern`, `minimum`,
|
|
8
|
+
* `maximum`, object-shape `additionalProperties`, etc.) is silently skipped so
|
|
9
|
+
* a richer schema can never cause us to reject a legitimate call.
|
|
10
|
+
*
|
|
11
|
+
* Each error message is written to be agent-readable and self-correcting
|
|
12
|
+
* (e.g. `surface_id is required`, `mode must be one of "replace", "append"`).
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { isPlainObject } from "../util/object.js";
|
|
16
|
+
|
|
17
|
+
export interface InputValidationSuccess {
|
|
18
|
+
ok: true;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface InputValidationFailure {
|
|
22
|
+
ok: false;
|
|
23
|
+
/** Human-readable messages, one per problem. */
|
|
24
|
+
errors: string[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type InputValidationResult =
|
|
28
|
+
| InputValidationSuccess
|
|
29
|
+
| InputValidationFailure;
|
|
30
|
+
|
|
31
|
+
type SupportedType =
|
|
32
|
+
| "string"
|
|
33
|
+
| "number"
|
|
34
|
+
| "integer"
|
|
35
|
+
| "boolean"
|
|
36
|
+
| "array"
|
|
37
|
+
| "object";
|
|
38
|
+
|
|
39
|
+
const SUPPORTED_TYPES: ReadonlySet<string> = new Set([
|
|
40
|
+
"string",
|
|
41
|
+
"number",
|
|
42
|
+
"integer",
|
|
43
|
+
"boolean",
|
|
44
|
+
"array",
|
|
45
|
+
"object",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
function matchesType(value: unknown, type: SupportedType): boolean {
|
|
49
|
+
switch (type) {
|
|
50
|
+
case "string":
|
|
51
|
+
return typeof value === "string";
|
|
52
|
+
case "number":
|
|
53
|
+
return typeof value === "number";
|
|
54
|
+
case "integer":
|
|
55
|
+
return typeof value === "number" && Number.isInteger(value);
|
|
56
|
+
case "boolean":
|
|
57
|
+
return typeof value === "boolean";
|
|
58
|
+
case "array":
|
|
59
|
+
return Array.isArray(value);
|
|
60
|
+
case "object":
|
|
61
|
+
return isPlainObject(value);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function quoteList(values: readonly string[]): string {
|
|
66
|
+
return values.map((v) => `"${v}"`).join(", ");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Validate a tool input object against the (optional) JSON-schema definition
|
|
71
|
+
* declared on the tool entry. Returns `{ ok: true }` if the input is valid (or
|
|
72
|
+
* if there is nothing actionable to validate); otherwise returns a list of
|
|
73
|
+
* human-readable error strings.
|
|
74
|
+
*
|
|
75
|
+
* Pure: never mutates `input` or `schema`, no I/O.
|
|
76
|
+
*/
|
|
77
|
+
export function validateInputAgainstSchema(
|
|
78
|
+
_toolName: string,
|
|
79
|
+
input: Record<string, unknown>,
|
|
80
|
+
schema: Record<string, unknown> | undefined,
|
|
81
|
+
): InputValidationResult {
|
|
82
|
+
// Skip when there's no schema or no properties block — matches today's
|
|
83
|
+
// lenient behaviour for tools that declare only `{ type: "object" }`.
|
|
84
|
+
if (!schema) return { ok: true };
|
|
85
|
+
const properties = schema.properties;
|
|
86
|
+
if (!isPlainObject(properties)) return { ok: true };
|
|
87
|
+
|
|
88
|
+
const errors: string[] = [];
|
|
89
|
+
const knownKeys = Object.keys(properties);
|
|
90
|
+
const knownKeySet = new Set(knownKeys);
|
|
91
|
+
|
|
92
|
+
// 1. Required fields — presence-only check per JSON Schema spec.
|
|
93
|
+
// `required` only requires the property to be present; `null` is a valid
|
|
94
|
+
// value when the schema allows it (e.g. `type: ["string", "null"]`).
|
|
95
|
+
const required = schema.required;
|
|
96
|
+
if (Array.isArray(required)) {
|
|
97
|
+
for (const key of required) {
|
|
98
|
+
if (typeof key !== "string") continue;
|
|
99
|
+
if (!(key in input)) {
|
|
100
|
+
errors.push(`${key} is required`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 2. Per-property checks: type, enum, items.type.
|
|
106
|
+
for (const [key, rawSubSchema] of Object.entries(properties)) {
|
|
107
|
+
if (!(key in input)) continue;
|
|
108
|
+
const value = input[key];
|
|
109
|
+
// Skip type-checking for absent values; presence is enforced by the
|
|
110
|
+
// `required` check above. Note: `null` IS a present value and is
|
|
111
|
+
// type-checked below — only schemas that explicitly opt in to null via
|
|
112
|
+
// a union type (`type: ["string","null"]`) bypass the check, handled
|
|
113
|
+
// by the `Array.isArray(declaredType)` skip immediately below.
|
|
114
|
+
if (value === undefined) continue;
|
|
115
|
+
if (!isPlainObject(rawSubSchema)) continue;
|
|
116
|
+
|
|
117
|
+
const declaredType = rawSubSchema.type;
|
|
118
|
+
// Skip union types (e.g. `["string", "null"]`) — same lenient treatment
|
|
119
|
+
// we give `oneOf`/`anyOf`/`$ref`. We only validate single-type schemas.
|
|
120
|
+
if (Array.isArray(declaredType)) continue;
|
|
121
|
+
if (typeof declaredType === "string" && SUPPORTED_TYPES.has(declaredType)) {
|
|
122
|
+
const type = declaredType as SupportedType;
|
|
123
|
+
if (!matchesType(value, type)) {
|
|
124
|
+
errors.push(`${key} must be ${typeArticle(type)} ${type}`);
|
|
125
|
+
// No point checking enum/items if the base type is wrong.
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// 2a. Enum (string enums are the only shape used today).
|
|
130
|
+
const enumValues = rawSubSchema.enum;
|
|
131
|
+
if (Array.isArray(enumValues) && enumValues.length > 0) {
|
|
132
|
+
if (!enumValues.includes(value)) {
|
|
133
|
+
errors.push(
|
|
134
|
+
`${key} must be one of ${quoteList(enumValues.map(String))}`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// 2b. Array items.type — per-element check.
|
|
140
|
+
if (type === "array" && isPlainObject(rawSubSchema.items)) {
|
|
141
|
+
const itemType = rawSubSchema.items.type;
|
|
142
|
+
if (
|
|
143
|
+
typeof itemType === "string" &&
|
|
144
|
+
SUPPORTED_TYPES.has(itemType) &&
|
|
145
|
+
Array.isArray(value)
|
|
146
|
+
) {
|
|
147
|
+
const itemTypeName = itemType as SupportedType;
|
|
148
|
+
value.forEach((element, index) => {
|
|
149
|
+
if (!matchesType(element, itemTypeName)) {
|
|
150
|
+
errors.push(
|
|
151
|
+
`${key}[${index}] must be ${typeArticle(itemTypeName)} ${itemTypeName}`,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 3. Unknown keys — parity with the previous `validateNoUnknownParams`.
|
|
161
|
+
const unknownKeys = Object.keys(input).filter((k) => !knownKeySet.has(k));
|
|
162
|
+
for (const key of unknownKeys) {
|
|
163
|
+
errors.push(
|
|
164
|
+
`Unknown parameter "${key}". Supported: ${quoteList(knownKeys)}`,
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
if (errors.length === 0) return { ok: true };
|
|
169
|
+
return { ok: false, errors };
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function typeArticle(type: SupportedType): "a" | "an" {
|
|
173
|
+
// `integer`, `array`, `object` start with a vowel sound.
|
|
174
|
+
return type === "integer" || type === "array" || type === "object"
|
|
175
|
+
? "an"
|
|
176
|
+
: "a";
|
|
177
|
+
}
|
package/src/subagent/manager.ts
CHANGED
|
@@ -365,6 +365,7 @@ export class SubagentManager {
|
|
|
365
365
|
label: config.label,
|
|
366
366
|
objective: config.objective,
|
|
367
367
|
isFork: config.fork ?? false,
|
|
368
|
+
parentToolUseId: config.parentToolUseId,
|
|
368
369
|
} as ServerMessage);
|
|
369
370
|
|
|
370
371
|
log.info(
|
|
@@ -435,7 +436,9 @@ export class SubagentManager {
|
|
|
435
436
|
"⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯",
|
|
436
437
|
].join("\n")
|
|
437
438
|
: objective;
|
|
438
|
-
const messageId = await conversation.persistUserMessage(
|
|
439
|
+
const { id: messageId } = await conversation.persistUserMessage({
|
|
440
|
+
content: message,
|
|
441
|
+
});
|
|
439
442
|
await conversation.runAgentLoop(message, messageId, undefined, {
|
|
440
443
|
callSite: "subagentSpawn",
|
|
441
444
|
...(managed.state.config.overrideProfile
|
|
@@ -609,7 +612,7 @@ export class SubagentManager {
|
|
|
609
612
|
return "terminal";
|
|
610
613
|
|
|
611
614
|
// If the conversation is busy, queue the message; otherwise process immediately.
|
|
612
|
-
const result = managed.conversation.enqueueMessage(trimmed
|
|
615
|
+
const result = managed.conversation.enqueueMessage({ content: trimmed });
|
|
613
616
|
if (result.rejected) {
|
|
614
617
|
return "sent"; // error event already delivered via sendToClient
|
|
615
618
|
}
|
|
@@ -620,7 +623,9 @@ export class SubagentManager {
|
|
|
620
623
|
// Capture conversation before the await — managed.conversation may be
|
|
621
624
|
// nulled by an external dispose() while persistUserMessage is awaited.
|
|
622
625
|
const conversation = managed.conversation;
|
|
623
|
-
const messageId = await conversation.persistUserMessage(
|
|
626
|
+
const { id: messageId } = await conversation.persistUserMessage({
|
|
627
|
+
content: trimmed,
|
|
628
|
+
});
|
|
624
629
|
conversation
|
|
625
630
|
.runAgentLoop(trimmed, messageId, undefined, {
|
|
626
631
|
callSite: "subagentSpawn",
|
|
@@ -984,19 +989,14 @@ export class SubagentManager {
|
|
|
984
989
|
);
|
|
985
990
|
return;
|
|
986
991
|
}
|
|
987
|
-
const enqueueResult = parentConversation.enqueueMessage(
|
|
988
|
-
message,
|
|
989
|
-
[],
|
|
990
|
-
undefined,
|
|
991
|
-
undefined,
|
|
992
|
-
undefined,
|
|
993
|
-
undefined,
|
|
992
|
+
const enqueueResult = parentConversation.enqueueMessage({
|
|
993
|
+
content: message,
|
|
994
994
|
metadata,
|
|
995
|
-
);
|
|
995
|
+
});
|
|
996
996
|
if (!enqueueResult.queued && !enqueueResult.rejected) {
|
|
997
997
|
parentConversation
|
|
998
|
-
.persistUserMessage(
|
|
999
|
-
.then((messageId) =>
|
|
998
|
+
.persistUserMessage({ content: message, metadata })
|
|
999
|
+
.then(({ id: messageId }) =>
|
|
1000
1000
|
parentConversation.runAgentLoop(message, messageId),
|
|
1001
1001
|
)
|
|
1002
1002
|
.catch((err) => {
|