@vellumai/assistant 0.7.2 → 0.8.0
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/ARCHITECTURE.md +45 -29
- package/Dockerfile +1 -0
- package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
- package/bun.lock +3 -0
- package/docs/architecture/memory.md +5 -2
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
- package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
- package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
- package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
- package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
- package/openapi.yaml +470 -25
- package/package.json +3 -1
- package/src/__tests__/annotate-risk-options.test.ts +291 -0
- package/src/__tests__/app-control-flow.test.ts +21 -11
- package/src/__tests__/approval-cascade.test.ts +8 -16
- package/src/__tests__/approval-routes-http.test.ts +6 -0
- package/src/__tests__/assistant-event-hub.test.ts +48 -0
- package/src/__tests__/assistant-event.test.ts +0 -10
- package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +48 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
- package/src/__tests__/call-constants.test.ts +10 -1
- package/src/__tests__/call-controller.test.ts +127 -0
- package/src/__tests__/call-conversation-messages.test.ts +8 -2
- package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
- package/src/__tests__/channel-readiness-service.test.ts +4 -2
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +58 -28
- package/src/__tests__/config-loader-backfill.test.ts +379 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +284 -1
- package/src/__tests__/config-schema.test.ts +1 -0
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
- package/src/__tests__/config-watcher.test.ts +140 -69
- package/src/__tests__/context-search-agent-runner.test.ts +61 -3
- package/src/__tests__/context-search-conversations-source.test.ts +0 -24
- package/src/__tests__/context-search-fanout.test.ts +0 -1
- package/src/__tests__/context-search-memory-source.test.ts +6 -33
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +12 -7
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop.test.ts +457 -8
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-init.benchmark.test.ts +1 -1
- package/src/__tests__/conversation-process-callsite.test.ts +38 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +74 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-store.test.ts +0 -18
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
- package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +476 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +61 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/credentials-cli.test.ts +7 -0
- package/src/__tests__/cu-unified-flow.test.ts +176 -10
- package/src/__tests__/date-context.test.ts +164 -2
- package/src/__tests__/disk-pressure-guard.test.ts +262 -0
- package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
- package/src/__tests__/disk-pressure-policy.test.ts +241 -0
- package/src/__tests__/disk-pressure-routes.test.ts +379 -0
- package/src/__tests__/disk-pressure-tools.test.ts +277 -0
- package/src/__tests__/disk-usage.test.ts +150 -0
- package/src/__tests__/events-client-registration.test.ts +52 -0
- package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
- package/src/__tests__/file-write-tool.test.ts +4 -10
- package/src/__tests__/filing-service.test.ts +2 -20
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -26
- package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
- package/src/__tests__/heartbeat-service.test.ts +260 -11
- package/src/__tests__/host-app-control-proxy.test.ts +195 -25
- package/src/__tests__/host-bash-proxy.test.ts +227 -34
- package/src/__tests__/host-bash-routes.test.ts +178 -13
- package/src/__tests__/host-cu-proxy.test.ts +210 -3
- package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
- package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
- package/src/__tests__/host-file-proxy.test.ts +268 -6
- package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
- package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
- package/src/__tests__/http-user-message-parity.test.ts +107 -1
- package/src/__tests__/injector-chain.test.ts +36 -16
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +154 -67
- package/src/__tests__/managed-profile-guard.test.ts +18 -0
- package/src/__tests__/mcp-abort-signal.test.ts +130 -0
- package/src/__tests__/memory-admin-recall.test.ts +3 -11
- package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
- package/src/__tests__/normalize-onboarding.test.ts +180 -0
- package/src/__tests__/notification-decision-fallback.test.ts +91 -0
- package/src/__tests__/notification-decision-strategy.test.ts +22 -0
- package/src/__tests__/oauth-cli.test.ts +121 -0
- package/src/__tests__/oauth-connect-routes.test.ts +316 -0
- package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
- package/src/__tests__/onboarding-persona-write.test.ts +308 -0
- package/src/__tests__/openai-provider.test.ts +45 -8
- package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
- package/src/__tests__/platform-callback-registration.test.ts +21 -4
- package/src/__tests__/platform.test.ts +2 -1
- package/src/__tests__/playbook-execution.test.ts +0 -43
- package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
- package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
- package/src/__tests__/provider-tool-name.test.ts +23 -0
- package/src/__tests__/relay-server.test.ts +60 -5
- package/src/__tests__/runtime-events-sse.test.ts +4 -8
- package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
- package/src/__tests__/secret-ingress-http.test.ts +0 -1
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
- package/src/__tests__/secret-response-routing.test.ts +7 -5
- package/src/__tests__/server-history-render.test.ts +82 -0
- package/src/__tests__/skill-include-graph.test.ts +31 -0
- package/src/__tests__/skill-load-tool.test.ts +44 -16
- package/src/__tests__/skills.test.ts +39 -0
- package/src/__tests__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
- package/src/__tests__/tool-executor.test.ts +155 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- package/src/__tests__/voice-session-bridge.test.ts +3 -0
- package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
- package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
- package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +120 -0
- package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +78 -0
- package/src/agent/loop.ts +11 -0
- package/src/approvals/guardian-request-resolvers.ts +3 -32
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-constants.ts +5 -8
- package/src/calls/call-controller.ts +130 -67
- package/src/calls/call-conversation-messages.ts +46 -10
- package/src/calls/relay-server.ts +7 -1
- package/src/calls/voice-session-bridge.ts +1 -1
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
- package/src/cli/commands/bash.ts +35 -108
- package/src/cli/commands/contacts.ts +64 -25
- package/src/cli/commands/credentials.ts +56 -0
- package/src/cli/commands/memory-v2.ts +11 -10
- package/src/cli/commands/oauth/__tests__/connect.test.ts +401 -219
- package/src/cli/commands/oauth/connect.ts +124 -40
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
- package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
- package/src/cli/commands/platform/index.ts +16 -7
- package/src/cli/commands/status.ts +57 -0
- package/src/cli/program.ts +4 -2
- package/src/config/assistant-feature-flags.ts +13 -3
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
- package/src/config/env.ts +0 -8
- package/src/config/feature-flag-registry.json +13 -5
- package/src/config/loader.ts +199 -27
- package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -5
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +2 -0
- package/src/config/schemas/memory-lifecycle.ts +13 -0
- package/src/config/schemas/memory-v2.ts +76 -12
- package/src/config/schemas/platform.ts +43 -3
- package/src/config/schemas/services.ts +28 -0
- package/src/config/seed-inference-profiles.ts +230 -33
- package/src/contacts/contact-store.ts +0 -25
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +32 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
- package/src/daemon/assistant-attachments.ts +4 -4
- package/src/daemon/config-watcher.ts +85 -57
- package/src/daemon/conversation-agent-loop-handlers.ts +38 -0
- package/src/daemon/conversation-agent-loop.ts +183 -43
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +22 -10
- package/src/daemon/conversation-process.ts +8 -0
- package/src/daemon/conversation-runtime-assembly.ts +26 -0
- package/src/daemon/conversation-store.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +211 -29
- package/src/daemon/conversation-tool-setup.ts +66 -19
- package/src/daemon/conversation.ts +18 -23
- package/src/daemon/date-context.ts +71 -22
- package/src/daemon/disk-pressure-background-gate.ts +73 -0
- package/src/daemon/disk-pressure-guard.ts +343 -0
- package/src/daemon/disk-pressure-policy.ts +163 -0
- package/src/daemon/handlers/shared.ts +26 -1
- package/src/daemon/handlers/skills.ts +3 -4
- package/src/daemon/host-app-control-proxy.ts +137 -41
- package/src/daemon/host-bash-proxy.ts +47 -22
- package/src/daemon/host-browser-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +50 -4
- package/src/daemon/host-file-proxy.ts +44 -8
- package/src/daemon/host-transfer-proxy.ts +97 -6
- package/src/daemon/lifecycle.ts +167 -101
- package/src/daemon/meet-host-supervisor.ts +4 -4
- package/src/daemon/meet-manifest-loader.ts +0 -1
- package/src/daemon/memory-v2-startup.ts +66 -15
- package/src/daemon/message-protocol.ts +3 -0
- package/src/daemon/message-types/conversations.ts +4 -0
- package/src/daemon/message-types/disk-pressure.ts +9 -0
- package/src/daemon/message-types/messages.ts +22 -1
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +119 -0
- package/src/filing/filing-service.ts +29 -5
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
- package/src/heartbeat/heartbeat-run-store.ts +13 -0
- package/src/heartbeat/heartbeat-service.ts +205 -31
- package/src/home/feed-scheduler.ts +18 -0
- package/src/inbound/platform-callback-registration.ts +8 -15
- package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
- package/src/ipc/assistant-server.ts +149 -38
- package/src/ipc/gateway-client.ts +37 -3
- package/src/ipc/skill-server.ts +99 -42
- package/src/live-voice/live-voice-archive.ts +4 -4
- package/src/live-voice/protocol.ts +5 -7
- package/src/media/image-service.ts +1 -7
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +34 -51
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
- package/src/memory/admin.ts +5 -9
- package/src/memory/context-search/agent-runner.ts +19 -2
- package/src/memory/context-search/sources/conversations.ts +2 -11
- package/src/memory/context-search/sources/memory-v2.ts +1 -16
- package/src/memory/context-search/sources/memory.ts +2 -3
- package/src/memory/context-search/sources/pkb.ts +2 -3
- package/src/memory/context-search/types.ts +0 -1
- package/src/memory/conversation-crud.ts +4 -12
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-runtime-manager.ts +119 -5
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +136 -82
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
- package/src/memory/graph/conversation-graph-memory.ts +72 -61
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +11 -67
- package/src/memory/graph/graph-search.ts +4 -24
- package/src/memory/graph/retriever.test.ts +12 -1
- package/src/memory/graph/retriever.ts +10 -15
- package/src/memory/graph/tool-handlers.ts +3 -4
- package/src/memory/graph/tools.ts +4 -4
- package/src/memory/indexer.ts +53 -45
- package/src/memory/job-handlers/backfill.ts +2 -11
- package/src/memory/job-handlers/cleanup.ts +43 -0
- package/src/memory/job-handlers/embedding.ts +6 -8
- package/src/memory/job-handlers/summarization.ts +2 -7
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +116 -0
- package/src/memory/jobs/embed-concept-page.ts +223 -87
- package/src/memory/jobs-store.ts +48 -0
- package/src/memory/jobs-worker.ts +85 -43
- package/src/memory/memory-v2-activation-log-store.ts +32 -14
- package/src/memory/memory-v2-concept-frequency.ts +169 -0
- package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +7 -0
- package/src/memory/pkb/pkb-search.ts +4 -5
- package/src/memory/qdrant-client.ts +3 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +10 -72
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +346 -255
- package/src/memory/v2/__tests__/consolidation-job.test.ts +61 -40
- package/src/memory/v2/__tests__/injection.test.ts +297 -190
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +326 -9
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +113 -196
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +77 -14
- package/src/memory/v2/__tests__/sweep-job.test.ts +19 -33
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +69 -20
- package/src/memory/v2/injection.ts +75 -68
- package/src/memory/v2/page-store.ts +39 -0
- package/src/memory/v2/prompts/consolidation.ts +41 -1
- package/src/memory/v2/qdrant.ts +306 -46
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +77 -110
- package/src/memory/v2/skill-content.ts +4 -3
- package/src/memory/v2/skill-store.ts +82 -59
- package/src/memory/v2/static-context.ts +26 -8
- package/src/memory/v2/sweep-job.ts +5 -6
- package/src/memory/v2/types.ts +17 -10
- package/src/notifications/copy-composer.ts +47 -0
- package/src/notifications/decision-engine.ts +46 -0
- package/src/notifications/signal.ts +4 -0
- package/src/oauth/AGENTS.md +3 -1
- package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
- package/src/oauth/connect-orchestrator.ts +2 -0
- package/src/oauth/connection-resolver.test.ts +66 -1
- package/src/oauth/connection-resolver.ts +55 -1
- package/src/oauth/oauth-connect-state.ts +77 -0
- package/src/oauth/seed-providers.ts +58 -1
- package/src/permissions/gateway-threshold-reader.ts +116 -8
- package/src/permissions/prompter.ts +86 -96
- package/src/permissions/secret-prompter.ts +31 -31
- package/src/plugins/defaults/injectors.ts +36 -4
- package/src/plugins/defaults/memory-retrieval.ts +5 -6
- package/src/plugins/types.ts +7 -0
- package/src/proactive-artifact/aux-message-injector.ts +74 -0
- package/src/proactive-artifact/decision.test.ts +226 -0
- package/src/proactive-artifact/decision.ts +165 -0
- package/src/proactive-artifact/index.ts +7 -0
- package/src/proactive-artifact/job.test.ts +914 -0
- package/src/proactive-artifact/job.ts +366 -0
- package/src/proactive-artifact/message-copy.ts +58 -0
- package/src/proactive-artifact/trigger-state.test.ts +277 -0
- package/src/proactive-artifact/trigger-state.ts +119 -0
- package/src/prompts/normalize-onboarding.ts +80 -0
- package/src/prompts/persona-resolver.ts +101 -9
- package/src/prompts/system-prompt.ts +21 -7
- package/src/prompts/templates/BOOTSTRAP.md +13 -5
- package/src/prompts/templates/SOUL.md +13 -28
- package/src/providers/__tests__/retry-callsite.test.ts +222 -1
- package/src/providers/model-intents.ts +7 -0
- package/src/providers/openrouter/client.ts +8 -0
- package/src/providers/retry.ts +50 -0
- package/src/providers/types.ts +1 -0
- package/src/runtime/__tests__/agent-wake.test.ts +456 -3
- package/src/runtime/agent-wake.ts +238 -100
- package/src/runtime/assistant-event-hub.ts +36 -6
- package/src/runtime/assistant-event.ts +0 -1
- package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
- package/src/runtime/auth/route-policy.ts +15 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-approvals.ts +3 -2
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +27 -15
- package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
- package/src/runtime/routes/approval-routes.ts +7 -3
- package/src/runtime/routes/client-routes.ts +20 -2
- package/src/runtime/routes/consolidation-routes.ts +8 -9
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-query-routes.ts +44 -1
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +165 -0
- package/src/runtime/routes/disk-pressure-routes.ts +121 -0
- package/src/runtime/routes/document-pdf-renderer.ts +6 -2
- package/src/runtime/routes/documents-routes.ts +2 -75
- package/src/runtime/routes/events-routes.ts +41 -9
- package/src/runtime/routes/filing-routes.ts +2 -3
- package/src/runtime/routes/host-bash-routes.ts +23 -3
- package/src/runtime/routes/host-cu-routes.ts +33 -6
- package/src/runtime/routes/host-file-routes.ts +32 -6
- package/src/runtime/routes/host-transfer-routes.ts +79 -16
- package/src/runtime/routes/identity-routes.ts +7 -138
- package/src/runtime/routes/inbound-message-handler.ts +77 -12
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +37 -17
- package/src/runtime/routes/memory-item-routes.ts +5 -6
- package/src/runtime/routes/memory-v2-routes.ts +136 -17
- package/src/runtime/routes/oauth-connect-routes.ts +153 -0
- package/src/runtime/verification-outbound-actions.ts +4 -4
- package/src/schedule/run-script.ts +37 -5
- package/src/schedule/scheduler.ts +20 -1
- package/src/security/encrypted-store.ts +2 -0
- package/src/security/secure-keys.ts +55 -0
- package/src/skills/include-graph.ts +35 -13
- package/src/skills/remote-skill-policy.ts +4 -10
- package/src/subagent/index.ts +1 -7
- package/src/subagent/manager.ts +1 -15
- package/src/tasks/task-runner.ts +0 -1
- package/src/tasks/task-store.ts +0 -3
- package/src/tools/background-tool-registry.ts +17 -3
- package/src/tools/document/document-tool.ts +20 -0
- package/src/tools/executor.ts +18 -2
- package/src/tools/host-filesystem/edit.test.ts +151 -0
- package/src/tools/host-filesystem/edit.ts +43 -1
- package/src/tools/host-filesystem/read.test.ts +129 -0
- package/src/tools/host-filesystem/read.ts +43 -1
- package/src/tools/host-filesystem/transfer.test.ts +127 -2
- package/src/tools/host-filesystem/transfer.ts +56 -11
- package/src/tools/host-filesystem/write.test.ts +134 -0
- package/src/tools/host-filesystem/write.ts +43 -1
- package/src/tools/host-terminal/host-shell.ts +13 -6
- package/src/tools/mcp/mcp-tool-factory.ts +2 -1
- package/src/tools/memory/register.test.ts +14 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/permission-checker.ts +15 -0
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/skills/load.ts +24 -20
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/tool-name-aliases.ts +19 -0
- package/src/tools/types.ts +43 -3
- package/src/tts/provider-catalog.ts +3 -5
- package/src/util/disk-usage.ts +138 -0
- package/src/util/platform.ts +21 -11
- package/src/util/process-liveness.ts +26 -0
- package/src/workspace/heartbeat-service.ts +19 -0
- package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
- package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +14 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +28 -0
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
- package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
- package/src/workspace/migrations/registry.ts +14 -0
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
- package/src/memory/v2/skill-qdrant.ts +0 -404
- package/src/signals/bash.ts +0 -198
|
@@ -26,6 +26,7 @@ import type { TtsProvider, TtsProviderId } from "../tts/types.js";
|
|
|
26
26
|
import { getLogger } from "../util/logger.js";
|
|
27
27
|
import { createStreamingEntry } from "./audio-store.js";
|
|
28
28
|
import {
|
|
29
|
+
getEndCallListenWindowMs,
|
|
29
30
|
getMaxCallDurationMs,
|
|
30
31
|
getSilenceTimeoutMs,
|
|
31
32
|
getUserConsultationTimeoutMs,
|
|
@@ -37,6 +38,7 @@ import {
|
|
|
37
38
|
registerCallController,
|
|
38
39
|
unregisterCallController,
|
|
39
40
|
} from "./call-state.js";
|
|
41
|
+
import { isTerminalState } from "./call-state-machine.js";
|
|
40
42
|
import {
|
|
41
43
|
createPendingQuestion,
|
|
42
44
|
expirePendingQuestions,
|
|
@@ -93,6 +95,7 @@ export class CallController {
|
|
|
93
95
|
private currentTurnPromise: Promise<void> | null = null;
|
|
94
96
|
private destroyed = false;
|
|
95
97
|
private silenceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
98
|
+
private endCallListenTimer: ReturnType<typeof setTimeout> | null = null;
|
|
96
99
|
private durationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
97
100
|
private durationWarningTimer: ReturnType<typeof setTimeout> | null = null;
|
|
98
101
|
/**
|
|
@@ -244,6 +247,8 @@ export class CallController {
|
|
|
244
247
|
transcript: string,
|
|
245
248
|
speaker?: PromptSpeakerContext,
|
|
246
249
|
): Promise<void> {
|
|
250
|
+
this.cancelPendingEndCall();
|
|
251
|
+
|
|
247
252
|
const interruptedInFlight =
|
|
248
253
|
this.state === "processing" || this.state === "speaking";
|
|
249
254
|
// If we're already processing or speaking, abort the in-flight generation
|
|
@@ -295,6 +300,8 @@ export class CallController {
|
|
|
295
300
|
return false;
|
|
296
301
|
}
|
|
297
302
|
|
|
303
|
+
this.cancelPendingEndCall();
|
|
304
|
+
|
|
298
305
|
// Clear the consultation timeout and record
|
|
299
306
|
clearTimeout(this.pendingGuardianInput.timer);
|
|
300
307
|
this.pendingGuardianInput = null;
|
|
@@ -326,6 +333,8 @@ export class CallController {
|
|
|
326
333
|
* position once the current turn completes.
|
|
327
334
|
*/
|
|
328
335
|
async handleUserInstruction(instructionText: string): Promise<void> {
|
|
336
|
+
this.cancelPendingEndCall();
|
|
337
|
+
|
|
329
338
|
recordCallEvent(this.callSessionId, "user_instruction_relayed", {
|
|
330
339
|
instruction: instructionText,
|
|
331
340
|
});
|
|
@@ -408,6 +417,7 @@ export class CallController {
|
|
|
408
417
|
destroy(): void {
|
|
409
418
|
this.destroyed = true;
|
|
410
419
|
if (this.silenceTimer) clearTimeout(this.silenceTimer);
|
|
420
|
+
if (this.endCallListenTimer) clearTimeout(this.endCallListenTimer);
|
|
411
421
|
if (this.durationTimer) clearTimeout(this.durationTimer);
|
|
412
422
|
if (this.durationWarningTimer) clearTimeout(this.durationWarningTimer);
|
|
413
423
|
if (this.pendingGuardianInput) {
|
|
@@ -419,6 +429,7 @@ export class CallController {
|
|
|
419
429
|
this.durationEndTimer = null;
|
|
420
430
|
}
|
|
421
431
|
this.pendingInstructions = [];
|
|
432
|
+
this.endCallListenTimer = null;
|
|
422
433
|
this.llmRunVersion++;
|
|
423
434
|
this.abortCurrentTurn();
|
|
424
435
|
if (this.activeSynthesisAbort) {
|
|
@@ -1075,73 +1086,7 @@ export class CallController {
|
|
|
1075
1086
|
|
|
1076
1087
|
// Check for END_CALL marker
|
|
1077
1088
|
if (responseText.includes(END_CALL_MARKER)) {
|
|
1078
|
-
|
|
1079
|
-
// Without this, the consultation timeout can fire on an already-ended
|
|
1080
|
-
// call, overwriting 'completed' status back to 'in_progress' and
|
|
1081
|
-
// starting a new LLM turn on a dead conversation. Similarly, a late
|
|
1082
|
-
// handleUserAnswer could be accepted since pendingGuardianInput is
|
|
1083
|
-
// still non-null.
|
|
1084
|
-
if (this.pendingGuardianInput) {
|
|
1085
|
-
clearTimeout(this.pendingGuardianInput.timer);
|
|
1086
|
-
|
|
1087
|
-
// Expire store-side consultation records so clients don't observe
|
|
1088
|
-
// a completed call with a dangling pendingQuestion, and guardian
|
|
1089
|
-
// replies are cleanly rejected instead of hitting answerCall failures.
|
|
1090
|
-
expirePendingQuestions(this.callSessionId);
|
|
1091
|
-
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1092
|
-
this.callSessionId,
|
|
1093
|
-
);
|
|
1094
|
-
if (previousRequest) {
|
|
1095
|
-
expireCanonicalGuardianRequest(previousRequest.id);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
this.pendingGuardianInput = null;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
const currentSession = getCallSession(this.callSessionId);
|
|
1102
|
-
const shouldNotifyCompletion = currentSession
|
|
1103
|
-
? currentSession.status !== "completed" &&
|
|
1104
|
-
currentSession.status !== "failed" &&
|
|
1105
|
-
currentSession.status !== "cancelled"
|
|
1106
|
-
: false;
|
|
1107
|
-
|
|
1108
|
-
this.transport.endSession("Call completed");
|
|
1109
|
-
updateCallSession(this.callSessionId, {
|
|
1110
|
-
status: "completed",
|
|
1111
|
-
endedAt: Date.now(),
|
|
1112
|
-
});
|
|
1113
|
-
recordCallEvent(this.callSessionId, "call_ended", {
|
|
1114
|
-
reason: "completed",
|
|
1115
|
-
});
|
|
1116
|
-
|
|
1117
|
-
// Notify the voice conversation
|
|
1118
|
-
if (shouldNotifyCompletion && currentSession) {
|
|
1119
|
-
finalizeCall(this.callSessionId, currentSession.conversationId);
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
// Post a pointer message in the initiating conversation
|
|
1123
|
-
if (currentSession?.initiatedFromConversationId) {
|
|
1124
|
-
const durationMs = currentSession.startedAt
|
|
1125
|
-
? Date.now() - currentSession.startedAt
|
|
1126
|
-
: 0;
|
|
1127
|
-
addPointerMessage(
|
|
1128
|
-
currentSession.initiatedFromConversationId,
|
|
1129
|
-
"completed",
|
|
1130
|
-
currentSession.toNumber,
|
|
1131
|
-
{
|
|
1132
|
-
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1133
|
-
},
|
|
1134
|
-
).catch((err) => {
|
|
1135
|
-
log.warn(
|
|
1136
|
-
{
|
|
1137
|
-
conversationId: currentSession.initiatedFromConversationId,
|
|
1138
|
-
err,
|
|
1139
|
-
},
|
|
1140
|
-
"Skipping pointer write — origin conversation may no longer exist",
|
|
1141
|
-
);
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
this.state = "idle";
|
|
1089
|
+
this.scheduleEndCallAfterListenWindow();
|
|
1145
1090
|
return;
|
|
1146
1091
|
}
|
|
1147
1092
|
|
|
@@ -1153,6 +1098,124 @@ export class CallController {
|
|
|
1153
1098
|
this.flushPendingInstructions();
|
|
1154
1099
|
}
|
|
1155
1100
|
|
|
1101
|
+
private scheduleEndCallAfterListenWindow(): void {
|
|
1102
|
+
const currentSession = getCallSession(this.callSessionId);
|
|
1103
|
+
if (currentSession && isTerminalState(currentSession.status)) {
|
|
1104
|
+
this.state = "idle";
|
|
1105
|
+
this.currentTurnHandle = null;
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const clearedPendingGuardianInput =
|
|
1110
|
+
this.clearPendingGuardianInputForCallEnd();
|
|
1111
|
+
this.state = "idle";
|
|
1112
|
+
this.currentTurnHandle = null;
|
|
1113
|
+
|
|
1114
|
+
if (this.endCallListenTimer) {
|
|
1115
|
+
clearTimeout(this.endCallListenTimer);
|
|
1116
|
+
this.endCallListenTimer = null;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
const listenWindowMs = getEndCallListenWindowMs();
|
|
1120
|
+
const callContinues =
|
|
1121
|
+
this.pendingInstructions.length > 0 || listenWindowMs > 0;
|
|
1122
|
+
if (clearedPendingGuardianInput && callContinues) {
|
|
1123
|
+
updateCallSession(this.callSessionId, { status: "in_progress" });
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (this.pendingInstructions.length > 0) {
|
|
1127
|
+
this.flushPendingInstructions();
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
if (listenWindowMs <= 0) {
|
|
1132
|
+
this.completeCallFromEndMarker();
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
this.resetSilenceTimer();
|
|
1137
|
+
this.endCallListenTimer = setTimeout(() => {
|
|
1138
|
+
this.endCallListenTimer = null;
|
|
1139
|
+
this.completeCallFromEndMarker();
|
|
1140
|
+
}, listenWindowMs);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
private cancelPendingEndCall(): void {
|
|
1144
|
+
if (!this.endCallListenTimer) return;
|
|
1145
|
+
clearTimeout(this.endCallListenTimer);
|
|
1146
|
+
this.endCallListenTimer = null;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
private clearPendingGuardianInputForCallEnd(): boolean {
|
|
1150
|
+
if (!this.pendingGuardianInput) return false;
|
|
1151
|
+
|
|
1152
|
+
clearTimeout(this.pendingGuardianInput.timer);
|
|
1153
|
+
|
|
1154
|
+
// Expire store-side consultation records so clients don't observe
|
|
1155
|
+
// a completed call with a dangling pendingQuestion, and guardian
|
|
1156
|
+
// replies are cleanly rejected instead of hitting answerCall failures.
|
|
1157
|
+
expirePendingQuestions(this.callSessionId);
|
|
1158
|
+
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1159
|
+
this.callSessionId,
|
|
1160
|
+
);
|
|
1161
|
+
if (previousRequest) {
|
|
1162
|
+
expireCanonicalGuardianRequest(previousRequest.id);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
this.pendingGuardianInput = null;
|
|
1166
|
+
return true;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
private completeCallFromEndMarker(): void {
|
|
1170
|
+
if (this.destroyed) return;
|
|
1171
|
+
|
|
1172
|
+
const currentSession = getCallSession(this.callSessionId);
|
|
1173
|
+
if (currentSession && isTerminalState(currentSession.status)) {
|
|
1174
|
+
this.state = "idle";
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const shouldNotifyCompletion = !!currentSession;
|
|
1179
|
+
|
|
1180
|
+
this.transport.endSession("Call completed");
|
|
1181
|
+
updateCallSession(this.callSessionId, {
|
|
1182
|
+
status: "completed",
|
|
1183
|
+
endedAt: Date.now(),
|
|
1184
|
+
});
|
|
1185
|
+
recordCallEvent(this.callSessionId, "call_ended", {
|
|
1186
|
+
reason: "completed",
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
// Notify the voice conversation
|
|
1190
|
+
if (shouldNotifyCompletion && currentSession) {
|
|
1191
|
+
finalizeCall(this.callSessionId, currentSession.conversationId);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// Post a pointer message in the initiating conversation
|
|
1195
|
+
if (currentSession?.initiatedFromConversationId) {
|
|
1196
|
+
const durationMs = currentSession.startedAt
|
|
1197
|
+
? Date.now() - currentSession.startedAt
|
|
1198
|
+
: 0;
|
|
1199
|
+
addPointerMessage(
|
|
1200
|
+
currentSession.initiatedFromConversationId,
|
|
1201
|
+
"completed",
|
|
1202
|
+
currentSession.toNumber,
|
|
1203
|
+
{
|
|
1204
|
+
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1205
|
+
},
|
|
1206
|
+
).catch((err) => {
|
|
1207
|
+
log.warn(
|
|
1208
|
+
{
|
|
1209
|
+
conversationId: currentSession.initiatedFromConversationId,
|
|
1210
|
+
err,
|
|
1211
|
+
},
|
|
1212
|
+
"Skipping pointer write — origin conversation may no longer exist",
|
|
1213
|
+
);
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
this.state = "idle";
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1156
1219
|
private isExpectedAbortError(err: unknown): boolean {
|
|
1157
1220
|
if (!(err instanceof Error)) return false;
|
|
1158
1221
|
return err.name === "AbortError" || err.name === "APIUserAbortError";
|
|
@@ -6,6 +6,21 @@
|
|
|
6
6
|
import { addMessage } from "../memory/conversation-crud.js";
|
|
7
7
|
import { getCallEvents, getCallSession } from "./call-store.js";
|
|
8
8
|
|
|
9
|
+
function buildCallSummaryLabel(
|
|
10
|
+
status: string | undefined,
|
|
11
|
+
duration: number | null,
|
|
12
|
+
eventCount: number,
|
|
13
|
+
): string {
|
|
14
|
+
const statusLabel =
|
|
15
|
+
status === "failed"
|
|
16
|
+
? "Call failed"
|
|
17
|
+
: status === "cancelled"
|
|
18
|
+
? "Call cancelled"
|
|
19
|
+
: "Call completed";
|
|
20
|
+
const durationStr = duration != null ? ` (${duration}s)` : "";
|
|
21
|
+
return `**${statusLabel}**${durationStr}. ${eventCount} event(s) recorded.`;
|
|
22
|
+
}
|
|
23
|
+
|
|
9
24
|
export function buildCallCompletionMessage(callSessionId: string): string {
|
|
10
25
|
const callSession = getCallSession(callSessionId);
|
|
11
26
|
const events = getCallEvents(callSessionId);
|
|
@@ -13,25 +28,46 @@ export function buildCallCompletionMessage(callSessionId: string): string {
|
|
|
13
28
|
callSession?.endedAt && callSession?.startedAt
|
|
14
29
|
? Math.round((callSession.endedAt - callSession.startedAt) / 1000)
|
|
15
30
|
: null;
|
|
16
|
-
|
|
17
|
-
const statusLabel =
|
|
18
|
-
callSession?.status === "failed"
|
|
19
|
-
? "Call failed"
|
|
20
|
-
: callSession?.status === "cancelled"
|
|
21
|
-
? "Call cancelled"
|
|
22
|
-
: "Call completed";
|
|
23
|
-
return `**${statusLabel}**${durationStr}. ${events.length} event(s) recorded.`;
|
|
31
|
+
return buildCallSummaryLabel(callSession?.status, duration, events.length);
|
|
24
32
|
}
|
|
25
33
|
|
|
26
34
|
export async function persistCallCompletionMessage(
|
|
27
35
|
conversationId: string,
|
|
28
36
|
callSessionId: string,
|
|
29
37
|
): Promise<string> {
|
|
30
|
-
const
|
|
38
|
+
const callSession = getCallSession(callSessionId);
|
|
39
|
+
const events = getCallEvents(callSessionId);
|
|
40
|
+
const duration =
|
|
41
|
+
callSession?.endedAt && callSession?.startedAt
|
|
42
|
+
? Math.round((callSession.endedAt - callSession.startedAt) / 1000)
|
|
43
|
+
: null;
|
|
44
|
+
const summaryText = buildCallSummaryLabel(
|
|
45
|
+
callSession?.status,
|
|
46
|
+
duration,
|
|
47
|
+
events.length,
|
|
48
|
+
);
|
|
49
|
+
|
|
31
50
|
await addMessage(
|
|
32
51
|
conversationId,
|
|
33
52
|
"assistant",
|
|
34
|
-
JSON.stringify([
|
|
53
|
+
JSON.stringify([
|
|
54
|
+
{
|
|
55
|
+
type: "ui_surface",
|
|
56
|
+
surfaceType: "call_summary",
|
|
57
|
+
surfaceId: crypto.randomUUID(),
|
|
58
|
+
completed: true,
|
|
59
|
+
data: {
|
|
60
|
+
summaryText,
|
|
61
|
+
status: callSession?.status ?? "completed",
|
|
62
|
+
duration,
|
|
63
|
+
events: events.map((e) => ({
|
|
64
|
+
eventType: e.eventType,
|
|
65
|
+
payloadJson: e.payloadJson,
|
|
66
|
+
createdAt: e.createdAt,
|
|
67
|
+
})),
|
|
68
|
+
},
|
|
69
|
+
},
|
|
70
|
+
]),
|
|
35
71
|
{
|
|
36
72
|
userMessageChannel: "phone",
|
|
37
73
|
assistantMessageChannel: "phone",
|
|
@@ -66,6 +66,8 @@ import {
|
|
|
66
66
|
} from "./speaker-identification.js";
|
|
67
67
|
|
|
68
68
|
const log = getLogger("relay-server");
|
|
69
|
+
const UUID_SHAPED_NAME =
|
|
70
|
+
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
69
71
|
|
|
70
72
|
// ── ConversationRelay message types ──────────────────────────────────
|
|
71
73
|
|
|
@@ -1615,7 +1617,11 @@ export class RelayConnection {
|
|
|
1615
1617
|
private resolveAssistantLabel(): string | null {
|
|
1616
1618
|
try {
|
|
1617
1619
|
const name = getAssistantName();
|
|
1618
|
-
|
|
1620
|
+
const trimmedName = name?.trim();
|
|
1621
|
+
if (!trimmedName || UUID_SHAPED_NAME.test(trimmedName)) {
|
|
1622
|
+
return null;
|
|
1623
|
+
}
|
|
1624
|
+
return trimmedName;
|
|
1619
1625
|
} catch {
|
|
1620
1626
|
return null;
|
|
1621
1627
|
}
|
|
@@ -233,7 +233,7 @@ function buildVoiceCallControlPrompt(opts: {
|
|
|
233
233
|
);
|
|
234
234
|
} else {
|
|
235
235
|
lines.push(
|
|
236
|
-
'7. If the latest user turn is "(call connected — deliver opening greeting)", this is an inbound call you are answering (not a call you initiated). Greet the caller warmly and ask how you can help. Introduce yourself once at the start using your assistant name if you know it (for example: "Hey there, this is Ava, Sam\'s assistant. How can I help?"). If your assistant name is not known, skip the name and just identify yourself as the guardian\'s assistant. Do NOT say "I\'m calling" or "I\'m calling on behalf of". Vary the wording; do not use a fixed template.',
|
|
236
|
+
'7. If the latest user turn is "(call connected — deliver opening greeting)", this is an inbound call you are answering (not a call you initiated). Greet the caller warmly and ask how you can help. Introduce yourself once at the start using your assistant name if you know it (for example: "Hey there, this is Ava, Sam\'s assistant. How can I help?"). If your assistant name is not known, skip the name and just identify yourself as the guardian\'s assistant. Never use a UUID-shaped internal assistant ID as your spoken name. Do NOT say "I\'m calling" or "I\'m calling on behalf of". Vary the wording; do not use a fixed template.',
|
|
237
237
|
);
|
|
238
238
|
}
|
|
239
239
|
lines.push(
|
|
@@ -14,7 +14,6 @@ let mockPlatformContext: Record<string, unknown> = {
|
|
|
14
14
|
isPlatform: false,
|
|
15
15
|
platformBaseUrl: "",
|
|
16
16
|
assistantId: "",
|
|
17
|
-
hasInternalApiKey: false,
|
|
18
17
|
hasAssistantApiKey: false,
|
|
19
18
|
authHeader: null,
|
|
20
19
|
enabled: false,
|
|
@@ -128,7 +127,6 @@ function connectedContext(
|
|
|
128
127
|
isPlatform: false,
|
|
129
128
|
platformBaseUrl: "https://test-platform.vellum.ai",
|
|
130
129
|
assistantId: "019d6d4f-6dbd-779f-91d3-cb273b9429a5",
|
|
131
|
-
hasInternalApiKey: false,
|
|
132
130
|
hasAssistantApiKey: true,
|
|
133
131
|
authHeader: "Api-Key vak_test123",
|
|
134
132
|
enabled: true,
|
|
@@ -145,7 +143,6 @@ describe("assistant webhooks register", () => {
|
|
|
145
143
|
isPlatform: false,
|
|
146
144
|
platformBaseUrl: "",
|
|
147
145
|
assistantId: "",
|
|
148
|
-
hasInternalApiKey: false,
|
|
149
146
|
hasAssistantApiKey: false,
|
|
150
147
|
authHeader: null,
|
|
151
148
|
enabled: false,
|
|
@@ -466,7 +463,6 @@ describe("assistant webhooks list", () => {
|
|
|
466
463
|
isPlatform: false,
|
|
467
464
|
platformBaseUrl: "",
|
|
468
465
|
assistantId: "",
|
|
469
|
-
hasInternalApiKey: false,
|
|
470
466
|
hasAssistantApiKey: false,
|
|
471
467
|
authHeader: null,
|
|
472
468
|
enabled: false,
|
package/src/cli/commands/bash.ts
CHANGED
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
import { randomUUID } from "node:crypto";
|
|
2
|
-
import {
|
|
3
|
-
existsSync,
|
|
4
|
-
mkdirSync,
|
|
5
|
-
readFileSync,
|
|
6
|
-
unlinkSync,
|
|
7
|
-
writeFileSync,
|
|
8
|
-
} from "node:fs";
|
|
9
|
-
import { join } from "node:path";
|
|
10
|
-
|
|
11
1
|
import type { Command } from "commander";
|
|
12
2
|
|
|
13
|
-
import {
|
|
3
|
+
import { cliIpcCall } from "../../ipc/cli-client.js";
|
|
14
4
|
import { log } from "../logger.js";
|
|
15
5
|
|
|
16
6
|
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
17
|
-
const POLL_INTERVAL_MS = 100;
|
|
18
7
|
|
|
19
|
-
interface
|
|
20
|
-
requestId: string;
|
|
8
|
+
interface DebugBashResult {
|
|
21
9
|
stdout: string;
|
|
22
10
|
stderr: string;
|
|
23
11
|
exitCode: number | null;
|
|
@@ -39,20 +27,16 @@ export function registerBashCommand(program: Command): void {
|
|
|
39
27
|
.addHelpText(
|
|
40
28
|
"after",
|
|
41
29
|
`
|
|
42
|
-
Sends a shell command to the running assistant for execution via the
|
|
43
|
-
|
|
44
|
-
|
|
30
|
+
Sends a shell command to the running assistant for execution via the IPC
|
|
31
|
+
socket. The assistant spawns the command in its own process environment and
|
|
32
|
+
returns stdout, stderr, and the exit code.
|
|
45
33
|
|
|
46
34
|
This is a developer debugging tool for inspecting how the assistant invokes and
|
|
47
35
|
observes shell commands. The command runs with the assistant's environment, working
|
|
48
36
|
directory, and process context — not the caller's shell.
|
|
49
37
|
|
|
50
38
|
Requires the assistant to be running with VELLUM_DEBUG=1. When debug mode is off
|
|
51
|
-
(the default), the assistant
|
|
52
|
-
|
|
53
|
-
The CLI writes the command to signals/bash.<requestId> and polls
|
|
54
|
-
signals/bash.<requestId>.result for the output. The assistant must be running
|
|
55
|
-
for this to work.
|
|
39
|
+
(the default), the assistant returns an error immediately.
|
|
56
40
|
|
|
57
41
|
Arguments:
|
|
58
42
|
command The shell command string to execute (e.g. "echo hello", "ls -la").
|
|
@@ -64,7 +48,7 @@ Examples:
|
|
|
64
48
|
$ assistant bash "env | grep PATH" --timeout 10000
|
|
65
49
|
$ assistant bash "ls -la"`,
|
|
66
50
|
)
|
|
67
|
-
.action((command: string, opts: { timeout: string }) => {
|
|
51
|
+
.action(async (command: string, opts: { timeout: string }) => {
|
|
68
52
|
const timeoutMs = parseInt(opts.timeout, 10);
|
|
69
53
|
if (!Number.isFinite(timeoutMs) || timeoutMs < 1) {
|
|
70
54
|
log.error("Invalid timeout value. Must be a positive integer.");
|
|
@@ -72,105 +56,48 @@ Examples:
|
|
|
72
56
|
return;
|
|
73
57
|
}
|
|
74
58
|
|
|
75
|
-
const
|
|
76
|
-
|
|
59
|
+
const result = await cliIpcCall<DebugBashResult>(
|
|
60
|
+
"debug_bash",
|
|
61
|
+
{ body: { command, timeoutMs } },
|
|
62
|
+
{ timeoutMs: timeoutMs + 10_000 },
|
|
63
|
+
);
|
|
77
64
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} catch {
|
|
81
|
-
log.error("Failed to create signals directory.");
|
|
65
|
+
if (!result.ok) {
|
|
66
|
+
log.error(result.error ?? "Failed to reach the assistant.");
|
|
82
67
|
process.exitCode = 1;
|
|
83
68
|
return;
|
|
84
69
|
}
|
|
85
70
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
try {
|
|
91
|
-
writeFileSync(
|
|
92
|
-
signalPath,
|
|
93
|
-
JSON.stringify({ requestId, command, timeoutMs }),
|
|
94
|
-
);
|
|
95
|
-
} catch {
|
|
96
|
-
log.error("Failed to write bash signal file.");
|
|
71
|
+
const data = result.result!;
|
|
72
|
+
|
|
73
|
+
if (data.error) {
|
|
74
|
+
log.error(data.error);
|
|
97
75
|
process.exitCode = 1;
|
|
98
76
|
return;
|
|
99
77
|
}
|
|
100
78
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
const deadline = Date.now() + timeoutMs + 5_000; // extra buffer for assistant overhead
|
|
106
|
-
|
|
107
|
-
const poll = setInterval(() => {
|
|
108
|
-
if (Date.now() > deadline) {
|
|
109
|
-
clearInterval(poll);
|
|
110
|
-
cleanupSignalFiles();
|
|
111
|
-
log.error(
|
|
112
|
-
"Timed out waiting for response. Is the assistant running?",
|
|
113
|
-
);
|
|
114
|
-
process.exitCode = 1;
|
|
115
|
-
return;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (!existsSync(resultPath)) return;
|
|
119
|
-
|
|
120
|
-
let result: BashSignalResult;
|
|
121
|
-
try {
|
|
122
|
-
const content = readFileSync(resultPath, "utf-8");
|
|
123
|
-
result = JSON.parse(content) as BashSignalResult;
|
|
124
|
-
} catch {
|
|
125
|
-
// File may be partially written; retry on next poll.
|
|
126
|
-
return;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Ignore stale results from a previous invocation.
|
|
130
|
-
if (result.requestId !== requestId) return;
|
|
131
|
-
|
|
132
|
-
clearInterval(poll);
|
|
133
|
-
cleanupSignalFiles();
|
|
134
|
-
|
|
135
|
-
if (result.error) {
|
|
136
|
-
log.error(result.error);
|
|
137
|
-
process.exitCode = 1;
|
|
138
|
-
return;
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
if (result.stdout) {
|
|
142
|
-
process.stdout.write(result.stdout);
|
|
143
|
-
if (!result.stdout.endsWith("\n")) {
|
|
144
|
-
process.stdout.write("\n");
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
if (result.stderr) {
|
|
149
|
-
process.stderr.write(result.stderr);
|
|
150
|
-
if (!result.stderr.endsWith("\n")) {
|
|
151
|
-
process.stderr.write("\n");
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
if (result.timedOut) {
|
|
156
|
-
log.info(`Command timed out in assistant.`);
|
|
79
|
+
if (data.stdout) {
|
|
80
|
+
process.stdout.write(data.stdout);
|
|
81
|
+
if (!data.stdout.endsWith("\n")) {
|
|
82
|
+
process.stdout.write("\n");
|
|
157
83
|
}
|
|
84
|
+
}
|
|
158
85
|
|
|
159
|
-
|
|
160
|
-
|
|
86
|
+
if (data.stderr) {
|
|
87
|
+
process.stderr.write(data.stderr);
|
|
88
|
+
if (!data.stderr.endsWith("\n")) {
|
|
89
|
+
process.stderr.write("\n");
|
|
161
90
|
}
|
|
91
|
+
}
|
|
162
92
|
|
|
163
|
-
|
|
164
|
-
|
|
93
|
+
if (data.timedOut) {
|
|
94
|
+
log.info(`Command timed out in assistant.`);
|
|
95
|
+
}
|
|
165
96
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
try {
|
|
169
|
-
unlinkSync(p);
|
|
170
|
-
} catch {
|
|
171
|
-
// Best-effort cleanup; the file may already be gone.
|
|
172
|
-
}
|
|
173
|
-
}
|
|
97
|
+
if (data.exitCode != null && data.exitCode !== 0) {
|
|
98
|
+
log.info(`Exit code: ${data.exitCode}`);
|
|
174
99
|
}
|
|
100
|
+
|
|
101
|
+
process.exitCode = data.exitCode ?? 1;
|
|
175
102
|
});
|
|
176
103
|
}
|