vellum 0.2.0 → 0.2.2
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/README.md +15 -2
- package/bun.lock +5 -2
- package/package.json +4 -2
- package/scripts/capture-x-graphql.ts +562 -0
- package/scripts/ipc/check-swift-decoder-drift.ts +2 -1
- package/scripts/test.sh +5 -0
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +161 -34
- package/src/__tests__/account-registry.test.ts +2 -1
- package/src/__tests__/agent-heartbeat-service.test.ts +250 -0
- package/src/__tests__/app-bundler.test.ts +12 -33
- package/src/__tests__/asset-materialize-tool.test.ts +16 -15
- package/src/__tests__/asset-search-tool.test.ts +23 -22
- package/src/__tests__/attachments-store.test.ts +56 -127
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +5 -4
- package/src/__tests__/browser-skill-endstate.test.ts +5 -8
- package/src/__tests__/call-bridge.test.ts +385 -0
- package/src/__tests__/call-constants.test.ts +40 -0
- package/src/__tests__/call-orchestrator.test.ts +454 -0
- package/src/__tests__/call-recovery.test.ts +518 -0
- package/src/__tests__/call-routes-http.test.ts +459 -0
- package/src/__tests__/call-state-machine.test.ts +143 -0
- package/src/__tests__/call-state.test.ts +133 -0
- package/src/__tests__/call-store.test.ts +691 -0
- package/src/__tests__/cli-discover.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +550 -0
- package/src/__tests__/compaction.benchmark.test.ts +176 -0
- package/src/__tests__/computer-use-tools.test.ts +250 -0
- package/src/__tests__/config-schema.test.ts +348 -3
- package/src/__tests__/conflict-store.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +331 -0
- package/src/__tests__/conversation-store.test.ts +30 -32
- package/src/__tests__/credential-security-invariants.test.ts +4 -0
- package/src/__tests__/date-context.test.ts +373 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +129 -0
- package/src/__tests__/doordash-session.test.ts +9 -0
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +3 -3
- package/src/__tests__/followup-tools.test.ts +303 -0
- package/src/__tests__/handlers-twitter-config.test.ts +718 -0
- package/src/__tests__/intent-routing.test.ts +64 -57
- package/src/__tests__/ipc-roundtrip.benchmark.test.ts +237 -0
- package/src/__tests__/ipc-snapshot.test.ts +96 -28
- package/src/__tests__/llm-usage-store.test.ts +3 -8
- package/src/__tests__/media-generate-image.test.ts +1 -1
- package/src/__tests__/media-reuse-story.e2e.test.ts +7 -7
- package/src/__tests__/memory-retrieval.benchmark.test.ts +430 -0
- package/src/__tests__/parallel-tool.benchmark.test.ts +294 -0
- package/src/__tests__/playbook-tools.test.ts +342 -0
- package/src/__tests__/profile-compiler.test.ts +2 -1
- package/src/__tests__/provider-streaming.benchmark.test.ts +773 -0
- package/src/__tests__/recurrence-engine-rruleset.test.ts +78 -0
- package/src/__tests__/recurrence-engine.test.ts +69 -0
- package/src/__tests__/recurrence-types.test.ts +71 -0
- package/src/__tests__/registry.test.ts +17 -10
- package/src/__tests__/relay-server.test.ts +633 -0
- package/src/__tests__/reminder-store.test.ts +6 -3
- package/src/__tests__/reminder.test.ts +43 -77
- package/src/__tests__/run-orchestrator-assistant-events.test.ts +222 -0
- package/src/__tests__/run-orchestrator.test.ts +7 -7
- package/src/__tests__/runtime-attachment-metadata.test.ts +19 -20
- package/src/__tests__/runtime-runs-http.test.ts +5 -23
- package/src/__tests__/runtime-runs.test.ts +11 -11
- package/src/__tests__/schedule-store.test.ts +482 -0
- package/src/__tests__/schedule-tools.test.ts +700 -0
- package/src/__tests__/scheduler-recurrence.test.ts +329 -0
- package/src/__tests__/server-history-render.test.ts +14 -13
- package/src/__tests__/session-error.test.ts +28 -0
- package/src/__tests__/session-init.benchmark.test.ts +462 -0
- package/src/__tests__/session-queue.test.ts +89 -16
- package/src/__tests__/session-runtime-assembly.test.ts +161 -0
- package/src/__tests__/session-surfaces-task-progress.test.ts +104 -0
- package/src/__tests__/signup-e2e.test.ts +2 -1
- package/src/__tests__/skill-projection.benchmark.test.ts +328 -0
- package/src/__tests__/skill-script-runner.test.ts +159 -0
- package/src/__tests__/speaker-identification.test.ts +52 -0
- package/src/__tests__/subagent-manager-notify.test.ts +42 -10
- package/src/__tests__/subagent-tools.test.ts +141 -41
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-runner.test.ts +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/task-tools.test.ts +49 -56
- package/src/__tests__/tool-audit-listener.test.ts +1 -0
- package/src/__tests__/tool-domain-event-publisher.test.ts +2 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +500 -0
- package/src/__tests__/tool-executor.test.ts +13 -17
- package/src/__tests__/turn-commit.test.ts +273 -2
- package/src/__tests__/twilio-provider.test.ts +143 -0
- package/src/__tests__/twilio-routes.test.ts +789 -0
- package/src/__tests__/twitter-auth-handler.test.ts +581 -0
- package/src/__tests__/view-image-tool.test.ts +217 -0
- package/src/__tests__/workspace-git-service.test.ts +403 -0
- package/src/__tests__/workspace-heartbeat-service.test.ts +141 -2
- package/src/agent-heartbeat/agent-heartbeat-service.ts +155 -0
- package/src/bundler/app-bundler.ts +35 -14
- package/src/calls/call-bridge.ts +95 -0
- package/src/calls/call-constants.ts +48 -0
- package/src/calls/call-domain.ts +276 -0
- package/src/calls/call-orchestrator.ts +390 -0
- package/src/calls/call-recovery.ts +207 -0
- package/src/calls/call-state-machine.ts +68 -0
- package/src/calls/call-state.ts +64 -0
- package/src/calls/call-store.ts +416 -0
- package/src/calls/relay-server.ts +335 -0
- package/src/calls/speaker-identification.ts +213 -0
- package/src/calls/twilio-config.ts +34 -0
- package/src/calls/twilio-provider.ts +173 -0
- package/src/calls/twilio-routes.ts +250 -0
- package/src/calls/types.ts +37 -0
- package/src/calls/voice-provider.ts +14 -0
- package/src/cli/config-commands.ts +334 -0
- package/src/cli/core-commands.ts +776 -0
- package/src/cli/doordash.ts +256 -25
- package/src/cli/ipc-client.ts +82 -0
- package/src/cli/map.ts +246 -0
- package/src/cli/twitter.ts +575 -0
- package/src/cli.ts +7 -5
- package/src/commands/__tests__/cc-command-registry.test.ts +319 -0
- package/src/commands/cc-command-registry.ts +209 -0
- package/src/config/bundled-skills/contacts/SKILL.md +39 -0
- package/src/config/bundled-skills/contacts/TOOLS.json +122 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +9 -0
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +9 -0
- package/src/config/bundled-skills/document/SKILL.md +18 -0
- package/src/config/bundled-skills/document/TOOLS.json +53 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +9 -0
- package/src/config/bundled-skills/document/tools/document-update.ts +9 -0
- package/src/config/bundled-skills/doordash/SKILL.md +163 -0
- package/src/config/bundled-skills/followups/SKILL.md +32 -0
- package/src/config/bundled-skills/followups/TOOLS.json +100 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-list.ts +9 -0
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +9 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -24
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -1
- package/src/config/bundled-skills/playbooks/SKILL.md +31 -0
- package/src/config/bundled-skills/playbooks/TOOLS.json +126 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +9 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +9 -0
- package/src/config/bundled-skills/reminder/SKILL.md +20 -0
- package/src/config/bundled-skills/reminder/TOOLS.json +67 -0
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +9 -0
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +9 -0
- package/src/config/bundled-skills/schedule/SKILL.md +74 -0
- package/src/config/bundled-skills/schedule/TOOLS.json +135 -0
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +9 -0
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +9 -0
- package/src/config/bundled-skills/subagent/SKILL.md +25 -0
- package/src/config/bundled-skills/subagent/TOOLS.json +107 -0
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +9 -0
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +9 -0
- package/src/config/bundled-skills/tasks/SKILL.md +28 -0
- package/src/config/bundled-skills/tasks/TOOLS.json +256 -0
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-list.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-run.ts +9 -0
- package/src/config/bundled-skills/tasks/tools/task-save.ts +9 -0
- package/src/config/bundled-skills/twitter/SKILL.md +134 -0
- package/src/config/bundled-skills/watcher/SKILL.md +27 -0
- package/src/config/bundled-skills/watcher/TOOLS.json +147 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +9 -0
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +9 -0
- package/src/config/defaults.ts +44 -0
- package/src/config/loader.ts +4 -1
- package/src/config/schema.ts +218 -1
- package/src/config/system-prompt.ts +100 -6
- package/src/config/templates/IDENTITY.md +7 -0
- package/src/config/types.ts +5 -0
- package/src/contacts/contact-store.ts +4 -4
- package/src/daemon/assistant-attachments.ts +10 -0
- package/src/daemon/classifier.ts +3 -1
- package/src/daemon/computer-use-session.ts +3 -1
- package/src/daemon/date-context.ts +136 -0
- package/src/daemon/handlers/apps.ts +16 -1
- package/src/daemon/handlers/browser.ts +54 -0
- package/src/daemon/handlers/computer-use.ts +7 -1
- package/src/daemon/handlers/config.ts +192 -4
- package/src/daemon/handlers/diagnostics.ts +5 -1
- package/src/daemon/handlers/documents.ts +18 -29
- package/src/daemon/handlers/home-base.ts +5 -1
- package/src/daemon/handlers/index.ts +40 -271
- package/src/daemon/handlers/misc.ts +9 -1
- package/src/daemon/handlers/publish.ts +6 -1
- package/src/daemon/handlers/sessions.ts +65 -12
- package/src/daemon/handlers/shared.ts +36 -1
- package/src/daemon/handlers/signing.ts +37 -0
- package/src/daemon/handlers/skills.ts +20 -6
- package/src/daemon/handlers/subagents.ts +8 -3
- package/src/daemon/handlers/twitter-auth.ts +169 -0
- package/src/daemon/handlers/work-items.ts +495 -39
- package/src/daemon/ipc-contract-inventory.json +40 -4
- package/src/daemon/ipc-contract.ts +185 -37
- package/src/daemon/ipc-protocol.ts +7 -2
- package/src/daemon/lifecycle.ts +48 -5
- package/src/daemon/main.ts +10 -4
- package/src/daemon/ride-shotgun-handler.ts +74 -10
- package/src/daemon/server.ts +144 -29
- package/src/daemon/session-agent-loop.ts +887 -0
- package/src/daemon/session-attachments.ts +28 -5
- package/src/daemon/session-error.ts +24 -3
- package/src/daemon/session-lifecycle.ts +147 -0
- package/src/daemon/session-media-retry.ts +147 -0
- package/src/daemon/session-messaging.ts +145 -0
- package/src/daemon/session-notifiers.ts +164 -0
- package/src/daemon/session-process.ts +2 -2
- package/src/daemon/session-queue-manager.ts +1 -0
- package/src/daemon/session-runtime-assembly.ts +52 -0
- package/src/daemon/session-skill-tools.ts +124 -5
- package/src/daemon/session-slash.ts +3 -0
- package/src/daemon/session-surfaces.ts +77 -2
- package/src/daemon/session-tool-setup.ts +222 -2
- package/src/daemon/session-usage.ts +0 -2
- package/src/daemon/session.ts +114 -1365
- package/src/daemon/video-thumbnail.ts +60 -0
- package/src/doordash/client.ts +121 -27
- package/src/doordash/queries.ts +1 -2
- package/src/export/formatter.ts +3 -1
- package/src/followups/followup-store.ts +4 -2
- package/src/followups/types.ts +6 -0
- package/src/hooks/templates.ts +1 -1
- package/src/index.ts +32 -1151
- package/src/media/gemini-image-service.ts +1 -1
- package/src/memory/attachments-store.ts +28 -83
- package/src/memory/channel-delivery-store.ts +7 -21
- package/src/memory/clarification-resolver.ts +6 -5
- package/src/memory/contradiction-checker.ts +3 -2
- package/src/memory/conversation-key-store.ts +10 -29
- package/src/memory/conversation-store.ts +2 -1
- package/src/memory/db.ts +362 -2
- package/src/memory/entity-extractor.ts +6 -3
- package/src/memory/items-extractor.ts +5 -4
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/llm-usage-store.ts +1 -2
- package/src/memory/runs-store.ts +1 -2
- package/src/memory/schema.ts +65 -2
- package/src/messaging/style-analyzer.ts +3 -2
- package/src/messaging/thread-summarizer.ts +8 -12
- package/src/messaging/triage-engine.ts +4 -2
- package/src/providers/openrouter/client.ts +20 -0
- package/src/providers/registry.ts +8 -0
- package/src/runtime/http-server.ts +277 -25
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/routes/attachment-routes.ts +5 -6
- package/src/runtime/routes/call-routes.ts +140 -0
- package/src/runtime/routes/channel-routes.ts +12 -19
- package/src/runtime/routes/conversation-routes.ts +5 -9
- package/src/runtime/routes/run-routes.ts +4 -8
- package/src/runtime/run-orchestrator.ts +39 -6
- package/src/schedule/recurrence-engine.ts +138 -0
- package/src/schedule/recurrence-types.ts +67 -0
- package/src/schedule/schedule-store.ts +102 -57
- package/src/schedule/scheduler.ts +9 -6
- package/src/security/oauth2.ts +29 -4
- package/src/security/secret-allowlist.ts +46 -0
- package/src/skills/clawhub.ts +1 -1
- package/src/subagent/manager.ts +40 -8
- package/src/swarm/backend-claude-code.ts +64 -9
- package/src/swarm/worker-prompts.ts +2 -1
- package/src/tasks/SPEC.md +34 -28
- package/src/tasks/ephemeral-permissions.ts +16 -7
- package/src/tasks/task-compiler.ts +5 -4
- package/src/tasks/task-runner.ts +10 -5
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/tool-sanitizer.ts +36 -0
- package/src/tools/assets/search.ts +4 -4
- package/src/tools/browser/api-map.ts +220 -0
- package/src/tools/browser/auto-navigate.ts +270 -0
- package/src/tools/browser/browser-execution.ts +2 -1
- package/src/tools/browser/browser-manager.ts +2 -2
- package/src/tools/browser/network-recorder.ts +5 -4
- package/src/tools/browser/x-auto-navigate.ts +207 -0
- package/src/tools/calls/call-end.ts +67 -0
- package/src/tools/calls/call-start.ts +73 -0
- package/src/tools/calls/call-status.ts +81 -0
- package/src/tools/claude-code/claude-code.ts +77 -11
- package/src/tools/contacts/contact-merge.ts +46 -78
- package/src/tools/contacts/contact-search.ts +35 -79
- package/src/tools/contacts/contact-upsert.ts +35 -108
- package/src/tools/credentials/vault.ts +21 -5
- package/src/tools/document/document-tool.ts +71 -144
- package/src/tools/executor.ts +129 -10
- package/src/tools/followups/followup_create.ts +46 -88
- package/src/tools/followups/followup_list.ts +34 -74
- package/src/tools/followups/followup_resolve.ts +31 -66
- package/src/tools/host-terminal/cli-discover.ts +2 -1
- package/src/tools/host-terminal/host-shell.ts +10 -0
- package/src/tools/memory/handlers.ts +5 -4
- package/src/tools/network/__tests__/web-search.test.ts +427 -0
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +248 -0
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +234 -0
- package/src/tools/network/script-proxy/__tests__/router.test.ts +76 -0
- package/src/tools/network/web-fetch.ts +18 -6
- package/src/tools/playbooks/index.ts +4 -5
- package/src/tools/playbooks/playbook-create.ts +3 -47
- package/src/tools/playbooks/playbook-delete.ts +1 -25
- package/src/tools/playbooks/playbook-list.ts +1 -28
- package/src/tools/playbooks/playbook-update.ts +3 -51
- package/src/tools/registry.ts +2 -4
- package/src/tools/reminder/reminder.ts +5 -78
- package/src/tools/schedule/create.ts +69 -74
- package/src/tools/schedule/delete.ts +21 -47
- package/src/tools/schedule/list.ts +55 -74
- package/src/tools/schedule/update.ts +77 -84
- package/src/tools/subagent/abort.ts +29 -58
- package/src/tools/subagent/message.ts +30 -63
- package/src/tools/subagent/read.ts +53 -84
- package/src/tools/subagent/spawn.ts +43 -82
- package/src/tools/subagent/status.ts +42 -71
- package/src/tools/swarm/delegate.ts +2 -1
- package/src/tools/tasks/index.ts +8 -6
- package/src/tools/tasks/task-delete.ts +69 -56
- package/src/tools/tasks/task-list.ts +31 -52
- package/src/tools/tasks/task-run.ts +74 -102
- package/src/tools/tasks/task-save.ts +33 -65
- package/src/tools/tasks/work-item-enqueue.ts +192 -134
- package/src/tools/tasks/work-item-list.ts +33 -78
- package/src/tools/tasks/work-item-remove.ts +60 -0
- package/src/tools/tasks/work-item-update.ts +114 -0
- package/src/tools/terminal/backends/native.ts +3 -1
- package/src/tools/tool-manifest.ts +20 -74
- package/src/tools/types.ts +6 -0
- package/src/tools/ui-surface/definitions.ts +6 -1
- package/src/tools/watch/screen-watch.ts +3 -1
- package/src/tools/watcher/create.ts +52 -98
- package/src/tools/watcher/delete.ts +20 -46
- package/src/tools/watcher/digest.ts +36 -70
- package/src/tools/watcher/list.ts +49 -79
- package/src/tools/watcher/update.ts +45 -91
- package/src/twitter/client.ts +690 -0
- package/src/twitter/session.ts +91 -0
- package/src/usage/types.ts +0 -1
- package/src/util/truncate.ts +6 -0
- package/src/watcher/providers/slack.ts +2 -1
- package/src/watcher/watcher-store.ts +3 -2
- package/src/work-items/work-item-store.ts +236 -2
- package/src/workspace/commit-message-enrichment-service.ts +284 -0
- package/src/workspace/commit-message-provider.ts +95 -0
- package/src/workspace/git-service.ts +272 -52
- package/src/workspace/heartbeat-service.ts +70 -13
- package/src/workspace/provider-commit-message-generator.ts +242 -0
- package/src/workspace/turn-commit.ts +100 -51
- package/src/tools/contacts/index.ts +0 -4
- package/src/tools/document/index.ts +0 -5
- package/src/tools/followups/index.ts +0 -3
- package/src/tools/subagent/index.ts +0 -5
- /package/src/__tests__/{memory-context-benchmark.test.ts → memory-context-benchmark.benchmark.test.ts} +0 -0
|
@@ -1,51 +1,33 @@
|
|
|
1
|
-
import { describe, test, expect, beforeEach } from 'bun:test';
|
|
2
|
-
import { initializeDb } from '../memory/db.js';
|
|
3
|
-
import { getDb } from '../memory/db.js';
|
|
1
|
+
import { afterAll, describe, test, expect, beforeEach } from 'bun:test';
|
|
2
|
+
import { initializeDb, getDb, resetDb } from '../memory/db.js';
|
|
4
3
|
import { reminders } from '../memory/schema.js';
|
|
5
|
-
import {
|
|
4
|
+
import { executeReminderCreate, executeReminderList, executeReminderCancel } from '../tools/reminder/reminder.js';
|
|
6
5
|
import { claimDueReminders } from '../tools/reminder/reminder-store.js';
|
|
7
6
|
|
|
8
7
|
initializeDb();
|
|
9
8
|
|
|
10
|
-
const dummyContext = {
|
|
11
|
-
workingDir: '/tmp',
|
|
12
|
-
sessionId: 'test-session',
|
|
13
|
-
conversationId: 'test-conversation',
|
|
14
|
-
};
|
|
15
|
-
|
|
16
9
|
function clearReminders() {
|
|
17
10
|
getDb().delete(reminders).run();
|
|
18
11
|
}
|
|
19
12
|
|
|
13
|
+
afterAll(() => {
|
|
14
|
+
resetDb();
|
|
15
|
+
});
|
|
16
|
+
|
|
20
17
|
describe('reminder tool', () => {
|
|
21
18
|
beforeEach(() => {
|
|
22
19
|
clearReminders();
|
|
23
20
|
});
|
|
24
21
|
|
|
25
|
-
// ── action validation ───────────────────────────────────────────────
|
|
26
|
-
|
|
27
|
-
test('rejects missing action', async () => {
|
|
28
|
-
const result = await reminderTool.execute({}, dummyContext);
|
|
29
|
-
expect(result.isError).toBe(true);
|
|
30
|
-
expect(result.content).toContain('action is required');
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
test('rejects unknown action', async () => {
|
|
34
|
-
const result = await reminderTool.execute({ action: 'explode' }, dummyContext);
|
|
35
|
-
expect(result.isError).toBe(true);
|
|
36
|
-
expect(result.content).toContain('Unknown action');
|
|
37
|
-
});
|
|
38
|
-
|
|
39
22
|
// ── create ──────────────────────────────────────────────────────────
|
|
40
23
|
|
|
41
24
|
test('create with valid future ISO timestamp succeeds', async () => {
|
|
42
25
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
43
|
-
const result =
|
|
44
|
-
action: 'create',
|
|
26
|
+
const result = executeReminderCreate({
|
|
45
27
|
fire_at: future,
|
|
46
28
|
label: 'Call Sidd',
|
|
47
29
|
message: 'Remember to call Sidd',
|
|
48
|
-
}
|
|
30
|
+
});
|
|
49
31
|
|
|
50
32
|
expect(result.isError).toBe(false);
|
|
51
33
|
expect(result.content).toContain('Reminder created');
|
|
@@ -55,48 +37,44 @@ describe('reminder tool', () => {
|
|
|
55
37
|
|
|
56
38
|
test('create with past timestamp returns error', async () => {
|
|
57
39
|
const past = new Date(Date.now() - 60_000).toISOString();
|
|
58
|
-
const result =
|
|
59
|
-
action: 'create',
|
|
40
|
+
const result = executeReminderCreate({
|
|
60
41
|
fire_at: past,
|
|
61
42
|
label: 'Too late',
|
|
62
43
|
message: 'This is in the past',
|
|
63
|
-
}
|
|
44
|
+
});
|
|
64
45
|
|
|
65
46
|
expect(result.isError).toBe(true);
|
|
66
47
|
expect(result.content).toContain('must be in the future');
|
|
67
48
|
});
|
|
68
49
|
|
|
69
50
|
test('create with invalid timestamp string returns error', async () => {
|
|
70
|
-
const result =
|
|
71
|
-
action: 'create',
|
|
51
|
+
const result = executeReminderCreate({
|
|
72
52
|
fire_at: 'not-a-date',
|
|
73
53
|
label: 'Bad date',
|
|
74
54
|
message: 'This has a bad date',
|
|
75
|
-
}
|
|
55
|
+
});
|
|
76
56
|
|
|
77
57
|
expect(result.isError).toBe(true);
|
|
78
58
|
expect(result.content).toContain('Invalid timestamp');
|
|
79
59
|
});
|
|
80
60
|
|
|
81
61
|
test('create rejects non-ISO date formats like MM/DD/YYYY', async () => {
|
|
82
|
-
const result =
|
|
83
|
-
action: 'create',
|
|
62
|
+
const result = executeReminderCreate({
|
|
84
63
|
fire_at: '03/04/2027',
|
|
85
64
|
label: 'Ambiguous date',
|
|
86
65
|
message: 'This format is locale-dependent',
|
|
87
|
-
}
|
|
66
|
+
});
|
|
88
67
|
|
|
89
68
|
expect(result.isError).toBe(true);
|
|
90
69
|
expect(result.content).toContain('Invalid timestamp');
|
|
91
70
|
});
|
|
92
71
|
|
|
93
72
|
test('create rejects ISO timestamp without timezone', async () => {
|
|
94
|
-
const result =
|
|
95
|
-
action: 'create',
|
|
73
|
+
const result = executeReminderCreate({
|
|
96
74
|
fire_at: '2027-03-15T09:00:00',
|
|
97
75
|
label: 'No timezone',
|
|
98
76
|
message: 'Missing timezone offset',
|
|
99
|
-
}
|
|
77
|
+
});
|
|
100
78
|
|
|
101
79
|
expect(result.isError).toBe(true);
|
|
102
80
|
expect(result.content).toContain('Invalid timestamp');
|
|
@@ -106,12 +84,11 @@ describe('reminder tool', () => {
|
|
|
106
84
|
const future = new Date(Date.now() + 120_000);
|
|
107
85
|
const offset = '-05:00';
|
|
108
86
|
const isoWithOffset = future.toISOString().replace('Z', offset);
|
|
109
|
-
const result =
|
|
110
|
-
action: 'create',
|
|
87
|
+
const result = executeReminderCreate({
|
|
111
88
|
fire_at: isoWithOffset,
|
|
112
89
|
label: 'With offset',
|
|
113
90
|
message: 'Has explicit timezone',
|
|
114
|
-
}
|
|
91
|
+
});
|
|
115
92
|
|
|
116
93
|
expect(result.isError).toBe(false);
|
|
117
94
|
expect(result.content).toContain('Reminder created');
|
|
@@ -119,12 +96,11 @@ describe('reminder tool', () => {
|
|
|
119
96
|
|
|
120
97
|
test('create defaults mode to notify', async () => {
|
|
121
98
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
122
|
-
const result =
|
|
123
|
-
action: 'create',
|
|
99
|
+
const result = executeReminderCreate({
|
|
124
100
|
fire_at: future,
|
|
125
101
|
label: 'Default mode',
|
|
126
102
|
message: 'Should be notify',
|
|
127
|
-
}
|
|
103
|
+
});
|
|
128
104
|
|
|
129
105
|
expect(result.isError).toBe(false);
|
|
130
106
|
expect(result.content).toContain('Mode: notify');
|
|
@@ -132,24 +108,22 @@ describe('reminder tool', () => {
|
|
|
132
108
|
|
|
133
109
|
test('create with mode execute sets mode correctly', async () => {
|
|
134
110
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
135
|
-
const result =
|
|
136
|
-
action: 'create',
|
|
111
|
+
const result = executeReminderCreate({
|
|
137
112
|
fire_at: future,
|
|
138
113
|
label: 'Execute mode',
|
|
139
114
|
message: 'Should be execute',
|
|
140
115
|
mode: 'execute',
|
|
141
|
-
}
|
|
116
|
+
});
|
|
142
117
|
|
|
143
118
|
expect(result.isError).toBe(false);
|
|
144
119
|
expect(result.content).toContain('Mode: execute');
|
|
145
120
|
});
|
|
146
121
|
|
|
147
122
|
test('create requires fire_at', async () => {
|
|
148
|
-
const result =
|
|
149
|
-
action: 'create',
|
|
123
|
+
const result = executeReminderCreate({
|
|
150
124
|
label: 'No fire_at',
|
|
151
125
|
message: 'Missing fire_at',
|
|
152
|
-
}
|
|
126
|
+
});
|
|
153
127
|
|
|
154
128
|
expect(result.isError).toBe(true);
|
|
155
129
|
expect(result.content).toContain('fire_at is required');
|
|
@@ -157,11 +131,10 @@ describe('reminder tool', () => {
|
|
|
157
131
|
|
|
158
132
|
test('create requires label', async () => {
|
|
159
133
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
160
|
-
const result =
|
|
161
|
-
action: 'create',
|
|
134
|
+
const result = executeReminderCreate({
|
|
162
135
|
fire_at: future,
|
|
163
136
|
message: 'Missing label',
|
|
164
|
-
}
|
|
137
|
+
});
|
|
165
138
|
|
|
166
139
|
expect(result.isError).toBe(true);
|
|
167
140
|
expect(result.content).toContain('label is required');
|
|
@@ -169,11 +142,10 @@ describe('reminder tool', () => {
|
|
|
169
142
|
|
|
170
143
|
test('create requires message', async () => {
|
|
171
144
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
172
|
-
const result =
|
|
173
|
-
action: 'create',
|
|
145
|
+
const result = executeReminderCreate({
|
|
174
146
|
fire_at: future,
|
|
175
147
|
label: 'No message',
|
|
176
|
-
}
|
|
148
|
+
});
|
|
177
149
|
|
|
178
150
|
expect(result.isError).toBe(true);
|
|
179
151
|
expect(result.content).toContain('message is required');
|
|
@@ -182,21 +154,20 @@ describe('reminder tool', () => {
|
|
|
182
154
|
// ── list ────────────────────────────────────────────────────────────
|
|
183
155
|
|
|
184
156
|
test('list returns "No reminders found" when empty', async () => {
|
|
185
|
-
const result =
|
|
157
|
+
const result = executeReminderList();
|
|
186
158
|
expect(result.isError).toBe(false);
|
|
187
159
|
expect(result.content).toContain('No reminders found');
|
|
188
160
|
});
|
|
189
161
|
|
|
190
162
|
test('list returns formatted reminders', async () => {
|
|
191
163
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
192
|
-
|
|
193
|
-
action: 'create',
|
|
164
|
+
executeReminderCreate({
|
|
194
165
|
fire_at: future,
|
|
195
166
|
label: 'Test reminder',
|
|
196
167
|
message: 'Test message',
|
|
197
|
-
}
|
|
168
|
+
});
|
|
198
169
|
|
|
199
|
-
const result =
|
|
170
|
+
const result = executeReminderList();
|
|
200
171
|
expect(result.isError).toBe(false);
|
|
201
172
|
expect(result.content).toContain('Test reminder');
|
|
202
173
|
expect(result.content).toContain('pending');
|
|
@@ -206,32 +177,29 @@ describe('reminder tool', () => {
|
|
|
206
177
|
|
|
207
178
|
test('cancel with valid pending reminder succeeds', async () => {
|
|
208
179
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
209
|
-
const createResult =
|
|
210
|
-
action: 'create',
|
|
180
|
+
const createResult = executeReminderCreate({
|
|
211
181
|
fire_at: future,
|
|
212
182
|
label: 'Cancel me',
|
|
213
183
|
message: 'To be cancelled',
|
|
214
|
-
}
|
|
184
|
+
});
|
|
215
185
|
|
|
216
186
|
// Extract ID from the create result
|
|
217
187
|
const idMatch = createResult.content.match(/ID: (.+)/);
|
|
218
188
|
expect(idMatch).not.toBeNull();
|
|
219
189
|
const id = idMatch![1].trim();
|
|
220
190
|
|
|
221
|
-
const result =
|
|
222
|
-
action: 'cancel',
|
|
191
|
+
const result = executeReminderCancel({
|
|
223
192
|
reminder_id: id,
|
|
224
|
-
}
|
|
193
|
+
});
|
|
225
194
|
|
|
226
195
|
expect(result.isError).toBe(false);
|
|
227
196
|
expect(result.content).toContain('cancelled');
|
|
228
197
|
});
|
|
229
198
|
|
|
230
199
|
test('cancel with nonexistent ID returns error', async () => {
|
|
231
|
-
const result =
|
|
232
|
-
action: 'cancel',
|
|
200
|
+
const result = executeReminderCancel({
|
|
233
201
|
reminder_id: 'nonexistent',
|
|
234
|
-
}
|
|
202
|
+
});
|
|
235
203
|
|
|
236
204
|
expect(result.isError).toBe(true);
|
|
237
205
|
expect(result.content).toContain('not found');
|
|
@@ -239,12 +207,11 @@ describe('reminder tool', () => {
|
|
|
239
207
|
|
|
240
208
|
test('cancel with already-fired reminder returns error', async () => {
|
|
241
209
|
const future = new Date(Date.now() + 60_000).toISOString();
|
|
242
|
-
const createResult =
|
|
243
|
-
action: 'create',
|
|
210
|
+
const createResult = executeReminderCreate({
|
|
244
211
|
fire_at: future,
|
|
245
212
|
label: 'Fire then cancel',
|
|
246
213
|
message: 'x',
|
|
247
|
-
}
|
|
214
|
+
});
|
|
248
215
|
|
|
249
216
|
const idMatch = createResult.content.match(/ID: (.+)/);
|
|
250
217
|
const id = idMatch![1].trim();
|
|
@@ -252,10 +219,9 @@ describe('reminder tool', () => {
|
|
|
252
219
|
// Force-fire by claiming with a future timestamp
|
|
253
220
|
claimDueReminders(Date.now() + 120_000);
|
|
254
221
|
|
|
255
|
-
const result =
|
|
256
|
-
action: 'cancel',
|
|
222
|
+
const result = executeReminderCancel({
|
|
257
223
|
reminder_id: id,
|
|
258
|
-
}
|
|
224
|
+
});
|
|
259
225
|
|
|
260
226
|
expect(result.isError).toBe(true);
|
|
261
227
|
expect(result.content).toContain('not found or already fired');
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests that HTTP-triggered run/session flows mirror messages into the
|
|
3
|
+
* assistant-events hub with payload parity to IPC outbound messages.
|
|
4
|
+
*
|
|
5
|
+
* The Session class has two distinct outbound paths:
|
|
6
|
+
* 1. updateClient handler — used by the prompter for confirmation_request,
|
|
7
|
+
* trace emitter, secret prompter.
|
|
8
|
+
* 2. runAgentLoop onEvent callback — used for the primary streaming events:
|
|
9
|
+
* assistant_text_delta, message_complete, tool_use_start, tool_result, etc.
|
|
10
|
+
*
|
|
11
|
+
* Both paths must publish to the hub.
|
|
12
|
+
*
|
|
13
|
+
* Tests:
|
|
14
|
+
* - confirmation_request (updateClient path) → hub emits one AssistantEvent
|
|
15
|
+
* - assistant_text_delta + message_complete (onEvent path) → hub emits in order
|
|
16
|
+
* - sessionId falls back to conversationId when the message lacks it
|
|
17
|
+
*/
|
|
18
|
+
import { afterAll, describe, test, expect, beforeEach, mock } from 'bun:test';
|
|
19
|
+
import { mkdtempSync } from 'node:fs';
|
|
20
|
+
import { tmpdir } from 'node:os';
|
|
21
|
+
import { join } from 'node:path';
|
|
22
|
+
import type { ServerMessage } from '../daemon/ipc-protocol.js';
|
|
23
|
+
import type { Session } from '../daemon/session.js';
|
|
24
|
+
import type { AssistantEvent } from '../runtime/assistant-event.js';
|
|
25
|
+
|
|
26
|
+
const testDir = mkdtempSync(join(tmpdir(), 'run-orch-hub-test-'));
|
|
27
|
+
|
|
28
|
+
mock.module('../util/platform.js', () => ({
|
|
29
|
+
getRootDir: () => testDir,
|
|
30
|
+
getDataDir: () => testDir,
|
|
31
|
+
isMacOS: () => process.platform === 'darwin',
|
|
32
|
+
isLinux: () => process.platform === 'linux',
|
|
33
|
+
isWindows: () => process.platform === 'win32',
|
|
34
|
+
getSocketPath: () => join(testDir, 'test.sock'),
|
|
35
|
+
getPidPath: () => join(testDir, 'test.pid'),
|
|
36
|
+
getDbPath: () => join(testDir, 'test.db'),
|
|
37
|
+
getLogPath: () => join(testDir, 'test.log'),
|
|
38
|
+
ensureDataDir: () => {},
|
|
39
|
+
}));
|
|
40
|
+
|
|
41
|
+
mock.module('../util/logger.js', () => ({
|
|
42
|
+
getLogger: () => new Proxy({} as Record<string, unknown>, {
|
|
43
|
+
get: () => () => {},
|
|
44
|
+
}),
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
import { initializeDb, getDb, resetDb } from '../memory/db.js';
|
|
48
|
+
import { createConversation } from '../memory/conversation-store.js';
|
|
49
|
+
import { RunOrchestrator } from '../runtime/run-orchestrator.js';
|
|
50
|
+
import { assistantEventHub } from '../runtime/assistant-event-hub.js';
|
|
51
|
+
|
|
52
|
+
initializeDb();
|
|
53
|
+
|
|
54
|
+
afterAll(() => {
|
|
55
|
+
resetDb();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Build a session that calls the updateClient handler with the given messages
|
|
62
|
+
* (simulates prompter / confirmation path).
|
|
63
|
+
*/
|
|
64
|
+
function makeSessionEmittingViaClient(...messages: ServerMessage[]): Session {
|
|
65
|
+
let clientHandler: (msg: ServerMessage) => void = () => {};
|
|
66
|
+
return {
|
|
67
|
+
isProcessing: () => false,
|
|
68
|
+
persistUserMessage: () => undefined as unknown as string,
|
|
69
|
+
setChannelCapabilities: () => {},
|
|
70
|
+
updateClient: (handler: (msg: ServerMessage) => void) => {
|
|
71
|
+
clientHandler = handler;
|
|
72
|
+
},
|
|
73
|
+
runAgentLoop: async () => {
|
|
74
|
+
for (const msg of messages) {
|
|
75
|
+
clientHandler(msg);
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
handleConfirmationResponse: () => {},
|
|
79
|
+
} as unknown as Session;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Build a session that calls the onEvent callback with the given messages
|
|
84
|
+
* (simulates the primary agent-loop streaming path).
|
|
85
|
+
*/
|
|
86
|
+
function makeSessionEmittingViaAgentLoop(...messages: ServerMessage[]): Session {
|
|
87
|
+
return {
|
|
88
|
+
isProcessing: () => false,
|
|
89
|
+
persistUserMessage: () => undefined as unknown as string,
|
|
90
|
+
setChannelCapabilities: () => {},
|
|
91
|
+
updateClient: () => {},
|
|
92
|
+
runAgentLoop: async (_content: string, _messageId: string, onEvent: (msg: ServerMessage) => void) => {
|
|
93
|
+
for (const msg of messages) {
|
|
94
|
+
onEvent(msg);
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
handleConfirmationResponse: () => {},
|
|
98
|
+
} as unknown as Session;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// ── Tests ─────────────────────────────────────────────────────────────────────
|
|
102
|
+
|
|
103
|
+
describe('HTTP run → confirmation_request mirrors to assistant-events hub', () => {
|
|
104
|
+
beforeEach(() => {
|
|
105
|
+
const db = getDb();
|
|
106
|
+
db.run('DELETE FROM message_runs');
|
|
107
|
+
db.run('DELETE FROM messages');
|
|
108
|
+
db.run('DELETE FROM conversations');
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('confirmation_request (updateClient path) emits one AssistantEvent', async () => {
|
|
112
|
+
const conversation = createConversation('http-confirmation-test');
|
|
113
|
+
const confirmationMsg: ServerMessage = {
|
|
114
|
+
type: 'confirmation_request',
|
|
115
|
+
requestId: 'req-http-1',
|
|
116
|
+
toolName: 'bash',
|
|
117
|
+
input: { command: 'ls' },
|
|
118
|
+
riskLevel: 'medium',
|
|
119
|
+
allowlistOptions: [{ label: 'ls', description: 'List files', pattern: 'ls' }],
|
|
120
|
+
scopeOptions: [{ label: 'everywhere', scope: 'everywhere' }],
|
|
121
|
+
};
|
|
122
|
+
const session = makeSessionEmittingViaClient(confirmationMsg);
|
|
123
|
+
|
|
124
|
+
const received: AssistantEvent[] = [];
|
|
125
|
+
const sub = assistantEventHub.subscribe(
|
|
126
|
+
{ assistantId: 'self' },
|
|
127
|
+
(e) => { received.push(e); },
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
const orchestrator = new RunOrchestrator({
|
|
131
|
+
getOrCreateSession: async () => session,
|
|
132
|
+
resolveAttachments: () => [],
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
await orchestrator.startRun(conversation.id, 'Do something');
|
|
136
|
+
// Wait for the async hub chain to flush.
|
|
137
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
138
|
+
|
|
139
|
+
sub.dispose();
|
|
140
|
+
|
|
141
|
+
expect(received).toHaveLength(1);
|
|
142
|
+
expect(received[0].assistantId).toBe('self');
|
|
143
|
+
expect(received[0].sessionId).toBe(conversation.id);
|
|
144
|
+
expect(received[0].message.type).toBe('confirmation_request');
|
|
145
|
+
expect(received[0].message).toBe(confirmationMsg);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
describe('HTTP run → message flow mirrors to assistant-events hub', () => {
|
|
150
|
+
beforeEach(() => {
|
|
151
|
+
const db = getDb();
|
|
152
|
+
db.run('DELETE FROM message_runs');
|
|
153
|
+
db.run('DELETE FROM messages');
|
|
154
|
+
db.run('DELETE FROM conversations');
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
test('assistant_text_delta and message_complete (onEvent path) emit in order', async () => {
|
|
158
|
+
const conversation = createConversation('http-message-flow-test');
|
|
159
|
+
const deltaMsg: ServerMessage = {
|
|
160
|
+
type: 'assistant_text_delta',
|
|
161
|
+
sessionId: conversation.id,
|
|
162
|
+
text: 'Working on it...',
|
|
163
|
+
};
|
|
164
|
+
const completeMsg: ServerMessage = {
|
|
165
|
+
type: 'message_complete',
|
|
166
|
+
sessionId: conversation.id,
|
|
167
|
+
};
|
|
168
|
+
const session = makeSessionEmittingViaAgentLoop(deltaMsg, completeMsg);
|
|
169
|
+
|
|
170
|
+
const received: AssistantEvent[] = [];
|
|
171
|
+
const sub = assistantEventHub.subscribe(
|
|
172
|
+
{ assistantId: 'self' },
|
|
173
|
+
(e) => { received.push(e); },
|
|
174
|
+
);
|
|
175
|
+
|
|
176
|
+
const orchestrator = new RunOrchestrator({
|
|
177
|
+
getOrCreateSession: async () => session,
|
|
178
|
+
resolveAttachments: () => [],
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
await orchestrator.startRun(conversation.id, 'Hello');
|
|
182
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
183
|
+
|
|
184
|
+
sub.dispose();
|
|
185
|
+
|
|
186
|
+
expect(received).toHaveLength(2);
|
|
187
|
+
expect(received[0].message.type).toBe('assistant_text_delta');
|
|
188
|
+
expect(received[1].message.type).toBe('message_complete');
|
|
189
|
+
// Both should carry the session id
|
|
190
|
+
expect(received[0].sessionId).toBe(conversation.id);
|
|
191
|
+
expect(received[1].sessionId).toBe(conversation.id);
|
|
192
|
+
// Messages are the unmodified originals
|
|
193
|
+
expect(received[0].message).toBe(deltaMsg);
|
|
194
|
+
expect(received[1].message).toBe(completeMsg);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
test('sessionId falls back to conversationId when message lacks it (onEvent path)', async () => {
|
|
198
|
+
const conversation = createConversation('http-session-fallback-test');
|
|
199
|
+
// pong has no sessionId field
|
|
200
|
+
const msg: ServerMessage = { type: 'pong' };
|
|
201
|
+
const session = makeSessionEmittingViaAgentLoop(msg);
|
|
202
|
+
|
|
203
|
+
const received: AssistantEvent[] = [];
|
|
204
|
+
const sub = assistantEventHub.subscribe(
|
|
205
|
+
{ assistantId: 'self' },
|
|
206
|
+
(e) => { received.push(e); },
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const orchestrator = new RunOrchestrator({
|
|
210
|
+
getOrCreateSession: async () => session,
|
|
211
|
+
resolveAttachments: () => [],
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
await orchestrator.startRun(conversation.id, 'ping');
|
|
215
|
+
await new Promise((r) => setTimeout(r, 20));
|
|
216
|
+
|
|
217
|
+
sub.dispose();
|
|
218
|
+
|
|
219
|
+
expect(received).toHaveLength(1);
|
|
220
|
+
expect(received[0].sessionId).toBe(conversation.id);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
@@ -40,7 +40,7 @@ function makeSessionWithConfirmation(message: ServerMessage): Session {
|
|
|
40
40
|
// Return undefined so createRun stores messageId as null and avoids
|
|
41
41
|
// a foreign-key dependency on the conversation-store message table.
|
|
42
42
|
persistUserMessage: () => undefined as unknown as string,
|
|
43
|
-
|
|
43
|
+
setChannelCapabilities: () => {},
|
|
44
44
|
updateClient: (handler: (msg: ServerMessage) => void) => {
|
|
45
45
|
clientHandler = handler;
|
|
46
46
|
},
|
|
@@ -60,7 +60,7 @@ function makeSessionWithEvent(message: ServerMessage): Session {
|
|
|
60
60
|
return {
|
|
61
61
|
isProcessing: () => false,
|
|
62
62
|
persistUserMessage: () => undefined as unknown as string,
|
|
63
|
-
|
|
63
|
+
setChannelCapabilities: () => {},
|
|
64
64
|
updateClient: () => {},
|
|
65
65
|
runAgentLoop: async (_content: string, _messageId: string, onEvent: (msg: ServerMessage) => void) => {
|
|
66
66
|
onEvent(message);
|
|
@@ -92,7 +92,7 @@ describe('run failure detection', () => {
|
|
|
92
92
|
resolveAttachments: () => [],
|
|
93
93
|
});
|
|
94
94
|
|
|
95
|
-
const run = await orchestrator.startRun(
|
|
95
|
+
const run = await orchestrator.startRun(conversation.id, 'Hello');
|
|
96
96
|
|
|
97
97
|
// The agent loop fires asynchronously; give it a tick to settle.
|
|
98
98
|
await new Promise((r) => setTimeout(r, 50));
|
|
@@ -114,7 +114,7 @@ describe('run failure detection', () => {
|
|
|
114
114
|
resolveAttachments: () => [],
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
const run = await orchestrator.startRun(
|
|
117
|
+
const run = await orchestrator.startRun(conversation.id, 'Hello');
|
|
118
118
|
|
|
119
119
|
await new Promise((r) => setTimeout(r, 50));
|
|
120
120
|
|
|
@@ -139,7 +139,7 @@ describe('run approval state executionTarget', () => {
|
|
|
139
139
|
|
|
140
140
|
test('stores pending confirmation executionTarget when provided', () => {
|
|
141
141
|
const conversation = createConversation('run test');
|
|
142
|
-
const run = createRun(
|
|
142
|
+
const run = createRun(conversation.id);
|
|
143
143
|
|
|
144
144
|
setRunConfirmation(run.id, {
|
|
145
145
|
toolName: 'host_file_read',
|
|
@@ -158,7 +158,7 @@ describe('run approval state executionTarget', () => {
|
|
|
158
158
|
|
|
159
159
|
test('parses pending confirmations without executionTarget for legacy rows', () => {
|
|
160
160
|
const conversation = createConversation('legacy run test');
|
|
161
|
-
const run = createRun(
|
|
161
|
+
const run = createRun(conversation.id);
|
|
162
162
|
|
|
163
163
|
setRunConfirmation(run.id, {
|
|
164
164
|
toolName: 'bash',
|
|
@@ -192,7 +192,7 @@ describe('run approval state executionTarget', () => {
|
|
|
192
192
|
resolveAttachments: () => [],
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
-
const run = await orchestrator.startRun(
|
|
195
|
+
const run = await orchestrator.startRun(conversation.id, 'Run host command');
|
|
196
196
|
const stored = orchestrator.getRun(run.id);
|
|
197
197
|
expect(stored?.status).toBe('needs_confirmation');
|
|
198
198
|
expect(stored?.pendingConfirmation?.executionTarget).toBe('host');
|