@vellumai/assistant 0.7.2 → 0.7.3
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 +16 -1
- package/docs/architecture/memory.md +5 -2
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
- 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 +449 -22
- package/package.json +1 -1
- package/src/__tests__/app-control-flow.test.ts +21 -11
- 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 +62 -1
- package/src/__tests__/background-workers-disk-pressure.test.ts +268 -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__/config-loader-backfill.test.ts +379 -0
- 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 +3 -7
- package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -1
- package/src/__tests__/context-search-workspace-source.test.ts +0 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
- package/src/__tests__/conversation-agent-loop.test.ts +454 -5
- package/src/__tests__/conversation-error.test.ts +150 -3
- package/src/__tests__/conversation-process-callsite.test.ts +43 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
- package/src/__tests__/conversation-slash-unknown.test.ts +6 -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-app-control.test.ts +15 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
- package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
- 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 +3 -4
- 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 +18 -6
- package/src/__tests__/injector-disk-pressure.test.ts +224 -0
- 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__/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 +15 -4
- 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__/suggestion-routes.test.ts +46 -0
- package/src/__tests__/twilio-validation.test.ts +2 -2
- 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-safe-storage-limits-release.test.ts +90 -0
- package/src/approvals/guardian-decision-primitive.ts +13 -0
- package/src/approvals/guardian-request-resolvers.ts +16 -17
- package/src/backup/snapshot-lock.ts +2 -27
- package/src/bundler/compiler-tools.ts +3 -2
- package/src/calls/call-conversation-messages.ts +46 -10
- 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 +7 -6
- package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
- package/src/cli/commands/oauth/connect.ts +127 -1
- 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/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 +27 -3
- package/src/config/loader.ts +127 -8
- 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 +75 -11
- 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-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 +6 -0
- package/src/daemon/conversation-agent-loop.ts +170 -33
- package/src/daemon/conversation-error.ts +87 -15
- package/src/daemon/conversation-lifecycle.ts +1 -3
- 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 +195 -15
- package/src/daemon/conversation-tool-setup.ts +57 -14
- package/src/daemon/conversation.ts +17 -22
- 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 +0 -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 +46 -21
- package/src/daemon/host-cu-proxy.ts +49 -3
- package/src/daemon/host-file-proxy.ts +43 -7
- package/src/daemon/host-transfer-proxy.ts +95 -4
- package/src/daemon/lifecycle.ts +79 -28
- 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 +14 -4
- 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 +3 -0
- package/src/daemon/profiler-run-store.ts +5 -5
- package/src/daemon/tool-setup-types.ts +2 -2
- package/src/documents/document-store.ts +85 -0
- package/src/filing/filing-service.ts +30 -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 +56 -2
- package/src/ipc/gateway-client.ts +37 -3
- 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 +52 -22
- 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 +5 -4
- package/src/memory/context-search/sources/memory.ts +0 -1
- 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 +32 -21
- package/src/memory/graph/conversation-graph-memory.ts +42 -54
- package/src/memory/graph/extraction.ts +1 -3
- package/src/memory/graph/graph-search.test.ts +10 -67
- package/src/memory/graph/graph-search.ts +1 -20
- package/src/memory/graph/retriever.test.ts +6 -0
- package/src/memory/graph/retriever.ts +6 -10
- package/src/memory/indexer.ts +54 -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-store.ts +48 -0
- package/src/memory/jobs-worker.ts +81 -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 +6 -0
- package/src/memory/qdrant-client.ts +0 -13
- package/src/memory/rerank-local.ts +374 -0
- package/src/memory/search/semantic.ts +6 -67
- package/src/memory/trace-event-store.ts +1 -17
- package/src/memory/v2/__tests__/activation.test.ts +311 -250
- package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
- package/src/memory/v2/__tests__/injection.test.ts +157 -167
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
- package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
- package/src/memory/v2/__tests__/reranker.test.ts +338 -0
- package/src/memory/v2/__tests__/sim.test.ts +5 -199
- package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
- package/src/memory/v2/__tests__/static-context.test.ts +76 -1
- package/src/memory/v2/activation.ts +149 -156
- package/src/memory/v2/consolidation-job.ts +62 -12
- package/src/memory/v2/injection.ts +47 -60
- package/src/memory/v2/prompts/consolidation.ts +36 -1
- package/src/memory/v2/qdrant.ts +99 -0
- package/src/memory/v2/reranker.ts +177 -0
- package/src/memory/v2/sim.ts +10 -84
- 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 +22 -0
- package/src/memory/v2/types.ts +10 -10
- package/src/notifications/copy-composer.ts +13 -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/plugins/defaults/injectors.ts +35 -2
- 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 +867 -0
- package/src/proactive-artifact/job.ts +352 -0
- package/src/proactive-artifact/message-copy.ts +41 -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/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 +14 -1
- package/src/runtime/auth/same-actor.ts +216 -0
- package/src/runtime/channel-retry-sweep.ts +65 -1
- package/src/runtime/guardian-reply-router.ts +10 -0
- package/src/runtime/local-actor-identity.ts +52 -11
- package/src/runtime/pending-interactions.ts +8 -0
- 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/client-routes.ts +20 -2
- package/src/runtime/routes/contact-routes.ts +0 -25
- package/src/runtime/routes/conversation-routes.ts +35 -26
- package/src/runtime/routes/debug-bash-routes.ts +163 -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/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/inbound-stages/guardian-reply-intercept.ts +3 -0
- package/src/runtime/routes/index.ts +6 -0
- package/src/runtime/routes/memory-item-routes.test.ts +41 -15
- package/src/runtime/routes/memory-v2-routes.ts +33 -0
- 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/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/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 +12 -9
- package/src/tools/memory/register.ts +1 -2
- package/src/tools/provider-tool-name.ts +28 -0
- package/src/tools/registry.ts +30 -9
- package/src/tools/terminal/shell.ts +9 -1
- package/src/tools/tool-approval-handler.ts +31 -6
- package/src/tools/types.ts +24 -2
- 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 +72 -0
- package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
- package/src/workspace/migrations/registry.ts +8 -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
|
@@ -28,8 +28,9 @@ mock.module("../runtime/pending-interactions.js", () => ({
|
|
|
28
28
|
|
|
29
29
|
const {
|
|
30
30
|
HostAppControlProxy,
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
_getActiveAppControlSession,
|
|
32
|
+
_resetActiveAppControlSession,
|
|
33
|
+
_setActiveAppControlSession,
|
|
33
34
|
} = await import("../daemon/host-app-control-proxy.js");
|
|
34
35
|
|
|
35
36
|
import type { HostAppControlResultPayload } from "../daemon/message-types/host-app-control.js";
|
|
@@ -58,11 +59,11 @@ describe("HostAppControlProxy", () => {
|
|
|
58
59
|
sentMessages.length = 0;
|
|
59
60
|
resolvedInteractionIds.length = 0;
|
|
60
61
|
mockHasClient = false;
|
|
61
|
-
|
|
62
|
+
_resetActiveAppControlSession();
|
|
62
63
|
});
|
|
63
64
|
|
|
64
65
|
afterEach(() => {
|
|
65
|
-
|
|
66
|
+
_resetActiveAppControlSession();
|
|
66
67
|
});
|
|
67
68
|
|
|
68
69
|
// -------------------------------------------------------------------------
|
|
@@ -120,8 +121,10 @@ describe("HostAppControlProxy", () => {
|
|
|
120
121
|
},
|
|
121
122
|
});
|
|
122
123
|
|
|
123
|
-
//
|
|
124
|
-
|
|
124
|
+
// Session lock acquired by this conversation, bound to the started app.
|
|
125
|
+
const session = _getActiveAppControlSession();
|
|
126
|
+
expect(session?.conversationId).toBe("conv-1");
|
|
127
|
+
expect(session?.app).toBe("com.example.editor");
|
|
125
128
|
|
|
126
129
|
proxy.dispose();
|
|
127
130
|
});
|
|
@@ -130,6 +133,22 @@ describe("HostAppControlProxy", () => {
|
|
|
130
133
|
const proxy = new HostAppControlProxy("conv-1");
|
|
131
134
|
const controller = new AbortController();
|
|
132
135
|
|
|
136
|
+
// Acquire a session first so the click below passes the auth gate
|
|
137
|
+
// and reaches dispatch.
|
|
138
|
+
const startCtrl = new AbortController();
|
|
139
|
+
const startPromise = proxy.request(
|
|
140
|
+
"app_control_start",
|
|
141
|
+
{ tool: "start", app: "com.example.editor" },
|
|
142
|
+
"conv-1",
|
|
143
|
+
startCtrl.signal,
|
|
144
|
+
);
|
|
145
|
+
proxy.resolve(
|
|
146
|
+
(sentMessages[0] as Record<string, unknown>).requestId as string,
|
|
147
|
+
payload({ pngBase64: PNG_A }),
|
|
148
|
+
);
|
|
149
|
+
await startPromise;
|
|
150
|
+
sentMessages.length = 0;
|
|
151
|
+
|
|
133
152
|
const resultPromise = proxy.request(
|
|
134
153
|
"app_control_click",
|
|
135
154
|
{ tool: "click", app: "com.example.editor", x: 100, y: 200 },
|
|
@@ -157,10 +176,10 @@ describe("HostAppControlProxy", () => {
|
|
|
157
176
|
});
|
|
158
177
|
|
|
159
178
|
// -------------------------------------------------------------------------
|
|
160
|
-
// (b)
|
|
179
|
+
// (b) Session lock
|
|
161
180
|
// -------------------------------------------------------------------------
|
|
162
181
|
|
|
163
|
-
describe("
|
|
182
|
+
describe("session lock", () => {
|
|
164
183
|
test("second conversation's start returns isError naming the holder", async () => {
|
|
165
184
|
const proxy1 = new HostAppControlProxy("conv-1");
|
|
166
185
|
const ctrl1 = new AbortController();
|
|
@@ -175,7 +194,7 @@ describe("HostAppControlProxy", () => {
|
|
|
175
194
|
proxy1.resolve(sent1.requestId as string, payload({ pngBase64: PNG_A }));
|
|
176
195
|
await p1;
|
|
177
196
|
|
|
178
|
-
expect(
|
|
197
|
+
expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
|
|
179
198
|
|
|
180
199
|
// Second conversation tries to start — should be rejected without
|
|
181
200
|
// sending any envelope.
|
|
@@ -235,14 +254,33 @@ describe("HostAppControlProxy", () => {
|
|
|
235
254
|
proxy.dispose();
|
|
236
255
|
});
|
|
237
256
|
|
|
238
|
-
test("non-start
|
|
239
|
-
const proxy = new HostAppControlProxy("conv-
|
|
257
|
+
test("non-start tool with no active session is rejected before dispatch", async () => {
|
|
258
|
+
const proxy = new HostAppControlProxy("conv-1");
|
|
240
259
|
const ctrl = new AbortController();
|
|
241
260
|
|
|
242
|
-
|
|
243
|
-
|
|
261
|
+
const result = await proxy.request(
|
|
262
|
+
"app_control_type",
|
|
263
|
+
{
|
|
264
|
+
tool: "type",
|
|
265
|
+
app: "com.example.editor",
|
|
266
|
+
text: "rm -rf ~",
|
|
267
|
+
},
|
|
268
|
+
"conv-1",
|
|
269
|
+
ctrl.signal,
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
expect(result.isError).toBe(true);
|
|
273
|
+
expect(result.content).toContain("No app-control session is active");
|
|
274
|
+
expect(result.content).toContain("app_control_start");
|
|
275
|
+
expect(sentMessages).toHaveLength(0); // No envelope dispatched
|
|
276
|
+
|
|
277
|
+
proxy.dispose();
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
test("non-start tool from non-owning conversation is rejected", async () => {
|
|
244
281
|
const proxyOwner = new HostAppControlProxy("conv-1");
|
|
245
282
|
const startCtrl = new AbortController();
|
|
283
|
+
|
|
246
284
|
const pStart = proxyOwner.request(
|
|
247
285
|
"app_control_start",
|
|
248
286
|
{ tool: "start", app: "com.example.editor" },
|
|
@@ -254,27 +292,139 @@ describe("HostAppControlProxy", () => {
|
|
|
254
292
|
payload({ pngBase64: PNG_A }),
|
|
255
293
|
);
|
|
256
294
|
await pStart;
|
|
257
|
-
|
|
258
295
|
sentMessages.length = 0;
|
|
259
296
|
|
|
260
|
-
// conv-2
|
|
261
|
-
//
|
|
262
|
-
const
|
|
297
|
+
// conv-2 tries to observe the app conv-1 owns — must be rejected
|
|
298
|
+
// before any host dispatch.
|
|
299
|
+
const proxyOther = new HostAppControlProxy("conv-2");
|
|
300
|
+
const ctrl = new AbortController();
|
|
301
|
+
const result = await proxyOther.request(
|
|
263
302
|
"app_control_observe",
|
|
264
303
|
{ tool: "observe", app: "com.example.editor" },
|
|
265
304
|
"conv-2",
|
|
266
305
|
ctrl.signal,
|
|
267
306
|
);
|
|
307
|
+
|
|
308
|
+
expect(result.isError).toBe(true);
|
|
309
|
+
expect(result.content).toContain("conv-1");
|
|
310
|
+
expect(result.content).toContain("currently");
|
|
311
|
+
expect(sentMessages).toHaveLength(0);
|
|
312
|
+
|
|
313
|
+
proxyOwner.dispose();
|
|
314
|
+
proxyOther.dispose();
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
test("non-start tool with mismatched app is rejected (cross-app bypass)", async () => {
|
|
318
|
+
const proxy = new HostAppControlProxy("conv-1");
|
|
319
|
+
const startCtrl = new AbortController();
|
|
320
|
+
|
|
321
|
+
// User approves control of the editor.
|
|
322
|
+
const pStart = proxy.request(
|
|
323
|
+
"app_control_start",
|
|
324
|
+
{ tool: "start", app: "com.example.editor" },
|
|
325
|
+
"conv-1",
|
|
326
|
+
startCtrl.signal,
|
|
327
|
+
);
|
|
328
|
+
proxy.resolve(
|
|
329
|
+
(sentMessages[0] as Record<string, unknown>).requestId as string,
|
|
330
|
+
payload({ pngBase64: PNG_A }),
|
|
331
|
+
);
|
|
332
|
+
await pStart;
|
|
333
|
+
sentMessages.length = 0;
|
|
334
|
+
|
|
335
|
+
// The model attempts to type into a different app — must be
|
|
336
|
+
// rejected with an informative error.
|
|
337
|
+
const ctrl = new AbortController();
|
|
338
|
+
const result = await proxy.request(
|
|
339
|
+
"app_control_type",
|
|
340
|
+
{
|
|
341
|
+
tool: "type",
|
|
342
|
+
app: "com.apple.Terminal",
|
|
343
|
+
text: "rm -rf ~",
|
|
344
|
+
},
|
|
345
|
+
"conv-1",
|
|
346
|
+
ctrl.signal,
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
expect(result.isError).toBe(true);
|
|
350
|
+
expect(result.content).toContain("com.example.editor");
|
|
351
|
+
expect(result.content).toContain("com.apple.Terminal");
|
|
352
|
+
expect(result.content).toContain("app_control_stop");
|
|
353
|
+
expect(sentMessages).toHaveLength(0);
|
|
354
|
+
|
|
355
|
+
proxy.dispose();
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
test("non-start tool with case-different but otherwise matching app is allowed", async () => {
|
|
359
|
+
const proxy = new HostAppControlProxy("conv-1");
|
|
360
|
+
const startCtrl = new AbortController();
|
|
361
|
+
|
|
362
|
+
const pStart = proxy.request(
|
|
363
|
+
"app_control_start",
|
|
364
|
+
{ tool: "start", app: "com.apple.Safari" },
|
|
365
|
+
"conv-1",
|
|
366
|
+
startCtrl.signal,
|
|
367
|
+
);
|
|
368
|
+
proxy.resolve(
|
|
369
|
+
(sentMessages[0] as Record<string, unknown>).requestId as string,
|
|
370
|
+
payload({ pngBase64: PNG_A }),
|
|
371
|
+
);
|
|
372
|
+
await pStart;
|
|
373
|
+
sentMessages.length = 0;
|
|
374
|
+
|
|
375
|
+
// Different casing of the same bundle ID — bundle IDs are
|
|
376
|
+
// case-insensitive on macOS, so this should pass the gate.
|
|
377
|
+
const ctrl = new AbortController();
|
|
378
|
+
const obsPromise = proxy.request(
|
|
379
|
+
"app_control_observe",
|
|
380
|
+
{ tool: "observe", app: "COM.APPLE.SAFARI" },
|
|
381
|
+
"conv-1",
|
|
382
|
+
ctrl.signal,
|
|
383
|
+
);
|
|
384
|
+
expect(sentMessages).toHaveLength(1);
|
|
385
|
+
proxy.resolve(
|
|
386
|
+
(sentMessages[0] as Record<string, unknown>).requestId as string,
|
|
387
|
+
payload({ pngBase64: PNG_B }),
|
|
388
|
+
);
|
|
389
|
+
const result = await obsPromise;
|
|
390
|
+
expect(result.isError).toBe(false);
|
|
391
|
+
|
|
392
|
+
proxy.dispose();
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
test("non-start tool from owning conversation with matching app dispatches", async () => {
|
|
396
|
+
const proxy = new HostAppControlProxy("conv-1");
|
|
397
|
+
const startCtrl = new AbortController();
|
|
398
|
+
|
|
399
|
+
const pStart = proxy.request(
|
|
400
|
+
"app_control_start",
|
|
401
|
+
{ tool: "start", app: "com.example.editor" },
|
|
402
|
+
"conv-1",
|
|
403
|
+
startCtrl.signal,
|
|
404
|
+
);
|
|
405
|
+
proxy.resolve(
|
|
406
|
+
(sentMessages[0] as Record<string, unknown>).requestId as string,
|
|
407
|
+
payload({ pngBase64: PNG_A }),
|
|
408
|
+
);
|
|
409
|
+
await pStart;
|
|
410
|
+
sentMessages.length = 0;
|
|
411
|
+
|
|
412
|
+
const ctrl = new AbortController();
|
|
413
|
+
const obsPromise = proxy.request(
|
|
414
|
+
"app_control_observe",
|
|
415
|
+
{ tool: "observe", app: "com.example.editor" },
|
|
416
|
+
"conv-1",
|
|
417
|
+
ctrl.signal,
|
|
418
|
+
);
|
|
268
419
|
expect(sentMessages).toHaveLength(1);
|
|
269
420
|
const sent = sentMessages[0] as Record<string, unknown>;
|
|
270
421
|
expect(sent.toolName).toBe("app_control_observe");
|
|
271
422
|
|
|
272
423
|
proxy.resolve(sent.requestId as string, payload({ pngBase64: PNG_B }));
|
|
273
|
-
const result = await
|
|
424
|
+
const result = await obsPromise;
|
|
274
425
|
expect(result.isError).toBe(false);
|
|
275
426
|
|
|
276
427
|
proxy.dispose();
|
|
277
|
-
proxyOwner.dispose();
|
|
278
428
|
});
|
|
279
429
|
});
|
|
280
430
|
|
|
@@ -286,6 +436,10 @@ describe("HostAppControlProxy", () => {
|
|
|
286
436
|
test("attaches stuck warning after 5 identical observations", async () => {
|
|
287
437
|
const proxy = new HostAppControlProxy("conv-1");
|
|
288
438
|
const ctrl = new AbortController();
|
|
439
|
+
_setActiveAppControlSession({
|
|
440
|
+
conversationId: "conv-1",
|
|
441
|
+
app: "com.example.editor",
|
|
442
|
+
});
|
|
289
443
|
|
|
290
444
|
// First observation establishes the baseline (count = 0).
|
|
291
445
|
const p0 = proxy.request(
|
|
@@ -341,6 +495,10 @@ describe("HostAppControlProxy", () => {
|
|
|
341
495
|
test("resets repeat count when the screenshot hash differs", async () => {
|
|
342
496
|
const proxy = new HostAppControlProxy("conv-1");
|
|
343
497
|
const ctrl = new AbortController();
|
|
498
|
+
_setActiveAppControlSession({
|
|
499
|
+
conversationId: "conv-1",
|
|
500
|
+
app: "com.example.editor",
|
|
501
|
+
});
|
|
344
502
|
|
|
345
503
|
// Establish baseline at PNG_A.
|
|
346
504
|
const p1 = proxy.request(
|
|
@@ -391,6 +549,10 @@ describe("HostAppControlProxy", () => {
|
|
|
391
549
|
test("non-running states do not feed the loop guard", async () => {
|
|
392
550
|
const proxy = new HostAppControlProxy("conv-1");
|
|
393
551
|
const ctrl = new AbortController();
|
|
552
|
+
_setActiveAppControlSession({
|
|
553
|
+
conversationId: "conv-1",
|
|
554
|
+
app: "com.example.editor",
|
|
555
|
+
});
|
|
394
556
|
|
|
395
557
|
// Several observations with state != running (and identical PNGs)
|
|
396
558
|
// should not increment the repeat count.
|
|
@@ -435,10 +597,10 @@ describe("HostAppControlProxy", () => {
|
|
|
435
597
|
payload({ pngBase64: PNG_A }),
|
|
436
598
|
);
|
|
437
599
|
await p1;
|
|
438
|
-
expect(
|
|
600
|
+
expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
|
|
439
601
|
|
|
440
602
|
proxy1.dispose();
|
|
441
|
-
expect(
|
|
603
|
+
expect(_getActiveAppControlSession()).toBeUndefined();
|
|
442
604
|
|
|
443
605
|
// Now a new conversation can acquire the lock.
|
|
444
606
|
sentMessages.length = 0;
|
|
@@ -458,7 +620,7 @@ describe("HostAppControlProxy", () => {
|
|
|
458
620
|
);
|
|
459
621
|
const result = await p2;
|
|
460
622
|
expect(result.isError).toBe(false);
|
|
461
|
-
expect(
|
|
623
|
+
expect(_getActiveAppControlSession()?.conversationId).toBe("conv-2");
|
|
462
624
|
|
|
463
625
|
proxy2.dispose();
|
|
464
626
|
});
|
|
@@ -478,16 +640,16 @@ describe("HostAppControlProxy", () => {
|
|
|
478
640
|
payload({ pngBase64: PNG_A }),
|
|
479
641
|
);
|
|
480
642
|
await pStart;
|
|
481
|
-
expect(
|
|
643
|
+
expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
|
|
482
644
|
|
|
483
645
|
// A different conversation's proxy disposes — the lock should remain
|
|
484
646
|
// with conv-1.
|
|
485
647
|
const proxyOther = new HostAppControlProxy("conv-2");
|
|
486
648
|
proxyOther.dispose();
|
|
487
|
-
expect(
|
|
649
|
+
expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
|
|
488
650
|
|
|
489
651
|
proxyOwner.dispose();
|
|
490
|
-
expect(
|
|
652
|
+
expect(_getActiveAppControlSession()).toBeUndefined();
|
|
491
653
|
});
|
|
492
654
|
});
|
|
493
655
|
|
|
@@ -499,6 +661,10 @@ describe("HostAppControlProxy", () => {
|
|
|
499
661
|
test("propagates abort and emits cancel envelope", async () => {
|
|
500
662
|
const proxy = new HostAppControlProxy("conv-1");
|
|
501
663
|
const controller = new AbortController();
|
|
664
|
+
_setActiveAppControlSession({
|
|
665
|
+
conversationId: "conv-1",
|
|
666
|
+
app: "com.example.editor",
|
|
667
|
+
});
|
|
502
668
|
|
|
503
669
|
const resultPromise = proxy.request(
|
|
504
670
|
"app_control_observe",
|
|
@@ -557,6 +723,10 @@ describe("HostAppControlProxy", () => {
|
|
|
557
723
|
test("100 sequential requests dispatch without an artificial limit", async () => {
|
|
558
724
|
const proxy = new HostAppControlProxy("conv-1");
|
|
559
725
|
const ctrl = new AbortController();
|
|
726
|
+
_setActiveAppControlSession({
|
|
727
|
+
conversationId: "conv-1",
|
|
728
|
+
app: "com.example.editor",
|
|
729
|
+
});
|
|
560
730
|
|
|
561
731
|
for (let i = 0; i < 100; i++) {
|
|
562
732
|
const p = proxy.request(
|