@vellumai/assistant 0.7.0 → 0.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +6 -7
- package/Dockerfile +1 -0
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
- package/bun.lock +3 -0
- package/docs/architecture/security.md +18 -16
- package/knip.json +1 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
- package/node_modules/@vellumai/slack-text/bun.lock +24 -0
- package/node_modules/@vellumai/slack-text/package.json +18 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
- package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
- package/openapi.yaml +294 -107
- package/package.json +4 -2
- package/scripts/generate-openapi.ts +16 -111
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
- package/src/__tests__/anthropic-provider.test.ts +56 -13
- package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
- package/src/__tests__/app-conversation-ids.test.ts +151 -0
- package/src/__tests__/approval-cascade.test.ts +0 -15
- package/src/__tests__/approval-routes-http.test.ts +6 -17
- package/src/__tests__/assistant-event-hub.test.ts +126 -77
- package/src/__tests__/assistant-event.test.ts +0 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
- package/src/__tests__/background-shell-host-bash.test.ts +34 -43
- package/src/__tests__/call-controller.test.ts +1 -1
- package/src/__tests__/call-site-routing-provider.test.ts +193 -0
- package/src/__tests__/channel-approval-routes.test.ts +10 -296
- package/src/__tests__/channel-approvals.test.ts +25 -17
- package/src/__tests__/channel-guardian.test.ts +100 -146
- package/src/__tests__/checker.test.ts +20 -34
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/config-schema.test.ts +6 -48
- package/src/__tests__/config-watcher.test.ts +12 -0
- package/src/__tests__/connection-policy.test.ts +1 -52
- package/src/__tests__/contacts-write.test.ts +2 -64
- package/src/__tests__/context-image-dimensions.test.ts +1 -1
- package/src/__tests__/context-search-memory-source.test.ts +120 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
- package/src/__tests__/context-search-pkb-source.test.ts +49 -0
- package/src/__tests__/context-search-workspace-source.test.ts +9 -22
- package/src/__tests__/context-window-manager.test.ts +46 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
- package/src/__tests__/conversation-agent-loop.test.ts +980 -13
- package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
- package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
- package/src/__tests__/conversation-history-web-search.test.ts +4 -3
- package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
- package/src/__tests__/conversation-lifecycle.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +79 -2
- package/src/__tests__/conversation-queue.test.ts +3 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
- package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
- package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
- package/src/__tests__/conversation-slash-commands.test.ts +24 -4
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-starter-routes.test.ts +79 -2
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
- package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
- package/src/__tests__/conversation-usage.test.ts +253 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
- package/src/__tests__/credential-health-service.test.ts +68 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -5
- package/src/__tests__/credential-token-resolver.test.ts +180 -0
- package/src/__tests__/cu-unified-flow.test.ts +33 -16
- package/src/__tests__/daemon-assistant-events.test.ts +34 -21
- package/src/__tests__/daemon-credential-client.test.ts +4 -1
- package/src/__tests__/db-connection-isolation.test.ts +125 -0
- package/src/__tests__/db-migration-rollback.test.ts +101 -0
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
- package/src/__tests__/document-conversations.test.ts +332 -0
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
- package/src/__tests__/emit-event-signal.test.ts +4 -6
- package/src/__tests__/events-client-registration.test.ts +193 -49
- package/src/__tests__/filing-service.test.ts +58 -7
- package/src/__tests__/first-greeting.test.ts +156 -150
- package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
- package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +7 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
- package/src/__tests__/guardian-routing-state.test.ts +1 -1
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
- package/src/__tests__/headless-browser-mode.test.ts +4 -9
- package/src/__tests__/headless-browser-navigate.test.ts +21 -20
- package/src/__tests__/heartbeat-service.test.ts +289 -7
- package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
- package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
- package/src/__tests__/host-bash-proxy.test.ts +46 -122
- package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
- package/src/__tests__/host-browser-proxy.test.ts +111 -185
- package/src/__tests__/host-browser-routes.test.ts +45 -75
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
- package/src/__tests__/host-cu-proxy.test.ts +56 -111
- package/src/__tests__/host-file-proxy.test.ts +44 -98
- package/src/__tests__/host-file-read-tool.test.ts +42 -21
- package/src/__tests__/host-shell-tool.test.ts +33 -68
- package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
- package/src/__tests__/host-transfer-proxy.test.ts +43 -53
- package/src/__tests__/http-user-message-parity.test.ts +0 -6
- package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
- package/src/__tests__/injector-chain.test.ts +10 -5
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -66
- package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
- package/src/__tests__/install-skill-routing.test.ts +1 -13
- package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
- package/src/__tests__/llm-catalog-parity.test.ts +90 -0
- package/src/__tests__/llm-context-resolution.test.ts +180 -0
- package/src/__tests__/llm-resolver.test.ts +80 -12
- package/src/__tests__/llm-usage-store.test.ts +269 -4
- package/src/__tests__/log-export-routes.test.ts +89 -0
- package/src/__tests__/managed-profile-guard.test.ts +225 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
- package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
- package/src/__tests__/migration-export-http.test.ts +33 -26
- package/src/__tests__/migration-export-streaming.test.ts +18 -10
- package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
- package/src/__tests__/migration-import-commit-http.test.ts +66 -21
- package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
- package/src/__tests__/migration-import-from-url.test.ts +20 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
- package/src/__tests__/migration-parity-persistence.test.ts +62 -25
- package/src/__tests__/migration-transport.test.ts +115 -23
- package/src/__tests__/migration-validate-http.test.ts +105 -80
- package/src/__tests__/migration-wizard.test.ts +133 -27
- package/src/__tests__/non-member-access-request.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +19 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
- package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
- package/src/__tests__/pricing.test.ts +68 -4
- package/src/__tests__/process-message-background-slack.test.ts +331 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
- package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
- package/src/__tests__/provider-usage-tracking.test.ts +208 -0
- package/src/__tests__/reaction-persistence.test.ts +9 -6
- package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
- package/src/__tests__/recording-handler.test.ts +64 -81
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
- package/src/__tests__/relay-server.test.ts +18 -13
- package/src/__tests__/require-fresh-approval.test.ts +13 -22
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +3 -12
- package/src/__tests__/search-skills-unified.test.ts +9 -15
- package/src/__tests__/secret-ingress-cli.test.ts +2 -5
- package/src/__tests__/secret-ingress-http.test.ts +0 -4
- package/src/__tests__/secret-onetime-send.test.ts +4 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
- package/src/__tests__/secret-response-routing.test.ts +29 -15
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
- package/src/__tests__/secret-scanner.test.ts +2 -545
- package/src/__tests__/send-endpoint-busy.test.ts +9 -24
- package/src/__tests__/settings-routes.test.ts +1 -1
- package/src/__tests__/shell-credential-ref.test.ts +0 -8
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
- package/src/__tests__/skill-tool-factory.test.ts +97 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
- package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
- package/src/__tests__/slack-inbound-verification.test.ts +1 -62
- package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
- package/src/__tests__/subagent-manager-notify.test.ts +70 -70
- package/src/__tests__/subagent-notify-parent.test.ts +80 -83
- package/src/__tests__/system-prompt.test.ts +115 -13
- package/src/__tests__/terminal-tools.test.ts +0 -89
- package/src/__tests__/thread-backfill.test.ts +945 -31
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
- package/src/__tests__/tool-executor.test.ts +12 -19
- package/src/__tests__/tool-metrics-listener.test.ts +0 -35
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-trace-listener.test.ts +0 -17
- package/src/__tests__/transfer-progress-screen.test.ts +63 -26
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +16 -5
- package/src/__tests__/usage-attribution.test.ts +247 -0
- package/src/__tests__/usage-cli.test.ts +143 -0
- package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
- package/src/__tests__/usage-routes.test.ts +150 -0
- package/src/__tests__/validation-results-screen.test.ts +39 -16
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
- package/src/__tests__/voice-session-bridge.test.ts +5 -5
- package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
- package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
- package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
- package/src/acp/index.ts +0 -15
- package/src/acp/session-manager.ts +37 -34
- package/src/agent/loop.ts +16 -1
- package/src/approvals/AGENTS.md +4 -0
- package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
- package/src/approvals/guardian-request-resolvers.ts +10 -2
- package/src/backup/__tests__/backup-worker.test.ts +36 -8
- package/src/backup/__tests__/paths.test.ts +2 -2
- package/src/backup/__tests__/restore.test.ts +45 -28
- package/src/backup/backup-worker.ts +36 -2
- package/src/backup/paths.ts +9 -6
- package/src/browser-session/events.ts +0 -9
- package/src/calls/call-store.ts +1 -34
- package/src/calls/guardian-question-copy.ts +0 -108
- package/src/calls/relay-server.ts +0 -24
- package/src/calls/twilio-rest.ts +0 -38
- package/src/calls/twilio-routes.ts +1 -1
- package/src/calls/voice-session-bridge.ts +7 -38
- package/src/channels/types.ts +1 -36
- package/src/cli/commands/__tests__/cache.test.ts +152 -5
- package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
- package/src/cli/commands/__tests__/trust.test.ts +21 -387
- package/src/cli/commands/backup.ts +4 -4
- package/src/cli/commands/cache-fs.ts +8 -0
- package/src/cli/commands/cache.ts +153 -82
- package/src/cli/commands/clients.ts +63 -5
- package/src/cli/commands/completions.ts +3 -3
- package/src/cli/commands/contacts.ts +231 -76
- package/src/cli/commands/keys.ts +4 -1
- package/src/cli/commands/memory-v2.ts +24 -52
- package/src/cli/commands/oauth/shared.ts +2 -29
- package/src/cli/commands/pending.ts +102 -0
- package/src/cli/commands/skills.ts +77 -35
- package/src/cli/commands/trust.ts +70 -430
- package/src/cli/commands/usage.ts +25 -16
- package/src/cli/lib/daemon-credential-client.ts +14 -0
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +0 -21
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
- package/src/config/env-registry.ts +12 -2
- package/src/config/env.ts +3 -14
- package/src/config/feature-flag-registry.json +30 -30
- package/src/config/llm-callsite-catalog.ts +12 -0
- package/src/config/llm-context-resolution.ts +80 -0
- package/src/config/llm-resolver.ts +58 -22
- package/src/config/loader.ts +3 -3
- package/src/config/schema.ts +2 -158
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +271 -0
- package/src/config/schemas/calls.ts +5 -5
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +31 -3
- package/src/config/schemas/memory-retrieval.ts +2 -2
- package/src/config/schemas/memory-v2.ts +9 -0
- package/src/config/schemas/security.ts +1 -42
- package/src/config/schemas/services.ts +6 -6
- package/src/config/schemas/skills.ts +5 -5
- package/src/config/schemas/tts.ts +1 -1
- package/src/config/seed-inference-profiles.ts +117 -0
- package/src/config/skills.ts +0 -90
- package/src/config/types.ts +3 -6
- package/src/contacts/contact-store.ts +0 -17
- package/src/contacts/contacts-write.ts +1 -105
- package/src/context/window-manager.ts +44 -5
- package/src/credential-execution/process-manager.ts +34 -10
- package/src/credential-health/credential-health-service.ts +21 -16
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
- package/src/daemon/connection-policy.ts +1 -26
- package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
- package/src/daemon/conversation-agent-loop.ts +277 -36
- package/src/daemon/conversation-history.ts +8 -8
- package/src/daemon/conversation-launch.ts +20 -135
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-process.ts +83 -163
- package/src/daemon/conversation-runtime-assembly.ts +219 -76
- package/src/daemon/conversation-slash.ts +47 -5
- package/src/daemon/conversation-store.ts +7 -31
- package/src/daemon/conversation-surfaces.ts +22 -28
- package/src/daemon/conversation-tool-setup.ts +3 -33
- package/src/daemon/conversation-usage.ts +36 -0
- package/src/daemon/conversation.ts +117 -233
- package/src/daemon/daemon-control.ts +3 -71
- package/src/daemon/daemon-skill-host.ts +8 -11
- package/src/daemon/dictation-profile-store.ts +2 -26
- package/src/daemon/first-greeting.ts +44 -156
- package/src/daemon/handlers/config-channels.ts +12 -12
- package/src/daemon/handlers/config-ingress.ts +4 -165
- package/src/daemon/handlers/config-model.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +0 -42
- package/src/daemon/handlers/conversations.ts +11 -190
- package/src/daemon/handlers/recording.ts +26 -158
- package/src/daemon/handlers/shared.ts +23 -71
- package/src/daemon/handlers/skills.ts +42 -93
- package/src/daemon/host-bash-proxy.ts +67 -45
- package/src/daemon/host-browser-proxy.ts +65 -27
- package/src/daemon/host-cu-proxy.ts +40 -39
- package/src/daemon/host-file-proxy.ts +58 -37
- package/src/daemon/host-transfer-proxy.ts +84 -46
- package/src/daemon/lifecycle.ts +49 -15
- package/src/daemon/message-types/conversations.ts +7 -0
- package/src/daemon/message-types/host-bash.ts +1 -0
- package/src/daemon/message-types/host-cu.ts +1 -0
- package/src/daemon/message-types/host-file.ts +1 -0
- package/src/daemon/message-types/host-transfer.ts +1 -0
- package/src/daemon/message-types/messages.ts +10 -9
- package/src/daemon/message-types/workspace.ts +1 -1
- package/src/daemon/process-message.ts +102 -239
- package/src/daemon/server.ts +13 -462
- package/src/daemon/shutdown-handlers.ts +2 -2
- package/src/daemon/tool-side-effects.ts +125 -107
- package/src/daemon/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +4 -9
- package/src/events/domain-events.ts +0 -8
- package/src/events/tool-audit-listener.ts +3 -1
- package/src/events/tool-domain-event-publisher.ts +0 -10
- package/src/events/tool-metrics-listener.ts +0 -17
- package/src/events/tool-trace-listener.ts +0 -14
- package/src/filing/filing-service.ts +13 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
- package/src/heartbeat/heartbeat-service.ts +23 -5
- package/src/home/__tests__/feed-writer.test.ts +0 -4
- package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
- package/src/home/feed-writer.ts +1 -2
- package/src/home/relationship-state-writer.ts +16 -3
- package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
- package/src/ipc/assistant-server.ts +3 -10
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
- package/src/ipc/routes/route-adapter.ts +1 -1
- package/src/ipc/routes/trust-rules.test.ts +0 -95
- package/src/ipc/skill-ipc-types.ts +41 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
- package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
- package/src/ipc/skill-routes/events.ts +12 -23
- package/src/ipc/skill-routes/identity.ts +4 -17
- package/src/ipc/skill-routes/index.ts +1 -1
- package/src/ipc/skill-server.ts +6 -39
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
- package/src/live-voice/protocol.ts +4 -13
- package/src/mcp/manager.ts +0 -5
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
- package/src/memory/app-git-service.ts +0 -32
- package/src/memory/app-store.ts +154 -0
- package/src/memory/attachments-store.ts +6 -0
- package/src/memory/context-search/sources/memory-v2.ts +578 -0
- package/src/memory/context-search/sources/memory.ts +5 -0
- package/src/memory/context-search/sources/pkb.ts +10 -1
- package/src/memory/context-search/sources/workspace.ts +3 -2
- package/src/memory/conversation-crud.ts +29 -4
- package/src/memory/conversation-disk-view.ts +1 -5
- package/src/memory/conversation-starter-checkpoints.ts +63 -0
- package/src/memory/db-connection.ts +62 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +3 -21
- package/src/memory/embedding-gemini.ts +0 -2
- package/src/memory/embedding-local.ts +6 -6
- package/src/memory/embedding-ollama.ts +6 -6
- package/src/memory/embedding-openai.ts +6 -6
- package/src/memory/embedding-types.ts +21 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
- package/src/memory/graph/conversation-graph-memory.ts +35 -13
- package/src/memory/graph/injection.test.ts +2 -2
- package/src/memory/graph/injection.ts +1 -1
- package/src/memory/guardian-action-store.ts +0 -83
- package/src/memory/guardian-approvals.ts +0 -48
- package/src/memory/indexer.ts +1 -15
- package/src/memory/job-handlers/conversation-starters.ts +36 -53
- package/src/memory/job-utils.ts +0 -6
- package/src/memory/jobs-store.ts +0 -1
- package/src/memory/jobs-worker.ts +2 -16
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +129 -43
- package/src/memory/memory-v2-activation-log-store.ts +115 -0
- package/src/memory/migrations/233-document-conversations.ts +54 -0
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
- package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
- package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
- package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +24 -0
- package/src/memory/raw-query.ts +2 -68
- package/src/memory/schema/conversations.ts +7 -0
- package/src/memory/schema/infrastructure.ts +25 -0
- package/src/memory/search/semantic.ts +5 -16
- package/src/memory/tool-usage-store.ts +2 -0
- package/src/memory/usage-buckets.ts +40 -1
- package/src/memory/usage-grouped-buckets.ts +127 -0
- package/src/memory/v2/__tests__/activation.test.ts +289 -90
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
- package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
- package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
- package/src/memory/v2/__tests__/injection.test.ts +384 -15
- package/src/memory/v2/__tests__/migration.test.ts +64 -36
- package/src/memory/v2/__tests__/page-store.test.ts +191 -8
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
- package/src/memory/v2/__tests__/static-context.test.ts +153 -0
- package/src/memory/v2/activation.ts +168 -97
- package/src/memory/v2/backfill-jobs.ts +15 -100
- package/src/memory/v2/consolidation-job.ts +14 -12
- package/src/memory/v2/edge-index.ts +191 -0
- package/src/memory/v2/injection.ts +182 -58
- package/src/memory/v2/migration.ts +57 -64
- package/src/memory/v2/now-text.ts +2 -3
- package/src/memory/v2/page-store.ts +168 -31
- package/src/memory/v2/prompts/consolidation.ts +118 -42
- package/src/memory/v2/prompts/sweep.ts +3 -3
- package/src/memory/v2/skill-store.ts +55 -7
- package/src/memory/v2/static-context.ts +62 -0
- package/src/memory/v2/types.ts +10 -20
- package/src/memory/validation.ts +0 -11
- package/src/messaging/draft-store.ts +0 -6
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/client.ts +1 -121
- package/src/messaging/providers/outlook/client.ts +0 -73
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
- package/src/messaging/providers/slack/adapter.ts +122 -21
- package/src/messaging/providers/slack/backfill.test.ts +95 -6
- package/src/messaging/providers/slack/backfill.ts +89 -11
- package/src/messaging/providers/slack/client.ts +10 -124
- package/src/messaging/providers/slack/message-metadata.ts +12 -2
- package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
- package/src/messaging/providers/slack/render-transcript.ts +126 -25
- package/src/messaging/providers/slack/types.ts +1 -0
- package/src/oauth/connection-resolver.test.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -16
- package/src/oauth/credential-token-resolver.ts +97 -0
- package/src/oauth/manual-token-connection.ts +30 -34
- package/src/oauth/oauth-store.ts +6 -4
- package/src/outbound-proxy/certs.ts +0 -7
- package/src/outbound-proxy/config.ts +0 -74
- package/src/outbound-proxy/health.ts +0 -44
- package/src/outbound-proxy/index.ts +0 -22
- package/src/permissions/approval-provenance.test.ts +184 -0
- package/src/permissions/approval-provenance.ts +70 -0
- package/src/permissions/checker.ts +4 -1
- package/src/permissions/gateway-threshold-reader.ts +4 -1
- package/src/permissions/prompter.ts +9 -2
- package/src/permissions/secret-prompter.ts +21 -48
- package/src/permissions/types.ts +33 -0
- package/src/permissions/workspace-policy.ts +0 -5
- package/src/platform/sync-identity.ts +0 -8
- package/src/plugins/defaults/injectors.ts +69 -2
- package/src/plugins/defaults/overflow-reduce.ts +3 -2
- package/src/plugins/types.ts +8 -0
- package/src/prompts/system-prompt.ts +34 -70
- package/src/prompts/templates/BOOTSTRAP.md +52 -6
- package/src/prompts/update-bulletin-job.ts +2 -0
- package/src/providers/__tests__/retry-callsite.test.ts +138 -1
- package/src/providers/anthropic/client.ts +72 -33
- package/src/providers/call-site-routing.ts +42 -3
- package/src/providers/gemini/client.ts +18 -2
- package/src/providers/managed-proxy/context.ts +0 -5
- package/src/providers/model-catalog.ts +105 -19
- package/src/providers/openai/chat-completions-provider.ts +6 -0
- package/src/providers/openai/responses-provider.ts +7 -1
- package/src/providers/provider-send-message.ts +45 -2
- package/src/providers/ratelimit.ts +7 -2
- package/src/providers/registry.ts +14 -9
- package/src/providers/retry.ts +96 -8
- package/src/providers/types.ts +13 -0
- package/src/providers/usage-tracking.ts +96 -0
- package/src/runtime/AGENTS.md +10 -6
- package/src/runtime/__tests__/agent-wake.test.ts +89 -0
- package/src/runtime/agent-wake.ts +39 -2
- package/src/runtime/assistant-event-hub.ts +541 -45
- package/src/runtime/assistant-event.ts +1 -6
- package/src/runtime/auth/context.ts +0 -9
- package/src/runtime/auth/middleware.ts +1 -1
- package/src/runtime/auth/route-policy.ts +11 -9
- package/src/runtime/auth/token-service.ts +0 -11
- package/src/runtime/channel-approvals.ts +6 -2
- package/src/runtime/channel-verification-service.ts +3 -5
- package/src/runtime/http-errors.ts +0 -34
- package/src/runtime/http-router.ts +6 -3
- package/src/runtime/http-server.ts +22 -82
- package/src/runtime/http-types.ts +5 -0
- package/src/runtime/interactive-ui.ts +0 -1
- package/src/runtime/middleware/auth.ts +0 -20
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
- package/src/runtime/migrations/migration-transport.ts +46 -13
- package/src/runtime/migrations/migration-wizard.ts +2 -2
- package/src/runtime/migrations/origin-mode.ts +40 -0
- package/src/runtime/migrations/vbundle-builder.ts +133 -79
- package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
- package/src/runtime/migrations/vbundle-importer.ts +7 -7
- package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
- package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
- package/src/runtime/migrations/vbundle-validator.ts +214 -41
- package/src/runtime/pending-interactions.ts +13 -4
- package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
- package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
- package/src/runtime/routes/acp-routes.test.ts +0 -3
- package/src/runtime/routes/acp-routes.ts +3 -7
- package/src/runtime/routes/app-management-routes.ts +18 -9
- package/src/runtime/routes/approval-routes.ts +55 -14
- package/src/runtime/routes/avatar-routes.ts +3 -5
- package/src/runtime/routes/browser-routes.ts +1 -15
- package/src/runtime/routes/channel-guardian-routes.ts +1 -5
- package/src/runtime/routes/channel-readiness-routes.ts +3 -7
- package/src/runtime/routes/channel-route-shared.ts +2 -28
- package/src/runtime/routes/client-routes.ts +45 -12
- package/src/runtime/routes/consolidation-routes.ts +115 -0
- package/src/runtime/routes/conversation-list-routes.ts +12 -29
- package/src/runtime/routes/conversation-management-routes.ts +14 -51
- package/src/runtime/routes/conversation-query-routes.ts +120 -8
- package/src/runtime/routes/conversation-routes.ts +44 -528
- package/src/runtime/routes/conversation-starter-routes.ts +19 -40
- package/src/runtime/routes/documents-routes.ts +53 -18
- package/src/runtime/routes/events-routes.ts +59 -91
- package/src/runtime/routes/filing-routes.ts +18 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -9
- package/src/runtime/routes/host-bash-routes.ts +3 -2
- package/src/runtime/routes/host-browser-routes.ts +9 -33
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +3 -2
- package/src/runtime/routes/host-transfer-routes.ts +11 -15
- package/src/runtime/routes/identity-routes.ts +78 -6
- package/src/runtime/routes/inbound-message-handler.ts +580 -137
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/integrations/slack/channel.ts +0 -24
- package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
- package/src/runtime/routes/memory-v2-routes.ts +10 -15
- package/src/runtime/routes/migration-routes.ts +188 -31
- package/src/runtime/routes/playground/guard.ts +1 -1
- package/src/runtime/routes/playground/index.ts +0 -2
- package/src/runtime/routes/recording-routes.ts +4 -24
- package/src/runtime/routes/rename-conversation-routes.ts +2 -6
- package/src/runtime/routes/schedule-routes.ts +3 -6
- package/src/runtime/routes/secret-routes.ts +87 -18
- package/src/runtime/routes/settings-routes.ts +29 -28
- package/src/runtime/routes/skills-routes.ts +12 -31
- package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
- package/src/runtime/routes/task-routes.ts +6 -6
- package/src/runtime/routes/trust-rules-routes.ts +3 -94
- package/src/runtime/routes/types.ts +4 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
- package/src/runtime/routes/usage-routes.ts +87 -10
- package/src/runtime/routes/user-routes.ts +17 -31
- package/src/runtime/routes/work-items-routes.ts +1 -4
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
- package/src/runtime/services/analyze-conversation.ts +7 -17
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/runtime/verification-outbound-actions.ts +1 -1
- package/src/runtime/verification-rate-limiter.ts +1 -1
- package/src/schedule/schedule-store.ts +0 -16
- package/src/security/secret-scanner.ts +14 -547
- package/src/security/secure-keys.ts +31 -11
- package/src/security/token-manager.ts +7 -3
- package/src/signals/cancel.ts +16 -25
- package/src/signals/conversation-undo.ts +2 -27
- package/src/signals/emit-event.ts +1 -2
- package/src/signals/user-message.ts +108 -22
- package/src/skills/catalog-install.ts +1 -0
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/inline-command-runner.ts +1 -7
- package/src/subagent/manager.ts +67 -84
- package/src/tasks/task-store.ts +1 -28
- package/src/telemetry/types.ts +6 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
- package/src/telemetry/usage-telemetry-reporter.ts +3 -5
- package/src/tools/acp/spawn.test.ts +1 -2
- package/src/tools/acp/steer.test.ts +1 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
- package/src/tools/browser/browser-execution.ts +31 -147
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
- package/src/tools/browser/cdp-client/factory.ts +48 -76
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/executor.ts +44 -31
- package/src/tools/host-filesystem/edit.ts +3 -2
- package/src/tools/host-filesystem/read.ts +3 -2
- package/src/tools/host-filesystem/transfer.test.ts +45 -42
- package/src/tools/host-filesystem/transfer.ts +4 -3
- package/src/tools/host-filesystem/write.ts +3 -2
- package/src/tools/host-terminal/host-shell.ts +4 -3
- package/src/tools/network/script-proxy/index.ts +1 -10
- package/src/tools/permission-checker.ts +66 -1
- package/src/tools/skills/sandbox-runner.ts +1 -6
- package/src/tools/skills/skill-tool-factory.ts +32 -0
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/terminal/shell.ts +2 -78
- package/src/tools/types.ts +12 -39
- package/src/tts/__tests__/provider-catalog.test.ts +2 -2
- package/src/tts/provider-catalog.ts +1 -1
- package/src/usage/actors.ts +2 -1
- package/src/usage/attribution.ts +185 -0
- package/src/usage/pricing.ts +166 -0
- package/src/usage/types.ts +14 -0
- package/src/util/json.ts +13 -0
- package/src/util/logger.ts +3 -3
- package/src/util/pricing.ts +50 -3
- package/src/work-items/work-item-runner.ts +15 -42
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
- package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
- package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
- package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
- package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/provider-commit-message-generator.ts +3 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
- package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
- package/src/__tests__/secret-detection-handler.test.ts +0 -67
- package/src/__tests__/secret-scanner-executor.test.ts +0 -450
- package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
- package/src/__tests__/terminal-sandbox.test.ts +0 -374
- package/src/__tests__/tool-notification-listener.test.ts +0 -65
- package/src/context/__tests__/microcompact.test.ts +0 -805
- package/src/context/microcompact.ts +0 -443
- package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
- package/src/events/tool-notification-listener.ts +0 -17
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
- package/src/memory/v2/__tests__/edges.test.ts +0 -435
- package/src/memory/v2/edges.ts +0 -217
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
- package/src/runtime/__tests__/client-registry.test.ts +0 -271
- package/src/runtime/chrome-extension-registry.ts +0 -368
- package/src/runtime/client-registry.ts +0 -254
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
- package/src/tools/secret-detection-handler.ts +0 -269
- package/src/tools/terminal/backends/native.ts +0 -327
- package/src/tools/terminal/backends/types.ts +0 -37
- package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
- package/src/tools/terminal/sandbox.ts +0 -40
|
@@ -55,11 +55,11 @@ mock.module("../runtime/gateway-client.js", () => ({
|
|
|
55
55
|
},
|
|
56
56
|
}));
|
|
57
57
|
|
|
58
|
-
import { createGuardianBinding } from "../contacts/contacts-write.js";
|
|
59
58
|
import { getDb } from "../memory/db-connection.js";
|
|
60
59
|
import { initializeDb } from "../memory/db-init.js";
|
|
61
60
|
import { findActiveSession } from "../runtime/channel-verification-service.js";
|
|
62
61
|
import { handleChannelInbound } from "./helpers/channel-test-adapter.js";
|
|
62
|
+
import { createGuardianBinding } from "./helpers/create-guardian-binding.js";
|
|
63
63
|
|
|
64
64
|
initializeDb();
|
|
65
65
|
|
|
@@ -257,65 +257,4 @@ describe("Slack inbound trusted contact verification", () => {
|
|
|
257
257
|
// No Slack DM was sent
|
|
258
258
|
});
|
|
259
259
|
|
|
260
|
-
test("user can verify by replying with the code in the DM", async () => {
|
|
261
|
-
// Step 1: Unknown user sends a message, gets verification challenge
|
|
262
|
-
const req = buildSlackInboundRequest();
|
|
263
|
-
await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
|
|
264
|
-
|
|
265
|
-
const session = findActiveSession("slack");
|
|
266
|
-
expect(session).not.toBeNull();
|
|
267
|
-
|
|
268
|
-
// The challenge hash is stored in the session — extract the secret
|
|
269
|
-
// from the DM text sent to the user. The code is embedded in the
|
|
270
|
-
// template text. Since we're using a 6-digit code for identity-bound
|
|
271
|
-
// sessions, extract it from the session's challengeHash by consuming
|
|
272
|
-
// the challenge directly.
|
|
273
|
-
// The session was created with createOutboundSession which generates
|
|
274
|
-
// a 6-digit code. We can validate by calling validateAndConsumeVerification
|
|
275
|
-
// with the correct secret. Since the mock captures the DM text, we
|
|
276
|
-
// can extract the code indirectly. But for testing, we just verify
|
|
277
|
-
// the session properties and that validateAndConsumeVerification works
|
|
278
|
-
// with the correct identity.
|
|
279
|
-
|
|
280
|
-
// The actual secret was sent in the DM. For this test, let's use the
|
|
281
|
-
// session directly via the channel-verification-service to verify the
|
|
282
|
-
// consume path works.
|
|
283
|
-
// The DM text contains the verification code implicitly (it's in the
|
|
284
|
-
// template message). Since we need to test the full round-trip, let's
|
|
285
|
-
// verify via the inbound handler by sending the code as a message.
|
|
286
|
-
|
|
287
|
-
// Extract the session's challenge hash and verify that submitting the
|
|
288
|
-
// correct code works. We create a fresh session with a known secret for
|
|
289
|
-
// this part of the test.
|
|
290
|
-
resetState();
|
|
291
|
-
|
|
292
|
-
// Create a verification session manually to test the consume path
|
|
293
|
-
const { createOutboundSession } =
|
|
294
|
-
await import("../runtime/channel-verification-service.js");
|
|
295
|
-
|
|
296
|
-
const outboundSession = createOutboundSession({
|
|
297
|
-
channel: "slack",
|
|
298
|
-
expectedExternalUserId: "U0123UNKNOWN",
|
|
299
|
-
expectedChatId: "U0123UNKNOWN",
|
|
300
|
-
identityBindingStatus: "bound",
|
|
301
|
-
destinationAddress: "U0123UNKNOWN",
|
|
302
|
-
verificationPurpose: "trusted_contact",
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
// User replies with the code in the DM
|
|
306
|
-
const verifyReq = buildSlackInboundRequest({
|
|
307
|
-
conversationExternalId: "U0123UNKNOWN",
|
|
308
|
-
content: outboundSession.secret,
|
|
309
|
-
externalMessageId: `msg-verify-${Date.now()}`,
|
|
310
|
-
});
|
|
311
|
-
const verifyResp = await handleChannelInbound(
|
|
312
|
-
verifyReq,
|
|
313
|
-
undefined,
|
|
314
|
-
TEST_BEARER_TOKEN,
|
|
315
|
-
);
|
|
316
|
-
const verifyJson = (await verifyResp.json()) as Record<string, unknown>;
|
|
317
|
-
|
|
318
|
-
expect(verifyJson.accepted).toBe(true);
|
|
319
|
-
expect(verifyJson.verificationOutcome).toBe("verified");
|
|
320
|
-
});
|
|
321
260
|
});
|
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
1
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
// ── Module mocks ──────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Captured messages from injectMessageIntoParent → findConversation → enqueueMessage.
|
|
7
|
+
* Each test clears this before use.
|
|
8
|
+
*/
|
|
9
|
+
const capturedNotifications: {
|
|
10
|
+
parentConversationId: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}[] = [];
|
|
13
|
+
|
|
14
|
+
mock.module("../daemon/conversation-store.js", () => ({
|
|
15
|
+
findConversation: (id: string) => ({
|
|
16
|
+
enqueueMessage: (content: string) => {
|
|
17
|
+
capturedNotifications.push({
|
|
18
|
+
parentConversationId: id,
|
|
19
|
+
message: content,
|
|
20
|
+
});
|
|
21
|
+
return { queued: true };
|
|
22
|
+
},
|
|
23
|
+
persistUserMessage: async () => "mock-msg",
|
|
24
|
+
runAgentLoop: async () => {},
|
|
25
|
+
}),
|
|
26
|
+
addConversation: () => {},
|
|
27
|
+
removeConversation: () => {},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
31
|
+
broadcastMessage: () => {},
|
|
32
|
+
}));
|
|
2
33
|
|
|
3
34
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
4
35
|
import { SubagentManager } from "../subagent/manager.js";
|
|
@@ -108,8 +139,13 @@ function makeForkState(
|
|
|
108
139
|
});
|
|
109
140
|
}
|
|
110
141
|
|
|
142
|
+
function clearCaptured(): void {
|
|
143
|
+
capturedNotifications.length = 0;
|
|
144
|
+
}
|
|
145
|
+
|
|
111
146
|
describe("Fork completion notifications", () => {
|
|
112
147
|
test("fork completion notification includes last_n: 1 guidance", async () => {
|
|
148
|
+
clearCaptured();
|
|
113
149
|
const manager = new SubagentManager();
|
|
114
150
|
const subagentId = "fork-1";
|
|
115
151
|
const state = makeForkState(subagentId);
|
|
@@ -119,21 +155,16 @@ describe("Fork completion notifications", () => {
|
|
|
119
155
|
managed.conversation!.persistUserMessage = () => "msg-1";
|
|
120
156
|
managed.conversation!.runAgentLoop = async () => {};
|
|
121
157
|
|
|
122
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
123
|
-
[];
|
|
124
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
125
|
-
notifications.push({ parentConversationId, message });
|
|
126
|
-
};
|
|
127
|
-
|
|
128
158
|
await asInternals(manager).runSubagent(subagentId, "Analyze data");
|
|
129
159
|
|
|
130
|
-
expect(
|
|
131
|
-
expect(
|
|
160
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
161
|
+
expect(capturedNotifications[0].message).toContain("last_n: 1");
|
|
132
162
|
|
|
133
163
|
asInternals(manager).stopSweep();
|
|
134
164
|
});
|
|
135
165
|
|
|
136
166
|
test("fork completion notification includes internal-processing instruction", async () => {
|
|
167
|
+
clearCaptured();
|
|
137
168
|
const manager = new SubagentManager();
|
|
138
169
|
const subagentId = "fork-1";
|
|
139
170
|
const state = makeForkState(subagentId);
|
|
@@ -143,19 +174,13 @@ describe("Fork completion notifications", () => {
|
|
|
143
174
|
managed.conversation!.persistUserMessage = () => "msg-1";
|
|
144
175
|
managed.conversation!.runAgentLoop = async () => {};
|
|
145
176
|
|
|
146
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
147
|
-
[];
|
|
148
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
149
|
-
notifications.push({ parentConversationId, message });
|
|
150
|
-
};
|
|
151
|
-
|
|
152
177
|
await asInternals(manager).runSubagent(subagentId, "Analyze data");
|
|
153
178
|
|
|
154
|
-
expect(
|
|
155
|
-
expect(
|
|
179
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
180
|
+
expect(capturedNotifications[0].message).toContain(
|
|
156
181
|
"do NOT share raw fork output with the user",
|
|
157
182
|
);
|
|
158
|
-
expect(
|
|
183
|
+
expect(capturedNotifications[0].message).toContain(
|
|
159
184
|
'[Fork "Analysis fork" completed]',
|
|
160
185
|
);
|
|
161
186
|
|
|
@@ -163,6 +188,7 @@ describe("Fork completion notifications", () => {
|
|
|
163
188
|
});
|
|
164
189
|
|
|
165
190
|
test("fork failure notification uses [Fork prefix", async () => {
|
|
191
|
+
clearCaptured();
|
|
166
192
|
const manager = new SubagentManager();
|
|
167
193
|
const subagentId = "fork-1";
|
|
168
194
|
const state = makeForkState(subagentId);
|
|
@@ -174,20 +200,14 @@ describe("Fork completion notifications", () => {
|
|
|
174
200
|
throw new Error("Context too large");
|
|
175
201
|
};
|
|
176
202
|
|
|
177
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
178
|
-
[];
|
|
179
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
180
|
-
notifications.push({ parentConversationId, message });
|
|
181
|
-
};
|
|
182
|
-
|
|
183
203
|
await asInternals(manager).runSubagent(subagentId, "Analyze data");
|
|
184
204
|
|
|
185
|
-
expect(
|
|
186
|
-
expect(
|
|
205
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
206
|
+
expect(capturedNotifications[0].message).toContain(
|
|
187
207
|
'[Fork "Analysis fork" failed]',
|
|
188
208
|
);
|
|
189
|
-
expect(
|
|
190
|
-
expect(
|
|
209
|
+
expect(capturedNotifications[0].message).toContain("Context too large");
|
|
210
|
+
expect(capturedNotifications[0].message).not.toContain("[Subagent");
|
|
191
211
|
|
|
192
212
|
asInternals(manager).stopSweep();
|
|
193
213
|
});
|
|
@@ -233,6 +253,7 @@ describe("Status response includes isFork", () => {
|
|
|
233
253
|
|
|
234
254
|
describe("Regular sub-agent notifications are unchanged", () => {
|
|
235
255
|
test("regular completed subagent uses [Subagent prefix", async () => {
|
|
256
|
+
clearCaptured();
|
|
236
257
|
const manager = new SubagentManager();
|
|
237
258
|
const subagentId = "sub-1";
|
|
238
259
|
const state = makeState(subagentId);
|
|
@@ -242,25 +263,20 @@ describe("Regular sub-agent notifications are unchanged", () => {
|
|
|
242
263
|
managed.conversation!.persistUserMessage = () => "msg-1";
|
|
243
264
|
managed.conversation!.runAgentLoop = async () => {};
|
|
244
265
|
|
|
245
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
246
|
-
[];
|
|
247
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
248
|
-
notifications.push({ parentConversationId, message });
|
|
249
|
-
};
|
|
250
|
-
|
|
251
266
|
await asInternals(manager).runSubagent(subagentId, "Do something");
|
|
252
267
|
|
|
253
|
-
expect(
|
|
254
|
-
expect(
|
|
268
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
269
|
+
expect(capturedNotifications[0].message).toContain(
|
|
255
270
|
'[Subagent "Test subagent" completed]',
|
|
256
271
|
);
|
|
257
|
-
expect(
|
|
258
|
-
expect(
|
|
272
|
+
expect(capturedNotifications[0].message).not.toContain("[Fork");
|
|
273
|
+
expect(capturedNotifications[0].message).not.toContain("last_n: 1");
|
|
259
274
|
|
|
260
275
|
asInternals(manager).stopSweep();
|
|
261
276
|
});
|
|
262
277
|
|
|
263
278
|
test("regular failed subagent uses [Subagent prefix", async () => {
|
|
279
|
+
clearCaptured();
|
|
264
280
|
const manager = new SubagentManager();
|
|
265
281
|
const subagentId = "sub-1";
|
|
266
282
|
const state = makeState(subagentId);
|
|
@@ -272,19 +288,13 @@ describe("Regular sub-agent notifications are unchanged", () => {
|
|
|
272
288
|
throw new Error("Something went wrong");
|
|
273
289
|
};
|
|
274
290
|
|
|
275
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
276
|
-
[];
|
|
277
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
278
|
-
notifications.push({ parentConversationId, message });
|
|
279
|
-
};
|
|
280
|
-
|
|
281
291
|
await asInternals(manager).runSubagent(subagentId, "Do something");
|
|
282
292
|
|
|
283
|
-
expect(
|
|
284
|
-
expect(
|
|
293
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
294
|
+
expect(capturedNotifications[0].message).toContain(
|
|
285
295
|
'[Subagent "Test subagent" failed]',
|
|
286
296
|
);
|
|
287
|
-
expect(
|
|
297
|
+
expect(capturedNotifications[0].message).not.toContain("[Fork");
|
|
288
298
|
|
|
289
299
|
asInternals(manager).stopSweep();
|
|
290
300
|
});
|
|
@@ -1,4 +1,35 @@
|
|
|
1
|
-
import { describe, expect, test } from "bun:test";
|
|
1
|
+
import { describe, expect, mock, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
// ── Module mocks ──────────────────────────────────────────────────
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Captured messages from injectMessageIntoParent → findConversation → enqueueMessage.
|
|
7
|
+
* Each test clears this before use.
|
|
8
|
+
*/
|
|
9
|
+
const capturedNotifications: {
|
|
10
|
+
parentConversationId: string;
|
|
11
|
+
message: string;
|
|
12
|
+
}[] = [];
|
|
13
|
+
|
|
14
|
+
mock.module("../daemon/conversation-store.js", () => ({
|
|
15
|
+
findConversation: (id: string) => ({
|
|
16
|
+
enqueueMessage: (content: string) => {
|
|
17
|
+
capturedNotifications.push({
|
|
18
|
+
parentConversationId: id,
|
|
19
|
+
message: content,
|
|
20
|
+
});
|
|
21
|
+
return { queued: true };
|
|
22
|
+
},
|
|
23
|
+
persistUserMessage: async () => "mock-msg",
|
|
24
|
+
runAgentLoop: async () => {},
|
|
25
|
+
}),
|
|
26
|
+
addConversation: () => {},
|
|
27
|
+
removeConversation: () => {},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
31
|
+
broadcastMessage: () => {},
|
|
32
|
+
}));
|
|
2
33
|
|
|
3
34
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
4
35
|
import { SubagentManager } from "../subagent/manager.js";
|
|
@@ -94,19 +125,18 @@ function makeState(
|
|
|
94
125
|
};
|
|
95
126
|
}
|
|
96
127
|
|
|
128
|
+
function clearCaptured(): void {
|
|
129
|
+
capturedNotifications.length = 0;
|
|
130
|
+
}
|
|
131
|
+
|
|
97
132
|
describe("SubagentManager abort notification", () => {
|
|
98
133
|
test("abort notifies parent with do-not-respawn message", () => {
|
|
134
|
+
clearCaptured();
|
|
99
135
|
const manager = new SubagentManager();
|
|
100
136
|
const subagentId = "sub-1";
|
|
101
137
|
const state = makeState(subagentId);
|
|
102
138
|
injectFakeSubagent(manager, subagentId, state);
|
|
103
139
|
|
|
104
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
105
|
-
[];
|
|
106
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
107
|
-
notifications.push({ parentConversationId, message });
|
|
108
|
-
};
|
|
109
|
-
|
|
110
140
|
const clientMessages: ServerMessage[] = [];
|
|
111
141
|
const sendToClient = (msg: ServerMessage) => clientMessages.push(msg);
|
|
112
142
|
|
|
@@ -114,21 +144,16 @@ describe("SubagentManager abort notification", () => {
|
|
|
114
144
|
|
|
115
145
|
expect(result).toBe(true);
|
|
116
146
|
expect(state.status).toBe("aborted");
|
|
117
|
-
expect(
|
|
118
|
-
expect(
|
|
119
|
-
expect(
|
|
147
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
148
|
+
expect(capturedNotifications[0].message).toContain("explicitly aborted");
|
|
149
|
+
expect(capturedNotifications[0].message).toContain("Do NOT re-spawn");
|
|
120
150
|
});
|
|
121
151
|
|
|
122
|
-
test("abort notification
|
|
152
|
+
test("abort notification goes to parent conversation via findConversation", () => {
|
|
153
|
+
clearCaptured();
|
|
123
154
|
const manager = new SubagentManager();
|
|
124
155
|
const subagentId = "sub-1";
|
|
125
|
-
const state = makeState(subagentId);
|
|
126
|
-
|
|
127
|
-
// Track which sender onSubagentFinished receives.
|
|
128
|
-
let notificationSender: unknown = null;
|
|
129
|
-
manager.onSubagentFinished = (_pid, _message, sender) => {
|
|
130
|
-
notificationSender = sender;
|
|
131
|
-
};
|
|
156
|
+
const state = makeState(subagentId); // parentConversationId = 'parent-sess-1'
|
|
132
157
|
|
|
133
158
|
// The parent's stored sender (set at spawn time).
|
|
134
159
|
const parentSender = () => {};
|
|
@@ -141,9 +166,9 @@ describe("SubagentManager abort notification", () => {
|
|
|
141
166
|
|
|
142
167
|
manager.abort(subagentId, abortingSender);
|
|
143
168
|
|
|
144
|
-
//
|
|
145
|
-
expect(
|
|
146
|
-
expect(
|
|
169
|
+
// Notification should be routed to the parent conversation via findConversation.
|
|
170
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
171
|
+
expect(capturedNotifications[0].parentConversationId).toBe("parent-sess-1");
|
|
147
172
|
});
|
|
148
173
|
|
|
149
174
|
test("abort sends subagent_status_changed to client", () => {
|
|
@@ -195,21 +220,18 @@ describe("SubagentManager abort notification", () => {
|
|
|
195
220
|
});
|
|
196
221
|
|
|
197
222
|
test("abort without sendToClient sets status but does not notify", () => {
|
|
223
|
+
clearCaptured();
|
|
198
224
|
const manager = new SubagentManager();
|
|
199
225
|
const subagentId = "sub-1";
|
|
200
226
|
const state = makeState(subagentId);
|
|
201
227
|
injectFakeSubagent(manager, subagentId, state);
|
|
202
228
|
|
|
203
|
-
let notified = false;
|
|
204
|
-
manager.onSubagentFinished = () => {
|
|
205
|
-
notified = true;
|
|
206
|
-
};
|
|
207
|
-
|
|
208
229
|
const result = manager.abort(subagentId);
|
|
209
230
|
|
|
210
231
|
expect(result).toBe(true);
|
|
211
232
|
expect(state.status).toBe("aborted");
|
|
212
|
-
|
|
233
|
+
// Without parentSendToClient, abort skips both the status update and notification.
|
|
234
|
+
expect(capturedNotifications).toHaveLength(0);
|
|
213
235
|
});
|
|
214
236
|
|
|
215
237
|
test("abort rejects when callerConversationId does not match parent", () => {
|
|
@@ -249,27 +271,26 @@ describe("SubagentManager abort notification", () => {
|
|
|
249
271
|
expect(state.status).toBe("aborted");
|
|
250
272
|
});
|
|
251
273
|
|
|
252
|
-
test("abort with suppressNotification skips
|
|
274
|
+
test("abort with suppressNotification skips parent notification", () => {
|
|
275
|
+
clearCaptured();
|
|
253
276
|
const manager = new SubagentManager();
|
|
254
277
|
const subagentId = "sub-1";
|
|
255
278
|
const state = makeState(subagentId);
|
|
256
279
|
injectFakeSubagent(manager, subagentId, state);
|
|
257
280
|
|
|
258
|
-
const notifications: string[] = [];
|
|
259
|
-
manager.onSubagentFinished = (_pid, message) => notifications.push(message);
|
|
260
|
-
|
|
261
281
|
const result = manager.abort(subagentId, () => {}, undefined, {
|
|
262
282
|
suppressNotification: true,
|
|
263
283
|
});
|
|
264
284
|
|
|
265
285
|
expect(result).toBe(true);
|
|
266
286
|
expect(state.status).toBe("aborted");
|
|
267
|
-
expect(
|
|
287
|
+
expect(capturedNotifications).toHaveLength(0);
|
|
268
288
|
});
|
|
269
289
|
});
|
|
270
290
|
|
|
271
291
|
describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
272
292
|
test("completed subagent notifies parent to use subagent_read", async () => {
|
|
293
|
+
clearCaptured();
|
|
273
294
|
const manager = new SubagentManager();
|
|
274
295
|
const subagentId = "sub-1";
|
|
275
296
|
const state = makeState(subagentId);
|
|
@@ -280,12 +301,6 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
|
280
301
|
managed.conversation!.persistUserMessage = () => "msg-1";
|
|
281
302
|
managed.conversation!.runAgentLoop = async () => {};
|
|
282
303
|
|
|
283
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
284
|
-
[];
|
|
285
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
286
|
-
notifications.push({ parentConversationId, message });
|
|
287
|
-
};
|
|
288
|
-
|
|
289
304
|
await asInternals(manager).runSubagent(subagentId, "Do something");
|
|
290
305
|
|
|
291
306
|
expect(state.status).toBe("completed");
|
|
@@ -294,17 +309,18 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
|
294
309
|
outputTokens: 50,
|
|
295
310
|
estimatedCost: 0.005,
|
|
296
311
|
});
|
|
297
|
-
expect(
|
|
298
|
-
expect(
|
|
299
|
-
expect(
|
|
312
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
313
|
+
expect(capturedNotifications[0].parentConversationId).toBe("parent-sess-1");
|
|
314
|
+
expect(capturedNotifications[0].message).toContain(
|
|
300
315
|
'[Subagent "Test subagent" completed]',
|
|
301
316
|
);
|
|
302
|
-
expect(
|
|
317
|
+
expect(capturedNotifications[0].message).toContain("subagent_read");
|
|
303
318
|
|
|
304
319
|
asInternals(manager).stopSweep();
|
|
305
320
|
});
|
|
306
321
|
|
|
307
322
|
test("failed subagent notifies parent with error and asks user before retry", async () => {
|
|
323
|
+
clearCaptured();
|
|
308
324
|
const manager = new SubagentManager();
|
|
309
325
|
const subagentId = "sub-1";
|
|
310
326
|
const state = makeState(subagentId);
|
|
@@ -318,12 +334,6 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
|
318
334
|
throw new Error("API rate limit exceeded");
|
|
319
335
|
};
|
|
320
336
|
|
|
321
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
322
|
-
[];
|
|
323
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
324
|
-
notifications.push({ parentConversationId, message });
|
|
325
|
-
};
|
|
326
|
-
|
|
327
337
|
await asInternals(manager).runSubagent(subagentId, "Do something");
|
|
328
338
|
|
|
329
339
|
expect(state.status).toBe("failed");
|
|
@@ -333,15 +343,18 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
|
333
343
|
outputTokens: 50,
|
|
334
344
|
estimatedCost: 0.005,
|
|
335
345
|
});
|
|
336
|
-
expect(
|
|
337
|
-
expect(
|
|
338
|
-
expect(
|
|
339
|
-
|
|
346
|
+
expect(capturedNotifications).toHaveLength(1);
|
|
347
|
+
expect(capturedNotifications[0].message).toContain("failed");
|
|
348
|
+
expect(capturedNotifications[0].message).toContain(
|
|
349
|
+
"API rate limit exceeded",
|
|
350
|
+
);
|
|
351
|
+
expect(capturedNotifications[0].message).toContain("Do NOT re-spawn");
|
|
340
352
|
|
|
341
353
|
asInternals(manager).stopSweep();
|
|
342
354
|
});
|
|
343
355
|
|
|
344
356
|
test("failed subagent does not notify if already aborted", async () => {
|
|
357
|
+
clearCaptured();
|
|
345
358
|
const manager = new SubagentManager();
|
|
346
359
|
const subagentId = "sub-1";
|
|
347
360
|
const state = makeState(subagentId, { status: "aborted" });
|
|
@@ -354,16 +367,10 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
|
354
367
|
throw new Error("Conversation aborted");
|
|
355
368
|
};
|
|
356
369
|
|
|
357
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
358
|
-
[];
|
|
359
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
360
|
-
notifications.push({ parentConversationId, message });
|
|
361
|
-
};
|
|
362
|
-
|
|
363
370
|
await asInternals(manager).runSubagent(subagentId, "Do something");
|
|
364
371
|
|
|
365
372
|
// Should NOT notify — status was already terminal (aborted).
|
|
366
|
-
expect(
|
|
373
|
+
expect(capturedNotifications).toHaveLength(0);
|
|
367
374
|
|
|
368
375
|
asInternals(manager).stopSweep();
|
|
369
376
|
});
|
|
@@ -371,6 +378,7 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
|
|
|
371
378
|
|
|
372
379
|
describe("SubagentManager abortAllForParent", () => {
|
|
373
380
|
test("aborts all active children of a parent", () => {
|
|
381
|
+
clearCaptured();
|
|
374
382
|
const manager = new SubagentManager();
|
|
375
383
|
injectFakeSubagent(manager, "sub-1", makeState("sub-1"));
|
|
376
384
|
injectFakeSubagent(manager, "sub-2", makeState("sub-2"));
|
|
@@ -380,13 +388,10 @@ describe("SubagentManager abortAllForParent", () => {
|
|
|
380
388
|
makeState("sub-3", { status: "completed" }),
|
|
381
389
|
);
|
|
382
390
|
|
|
383
|
-
const notifications: string[] = [];
|
|
384
|
-
manager.onSubagentFinished = (_pid, message) => notifications.push(message);
|
|
385
|
-
|
|
386
391
|
const count = manager.abortAllForParent("parent-sess-1", () => {});
|
|
387
392
|
|
|
388
393
|
expect(count).toBe(2); // sub-1 and sub-2, not sub-3 (already completed)
|
|
389
|
-
expect(
|
|
394
|
+
expect(capturedNotifications).toHaveLength(2);
|
|
390
395
|
|
|
391
396
|
// All children should be disposed — parent is going away.
|
|
392
397
|
expect(manager.getState("sub-1")).toBeUndefined();
|
|
@@ -422,6 +427,7 @@ describe("SubagentManager sharedRequestTimestamps", () => {
|
|
|
422
427
|
|
|
423
428
|
describe("SubagentManager abort race guard", () => {
|
|
424
429
|
test("completed subagent does not notify if already aborted", async () => {
|
|
430
|
+
clearCaptured();
|
|
425
431
|
const manager = new SubagentManager();
|
|
426
432
|
const subagentId = "sub-1";
|
|
427
433
|
const state = makeState(subagentId, { status: "aborted" });
|
|
@@ -436,16 +442,10 @@ describe("SubagentManager abort race guard", () => {
|
|
|
436
442
|
{ role: "assistant", content: [{ type: "text", text: "Done!" }] },
|
|
437
443
|
];
|
|
438
444
|
|
|
439
|
-
const notifications: { parentConversationId: string; message: string }[] =
|
|
440
|
-
[];
|
|
441
|
-
manager.onSubagentFinished = (parentConversationId, message) => {
|
|
442
|
-
notifications.push({ parentConversationId, message });
|
|
443
|
-
};
|
|
444
|
-
|
|
445
445
|
await asInternals(manager).runSubagent(subagentId, "Do something");
|
|
446
446
|
|
|
447
447
|
// Should NOT notify — status was already terminal (aborted) when loop finished.
|
|
448
|
-
expect(
|
|
448
|
+
expect(capturedNotifications).toHaveLength(0);
|
|
449
449
|
// Status should remain aborted, not overwritten to completed.
|
|
450
450
|
expect(state.status).toBe("aborted");
|
|
451
451
|
|