@namzu/sdk 0.1.8 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +16 -0
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +5 -3
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/RouterAgent.d.ts.map +1 -1
- package/dist/agents/RouterAgent.js +3 -0
- package/dist/agents/RouterAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +18 -5
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/bridge/a2a/mapper.d.ts.map +1 -1
- package/dist/bridge/a2a/mapper.js +6 -0
- package/dist/bridge/a2a/mapper.js.map +1 -1
- package/dist/bridge/a2a/task.d.ts +2 -2
- package/dist/bridge/a2a/task.d.ts.map +1 -1
- package/dist/bridge/a2a/task.js.map +1 -1
- package/dist/bridge/sse/mapper.d.ts.map +1 -1
- package/dist/bridge/sse/mapper.js +6 -0
- package/dist/bridge/sse/mapper.js.map +1 -1
- package/dist/constants/a2a/index.d.ts +2 -2
- package/dist/constants/a2a/index.d.ts.map +1 -1
- package/dist/constants/a2a/index.js.map +1 -1
- package/dist/contracts/api.d.ts +22 -3
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +3 -1
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/gateway/local.d.ts.map +1 -1
- package/dist/gateway/local.js +6 -0
- package/dist/gateway/local.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/manager/agent/__tests__/lifecycle.test.d.ts +2 -0
- package/dist/manager/agent/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/manager/agent/__tests__/lifecycle.test.js +302 -0
- package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -0
- package/dist/manager/agent/lifecycle.d.ts +58 -3
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +311 -12
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +8 -1
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +15 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/run/reporter.d.ts.map +1 -1
- package/dist/run/reporter.js +25 -0
- package/dist/run/reporter.js.map +1 -1
- package/dist/runtime/query/__tests__/context.test.d.ts +2 -0
- package/dist/runtime/query/__tests__/context.test.d.ts.map +1 -0
- package/dist/runtime/query/__tests__/context.test.js +84 -0
- package/dist/runtime/query/__tests__/context.test.js.map +1 -0
- package/dist/runtime/query/context.d.ts +55 -2
- package/dist/runtime/query/context.d.ts.map +1 -1
- package/dist/runtime/query/context.js +48 -8
- package/dist/runtime/query/context.js.map +1 -1
- package/dist/runtime/query/events.d.ts.map +1 -1
- package/dist/runtime/query/events.js +8 -0
- package/dist/runtime/query/events.js.map +1 -1
- package/dist/runtime/query/index.d.ts +25 -2
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +11 -1
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/session/__tests__/integration/_fixtures.d.ts +115 -0
- package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -0
- package/dist/session/__tests__/integration/_fixtures.js +198 -0
- package/dist/session/__tests__/integration/_fixtures.js.map +1 -0
- package/dist/session/__tests__/integration/capacity-caps.test.d.ts +13 -0
- package/dist/session/__tests__/integration/capacity-caps.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/capacity-caps.test.js +116 -0
- package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.d.ts +18 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.js +226 -0
- package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts +15 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.js +323 -0
- package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts +12 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +170 -0
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts +18 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +146 -0
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts +15 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.js +163 -0
- package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts +12 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +157 -0
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.d.ts +11 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.js +140 -0
- package/dist/session/__tests__/integration/migration-filesystem.test.js.map +1 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts +13 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.js +84 -0
- package/dist/session/__tests__/integration/migration-id-prefix.test.js.map +1 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts +14 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.js +241 -0
- package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -0
- package/dist/session/__tests__/integration/retention-archive.test.d.ts +12 -0
- package/dist/session/__tests__/integration/retention-archive.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/retention-archive.test.js +186 -0
- package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts +18 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +200 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.d.ts +14 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.js +180 -0
- package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -0
- package/dist/session/errors.d.ts +60 -0
- package/dist/session/errors.d.ts.map +1 -0
- package/dist/session/errors.js +50 -0
- package/dist/session/errors.js.map +1 -0
- package/dist/session/events/index.d.ts +4 -0
- package/dist/session/events/index.d.ts.map +1 -0
- package/dist/session/events/index.js +8 -0
- package/dist/session/events/index.js.map +1 -0
- package/dist/session/events/schema-version.d.ts +13 -0
- package/dist/session/events/schema-version.d.ts.map +1 -0
- package/dist/session/events/schema-version.js +12 -0
- package/dist/session/events/schema-version.js.map +1 -0
- package/dist/session/events/types.d.ts +64 -0
- package/dist/session/events/types.d.ts.map +1 -0
- package/dist/session/events/types.js +2 -0
- package/dist/session/events/types.js.map +1 -0
- package/dist/session/handoff/__tests__/broadcast.test.d.ts +2 -0
- package/dist/session/handoff/__tests__/broadcast.test.d.ts.map +1 -0
- package/dist/session/handoff/__tests__/broadcast.test.js +243 -0
- package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -0
- package/dist/session/handoff/__tests__/capacity.test.d.ts +2 -0
- package/dist/session/handoff/__tests__/capacity.test.d.ts.map +1 -0
- package/dist/session/handoff/__tests__/capacity.test.js +100 -0
- package/dist/session/handoff/__tests__/capacity.test.js.map +1 -0
- package/dist/session/handoff/__tests__/single.test.d.ts +2 -0
- package/dist/session/handoff/__tests__/single.test.d.ts.map +1 -0
- package/dist/session/handoff/__tests__/single.test.js +230 -0
- package/dist/session/handoff/__tests__/single.test.js.map +1 -0
- package/dist/session/handoff/assignment.d.ts +59 -0
- package/dist/session/handoff/assignment.d.ts.map +1 -0
- package/dist/session/handoff/assignment.js +11 -0
- package/dist/session/handoff/assignment.js.map +1 -0
- package/dist/session/handoff/broadcast.d.ts +47 -0
- package/dist/session/handoff/broadcast.d.ts.map +1 -0
- package/dist/session/handoff/broadcast.js +296 -0
- package/dist/session/handoff/broadcast.js.map +1 -0
- package/dist/session/handoff/capacity.d.ts +66 -0
- package/dist/session/handoff/capacity.d.ts.map +1 -0
- package/dist/session/handoff/capacity.js +60 -0
- package/dist/session/handoff/capacity.js.map +1 -0
- package/dist/session/handoff/events.d.ts +66 -0
- package/dist/session/handoff/events.d.ts.map +1 -0
- package/dist/session/handoff/events.js +13 -0
- package/dist/session/handoff/events.js.map +1 -0
- package/dist/session/handoff/index.d.ts +12 -0
- package/dist/session/handoff/index.d.ts.map +1 -0
- package/dist/session/handoff/index.js +9 -0
- package/dist/session/handoff/index.js.map +1 -0
- package/dist/session/handoff/single.d.ts +62 -0
- package/dist/session/handoff/single.d.ts.map +1 -0
- package/dist/session/handoff/single.js +217 -0
- package/dist/session/handoff/single.js.map +1 -0
- package/dist/session/handoff/version.d.ts +52 -0
- package/dist/session/handoff/version.d.ts.map +1 -0
- package/dist/session/handoff/version.js +36 -0
- package/dist/session/handoff/version.js.map +1 -0
- package/dist/session/hierarchy/__tests__/session.test.d.ts +2 -0
- package/dist/session/hierarchy/__tests__/session.test.d.ts.map +1 -0
- package/dist/session/hierarchy/__tests__/session.test.js +67 -0
- package/dist/session/hierarchy/__tests__/session.test.js.map +1 -0
- package/dist/session/hierarchy/actor.d.ts +26 -0
- package/dist/session/hierarchy/actor.d.ts.map +1 -0
- package/dist/session/hierarchy/actor.js +2 -0
- package/dist/session/hierarchy/actor.js.map +1 -0
- package/dist/session/hierarchy/index.d.ts +8 -0
- package/dist/session/hierarchy/index.d.ts.map +1 -0
- package/dist/session/hierarchy/index.js +4 -0
- package/dist/session/hierarchy/index.js.map +1 -0
- package/dist/session/hierarchy/lineage.d.ts +15 -0
- package/dist/session/hierarchy/lineage.d.ts.map +1 -0
- package/dist/session/hierarchy/lineage.js +2 -0
- package/dist/session/hierarchy/lineage.js.map +1 -0
- package/dist/session/hierarchy/project.d.ts +40 -0
- package/dist/session/hierarchy/project.d.ts.map +1 -0
- package/dist/session/hierarchy/project.js +2 -0
- package/dist/session/hierarchy/project.js.map +1 -0
- package/dist/session/hierarchy/session.d.ts +59 -0
- package/dist/session/hierarchy/session.d.ts.map +1 -0
- package/dist/session/hierarchy/session.js +51 -0
- package/dist/session/hierarchy/session.js.map +1 -0
- package/dist/session/hierarchy/sub-session.d.ts +76 -0
- package/dist/session/hierarchy/sub-session.d.ts.map +1 -0
- package/dist/session/hierarchy/sub-session.js +2 -0
- package/dist/session/hierarchy/sub-session.js.map +1 -0
- package/dist/session/hierarchy/tenant.d.ts +13 -0
- package/dist/session/hierarchy/tenant.d.ts.map +1 -0
- package/dist/session/hierarchy/tenant.js +2 -0
- package/dist/session/hierarchy/tenant.js.map +1 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +15 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.d.ts +2 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.d.ts.map +1 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.js +179 -0
- package/dist/session/intervention/__tests__/prev-artifact.test.js.map +1 -0
- package/dist/session/intervention/index.d.ts +3 -0
- package/dist/session/intervention/index.d.ts.map +1 -0
- package/dist/session/intervention/index.js +8 -0
- package/dist/session/intervention/index.js.map +1 -0
- package/dist/session/intervention/prev-artifact.d.ts +103 -0
- package/dist/session/intervention/prev-artifact.d.ts.map +1 -0
- package/dist/session/intervention/prev-artifact.js +112 -0
- package/dist/session/intervention/prev-artifact.js.map +1 -0
- package/dist/session/migration/__tests__/filesystem.test.d.ts +2 -0
- package/dist/session/migration/__tests__/filesystem.test.d.ts.map +1 -0
- package/dist/session/migration/__tests__/filesystem.test.js +188 -0
- package/dist/session/migration/__tests__/filesystem.test.js.map +1 -0
- package/dist/session/migration/__tests__/id-prefix.test.d.ts +2 -0
- package/dist/session/migration/__tests__/id-prefix.test.d.ts.map +1 -0
- package/dist/session/migration/__tests__/id-prefix.test.js +83 -0
- package/dist/session/migration/__tests__/id-prefix.test.js.map +1 -0
- package/dist/session/migration/__tests__/marker.test.d.ts +2 -0
- package/dist/session/migration/__tests__/marker.test.d.ts.map +1 -0
- package/dist/session/migration/__tests__/marker.test.js +75 -0
- package/dist/session/migration/__tests__/marker.test.js.map +1 -0
- package/dist/session/migration/errors.d.ts +26 -0
- package/dist/session/migration/errors.d.ts.map +1 -0
- package/dist/session/migration/errors.js +22 -0
- package/dist/session/migration/errors.js.map +1 -0
- package/dist/session/migration/filesystem.d.ts +94 -0
- package/dist/session/migration/filesystem.d.ts.map +1 -0
- package/dist/session/migration/filesystem.js +319 -0
- package/dist/session/migration/filesystem.js.map +1 -0
- package/dist/session/migration/id-prefix.d.ts +98 -0
- package/dist/session/migration/id-prefix.d.ts.map +1 -0
- package/dist/session/migration/id-prefix.js +116 -0
- package/dist/session/migration/id-prefix.js.map +1 -0
- package/dist/session/migration/index.d.ts +8 -0
- package/dist/session/migration/index.d.ts.map +1 -0
- package/dist/session/migration/index.js +8 -0
- package/dist/session/migration/index.js.map +1 -0
- package/dist/session/migration/marker.d.ts +57 -0
- package/dist/session/migration/marker.d.ts.map +1 -0
- package/dist/session/migration/marker.js +111 -0
- package/dist/session/migration/marker.js.map +1 -0
- package/dist/session/retention/__tests__/archive.test.d.ts +2 -0
- package/dist/session/retention/__tests__/archive.test.d.ts.map +1 -0
- package/dist/session/retention/__tests__/archive.test.js +252 -0
- package/dist/session/retention/__tests__/archive.test.js.map +1 -0
- package/dist/session/retention/__tests__/disk-backend.test.d.ts +2 -0
- package/dist/session/retention/__tests__/disk-backend.test.d.ts.map +1 -0
- package/dist/session/retention/__tests__/disk-backend.test.js +154 -0
- package/dist/session/retention/__tests__/disk-backend.test.js.map +1 -0
- package/dist/session/retention/archive-backend-ref.d.ts +18 -0
- package/dist/session/retention/archive-backend-ref.d.ts.map +1 -0
- package/dist/session/retention/archive-backend-ref.js +2 -0
- package/dist/session/retention/archive-backend-ref.js.map +1 -0
- package/dist/session/retention/archive.d.ts +130 -0
- package/dist/session/retention/archive.d.ts.map +1 -0
- package/dist/session/retention/archive.js +203 -0
- package/dist/session/retention/archive.js.map +1 -0
- package/dist/session/retention/backend.d.ts +101 -0
- package/dist/session/retention/backend.d.ts.map +1 -0
- package/dist/session/retention/backend.js +15 -0
- package/dist/session/retention/backend.js.map +1 -0
- package/dist/session/retention/disk-backend.d.ts +59 -0
- package/dist/session/retention/disk-backend.d.ts.map +1 -0
- package/dist/session/retention/disk-backend.js +236 -0
- package/dist/session/retention/disk-backend.js.map +1 -0
- package/dist/session/retention/index.d.ts +9 -0
- package/dist/session/retention/index.d.ts.map +1 -0
- package/dist/session/retention/index.js +6 -0
- package/dist/session/retention/index.js.map +1 -0
- package/dist/session/retention/policy.d.ts +49 -0
- package/dist/session/retention/policy.d.ts.map +1 -0
- package/dist/session/retention/policy.js +21 -0
- package/dist/session/retention/policy.js.map +1 -0
- package/dist/session/summary/__tests__/materialize.test.d.ts +2 -0
- package/dist/session/summary/__tests__/materialize.test.d.ts.map +1 -0
- package/dist/session/summary/__tests__/materialize.test.js +269 -0
- package/dist/session/summary/__tests__/materialize.test.js.map +1 -0
- package/dist/session/summary/deliverable.d.ts +74 -0
- package/dist/session/summary/deliverable.d.ts.map +1 -0
- package/dist/session/summary/deliverable.js +20 -0
- package/dist/session/summary/deliverable.js.map +1 -0
- package/dist/session/summary/index.d.ts +6 -0
- package/dist/session/summary/index.d.ts.map +1 -0
- package/dist/session/summary/index.js +9 -0
- package/dist/session/summary/index.js.map +1 -0
- package/dist/session/summary/materialize.d.ts +82 -0
- package/dist/session/summary/materialize.d.ts.map +1 -0
- package/dist/session/summary/materialize.js +117 -0
- package/dist/session/summary/materialize.js.map +1 -0
- package/dist/session/summary/ref.d.ts +91 -0
- package/dist/session/summary/ref.d.ts.map +1 -0
- package/dist/session/summary/ref.js +51 -0
- package/dist/session/summary/ref.js.map +1 -0
- package/dist/session/workspace/__tests__/git-worktree.test.d.ts +2 -0
- package/dist/session/workspace/__tests__/git-worktree.test.d.ts.map +1 -0
- package/dist/session/workspace/__tests__/git-worktree.test.js +244 -0
- package/dist/session/workspace/__tests__/git-worktree.test.js.map +1 -0
- package/dist/session/workspace/__tests__/path-builder.test.d.ts +2 -0
- package/dist/session/workspace/__tests__/path-builder.test.d.ts.map +1 -0
- package/dist/session/workspace/__tests__/path-builder.test.js +37 -0
- package/dist/session/workspace/__tests__/path-builder.test.js.map +1 -0
- package/dist/session/workspace/driver.d.ts +55 -0
- package/dist/session/workspace/driver.d.ts.map +1 -0
- package/dist/session/workspace/driver.js +12 -0
- package/dist/session/workspace/driver.js.map +1 -0
- package/dist/session/workspace/git-worktree.d.ts +65 -0
- package/dist/session/workspace/git-worktree.d.ts.map +1 -0
- package/dist/session/workspace/git-worktree.js +156 -0
- package/dist/session/workspace/git-worktree.js.map +1 -0
- package/dist/session/workspace/index.d.ts +8 -0
- package/dist/session/workspace/index.d.ts.map +1 -0
- package/dist/session/workspace/index.js +7 -0
- package/dist/session/workspace/index.js.map +1 -0
- package/dist/session/workspace/path-builder.d.ts +50 -0
- package/dist/session/workspace/path-builder.d.ts.map +1 -0
- package/dist/session/workspace/path-builder.js +50 -0
- package/dist/session/workspace/path-builder.js.map +1 -0
- package/dist/session/workspace/ref.d.ts +46 -0
- package/dist/session/workspace/ref.d.ts.map +1 -0
- package/dist/session/workspace/ref.js +11 -0
- package/dist/session/workspace/ref.js.map +1 -0
- package/dist/session/workspace/registry.d.ts +26 -0
- package/dist/session/workspace/registry.d.ts.map +1 -0
- package/dist/session/workspace/registry.js +35 -0
- package/dist/session/workspace/registry.js.map +1 -0
- package/dist/store/conversation/memory.d.ts +22 -0
- package/dist/store/conversation/memory.d.ts.map +1 -1
- package/dist/store/conversation/memory.js +22 -0
- package/dist/store/conversation/memory.js.map +1 -1
- package/dist/store/session/__tests__/disk.test.d.ts +2 -0
- package/dist/store/session/__tests__/disk.test.d.ts.map +1 -0
- package/dist/store/session/__tests__/disk.test.js +240 -0
- package/dist/store/session/__tests__/disk.test.js.map +1 -0
- package/dist/store/session/__tests__/memory.test.d.ts +2 -0
- package/dist/store/session/__tests__/memory.test.d.ts.map +1 -0
- package/dist/store/session/__tests__/memory.test.js +217 -0
- package/dist/store/session/__tests__/memory.test.js.map +1 -0
- package/dist/store/session/disk.d.ts +85 -0
- package/dist/store/session/disk.d.ts.map +1 -0
- package/dist/store/session/disk.js +757 -0
- package/dist/store/session/disk.js.map +1 -0
- package/dist/store/session/index.d.ts +7 -0
- package/dist/store/session/index.d.ts.map +1 -0
- package/dist/store/session/index.js +11 -0
- package/dist/store/session/index.js.map +1 -0
- package/dist/store/session/linkage.d.ts +38 -0
- package/dist/store/session/linkage.d.ts.map +1 -0
- package/dist/store/session/linkage.js +64 -0
- package/dist/store/session/linkage.js.map +1 -0
- package/dist/store/session/memory.d.ts +48 -0
- package/dist/store/session/memory.d.ts.map +1 -0
- package/dist/store/session/memory.js +322 -0
- package/dist/store/session/memory.js.map +1 -0
- package/dist/store/session/messages.d.ts +20 -0
- package/dist/store/session/messages.d.ts.map +1 -0
- package/dist/store/session/messages.js +12 -0
- package/dist/store/session/messages.js.map +1 -0
- package/dist/tools/builtins/__tests__/structuredOutput.example.d.ts +1 -1
- package/dist/types/agent/base.d.ts +28 -1
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +50 -2
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/agent/task.js.map +1 -1
- package/dist/types/conversation/index.d.ts +7 -0
- package/dist/types/conversation/index.d.ts.map +1 -1
- package/dist/types/ids/index.d.ts +26 -3
- package/dist/types/ids/index.d.ts.map +1 -1
- package/dist/types/ids/index.js +8 -1
- package/dist/types/ids/index.js.map +1 -1
- package/dist/types/invocation/__tests__/state.test.js +36 -29
- package/dist/types/invocation/__tests__/state.test.js.map +1 -1
- package/dist/types/invocation/index.d.ts +20 -4
- package/dist/types/invocation/index.d.ts.map +1 -1
- package/dist/types/invocation/index.js +10 -7
- package/dist/types/invocation/index.js.map +1 -1
- package/dist/types/run/config.d.ts +11 -1
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/events.d.ts +26 -1
- package/dist/types/run/events.d.ts.map +1 -1
- package/dist/types/run/index.d.ts.map +1 -1
- package/dist/types/run/index.js +8 -0
- package/dist/types/run/index.js.map +1 -1
- package/dist/types/run/metadata.d.ts +24 -1
- package/dist/types/run/metadata.d.ts.map +1 -1
- package/dist/types/run/status.d.ts +26 -0
- package/dist/types/run/status.d.ts.map +1 -0
- package/dist/types/run/status.js +2 -0
- package/dist/types/run/status.js.map +1 -0
- package/dist/types/session/ids.d.ts +18 -0
- package/dist/types/session/ids.d.ts.map +1 -0
- package/dist/types/session/ids.js +12 -0
- package/dist/types/session/ids.js.map +1 -0
- package/dist/types/session/index.d.ts +3 -0
- package/dist/types/session/index.d.ts.map +1 -0
- package/dist/types/session/index.js +5 -0
- package/dist/types/session/index.js.map +1 -0
- package/dist/types/session/store.d.ts +188 -0
- package/dist/types/session/store.d.ts.map +1 -0
- package/dist/types/session/store.js +14 -0
- package/dist/types/session/store.js.map +1 -0
- package/dist/utils/id.d.ts +18 -1
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +42 -4
- package/dist/utils/id.js.map +1 -1
- package/package.json +1 -1
- package/src/agents/ReactiveAgent.ts +7 -3
- package/src/agents/RouterAgent.ts +5 -0
- package/src/agents/SupervisorAgent.ts +26 -6
- package/src/bridge/a2a/mapper.ts +7 -0
- package/src/bridge/a2a/task.ts +2 -2
- package/src/bridge/sse/mapper.ts +8 -1
- package/src/constants/a2a/index.ts +2 -2
- package/src/contracts/api.ts +23 -3
- package/src/contracts/index.ts +2 -0
- package/src/gateway/local.ts +6 -0
- package/src/index.ts +14 -0
- package/src/manager/agent/__tests__/lifecycle.test.ts +452 -0
- package/src/manager/agent/lifecycle.ts +434 -19
- package/src/manager/run/persistence.ts +20 -1
- package/src/run/reporter.ts +28 -0
- package/src/runtime/query/__tests__/context.test.ts +101 -0
- package/src/runtime/query/context.ts +106 -10
- package/src/runtime/query/events.ts +8 -0
- package/src/runtime/query/index.ts +41 -3
- package/src/session/__tests__/integration/_fixtures.ts +282 -0
- package/src/session/__tests__/integration/capacity-caps.test.ts +164 -0
- package/src/session/__tests__/integration/e2e-spawn.test.ts +278 -0
- package/src/session/__tests__/integration/event-stream-ordering.test.ts +403 -0
- package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +245 -0
- package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +179 -0
- package/src/session/__tests__/integration/handoff-single-e2e.test.ts +220 -0
- package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +237 -0
- package/src/session/__tests__/integration/migration-filesystem.test.ts +209 -0
- package/src/session/__tests__/integration/migration-id-prefix.test.ts +101 -0
- package/src/session/__tests__/integration/prev-artifact-dag.test.ts +318 -0
- package/src/session/__tests__/integration/retention-archive.test.ts +231 -0
- package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +237 -0
- package/src/session/__tests__/integration/tenant-isolation.test.ts +282 -0
- package/src/session/errors.ts +70 -0
- package/src/session/events/index.ts +16 -0
- package/src/session/events/schema-version.ts +13 -0
- package/src/session/events/types.ts +71 -0
- package/src/session/handoff/__tests__/broadcast.test.ts +350 -0
- package/src/session/handoff/__tests__/capacity.test.ts +123 -0
- package/src/session/handoff/__tests__/single.test.ts +316 -0
- package/src/session/handoff/assignment.ts +62 -0
- package/src/session/handoff/broadcast.ts +381 -0
- package/src/session/handoff/capacity.ts +121 -0
- package/src/session/handoff/events.ts +72 -0
- package/src/session/handoff/index.ts +29 -0
- package/src/session/handoff/single.ts +288 -0
- package/src/session/handoff/version.ts +59 -0
- package/src/session/hierarchy/__tests__/session.test.ts +92 -0
- package/src/session/hierarchy/actor.ts +17 -0
- package/src/session/hierarchy/index.ts +17 -0
- package/src/session/hierarchy/lineage.ts +15 -0
- package/src/session/hierarchy/project.ts +41 -0
- package/src/session/hierarchy/session.ts +97 -0
- package/src/session/hierarchy/sub-session.ts +92 -0
- package/src/session/hierarchy/tenant.ts +13 -0
- package/src/session/index.ts +15 -0
- package/src/session/intervention/__tests__/prev-artifact.test.ts +234 -0
- package/src/session/intervention/index.ts +16 -0
- package/src/session/intervention/prev-artifact.ts +180 -0
- package/src/session/migration/__tests__/filesystem.test.ts +263 -0
- package/src/session/migration/__tests__/id-prefix.test.ts +101 -0
- package/src/session/migration/__tests__/marker.test.ts +84 -0
- package/src/session/migration/errors.ts +23 -0
- package/src/session/migration/filesystem.ts +401 -0
- package/src/session/migration/id-prefix.ts +146 -0
- package/src/session/migration/index.ts +38 -0
- package/src/session/migration/marker.ts +131 -0
- package/src/session/retention/__tests__/archive.test.ts +316 -0
- package/src/session/retention/__tests__/disk-backend.test.ts +180 -0
- package/src/session/retention/archive-backend-ref.ts +17 -0
- package/src/session/retention/archive.ts +281 -0
- package/src/session/retention/backend.ts +107 -0
- package/src/session/retention/disk-backend.ts +304 -0
- package/src/session/retention/index.ts +16 -0
- package/src/session/retention/policy.ts +53 -0
- package/src/session/summary/__tests__/materialize.test.ts +341 -0
- package/src/session/summary/deliverable.ts +84 -0
- package/src/session/summary/index.ts +31 -0
- package/src/session/summary/materialize.ts +169 -0
- package/src/session/summary/ref.ts +104 -0
- package/src/session/workspace/__tests__/git-worktree.test.ts +258 -0
- package/src/session/workspace/__tests__/path-builder.test.ts +51 -0
- package/src/session/workspace/driver.ts +60 -0
- package/src/session/workspace/git-worktree.ts +209 -0
- package/src/session/workspace/index.ts +25 -0
- package/src/session/workspace/path-builder.ts +71 -0
- package/src/session/workspace/ref.ts +50 -0
- package/src/session/workspace/registry.ts +42 -0
- package/src/store/conversation/memory.ts +23 -0
- package/src/store/session/__tests__/disk.test.ts +346 -0
- package/src/store/session/__tests__/memory.test.ts +327 -0
- package/src/store/session/disk.ts +920 -0
- package/src/store/session/index.ts +14 -0
- package/src/store/session/linkage.ts +80 -0
- package/src/store/session/memory.ts +400 -0
- package/src/store/session/messages.ts +21 -0
- package/src/types/agent/base.ts +31 -1
- package/src/types/agent/task.ts +58 -2
- package/src/types/conversation/index.ts +7 -0
- package/src/types/ids/index.ts +41 -3
- package/src/types/invocation/__tests__/state.test.ts +37 -29
- package/src/types/invocation/index.ts +26 -10
- package/src/types/run/config.ts +12 -1
- package/src/types/run/events.ts +36 -1
- package/src/types/run/index.ts +8 -0
- package/src/types/run/metadata.ts +24 -1
- package/src/types/run/status.ts +33 -0
- package/src/types/session/ids.ts +34 -0
- package/src/types/session/index.ts +28 -0
- package/src/types/session/store.ts +229 -0
- package/src/utils/id.ts +55 -4
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration — event stream ordering + lineage + schemaVersion envelope.
|
|
3
|
+
*
|
|
4
|
+
* Covers roadmap §5 invariants:
|
|
5
|
+
* - §10.1 schemaVersion: 2 on every sub-session RunEvent
|
|
6
|
+
* - §10.3 tree-scoped monotonic ordering by (rootSessionId, eventId)
|
|
7
|
+
* - §10.3 depth filter ('self' vs 'tree') at subscribe time
|
|
8
|
+
* - §10.4 lineage stamped on every sub-session event with parent + root + depth
|
|
9
|
+
*
|
|
10
|
+
* Orthogonal to `e2e-spawn.test.ts` (covers single-level spawn). This file
|
|
11
|
+
* drives a multi-level (3-deep) delegation tree so monotonic ordering across
|
|
12
|
+
* concurrent descendants is observable.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { describe, expect, it } from 'vitest'
|
|
16
|
+
import { EMPTY_TOKEN_USAGE } from '../../../constants/limits.js'
|
|
17
|
+
import type { AgentManager } from '../../../manager/agent/lifecycle.js'
|
|
18
|
+
import type { AgentInput, BaseAgentConfig, BaseAgentResult } from '../../../types/agent/base.js'
|
|
19
|
+
import type { RunId } from '../../../types/ids/index.js'
|
|
20
|
+
import { createAssistantMessage } from '../../../types/message/index.js'
|
|
21
|
+
import type { RunEvent } from '../../../types/run/events.js'
|
|
22
|
+
import { ZERO_COST } from '../../../utils/cost.js'
|
|
23
|
+
import {
|
|
24
|
+
DEFAULT_TENANT,
|
|
25
|
+
buildAgent,
|
|
26
|
+
buildAgentCustom,
|
|
27
|
+
buildDefinition,
|
|
28
|
+
buildHarness,
|
|
29
|
+
buildSendMessageOptions,
|
|
30
|
+
buildTaskContext,
|
|
31
|
+
seedActiveParent,
|
|
32
|
+
} from './_fixtures.js'
|
|
33
|
+
|
|
34
|
+
describe('Integration — event stream ordering + lineage + schemaVersion', () => {
|
|
35
|
+
it('every sub-session RunEvent carries schemaVersion: 2', async () => {
|
|
36
|
+
const harness = buildHarness()
|
|
37
|
+
const { project, session, actor } = await seedActiveParent(harness)
|
|
38
|
+
harness.registry.register(buildDefinition(buildAgent('worker')))
|
|
39
|
+
|
|
40
|
+
const captured: RunEvent[] = []
|
|
41
|
+
const task = await harness.manager.sendMessage(
|
|
42
|
+
buildSendMessageOptions({
|
|
43
|
+
agentId: 'worker',
|
|
44
|
+
parentSessionId: session.id,
|
|
45
|
+
projectId: project.id,
|
|
46
|
+
tenantId: DEFAULT_TENANT,
|
|
47
|
+
parentActor: actor,
|
|
48
|
+
}),
|
|
49
|
+
buildTaskContext({
|
|
50
|
+
sessionId: session.id,
|
|
51
|
+
projectId: project.id,
|
|
52
|
+
tenantId: DEFAULT_TENANT,
|
|
53
|
+
parentActor: actor,
|
|
54
|
+
}),
|
|
55
|
+
(ev) => {
|
|
56
|
+
captured.push(ev)
|
|
57
|
+
},
|
|
58
|
+
)
|
|
59
|
+
await harness.manager.waitForCompletion(task.taskId)
|
|
60
|
+
|
|
61
|
+
// Every sub-session lifecycle event is stamped with schemaVersion: 2.
|
|
62
|
+
const subSessionEvents = captured.filter(
|
|
63
|
+
(e) =>
|
|
64
|
+
e.type === 'subsession_spawned' ||
|
|
65
|
+
e.type === 'subsession_messaged' ||
|
|
66
|
+
e.type === 'subsession_idled',
|
|
67
|
+
)
|
|
68
|
+
expect(subSessionEvents.length).toBeGreaterThan(0)
|
|
69
|
+
for (const ev of subSessionEvents) {
|
|
70
|
+
expect(ev.schemaVersion).toBe(2)
|
|
71
|
+
}
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
it('every sub-session event carries lineage { parentSessionId, rootSessionId, depth }', async () => {
|
|
75
|
+
const harness = buildHarness()
|
|
76
|
+
const { project, session, actor } = await seedActiveParent(harness)
|
|
77
|
+
harness.registry.register(buildDefinition(buildAgent('worker')))
|
|
78
|
+
|
|
79
|
+
const captured: RunEvent[] = []
|
|
80
|
+
const task = await harness.manager.sendMessage(
|
|
81
|
+
buildSendMessageOptions({
|
|
82
|
+
agentId: 'worker',
|
|
83
|
+
parentSessionId: session.id,
|
|
84
|
+
projectId: project.id,
|
|
85
|
+
tenantId: DEFAULT_TENANT,
|
|
86
|
+
parentActor: actor,
|
|
87
|
+
}),
|
|
88
|
+
buildTaskContext({
|
|
89
|
+
sessionId: session.id,
|
|
90
|
+
projectId: project.id,
|
|
91
|
+
tenantId: DEFAULT_TENANT,
|
|
92
|
+
parentActor: actor,
|
|
93
|
+
}),
|
|
94
|
+
(ev) => {
|
|
95
|
+
captured.push(ev)
|
|
96
|
+
},
|
|
97
|
+
)
|
|
98
|
+
await harness.manager.waitForCompletion(task.taskId)
|
|
99
|
+
|
|
100
|
+
const spawned = captured.find((e) => e.type === 'subsession_spawned')
|
|
101
|
+
const idled = captured.find((e) => e.type === 'subsession_idled')
|
|
102
|
+
expect(spawned).toBeDefined()
|
|
103
|
+
expect(idled).toBeDefined()
|
|
104
|
+
|
|
105
|
+
if (spawned && 'lineage' in spawned) {
|
|
106
|
+
expect(spawned.lineage.parentSessionId).toBe(session.id)
|
|
107
|
+
expect(spawned.lineage.rootSessionId).toBe(session.id)
|
|
108
|
+
expect(spawned.lineage.depth).toBe(1)
|
|
109
|
+
}
|
|
110
|
+
if (idled && 'lineage' in idled) {
|
|
111
|
+
expect(idled.lineage.parentSessionId).toBe(session.id)
|
|
112
|
+
expect(idled.lineage.rootSessionId).toBe(session.id)
|
|
113
|
+
expect(idled.lineage.depth).toBe(1)
|
|
114
|
+
}
|
|
115
|
+
})
|
|
116
|
+
|
|
117
|
+
it('3-deep delegation: rootSessionId identical across tree; depth ascends 1→2→3', async () => {
|
|
118
|
+
const harness = buildHarness()
|
|
119
|
+
const { project, session, actor } = await seedActiveParent(harness)
|
|
120
|
+
|
|
121
|
+
// Wire a cascading agent: level-1 child spawns level-2 via its own
|
|
122
|
+
// sendMessage. We hand a reference to the manager into the child agent
|
|
123
|
+
// via a closure so level-2 can spawn level-3.
|
|
124
|
+
const manager: AgentManager = harness.manager
|
|
125
|
+
const nestedEventsCaptured: RunEvent[] = []
|
|
126
|
+
|
|
127
|
+
const leafAgent = buildAgent('leaf', 'leaf result')
|
|
128
|
+
const midAgent = buildAgentCustom(
|
|
129
|
+
'mid',
|
|
130
|
+
async (_input: AgentInput, config: BaseAgentConfig): Promise<BaseAgentResult> => {
|
|
131
|
+
// Spawn a level-2 child from inside the mid-agent's run.
|
|
132
|
+
if (!config.sessionId || !config.projectId || !config.tenantId) {
|
|
133
|
+
throw new Error('mid agent missing session scoping')
|
|
134
|
+
}
|
|
135
|
+
// Flip child session to active so it is a legal spawn parent.
|
|
136
|
+
const childSessionId = config.sessionId
|
|
137
|
+
const cs = await harness.store.getSession(childSessionId, config.tenantId)
|
|
138
|
+
if (cs && cs.status !== 'active') {
|
|
139
|
+
await harness.store.updateSession({ ...cs, status: 'active' }, config.tenantId)
|
|
140
|
+
}
|
|
141
|
+
const task2 = await manager.sendMessage(
|
|
142
|
+
{
|
|
143
|
+
agentId: 'leaf',
|
|
144
|
+
input: { messages: [], workingDirectory: '/tmp' },
|
|
145
|
+
parentSessionId: childSessionId,
|
|
146
|
+
tenantId: config.tenantId,
|
|
147
|
+
projectId: config.projectId,
|
|
148
|
+
parentActor: { kind: 'agent', agentId: 'mid' as never, tenantId: config.tenantId },
|
|
149
|
+
},
|
|
150
|
+
{
|
|
151
|
+
parentRunId: 'run_mid' as RunId,
|
|
152
|
+
parentAgentId: 'mid',
|
|
153
|
+
parentAbortController: new AbortController(),
|
|
154
|
+
depth: 1,
|
|
155
|
+
budgetTracker: { total: 10_000, remaining: 10_000 },
|
|
156
|
+
tenantId: config.tenantId,
|
|
157
|
+
sessionId: childSessionId,
|
|
158
|
+
projectId: config.projectId,
|
|
159
|
+
parentActor: { kind: 'agent', agentId: 'mid' as never, tenantId: config.tenantId },
|
|
160
|
+
},
|
|
161
|
+
(ev) => {
|
|
162
|
+
nestedEventsCaptured.push(ev)
|
|
163
|
+
},
|
|
164
|
+
)
|
|
165
|
+
await manager.waitForCompletion(task2.taskId)
|
|
166
|
+
|
|
167
|
+
return {
|
|
168
|
+
runId: 'run_mid_result' as RunId,
|
|
169
|
+
status: 'completed',
|
|
170
|
+
usage: { ...EMPTY_TOKEN_USAGE },
|
|
171
|
+
cost: { ...ZERO_COST },
|
|
172
|
+
iterations: 1,
|
|
173
|
+
durationMs: 1,
|
|
174
|
+
messages: [createAssistantMessage('mid done')],
|
|
175
|
+
result: 'mid done',
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
harness.registry.register(buildDefinition(leafAgent))
|
|
181
|
+
harness.registry.register(buildDefinition(midAgent))
|
|
182
|
+
|
|
183
|
+
const outerCaptured: RunEvent[] = []
|
|
184
|
+
const task = await harness.manager.sendMessage(
|
|
185
|
+
buildSendMessageOptions({
|
|
186
|
+
agentId: 'mid',
|
|
187
|
+
parentSessionId: session.id,
|
|
188
|
+
projectId: project.id,
|
|
189
|
+
tenantId: DEFAULT_TENANT,
|
|
190
|
+
parentActor: actor,
|
|
191
|
+
}),
|
|
192
|
+
buildTaskContext({
|
|
193
|
+
sessionId: session.id,
|
|
194
|
+
projectId: project.id,
|
|
195
|
+
tenantId: DEFAULT_TENANT,
|
|
196
|
+
parentActor: actor,
|
|
197
|
+
}),
|
|
198
|
+
(ev) => {
|
|
199
|
+
outerCaptured.push(ev)
|
|
200
|
+
},
|
|
201
|
+
)
|
|
202
|
+
await harness.manager.waitForCompletion(task.taskId)
|
|
203
|
+
|
|
204
|
+
// Outer capture has level-1 events with rootSessionId === session.id,
|
|
205
|
+
// depth 1. The nested capture has level-2 events with rootSessionId
|
|
206
|
+
// also === session.id (the whole tree shares a root) and depth 2.
|
|
207
|
+
const outerLineages = outerCaptured
|
|
208
|
+
.filter((e) => 'lineage' in e && e.lineage)
|
|
209
|
+
.map((e) => {
|
|
210
|
+
const l = (e as unknown as { lineage: { rootSessionId: string; depth: number } }).lineage
|
|
211
|
+
return { rootSessionId: l.rootSessionId, depth: l.depth }
|
|
212
|
+
})
|
|
213
|
+
expect(outerLineages.length).toBeGreaterThan(0)
|
|
214
|
+
for (const l of outerLineages) {
|
|
215
|
+
expect(l.rootSessionId).toBe(session.id)
|
|
216
|
+
expect(l.depth).toBe(1)
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// Nested level-2 events: same rootSessionId, depth 2.
|
|
220
|
+
const nestedLineages = nestedEventsCaptured
|
|
221
|
+
.filter((e) => 'lineage' in e && e.lineage)
|
|
222
|
+
.map((e) => {
|
|
223
|
+
const l = (e as unknown as { lineage: { rootSessionId: string; depth: number } }).lineage
|
|
224
|
+
return { rootSessionId: l.rootSessionId, depth: l.depth }
|
|
225
|
+
})
|
|
226
|
+
expect(nestedLineages.length).toBeGreaterThan(0)
|
|
227
|
+
for (const l of nestedLineages) {
|
|
228
|
+
expect(l.rootSessionId).toBe(session.id)
|
|
229
|
+
expect(l.depth).toBe(2)
|
|
230
|
+
}
|
|
231
|
+
})
|
|
232
|
+
|
|
233
|
+
it('self vs tree depth filter: outer listener sees only its session events; nested listener sees its own tree', async () => {
|
|
234
|
+
// The subscribe-time depth filter is implemented at the listener
|
|
235
|
+
// injection seam — the parent passes a listener that captures events
|
|
236
|
+
// from its own sendMessage call. A nested child's sendMessage receives
|
|
237
|
+
// its own listener — the outer listener does NOT see the nested
|
|
238
|
+
// listener's events (no cross-contamination).
|
|
239
|
+
const harness = buildHarness()
|
|
240
|
+
const { project, session, actor } = await seedActiveParent(harness)
|
|
241
|
+
|
|
242
|
+
const outerCaptured: RunEvent[] = []
|
|
243
|
+
const nestedCaptured: RunEvent[] = []
|
|
244
|
+
|
|
245
|
+
const leafAgent = buildAgent('leaf', 'leaf')
|
|
246
|
+
const midAgent = buildAgentCustom(
|
|
247
|
+
'mid',
|
|
248
|
+
async (_input: AgentInput, config: BaseAgentConfig): Promise<BaseAgentResult> => {
|
|
249
|
+
if (!config.sessionId || !config.projectId || !config.tenantId) {
|
|
250
|
+
throw new Error('mid missing scope')
|
|
251
|
+
}
|
|
252
|
+
const cs = await harness.store.getSession(config.sessionId, config.tenantId)
|
|
253
|
+
if (cs && cs.status !== 'active') {
|
|
254
|
+
await harness.store.updateSession({ ...cs, status: 'active' }, config.tenantId)
|
|
255
|
+
}
|
|
256
|
+
const inner = await harness.manager.sendMessage(
|
|
257
|
+
{
|
|
258
|
+
agentId: 'leaf',
|
|
259
|
+
input: { messages: [], workingDirectory: '/tmp' },
|
|
260
|
+
parentSessionId: config.sessionId,
|
|
261
|
+
tenantId: config.tenantId,
|
|
262
|
+
projectId: config.projectId,
|
|
263
|
+
parentActor: {
|
|
264
|
+
kind: 'agent',
|
|
265
|
+
agentId: 'mid' as never,
|
|
266
|
+
tenantId: config.tenantId,
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
{
|
|
270
|
+
parentRunId: 'run_mid_inner' as RunId,
|
|
271
|
+
parentAgentId: 'mid',
|
|
272
|
+
parentAbortController: new AbortController(),
|
|
273
|
+
depth: 1,
|
|
274
|
+
budgetTracker: { total: 10_000, remaining: 10_000 },
|
|
275
|
+
tenantId: config.tenantId,
|
|
276
|
+
sessionId: config.sessionId,
|
|
277
|
+
projectId: config.projectId,
|
|
278
|
+
parentActor: {
|
|
279
|
+
kind: 'agent',
|
|
280
|
+
agentId: 'mid' as never,
|
|
281
|
+
tenantId: config.tenantId,
|
|
282
|
+
},
|
|
283
|
+
},
|
|
284
|
+
(ev) => {
|
|
285
|
+
nestedCaptured.push(ev)
|
|
286
|
+
},
|
|
287
|
+
)
|
|
288
|
+
await harness.manager.waitForCompletion(inner.taskId)
|
|
289
|
+
return {
|
|
290
|
+
runId: 'run_mid_done' as RunId,
|
|
291
|
+
status: 'completed',
|
|
292
|
+
usage: { ...EMPTY_TOKEN_USAGE },
|
|
293
|
+
cost: { ...ZERO_COST },
|
|
294
|
+
iterations: 1,
|
|
295
|
+
durationMs: 1,
|
|
296
|
+
messages: [createAssistantMessage('mid')],
|
|
297
|
+
result: 'mid',
|
|
298
|
+
}
|
|
299
|
+
},
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
harness.registry.register(buildDefinition(leafAgent))
|
|
303
|
+
harness.registry.register(buildDefinition(midAgent))
|
|
304
|
+
|
|
305
|
+
const task = await harness.manager.sendMessage(
|
|
306
|
+
buildSendMessageOptions({
|
|
307
|
+
agentId: 'mid',
|
|
308
|
+
parentSessionId: session.id,
|
|
309
|
+
projectId: project.id,
|
|
310
|
+
tenantId: DEFAULT_TENANT,
|
|
311
|
+
parentActor: actor,
|
|
312
|
+
}),
|
|
313
|
+
buildTaskContext({
|
|
314
|
+
sessionId: session.id,
|
|
315
|
+
projectId: project.id,
|
|
316
|
+
tenantId: DEFAULT_TENANT,
|
|
317
|
+
parentActor: actor,
|
|
318
|
+
}),
|
|
319
|
+
(ev) => {
|
|
320
|
+
outerCaptured.push(ev)
|
|
321
|
+
},
|
|
322
|
+
)
|
|
323
|
+
await harness.manager.waitForCompletion(task.taskId)
|
|
324
|
+
|
|
325
|
+
// Outer only sees its own spawn events (depth 1).
|
|
326
|
+
const outerSpawnedDepths = outerCaptured
|
|
327
|
+
.filter((e) => e.type === 'subsession_spawned')
|
|
328
|
+
.map((e) => ('lineage' in e && e.lineage ? e.lineage.depth : -1))
|
|
329
|
+
expect(outerSpawnedDepths).toEqual([1])
|
|
330
|
+
|
|
331
|
+
// Nested listener only sees its own spawn events (depth 2).
|
|
332
|
+
const nestedSpawnedDepths = nestedCaptured
|
|
333
|
+
.filter((e) => e.type === 'subsession_spawned')
|
|
334
|
+
.map((e) => ('lineage' in e && e.lineage ? e.lineage.depth : -1))
|
|
335
|
+
expect(nestedSpawnedDepths).toEqual([2])
|
|
336
|
+
|
|
337
|
+
// Cross-contamination sentinel: outer listener MUST NOT contain any
|
|
338
|
+
// depth-2 events (those belong to the nested scope).
|
|
339
|
+
const outerDepths = outerCaptured
|
|
340
|
+
.filter((e) => 'lineage' in e && e.lineage)
|
|
341
|
+
.map((e) => ('lineage' in e && e.lineage ? e.lineage.depth : -1))
|
|
342
|
+
expect(outerDepths.every((d) => d === 1)).toBe(true)
|
|
343
|
+
})
|
|
344
|
+
|
|
345
|
+
it('run_started and other core RunEvents also carry schemaVersion: 2 when stamped by the child listener wrapper', async () => {
|
|
346
|
+
// The listener wrapper in `manager/agent/lifecycle.ts#wrapChildListener`
|
|
347
|
+
// stamps `schemaVersion: 2` + `lineage` on EVERY event emitted inside
|
|
348
|
+
// the child's run. Core events that pass through the wrapped listener
|
|
349
|
+
// therefore inherit the envelope even though they have no lineage in
|
|
350
|
+
// their own type definition.
|
|
351
|
+
const harness = buildHarness()
|
|
352
|
+
const { project, session, actor } = await seedActiveParent(harness)
|
|
353
|
+
|
|
354
|
+
const leafAgent = buildAgentCustom(
|
|
355
|
+
'leaf-emit',
|
|
356
|
+
async (_i, _c, listener): Promise<BaseAgentResult> => {
|
|
357
|
+
// Emit a core event inside the child's run via the listener passed in.
|
|
358
|
+
await listener?.({
|
|
359
|
+
type: 'run_started',
|
|
360
|
+
runId: 'run_child_inner' as RunId,
|
|
361
|
+
})
|
|
362
|
+
return {
|
|
363
|
+
runId: 'run_child_inner' as RunId,
|
|
364
|
+
status: 'completed',
|
|
365
|
+
usage: { ...EMPTY_TOKEN_USAGE },
|
|
366
|
+
cost: { ...ZERO_COST },
|
|
367
|
+
iterations: 1,
|
|
368
|
+
durationMs: 1,
|
|
369
|
+
messages: [createAssistantMessage('done')],
|
|
370
|
+
result: 'done',
|
|
371
|
+
}
|
|
372
|
+
},
|
|
373
|
+
)
|
|
374
|
+
harness.registry.register(buildDefinition(leafAgent))
|
|
375
|
+
|
|
376
|
+
const captured: RunEvent[] = []
|
|
377
|
+
const task = await harness.manager.sendMessage(
|
|
378
|
+
buildSendMessageOptions({
|
|
379
|
+
agentId: 'leaf-emit',
|
|
380
|
+
parentSessionId: session.id,
|
|
381
|
+
projectId: project.id,
|
|
382
|
+
tenantId: DEFAULT_TENANT,
|
|
383
|
+
parentActor: actor,
|
|
384
|
+
}),
|
|
385
|
+
buildTaskContext({
|
|
386
|
+
sessionId: session.id,
|
|
387
|
+
projectId: project.id,
|
|
388
|
+
tenantId: DEFAULT_TENANT,
|
|
389
|
+
parentActor: actor,
|
|
390
|
+
}),
|
|
391
|
+
(ev) => {
|
|
392
|
+
captured.push(ev)
|
|
393
|
+
},
|
|
394
|
+
)
|
|
395
|
+
await harness.manager.waitForCompletion(task.taskId)
|
|
396
|
+
|
|
397
|
+
const runStarted = captured.find((e) => e.type === 'run_started')
|
|
398
|
+
expect(runStarted).toBeDefined()
|
|
399
|
+
if (runStarted && 'schemaVersion' in runStarted) {
|
|
400
|
+
expect(runStarted.schemaVersion).toBe(2)
|
|
401
|
+
}
|
|
402
|
+
})
|
|
403
|
+
})
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Integration — broadcast handoff atomic fan-out + rollback wired through
|
|
3
|
+
* the real stack.
|
|
4
|
+
*
|
|
5
|
+
* Covers roadmap §5 invariants: §5.4 (source → `awaiting_merge` after
|
|
6
|
+
* successful commit), §6.2 (broadcast atomic rollback — zero orphan
|
|
7
|
+
* sub-sessions/sessions after rollback via `deleteSubSession` +
|
|
8
|
+
* `deleteSession`), §10.2 (broadcast.rollback event carries accurate
|
|
9
|
+
* partialState counts).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, expect, it, vi } from 'vitest'
|
|
13
|
+
import { InMemorySessionStore } from '../../../store/session/memory.js'
|
|
14
|
+
import type { SessionId } from '../../../types/ids/index.js'
|
|
15
|
+
import type { ProjectId } from '../../../types/session/ids.js'
|
|
16
|
+
import { generateHandoffId } from '../../../utils/id.js'
|
|
17
|
+
import type { HandoffAssignment } from '../../handoff/assignment.js'
|
|
18
|
+
import { type BroadcastHandoffDeps, executeBroadcastHandoff } from '../../handoff/broadcast.js'
|
|
19
|
+
import { DefaultCapacityValidator } from '../../handoff/capacity.js'
|
|
20
|
+
import type { HandoffEventSink } from '../../handoff/events.js'
|
|
21
|
+
import type { ActorRef } from '../../hierarchy/actor.js'
|
|
22
|
+
import type { ExecFile } from '../../workspace/git-worktree.js'
|
|
23
|
+
import { GitWorktreeDriver } from '../../workspace/git-worktree.js'
|
|
24
|
+
import { WorkspaceBackendRegistry } from '../../workspace/registry.js'
|
|
25
|
+
import { DEFAULT_TENANT, okExec, stubLogger, userActor } from './_fixtures.js'
|
|
26
|
+
|
|
27
|
+
function buildDeps(
|
|
28
|
+
store: InMemorySessionStore,
|
|
29
|
+
execOverride?: ExecFile,
|
|
30
|
+
): {
|
|
31
|
+
deps: BroadcastHandoffDeps
|
|
32
|
+
events: HandoffEventSink & { onBroadcastRollback: ReturnType<typeof vi.fn> }
|
|
33
|
+
} {
|
|
34
|
+
const exec: ExecFile = execOverride ?? (async () => okExec())
|
|
35
|
+
const driver = new GitWorktreeDriver({
|
|
36
|
+
repoRoot: '/repo',
|
|
37
|
+
logger: stubLogger(),
|
|
38
|
+
execFile: exec,
|
|
39
|
+
})
|
|
40
|
+
const workspaceRegistry = new WorkspaceBackendRegistry()
|
|
41
|
+
workspaceRegistry.register(driver)
|
|
42
|
+
|
|
43
|
+
const onBroadcastRollback = vi.fn()
|
|
44
|
+
const sink: HandoffEventSink = {
|
|
45
|
+
onLocked: vi.fn(),
|
|
46
|
+
onUnlocked: vi.fn(),
|
|
47
|
+
onCommitted: vi.fn(),
|
|
48
|
+
onBroadcastRollback,
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
deps: {
|
|
53
|
+
store,
|
|
54
|
+
workspaceRegistry,
|
|
55
|
+
capacity: new DefaultCapacityValidator(store),
|
|
56
|
+
events: sink,
|
|
57
|
+
},
|
|
58
|
+
events: { ...sink, onBroadcastRollback },
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function buildAssignments(
|
|
63
|
+
sourceSessionId: SessionId,
|
|
64
|
+
projectId: ProjectId,
|
|
65
|
+
recipients: ActorRef[],
|
|
66
|
+
broadcastId = 'bc_integration',
|
|
67
|
+
expectedOwnerVersion = 0,
|
|
68
|
+
): HandoffAssignment[] {
|
|
69
|
+
return recipients.map((recipientActor) => ({
|
|
70
|
+
id: generateHandoffId(),
|
|
71
|
+
mode: 'broadcast' as const,
|
|
72
|
+
sourceSessionId,
|
|
73
|
+
tenantId: DEFAULT_TENANT,
|
|
74
|
+
projectId,
|
|
75
|
+
sourceActor: userActor('usr_source'),
|
|
76
|
+
recipientActor,
|
|
77
|
+
expectedOwnerVersion,
|
|
78
|
+
broadcastId,
|
|
79
|
+
createdAt: new Date('2026-04-17'),
|
|
80
|
+
}))
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
describe('Integration — broadcast handoff E2E', () => {
|
|
84
|
+
it('happy: 3-recipient fan-out → each recipient has isolated worktree + source reaches awaiting_merge', async () => {
|
|
85
|
+
const store = new InMemorySessionStore()
|
|
86
|
+
const project = await store.createProject(
|
|
87
|
+
{ tenantId: DEFAULT_TENANT, name: 'bc-happy' },
|
|
88
|
+
DEFAULT_TENANT,
|
|
89
|
+
)
|
|
90
|
+
const source = await store.createSession(
|
|
91
|
+
{ projectId: project.id, currentActor: userActor('usr_source') },
|
|
92
|
+
DEFAULT_TENANT,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
// Track each `worktree add` call so we can assert each recipient got a
|
|
96
|
+
// distinct worktree path (isolation).
|
|
97
|
+
const addCalls: string[] = []
|
|
98
|
+
const exec: ExecFile = async (_file, args) => {
|
|
99
|
+
if (args.includes('add')) {
|
|
100
|
+
// args contains ['-C', ..., 'worktree', 'add', '-b', branch, path].
|
|
101
|
+
const path = args[args.length - 1]
|
|
102
|
+
if (typeof path === 'string') addCalls.push(path)
|
|
103
|
+
}
|
|
104
|
+
return okExec()
|
|
105
|
+
}
|
|
106
|
+
const { deps } = buildDeps(store, exec)
|
|
107
|
+
|
|
108
|
+
const recipients = [userActor('usr_bob'), userActor('usr_carol'), userActor('usr_dan')]
|
|
109
|
+
const assignments = buildAssignments(source.id, project.id, recipients)
|
|
110
|
+
|
|
111
|
+
const outcomes = await executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)
|
|
112
|
+
expect(outcomes).toHaveLength(3)
|
|
113
|
+
expect(new Set(outcomes.map((o) => o.newSessionId)).size).toBe(3)
|
|
114
|
+
expect(new Set(outcomes.map((o) => o.workspaceId)).size).toBe(3)
|
|
115
|
+
|
|
116
|
+
// Each recipient landed on a distinct worktree path — isolation holds.
|
|
117
|
+
expect(new Set(addCalls).size).toBe(3)
|
|
118
|
+
|
|
119
|
+
// §5.4: source transitions to awaiting_merge post-commit.
|
|
120
|
+
const reloaded = await store.getSession(source.id, DEFAULT_TENANT)
|
|
121
|
+
expect(reloaded?.status).toBe('awaiting_merge')
|
|
122
|
+
|
|
123
|
+
// Three children visible via getChildren.
|
|
124
|
+
const children = await store.getChildren(source.id, DEFAULT_TENANT)
|
|
125
|
+
expect(children).toHaveLength(3)
|
|
126
|
+
expect(children.every((c) => c.kind === 'user_handoff')).toBe(true)
|
|
127
|
+
})
|
|
128
|
+
|
|
129
|
+
it('rollback on 2nd-recipient provisioning failure: zero orphan records, partialState accurate', async () => {
|
|
130
|
+
const store = new InMemorySessionStore()
|
|
131
|
+
const project = await store.createProject(
|
|
132
|
+
{ tenantId: DEFAULT_TENANT, name: 'bc-rb' },
|
|
133
|
+
DEFAULT_TENANT,
|
|
134
|
+
)
|
|
135
|
+
const source = await store.createSession(
|
|
136
|
+
{ projectId: project.id, currentActor: userActor('usr_source') },
|
|
137
|
+
DEFAULT_TENANT,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
let addCount = 0
|
|
141
|
+
const exec: ExecFile = async (_file, args) => {
|
|
142
|
+
if (args.includes('add')) {
|
|
143
|
+
addCount += 1
|
|
144
|
+
if (addCount === 2) throw new Error('simulated fault on 2nd recipient')
|
|
145
|
+
}
|
|
146
|
+
return okExec()
|
|
147
|
+
}
|
|
148
|
+
const { deps, events } = buildDeps(store, exec)
|
|
149
|
+
|
|
150
|
+
const assignments = buildAssignments(source.id, project.id, [
|
|
151
|
+
userActor('usr_b'),
|
|
152
|
+
userActor('usr_c'),
|
|
153
|
+
userActor('usr_d'),
|
|
154
|
+
])
|
|
155
|
+
|
|
156
|
+
await expect(executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)).rejects.toThrow(
|
|
157
|
+
/Workspace backend git-worktree failed on create/,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
// Phase 8 closed the Known Delta: rollback now calls deleteSubSession +
|
|
161
|
+
// deleteSession rather than flipping to 'archived'. Zero orphan
|
|
162
|
+
// sub-session records remain.
|
|
163
|
+
const children = await store.getChildren(source.id, DEFAULT_TENANT)
|
|
164
|
+
expect(children).toHaveLength(0)
|
|
165
|
+
|
|
166
|
+
// Source reverted to idle with original ownerVersion.
|
|
167
|
+
const reloaded = await store.getSession(source.id, DEFAULT_TENANT)
|
|
168
|
+
expect(reloaded?.status).toBe('idle')
|
|
169
|
+
expect(reloaded?.ownerVersion).toBe(0)
|
|
170
|
+
|
|
171
|
+
// onBroadcastRollback emitted with accurate counts.
|
|
172
|
+
expect(events.onBroadcastRollback).toHaveBeenCalledTimes(1)
|
|
173
|
+
const rollbackCall = events.onBroadcastRollback.mock.calls[0]?.[0] as
|
|
174
|
+
| {
|
|
175
|
+
partialState: {
|
|
176
|
+
worktreesProvisioned: number
|
|
177
|
+
subsessionsCreated: number
|
|
178
|
+
assignmentsWritten: number
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
| undefined
|
|
182
|
+
expect(rollbackCall?.partialState.worktreesProvisioned).toBe(1)
|
|
183
|
+
expect(rollbackCall?.partialState.subsessionsCreated).toBe(1)
|
|
184
|
+
expect(rollbackCall?.partialState.assignmentsWritten).toBe(1)
|
|
185
|
+
})
|
|
186
|
+
|
|
187
|
+
it('source transitions to awaiting_merge + retains currentActor as coordinator (§5.4)', async () => {
|
|
188
|
+
const store = new InMemorySessionStore()
|
|
189
|
+
const project = await store.createProject(
|
|
190
|
+
{ tenantId: DEFAULT_TENANT, name: 'coord' },
|
|
191
|
+
DEFAULT_TENANT,
|
|
192
|
+
)
|
|
193
|
+
const coordinator = userActor('usr_source')
|
|
194
|
+
const source = await store.createSession(
|
|
195
|
+
{ projectId: project.id, currentActor: coordinator },
|
|
196
|
+
DEFAULT_TENANT,
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
const { deps } = buildDeps(store)
|
|
200
|
+
const assignments = buildAssignments(source.id, project.id, [
|
|
201
|
+
userActor('usr_b'),
|
|
202
|
+
userActor('usr_c'),
|
|
203
|
+
])
|
|
204
|
+
|
|
205
|
+
await executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)
|
|
206
|
+
|
|
207
|
+
const reloaded = await store.getSession(source.id, DEFAULT_TENANT)
|
|
208
|
+
expect(reloaded?.status).toBe('awaiting_merge')
|
|
209
|
+
// Coordinator retained as current actor (§5.4).
|
|
210
|
+
expect(reloaded?.currentActor).toEqual(coordinator)
|
|
211
|
+
expect(reloaded?.ownerVersion).toBe(1)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
it('all recipients get isolated worktrees — zero path collisions even under N=8', async () => {
|
|
215
|
+
const store = new InMemorySessionStore()
|
|
216
|
+
const project = await store.createProject(
|
|
217
|
+
{ tenantId: DEFAULT_TENANT, name: 'iso' },
|
|
218
|
+
DEFAULT_TENANT,
|
|
219
|
+
)
|
|
220
|
+
const source = await store.createSession(
|
|
221
|
+
{ projectId: project.id, currentActor: userActor('usr_source') },
|
|
222
|
+
DEFAULT_TENANT,
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
const seenPaths = new Set<string>()
|
|
226
|
+
const exec: ExecFile = async (_file, args) => {
|
|
227
|
+
if (args.includes('add')) {
|
|
228
|
+
const path = args[args.length - 1]
|
|
229
|
+
if (typeof path === 'string') {
|
|
230
|
+
if (seenPaths.has(path)) throw new Error(`path collision: ${path}`)
|
|
231
|
+
seenPaths.add(path)
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return okExec()
|
|
235
|
+
}
|
|
236
|
+
const { deps } = buildDeps(store, exec)
|
|
237
|
+
|
|
238
|
+
const recipients = Array.from({ length: 8 }, (_, i) => userActor(`usr_${i}`))
|
|
239
|
+
const assignments = buildAssignments(source.id, project.id, recipients)
|
|
240
|
+
|
|
241
|
+
const outcomes = await executeBroadcastHandoff(deps, assignments, DEFAULT_TENANT)
|
|
242
|
+
expect(outcomes).toHaveLength(8)
|
|
243
|
+
expect(seenPaths.size).toBe(8)
|
|
244
|
+
})
|
|
245
|
+
})
|