@vellumai/assistant 0.6.5 → 0.6.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 +9 -1
- package/ARCHITECTURE.md +15 -17
- package/Dockerfile +6 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +7 -6
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/plugins.md +761 -0
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +212 -68
- package/package.json +1 -1
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +7 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/checker.test.ts +459 -171
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema.test.ts +22 -9
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-window-manager.test.ts +355 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
- package/src/__tests__/conversation-agent-loop.test.ts +30 -141
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
- package/src/__tests__/conversation-process-callsite.test.ts +3 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
- package/src/__tests__/conversation-queue.test.ts +29 -14
- package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-queue.test.ts +7 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
- package/src/__tests__/conversation-speed-override.test.ts +6 -1
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +2 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +5 -68
- package/src/__tests__/model-intents.test.ts +4 -2
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +41 -76
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +44 -12
- package/src/__tests__/proxy-approval-callback.test.ts +69 -8
- package/src/__tests__/reaction-persistence.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/suggestion-routes.test.ts +103 -4
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +141 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/agent/loop.ts +340 -102
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -9
- package/src/cli/commands/conversations.ts +55 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/program.ts +25 -29
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-tool-registry.ts +0 -15
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +19 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/security.ts +6 -6
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +94 -5
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +190 -16
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/config-watcher.ts +0 -2
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
- package/src/daemon/conversation-agent-loop.ts +984 -683
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +14 -7
- package/src/daemon/conversation-runtime-assembly.ts +532 -411
- package/src/daemon/conversation-tool-setup.ts +41 -4
- package/src/daemon/conversation.ts +80 -35
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-model.ts +11 -0
- package/src/daemon/handlers/skills.ts +5 -1
- package/src/daemon/lifecycle.ts +33 -68
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +49 -0
- package/src/daemon/message-types/messages.ts +12 -0
- package/src/daemon/server.ts +5 -3
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +24 -1
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +41 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/ipc/__tests__/socket-path.test.ts +11 -50
- package/src/ipc/cli-client.ts +1 -1
- package/src/ipc/cli-server.ts +3 -3
- package/src/ipc/gateway-client.ts +4 -1
- package/src/ipc/routes/browser-context.ts +2 -0
- package/src/ipc/routes/browser.ts +1 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +14 -0
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/socket-path.ts +14 -38
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/conversation-crud.ts +48 -18
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +25 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/extraction.ts +10 -2
- package/src/memory/graph/graph-search.test.ts +1 -0
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/retriever.ts +10 -3
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/pkb/pkb-index.test.ts +1 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +65 -4
- package/src/memory/pkb/pkb-search.ts +40 -18
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +30 -14
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +293 -18
- package/src/permissions/approval-policy.ts +110 -58
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +414 -2
- package/src/permissions/bash-risk-classifier.ts +303 -60
- package/src/permissions/checker.ts +157 -29
- package/src/permissions/command-registry.test.ts +239 -0
- package/src/permissions/command-registry.ts +234 -54
- package/src/permissions/defaults.ts +5 -4
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +61 -4
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/types.ts +2 -0
- package/src/permissions/workspace-policy.ts +8 -3
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/providers/model-catalog.ts +52 -29
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/runtime/AGENTS.md +25 -16
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/http-server.ts +77 -8
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +17 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/conversation-routes.ts +223 -116
- package/src/runtime/routes/inbound-message-handler.ts +88 -13
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +0 -3
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +48 -8
- package/src/skills/catalog-cache.ts +12 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +88 -19
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/executor.ts +126 -74
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +98 -49
- package/src/tools/policy-context.ts +4 -0
- package/src/tools/registry.ts +140 -3
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/types.ts +28 -2
- package/src/util/platform.ts +7 -2
- package/src/util/pricing.ts +26 -3
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type { EmitFeedEventParams } from "../../../../../home/emit-feed-event.js";
|
|
4
|
+
|
|
5
|
+
// Capture all emitFeedEvent calls
|
|
6
|
+
const emittedEvents: EmitFeedEventParams[] = [];
|
|
7
|
+
|
|
8
|
+
mock.module("../../../../../home/emit-feed-event.js", () => ({
|
|
9
|
+
emitFeedEvent: async (params: EmitFeedEventParams) => {
|
|
10
|
+
emittedEvents.push(params);
|
|
11
|
+
return {
|
|
12
|
+
id: `emit:${params.source}:${params.dedupKey ?? "random"}`,
|
|
13
|
+
type: "action",
|
|
14
|
+
source: params.source,
|
|
15
|
+
title: params.title,
|
|
16
|
+
summary: params.summary,
|
|
17
|
+
priority: 50,
|
|
18
|
+
status: "new",
|
|
19
|
+
author: "assistant",
|
|
20
|
+
timestamp: new Date().toISOString(),
|
|
21
|
+
createdAt: new Date().toISOString(),
|
|
22
|
+
};
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
|
|
26
|
+
// Stub messaging provider dependencies
|
|
27
|
+
const mockCreateDraft = mock(async () => ({ id: "draft-123" }));
|
|
28
|
+
const mockCreateDraftRaw = mock(async () => ({ id: "draft-raw-456" }));
|
|
29
|
+
const mockGetThread = mock(async () => ({
|
|
30
|
+
messages: [
|
|
31
|
+
{
|
|
32
|
+
payload: {
|
|
33
|
+
headers: [
|
|
34
|
+
{ name: "From", value: "sender@example.com" },
|
|
35
|
+
{ name: "To", value: "user@example.com" },
|
|
36
|
+
{ name: "Subject", value: "Test Subject" },
|
|
37
|
+
{ name: "Message-ID", value: "<msg-1@example.com>" },
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
}));
|
|
43
|
+
const mockGetProfile = mock(async () => ({
|
|
44
|
+
emailAddress: "user@example.com",
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
mock.module("../../../../../messaging/providers/gmail/client.js", () => ({
|
|
48
|
+
createDraft: mockCreateDraft,
|
|
49
|
+
createDraftRaw: mockCreateDraftRaw,
|
|
50
|
+
getThread: mockGetThread,
|
|
51
|
+
getProfile: mockGetProfile,
|
|
52
|
+
}));
|
|
53
|
+
|
|
54
|
+
mock.module("../../../../../messaging/providers/gmail/mime-builder.js", () => ({
|
|
55
|
+
buildMultipartMime: () => "mock-raw-mime",
|
|
56
|
+
}));
|
|
57
|
+
|
|
58
|
+
const mockSendMessage = mock(async () => ({
|
|
59
|
+
id: "msg-sent-789",
|
|
60
|
+
threadId: "thread-1",
|
|
61
|
+
}));
|
|
62
|
+
const mockArchiveByQuery = mock(async () => ({
|
|
63
|
+
archived: 3,
|
|
64
|
+
truncated: false,
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
mock.module("../shared.js", () => ({
|
|
68
|
+
resolveProvider: async (platform?: string) => ({
|
|
69
|
+
id: platform === "slack" ? "slack" : "gmail",
|
|
70
|
+
displayName: platform === "slack" ? "Slack" : "Gmail",
|
|
71
|
+
sendMessage: mockSendMessage,
|
|
72
|
+
archiveByQuery: mockArchiveByQuery,
|
|
73
|
+
}),
|
|
74
|
+
getProviderConnection: async () => ({ token: "mock-token" }),
|
|
75
|
+
ok: (msg: string) => ({ status: "ok", output: msg }),
|
|
76
|
+
err: (msg: string) => ({ status: "error", output: msg }),
|
|
77
|
+
extractEmail: (addr: string) => addr.replace(/.*<(.+)>/, "$1").toLowerCase(),
|
|
78
|
+
extractHeader: (
|
|
79
|
+
headers: Array<{ name: string; value: string }>,
|
|
80
|
+
name: string,
|
|
81
|
+
) => headers.find((h: { name: string }) => h.name === name)?.value ?? null,
|
|
82
|
+
parseAddressList: (addrs: string | null) =>
|
|
83
|
+
addrs ? addrs.split(",").map((a: string) => a.trim()) : [],
|
|
84
|
+
}));
|
|
85
|
+
|
|
86
|
+
// Stub gmail-mime-helpers
|
|
87
|
+
mock.module("../gmail-mime-helpers.js", () => ({
|
|
88
|
+
guessMimeType: () => "application/octet-stream",
|
|
89
|
+
}));
|
|
90
|
+
|
|
91
|
+
// Stub conversation dependencies used by messaging-send cross-post
|
|
92
|
+
mock.module("../../../../../memory/conversation-crud.js", () => ({
|
|
93
|
+
addMessage: async () => ({ id: "msg-1" }),
|
|
94
|
+
getConversation: () => null,
|
|
95
|
+
}));
|
|
96
|
+
mock.module("../../../../../memory/conversation-disk-view.js", () => ({
|
|
97
|
+
syncMessageToDisk: () => {},
|
|
98
|
+
}));
|
|
99
|
+
mock.module("../../../../../memory/external-conversation-store.js", () => ({
|
|
100
|
+
getBindingByChannelChat: () => null,
|
|
101
|
+
}));
|
|
102
|
+
|
|
103
|
+
const { run: runSend } = await import("../messaging-send.js");
|
|
104
|
+
const { run: runArchive } = await import("../messaging-archive-by-sender.js");
|
|
105
|
+
|
|
106
|
+
const baseContext = {
|
|
107
|
+
workingDir: "/tmp/test",
|
|
108
|
+
conversationId: "conv-xyz",
|
|
109
|
+
assistantId: "assistant-1",
|
|
110
|
+
triggeredBySurfaceAction: true,
|
|
111
|
+
batchAuthorizedByTask: false,
|
|
112
|
+
approvedViaPrompt: false,
|
|
113
|
+
trustClass: "guardian" as const,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
beforeEach(() => {
|
|
117
|
+
emittedEvents.length = 0;
|
|
118
|
+
mockCreateDraft.mockClear();
|
|
119
|
+
mockCreateDraftRaw.mockClear();
|
|
120
|
+
mockSendMessage.mockClear();
|
|
121
|
+
mockArchiveByQuery.mockClear();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
afterEach(() => {
|
|
125
|
+
emittedEvents.length = 0;
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
describe("messaging-send feed events", () => {
|
|
129
|
+
test("Gmail draft creation emits with source 'gmail' and dedup by draft ID", async () => {
|
|
130
|
+
await runSend(
|
|
131
|
+
{
|
|
132
|
+
platform: "gmail",
|
|
133
|
+
conversation_id: "recipient@example.com",
|
|
134
|
+
text: "Hello there",
|
|
135
|
+
subject: "Test",
|
|
136
|
+
},
|
|
137
|
+
baseContext,
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
expect(emittedEvents).toHaveLength(1);
|
|
141
|
+
expect(emittedEvents[0].source).toBe("gmail");
|
|
142
|
+
expect(emittedEvents[0].title).toBe("Email Draft Created");
|
|
143
|
+
expect(emittedEvents[0].dedupKey).toBe("email-draft:draft-123");
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
test("Slack sends emit with source 'slack'", async () => {
|
|
147
|
+
await runSend(
|
|
148
|
+
{
|
|
149
|
+
platform: "slack",
|
|
150
|
+
conversation_id: "#general",
|
|
151
|
+
text: "Hello Slack",
|
|
152
|
+
},
|
|
153
|
+
baseContext,
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
expect(emittedEvents).toHaveLength(1);
|
|
157
|
+
expect(emittedEvents[0].source).toBe("slack");
|
|
158
|
+
expect(emittedEvents[0].title).toBe("Slack Message Sent");
|
|
159
|
+
expect(emittedEvents[0].dedupKey).toBe("message-sent:msg-sent-789");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("Non-Gmail, non-Slack sends emit with source 'gmail' as fallback", async () => {
|
|
163
|
+
await runSend(
|
|
164
|
+
{
|
|
165
|
+
platform: "other-email",
|
|
166
|
+
conversation_id: "user@example.com",
|
|
167
|
+
text: "Hello",
|
|
168
|
+
},
|
|
169
|
+
baseContext,
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(emittedEvents).toHaveLength(1);
|
|
173
|
+
expect(emittedEvents[0].source).toBe("gmail");
|
|
174
|
+
// Mock resolveProvider returns id:"gmail" for non-slack platforms,
|
|
175
|
+
// so this goes through the Gmail draft path
|
|
176
|
+
expect(emittedEvents[0].title).toBe("Email Draft Created");
|
|
177
|
+
expect(emittedEvents[0].summary).toBe("Created an email draft.");
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
describe("messaging-archive feed events", () => {
|
|
182
|
+
test("Archive emits only when result.archived > 0", async () => {
|
|
183
|
+
await runArchive(
|
|
184
|
+
{ platform: "gmail", query: "from:sender@example.com" },
|
|
185
|
+
baseContext,
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
expect(emittedEvents).toHaveLength(1);
|
|
189
|
+
expect(emittedEvents[0].source).toBe("gmail");
|
|
190
|
+
expect(emittedEvents[0].title).toBe("Messages Archived");
|
|
191
|
+
expect(emittedEvents[0].summary).toContain("Archived 3 message(s)");
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test("Zero-match archives do NOT emit", async () => {
|
|
195
|
+
mockArchiveByQuery.mockResolvedValueOnce({
|
|
196
|
+
archived: 0,
|
|
197
|
+
truncated: false,
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
await runArchive(
|
|
201
|
+
{ platform: "gmail", query: "from:nobody@example.com" },
|
|
202
|
+
baseContext,
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
expect(emittedEvents).toHaveLength(0);
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { emitFeedEvent } from "../../../../home/emit-feed-event.js";
|
|
1
2
|
import type {
|
|
2
3
|
ToolContext,
|
|
3
4
|
ToolExecutionResult,
|
|
4
5
|
} from "../../../../tools/types.js";
|
|
6
|
+
import { getLogger } from "../../../../util/logger.js";
|
|
5
7
|
import { err, getProviderConnection, ok, resolveProvider } from "./shared.js";
|
|
6
8
|
|
|
9
|
+
const log = getLogger("messaging-archive-by-sender");
|
|
10
|
+
|
|
7
11
|
export async function run(
|
|
8
12
|
input: Record<string, unknown>,
|
|
9
13
|
context: ToolContext,
|
|
@@ -46,6 +50,14 @@ export async function run(
|
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
const summary = `Archived ${result.archived} message(s) matching query: ${query}`;
|
|
53
|
+
void emitFeedEvent({
|
|
54
|
+
source: "gmail",
|
|
55
|
+
title: "Messages Archived",
|
|
56
|
+
summary,
|
|
57
|
+
dedupKey: `email-archive:${Date.now()}`,
|
|
58
|
+
}).catch((err) => {
|
|
59
|
+
log.warn({ err }, "Failed to emit email archive feed event");
|
|
60
|
+
});
|
|
49
61
|
if (result.truncated) {
|
|
50
62
|
return ok(
|
|
51
63
|
`${summary}\n\nNote: this operation was capped at 5000 messages. Additional messages matching the query may remain in the inbox. Run the command again to archive more.`,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { basename } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { emitFeedEvent } from "../../../../home/emit-feed-event.js";
|
|
4
5
|
import {
|
|
5
6
|
addMessage,
|
|
6
7
|
getConversation,
|
|
@@ -149,6 +150,14 @@ export async function run(
|
|
|
149
150
|
ccList.length > 0
|
|
150
151
|
? `To: ${toList.join(", ")}; Cc: ${ccList.join(", ")}`
|
|
151
152
|
: `To: ${toList.join(", ")}`;
|
|
153
|
+
void emitFeedEvent({
|
|
154
|
+
source: "gmail",
|
|
155
|
+
title: "Email Draft Created",
|
|
156
|
+
summary: `Drafted reply to ${recipientSummary}.`,
|
|
157
|
+
dedupKey: `email-draft:${draft.id}`,
|
|
158
|
+
}).catch((err) => {
|
|
159
|
+
log.warn({ err }, "Failed to emit email draft feed event");
|
|
160
|
+
});
|
|
152
161
|
return ok(
|
|
153
162
|
`Gmail draft created with ${attachments.length} attachment(s): ${filenames} (Draft ID: ${draft.id}). ${recipientSummary}. Review in Gmail Drafts, then tell me to send it or send it yourself.`,
|
|
154
163
|
);
|
|
@@ -169,6 +178,14 @@ export async function run(
|
|
|
169
178
|
ccList.length > 0
|
|
170
179
|
? `To: ${toList.join(", ")}; Cc: ${ccList.join(", ")}`
|
|
171
180
|
: `To: ${toList.join(", ")}`;
|
|
181
|
+
void emitFeedEvent({
|
|
182
|
+
source: "gmail",
|
|
183
|
+
title: "Email Draft Created",
|
|
184
|
+
summary: `Drafted reply to ${recipientSummary}.`,
|
|
185
|
+
dedupKey: `email-draft:${draft.id}`,
|
|
186
|
+
}).catch((err) => {
|
|
187
|
+
log.warn({ err }, "Failed to emit email draft feed event");
|
|
188
|
+
});
|
|
172
189
|
return ok(
|
|
173
190
|
`Gmail draft created (ID: ${draft.id}). ${recipientSummary}. Review in Gmail Drafts, then tell me to send it or send it yourself.`,
|
|
174
191
|
);
|
|
@@ -195,6 +212,14 @@ export async function run(
|
|
|
195
212
|
const draft = await createDraftRaw(gmailConn, raw, threadId);
|
|
196
213
|
|
|
197
214
|
const filenames = attachments.map((a) => a.filename).join(", ");
|
|
215
|
+
void emitFeedEvent({
|
|
216
|
+
source: "gmail",
|
|
217
|
+
title: "Email Draft Created",
|
|
218
|
+
summary: "Created an email draft.",
|
|
219
|
+
dedupKey: `email-draft:${draft.id}`,
|
|
220
|
+
}).catch((err) => {
|
|
221
|
+
log.warn({ err }, "Failed to emit email draft feed event");
|
|
222
|
+
});
|
|
198
223
|
return ok(
|
|
199
224
|
`Gmail draft created with ${attachments.length} attachment(s): ${filenames} (Draft ID: ${draft.id}). Review in Gmail Drafts, then tell me to send it or send it yourself.`,
|
|
200
225
|
);
|
|
@@ -211,6 +236,14 @@ export async function run(
|
|
|
211
236
|
undefined,
|
|
212
237
|
threadId,
|
|
213
238
|
);
|
|
239
|
+
void emitFeedEvent({
|
|
240
|
+
source: "gmail",
|
|
241
|
+
title: "Email Draft Created",
|
|
242
|
+
summary: "Created an email draft.",
|
|
243
|
+
dedupKey: `email-draft:${draft.id}`,
|
|
244
|
+
}).catch((err) => {
|
|
245
|
+
log.warn({ err }, "Failed to emit email draft feed event");
|
|
246
|
+
});
|
|
214
247
|
return ok(
|
|
215
248
|
`Gmail draft created (ID: ${draft.id}). Review it in your Gmail Drafts, then tell me to send it or send it yourself from Gmail.`,
|
|
216
249
|
);
|
|
@@ -224,6 +257,31 @@ export async function run(
|
|
|
224
257
|
assistantId: context.assistantId,
|
|
225
258
|
});
|
|
226
259
|
|
|
260
|
+
const sendSummary =
|
|
261
|
+
provider.id === "slack"
|
|
262
|
+
? "Sent a Slack message."
|
|
263
|
+
: provider.id === "telegram"
|
|
264
|
+
? "Sent a Telegram message."
|
|
265
|
+
: "Sent an email.";
|
|
266
|
+
void emitFeedEvent({
|
|
267
|
+
source:
|
|
268
|
+
provider.id === "slack"
|
|
269
|
+
? "slack"
|
|
270
|
+
: provider.id === "telegram"
|
|
271
|
+
? "telegram"
|
|
272
|
+
: "gmail",
|
|
273
|
+
title:
|
|
274
|
+
provider.id === "slack"
|
|
275
|
+
? "Slack Message Sent"
|
|
276
|
+
: provider.id === "telegram"
|
|
277
|
+
? "Telegram Message Sent"
|
|
278
|
+
: "Email Sent",
|
|
279
|
+
summary: sendSummary,
|
|
280
|
+
dedupKey: `message-sent:${result.id}`,
|
|
281
|
+
}).catch((err) => {
|
|
282
|
+
log.warn({ err }, "Failed to emit message send feed event");
|
|
283
|
+
});
|
|
284
|
+
|
|
227
285
|
const threadSuffix = result.threadId
|
|
228
286
|
? `, "thread_id": "${result.threadId}"`
|
|
229
287
|
: "";
|
|
@@ -8,7 +8,7 @@ metadata:
|
|
|
8
8
|
display-name: "Schedule"
|
|
9
9
|
---
|
|
10
10
|
|
|
11
|
-
Manage scheduled automations. Schedules can be **recurring** (cron or RRULE expression) or **one-shot** (a single `fire_at` timestamp).
|
|
11
|
+
Manage scheduled automations. Schedules can be **recurring** (cron or RRULE expression) or **one-shot** (a single `fire_at` timestamp). Schedules support three modes: **execute** (run a message through the assistant), **notify** (send a notification to the user), and **script** (run a shell command directly without LLM involvement).
|
|
12
12
|
|
|
13
13
|
## Schedule Syntax
|
|
14
14
|
|
|
@@ -70,11 +70,13 @@ Exclusions (EXDATE, EXRULE) always take precedence over inclusions (RRULE, RDATE
|
|
|
70
70
|
To create a one-time schedule that fires once and is done, pass `fire_at` (an ISO 8601 timestamp) instead of an `expression`. This replaces the old reminder concept - "remind me at 3pm" becomes a one-shot schedule with `fire_at`.
|
|
71
71
|
|
|
72
72
|
One-shot schedules:
|
|
73
|
+
|
|
73
74
|
- Fire once at the specified time, then are marked as `fired` and disabled.
|
|
74
75
|
- Support both `execute` and `notify` modes (see below).
|
|
75
76
|
- Can be cancelled before they fire.
|
|
76
77
|
|
|
77
78
|
Examples:
|
|
79
|
+
|
|
78
80
|
- "remind me at 3pm" → `schedule_create` with `fire_at: "2025-03-15T15:00:00-05:00"`, `mode: "notify"`
|
|
79
81
|
- "at 5pm, check my email and summarize it" → `schedule_create` with `fire_at`, `mode: "execute"`
|
|
80
82
|
|
|
@@ -84,8 +86,9 @@ The `mode` parameter controls what happens when a schedule fires:
|
|
|
84
86
|
|
|
85
87
|
- **execute** (default) - sends the schedule's message to a background assistant conversation for autonomous handling. The assistant processes the message as if the user sent it.
|
|
86
88
|
- **notify** - sends a notification to the user via the notification pipeline. No assistant processing occurs.
|
|
89
|
+
- **script** - runs the `script` field as a shell command directly. No LLM invoked, no conversation created. stdout/stderr are captured in the schedule run record. Exit code 0 = success, non-zero = error. Commands run in the workspace directory with a 60-second timeout.
|
|
87
90
|
|
|
88
|
-
Use `notify` for simple reminders ("remind me to take medicine at 9am")
|
|
91
|
+
Use `notify` for simple reminders ("remind me to take medicine at 9am"), `execute` for tasks that need assistant action ("check my calendar at 8am and send me a digest"), and `script` for lightweight shell automations that don't need LLM involvement ("refresh a cache", "poll an API", "rotate logs").
|
|
89
92
|
|
|
90
93
|
## Conversation Reuse
|
|
91
94
|
|
|
@@ -121,6 +124,7 @@ Optionally pass `routing_hints` (a JSON object) to influence routing decisions (
|
|
|
121
124
|
3. If neither field is present or the interface is `cli`, omit `preferred_channels`.
|
|
122
125
|
|
|
123
126
|
When a channel is determined, include it as a routing hint:
|
|
127
|
+
|
|
124
128
|
```
|
|
125
129
|
routing_hints: { preferred_channels: ["<resolved channel>"] }
|
|
126
130
|
routing_intent: "all_channels"
|
|
@@ -157,6 +161,7 @@ Phrases like "at the 45 minute mark", "at the top of the hour", "at noon", or "2
|
|
|
157
161
|
- "noon" / "midnight" → 12:00 PM or 12:00 AM today; if past, tomorrow
|
|
158
162
|
|
|
159
163
|
3. **Ask only if truly ambiguous** - if neither rule resolves, ask for clarification. Never silently default to "from now."
|
|
164
|
+
|
|
160
165
|
- Timezones default to the system timezone if omitted. Use IANA timezone identifiers (e.g. "America/Los_Angeles").
|
|
161
166
|
- Prefer RRULE for complex patterns that cron cannot express (e.g. "every other Tuesday", "last weekday of the month").
|
|
162
167
|
|
|
@@ -184,7 +189,7 @@ Scheduled messages run without user interaction. If the task produces output tha
|
|
|
184
189
|
Choose the right delivery tool based on the content:
|
|
185
190
|
|
|
186
191
|
- **Rich content** (digests, summaries, reports): For Gmail, use `messaging_send` with the target platform and conversation ID. For Slack, use the Slack Web API directly via CLI (`chat.postMessage`). This preserves the full content and posts directly.
|
|
187
|
-
- **Short alerts** (status updates, completion notices): Use `
|
|
192
|
+
- **Short alerts** (status updates, completion notices): Use `assistant notifications send` via `bash` to let the notification router pick the best channel. Note: the router's decision engine rewrites content into short alerts, so it is not suitable for rich content.
|
|
188
193
|
|
|
189
194
|
Example schedule message for a Slack digest:
|
|
190
195
|
|
|
@@ -32,7 +32,11 @@
|
|
|
32
32
|
},
|
|
33
33
|
"message": {
|
|
34
34
|
"type": "string",
|
|
35
|
-
"description": "The message to send to the assistant when the schedule triggers"
|
|
35
|
+
"description": "The message to send to the assistant when the schedule triggers. Required for execute and notify modes."
|
|
36
|
+
},
|
|
37
|
+
"script": {
|
|
38
|
+
"type": "string",
|
|
39
|
+
"description": "The shell command to run when the schedule triggers. Required for script mode. Runs in the workspace directory with a sanitized environment."
|
|
36
40
|
},
|
|
37
41
|
"enabled": {
|
|
38
42
|
"type": "boolean",
|
|
@@ -40,8 +44,8 @@
|
|
|
40
44
|
},
|
|
41
45
|
"mode": {
|
|
42
46
|
"type": "string",
|
|
43
|
-
"enum": ["notify", "execute"],
|
|
44
|
-
"description": "Whether to notify the user
|
|
47
|
+
"enum": ["notify", "execute", "script"],
|
|
48
|
+
"description": "Whether to notify the user, execute autonomously via LLM, or run a shell command directly. Defaults to \"execute\"."
|
|
45
49
|
},
|
|
46
50
|
"routing_intent": {
|
|
47
51
|
"type": "string",
|
|
@@ -65,7 +69,7 @@
|
|
|
65
69
|
"description": "Brief non-technical explanation of why this tool is being called"
|
|
66
70
|
}
|
|
67
71
|
},
|
|
68
|
-
"required": ["name"
|
|
72
|
+
"required": ["name"]
|
|
69
73
|
},
|
|
70
74
|
"executor": "tools/schedule-create.ts",
|
|
71
75
|
"execution_target": "host"
|
|
@@ -127,7 +131,11 @@
|
|
|
127
131
|
},
|
|
128
132
|
"message": {
|
|
129
133
|
"type": "string",
|
|
130
|
-
"description": "New message to send when triggered"
|
|
134
|
+
"description": "New message to send when triggered (for execute/notify modes)"
|
|
135
|
+
},
|
|
136
|
+
"script": {
|
|
137
|
+
"type": "string",
|
|
138
|
+
"description": "New shell command to run when triggered (for script mode)"
|
|
131
139
|
},
|
|
132
140
|
"enabled": {
|
|
133
141
|
"type": "boolean",
|
|
@@ -135,8 +143,8 @@
|
|
|
135
143
|
},
|
|
136
144
|
"mode": {
|
|
137
145
|
"type": "string",
|
|
138
|
-
"enum": ["notify", "execute"],
|
|
139
|
-
"description": "Whether to notify the user
|
|
146
|
+
"enum": ["notify", "execute", "script"],
|
|
147
|
+
"description": "Whether to notify the user, execute autonomously via LLM, or run a shell command directly"
|
|
140
148
|
},
|
|
141
149
|
"routing_intent": {
|
|
142
150
|
"type": "string",
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Script Mode Patterns
|
|
2
|
+
|
|
3
|
+
Script mode runs shell commands without LLM involvement, but scripts can escalate to the assistant or notify the user via CLI commands when conditions are met. This makes script mode a building block for conditional automation — fast, deterministic checks that only invoke heavier machinery when needed.
|
|
4
|
+
|
|
5
|
+
## Script → LLM Escalation
|
|
6
|
+
|
|
7
|
+
Use `assistant conversations wake` to hand off to the assistant when a script detects something that needs LLM reasoning. The wake command injects a hint into an existing conversation without creating a user-visible message.
|
|
8
|
+
|
|
9
|
+
Example: poll an API and wake the assistant only when results change.
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
LAST="/workspace/data/api-status-last.txt"
|
|
13
|
+
CURRENT=$(curl -sf https://api.example.com/status)
|
|
14
|
+
[ "$CURRENT" = "$(cat "$LAST" 2>/dev/null)" ] && exit 0
|
|
15
|
+
echo "$CURRENT" > "$LAST"
|
|
16
|
+
assistant conversations wake CONVERSATION_ID --hint "API status changed: $CURRENT" --source scheduled-poll
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Example: check disk usage and escalate to the assistant when it's high.
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
USAGE=$(df /workspace --output=pcent | tail -1 | tr -d ' %')
|
|
23
|
+
[ "$USAGE" -lt 90 ] && exit 0
|
|
24
|
+
assistant conversations wake CONVERSATION_ID --hint "Disk usage at ${USAGE}% — investigate and clean up" --source disk-monitor
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Script → Notification
|
|
28
|
+
|
|
29
|
+
Use `assistant notifications send` to alert the user directly when a script detects something noteworthy. No LLM is involved — the notification goes straight to the user's connected channels.
|
|
30
|
+
|
|
31
|
+
Example: check if a service is down and notify the user.
|
|
32
|
+
|
|
33
|
+
```sh
|
|
34
|
+
if ! curl -sf --max-time 5 https://myapp.example.com/health > /dev/null; then
|
|
35
|
+
assistant notifications send \
|
|
36
|
+
--source-channel scheduler \
|
|
37
|
+
--source-event-name schedule.notify \
|
|
38
|
+
--message "myapp.example.com health check failed" \
|
|
39
|
+
--urgency high \
|
|
40
|
+
--dedupe-key "myapp-health-$(date +%Y%m%d)"
|
|
41
|
+
fi
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
Example: notify when a long-running background job finishes.
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
if [ -f /workspace/data/export-complete.flag ]; then
|
|
48
|
+
assistant notifications send \
|
|
49
|
+
--source-channel scheduler \
|
|
50
|
+
--source-event-name schedule.notify \
|
|
51
|
+
--message "Data export finished — file ready at /workspace/data/export.csv" \
|
|
52
|
+
--no-requires-action
|
|
53
|
+
rm /workspace/data/export-complete.flag
|
|
54
|
+
fi
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Tips
|
|
58
|
+
|
|
59
|
+
Both patterns keep scheduled runs fast and cheap — the script exits immediately when nothing interesting happens, and only reaches for the assistant or notification system when there's something to act on. Use `quiet: true` on the schedule to suppress the per-run completion noise.
|
|
@@ -39,8 +39,6 @@ import * as contactMerge from "./bundled-skills/contacts/tools/contact-merge.js"
|
|
|
39
39
|
import * as contactSearch from "./bundled-skills/contacts/tools/contact-search.js";
|
|
40
40
|
import * as contactUpsert from "./bundled-skills/contacts/tools/contact-upsert.js";
|
|
41
41
|
import * as googleContacts from "./bundled-skills/contacts/tools/google-contacts.js";
|
|
42
|
-
// ── conversations ──────────────────────────────────────────────────────────────
|
|
43
|
-
import * as renameConversation from "./bundled-skills/conversations/tools/rename-conversation.js";
|
|
44
42
|
// ── document ───────────────────────────────────────────────────────────────────
|
|
45
43
|
import * as documentCreate from "./bundled-skills/document/tools/document-create.js";
|
|
46
44
|
import * as documentUpdate from "./bundled-skills/document/tools/document-update.js";
|
|
@@ -68,8 +66,6 @@ import * as messagingRead from "./bundled-skills/messaging/tools/messaging-read.
|
|
|
68
66
|
import * as messagingSearch from "./bundled-skills/messaging/tools/messaging-search.js";
|
|
69
67
|
import * as messagingSend from "./bundled-skills/messaging/tools/messaging-send.js";
|
|
70
68
|
import * as messagingSenderDigest from "./bundled-skills/messaging/tools/messaging-sender-digest.js";
|
|
71
|
-
// ── notifications ──────────────────────────────────────────────────────────────
|
|
72
|
-
import * as sendNotification from "./bundled-skills/notifications/tools/send-notification.js";
|
|
73
69
|
// ── phone-calls ────────────────────────────────────────────────────────────────
|
|
74
70
|
import * as callEnd from "./bundled-skills/phone-calls/tools/call-end.js";
|
|
75
71
|
import * as callStart from "./bundled-skills/phone-calls/tools/call-start.js";
|
|
@@ -84,8 +80,6 @@ import * as scheduleCreate from "./bundled-skills/schedule/tools/schedule-create
|
|
|
84
80
|
import * as scheduleDelete from "./bundled-skills/schedule/tools/schedule-delete.js";
|
|
85
81
|
import * as scheduleList from "./bundled-skills/schedule/tools/schedule-list.js";
|
|
86
82
|
import * as scheduleUpdate from "./bundled-skills/schedule/tools/schedule-update.js";
|
|
87
|
-
// ── screen-watch ───────────────────────────────────────────────────────────────
|
|
88
|
-
import * as startScreenWatch from "./bundled-skills/screen-watch/tools/start-screen-watch.js";
|
|
89
83
|
// ── sequences ──────────────────────────────────────────────────────────────────
|
|
90
84
|
import * as sequenceAnalytics from "./bundled-skills/sequences/tools/sequence-analytics.js";
|
|
91
85
|
import * as sequenceCreate from "./bundled-skills/sequences/tools/sequence-create.js";
|
|
@@ -152,9 +146,6 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
|
|
|
152
146
|
["contacts:tools/contact-merge.ts", contactMerge],
|
|
153
147
|
["contacts:tools/google-contacts.ts", googleContacts],
|
|
154
148
|
|
|
155
|
-
// conversations
|
|
156
|
-
["conversations:tools/rename-conversation.ts", renameConversation],
|
|
157
|
-
|
|
158
149
|
// document
|
|
159
150
|
["document:tools/document-create.ts", documentCreate],
|
|
160
151
|
["document:tools/document-update.ts", documentUpdate],
|
|
@@ -190,9 +181,6 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
|
|
|
190
181
|
["messaging:tools/messaging-sender-digest.ts", messagingSenderDigest],
|
|
191
182
|
["messaging:tools/messaging-archive-by-sender.ts", messagingArchiveBySender],
|
|
192
183
|
|
|
193
|
-
// notifications
|
|
194
|
-
["notifications:tools/send-notification.ts", sendNotification],
|
|
195
|
-
|
|
196
184
|
// phone-calls
|
|
197
185
|
["phone-calls:tools/call-start.ts", callStart],
|
|
198
186
|
["phone-calls:tools/call-status.ts", callStatus],
|
|
@@ -210,9 +198,6 @@ export const bundledToolRegistry = new Map<string, SkillToolScript>([
|
|
|
210
198
|
["schedule:tools/schedule-update.ts", scheduleUpdate],
|
|
211
199
|
["schedule:tools/schedule-delete.ts", scheduleDelete],
|
|
212
200
|
|
|
213
|
-
// screen-watch
|
|
214
|
-
["screen-watch:tools/start-screen-watch.ts", startScreenWatch],
|
|
215
|
-
|
|
216
201
|
// sequences
|
|
217
202
|
["sequences:tools/sequence-create.ts", sequenceCreate],
|
|
218
203
|
["sequences:tools/sequence-list.ts", sequenceList],
|
|
@@ -327,7 +327,7 @@
|
|
|
327
327
|
"key": "onboarding-pre-chat",
|
|
328
328
|
"label": "Pre-Chat Onboarding Flow",
|
|
329
329
|
"description": "Gates the 3-screen pre-chat onboarding flow (tools, tasks/tone, name exchange) shown before the first conversation",
|
|
330
|
-
"defaultEnabled":
|
|
330
|
+
"defaultEnabled": true
|
|
331
331
|
},
|
|
332
332
|
{
|
|
333
333
|
"id": "home-tab",
|
|
@@ -376,6 +376,22 @@
|
|
|
376
376
|
"label": "Message Height Cache",
|
|
377
377
|
"description": "Swap the transcript's LazyVStack for a plain VStack so scrollContentHeight is the true sum of row heights (no LazyVStack estimator drift). Row frames are not pinned — the earlier frame-pinning approach was removed because it caused overlap when rows grew past their first measurement (streaming, expanding thinking blocks). Tradeoff: eager layout — every row measures up-front, which can stall for many seconds to minutes on very long conversations.",
|
|
378
378
|
"defaultEnabled": true
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
"id": "permission-controls-v3",
|
|
382
|
+
"scope": "assistant",
|
|
383
|
+
"key": "permission-controls-v3",
|
|
384
|
+
"label": "Permission Controls v3",
|
|
385
|
+
"description": "Enables permission controls v3: gateway-backed auto-approve thresholds, risk badges on tool results, simplified Allow/Deny permission prompt, and rule editor modal.",
|
|
386
|
+
"defaultEnabled": false
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
"id": "compaction-playground",
|
|
390
|
+
"scope": "assistant",
|
|
391
|
+
"key": "compaction-playground",
|
|
392
|
+
"label": "Compaction Playground",
|
|
393
|
+
"description": "Expose the developer-only Compaction Playground tab in macOS Settings and enable the /playground/* HTTP endpoints for exercising compaction conditions. Dev-only; default off.",
|
|
394
|
+
"defaultEnabled": false
|
|
379
395
|
}
|
|
380
396
|
]
|
|
381
397
|
}
|
package/src/config/schema.ts
CHANGED
|
@@ -43,6 +43,8 @@ export {
|
|
|
43
43
|
TwilioConfigSchema,
|
|
44
44
|
WhatsAppConfigSchema,
|
|
45
45
|
} from "./schemas/channels.js";
|
|
46
|
+
export type { ConversationsConfig } from "./schemas/conversations.js";
|
|
47
|
+
export { ConversationsConfigSchema } from "./schemas/conversations.js";
|
|
46
48
|
export {
|
|
47
49
|
DEFAULT_ELEVENLABS_VOICE_ID,
|
|
48
50
|
VALID_CONVERSATION_TIMEOUTS,
|
|
@@ -240,6 +242,7 @@ import {
|
|
|
240
242
|
TwilioConfigSchema,
|
|
241
243
|
WhatsAppConfigSchema,
|
|
242
244
|
} from "./schemas/channels.js";
|
|
245
|
+
import { ConversationsConfigSchema } from "./schemas/conversations.js";
|
|
243
246
|
import { FilingConfigSchema } from "./schemas/filing.js";
|
|
244
247
|
import { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
|
|
245
248
|
import { HostBrowserConfigSchema } from "./schemas/host-browser.js";
|
|
@@ -307,6 +310,9 @@ export const AssistantConfigSchema = z
|
|
|
307
310
|
hostBrowser: HostBrowserConfigSchema.default(
|
|
308
311
|
HostBrowserConfigSchema.parse({}),
|
|
309
312
|
),
|
|
313
|
+
conversations: ConversationsConfigSchema.default(
|
|
314
|
+
ConversationsConfigSchema.parse({}),
|
|
315
|
+
),
|
|
310
316
|
journal: JournalConfigSchema.default(JournalConfigSchema.parse({})),
|
|
311
317
|
analysis: AnalysisConfigSchema.default(AnalysisConfigSchema.parse({})),
|
|
312
318
|
backup: BackupConfigSchema.default(BackupConfigSchema.parse({})),
|
|
@@ -328,6 +334,19 @@ export const AssistantConfigSchema = z
|
|
|
328
334
|
NotificationsConfigSchema.parse({}),
|
|
329
335
|
),
|
|
330
336
|
ui: UiConfigSchema.default(UiConfigSchema.parse({})),
|
|
337
|
+
// Per-plugin config blocks keyed by plugin name. The schema is intentionally
|
|
338
|
+
// permissive — each plugin's manifest supplies its own validator which the
|
|
339
|
+
// plugin bootstrap (`external-plugins-bootstrap.ts`) runs against the raw
|
|
340
|
+
// block under `plugins.<name>` before handing the parsed result to the
|
|
341
|
+
// plugin's `init()`. Keeping this open here means adding a new plugin does
|
|
342
|
+
// not require a core-schema change, while invalid configs still surface
|
|
343
|
+
// through the plugin's own validator at bootstrap.
|
|
344
|
+
plugins: z
|
|
345
|
+
.record(z.string(), z.unknown())
|
|
346
|
+
.optional()
|
|
347
|
+
.describe(
|
|
348
|
+
"Per-plugin configuration keyed by plugin name. Validated downstream by each plugin's manifest.config validator at bootstrap.",
|
|
349
|
+
),
|
|
331
350
|
collectUsageData: z
|
|
332
351
|
.boolean()
|
|
333
352
|
.default(true)
|
|
@@ -54,7 +54,7 @@ export const BackupConfigSchema = z
|
|
|
54
54
|
.int("backup.retention must be an integer")
|
|
55
55
|
.min(1, "backup.retention must be >= 1")
|
|
56
56
|
.max(100, "backup.retention must be <= 100")
|
|
57
|
-
.default(
|
|
57
|
+
.default(3)
|
|
58
58
|
.describe("Number of recent backups to retain"),
|
|
59
59
|
offsite: BackupOffsiteConfigSchema.default(
|
|
60
60
|
BackupOffsiteConfigSchema.parse({}),
|