@animalabs/agent-framework 0.22.2 → 0.23.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/README.md +108 -4
- package/dist/src/agent.d.ts +108 -17
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +207 -67
- package/dist/src/agent.js.map +1 -1
- package/dist/src/api/mcp-server-core.js +1 -1
- package/dist/src/api/mcp-server-core.js.map +1 -1
- package/dist/src/api/server.d.ts.map +1 -1
- package/dist/src/api/server.js +5 -1
- package/dist/src/api/server.js.map +1 -1
- package/dist/src/api/types.d.ts +1 -1
- package/dist/src/api/types.d.ts.map +1 -1
- package/dist/src/branch-names.d.ts +14 -0
- package/dist/src/branch-names.d.ts.map +1 -0
- package/dist/src/branch-names.js +22 -0
- package/dist/src/branch-names.js.map +1 -0
- package/dist/src/closest-names.d.ts +28 -0
- package/dist/src/closest-names.d.ts.map +1 -0
- package/dist/src/closest-names.js +98 -0
- package/dist/src/closest-names.js.map +1 -0
- package/dist/src/code-execution/index.d.ts +1 -1
- package/dist/src/code-execution/index.d.ts.map +1 -1
- package/dist/src/code-execution/index.js.map +1 -1
- package/dist/src/code-execution/py-runner.d.ts +50 -7
- package/dist/src/code-execution/py-runner.d.ts.map +1 -1
- package/dist/src/code-execution/py-runner.js +258 -90
- package/dist/src/code-execution/py-runner.js.map +1 -1
- package/dist/src/code-execution/runtime-py.d.ts +3 -2
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -1
- package/dist/src/code-execution/runtime-py.js +94 -8
- package/dist/src/code-execution/runtime-py.js.map +1 -1
- package/dist/src/code-execution/tool-definition.d.ts +17 -1
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -1
- package/dist/src/code-execution/tool-definition.js +72 -6
- package/dist/src/code-execution/tool-definition.js.map +1 -1
- package/dist/src/config-checks.d.ts +28 -0
- package/dist/src/config-checks.d.ts.map +1 -0
- package/dist/src/config-checks.js +56 -0
- package/dist/src/config-checks.js.map +1 -0
- package/dist/src/deadline-timer.d.ts +21 -0
- package/dist/src/deadline-timer.d.ts.map +1 -0
- package/dist/src/deadline-timer.js +43 -0
- package/dist/src/deadline-timer.js.map +1 -0
- package/dist/src/error-message.d.ts +30 -0
- package/dist/src/error-message.d.ts.map +1 -0
- package/dist/src/error-message.js +50 -0
- package/dist/src/error-message.js.map +1 -0
- package/dist/src/framework.d.ts +1529 -165
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +8264 -1939
- package/dist/src/framework.js.map +1 -1
- package/dist/src/gate/event-gate.d.ts +8 -0
- package/dist/src/gate/event-gate.d.ts.map +1 -1
- package/dist/src/gate/event-gate.js +36 -5
- package/dist/src/gate/event-gate.js.map +1 -1
- package/dist/src/held-writes.d.ts +16 -0
- package/dist/src/held-writes.d.ts.map +1 -0
- package/dist/src/held-writes.js +56 -0
- package/dist/src/held-writes.js.map +1 -0
- package/dist/src/index.d.ts +10 -4
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +11 -5
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/capability-grant.d.ts +4 -0
- package/dist/src/mcpl/capability-grant.d.ts.map +1 -1
- package/dist/src/mcpl/capability-grant.js +1 -1
- package/dist/src/mcpl/capability-grant.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +233 -18
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +975 -386
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts +21 -1
- package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
- package/dist/src/mcpl/checkpoint-manager.js +91 -30
- package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
- package/dist/src/mcpl/conversation-router.d.ts +19 -3
- package/dist/src/mcpl/conversation-router.d.ts.map +1 -1
- package/dist/src/mcpl/conversation-router.js +23 -8
- package/dist/src/mcpl/conversation-router.js.map +1 -1
- package/dist/src/mcpl/convert-block.d.ts +20 -0
- package/dist/src/mcpl/convert-block.d.ts.map +1 -0
- package/dist/src/mcpl/convert-block.js +88 -0
- package/dist/src/mcpl/convert-block.js.map +1 -0
- package/dist/src/mcpl/errors.d.ts +13 -0
- package/dist/src/mcpl/errors.d.ts.map +1 -1
- package/dist/src/mcpl/errors.js +28 -0
- package/dist/src/mcpl/errors.js.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.d.ts +23 -0
- package/dist/src/mcpl/hook-orchestrator.d.ts.map +1 -1
- package/dist/src/mcpl/hook-orchestrator.js +83 -72
- package/dist/src/mcpl/hook-orchestrator.js.map +1 -1
- package/dist/src/mcpl/inbound-source.d.ts +114 -0
- package/dist/src/mcpl/inbound-source.d.ts.map +1 -0
- package/dist/src/mcpl/inbound-source.js +83 -0
- package/dist/src/mcpl/inbound-source.js.map +1 -0
- package/dist/src/mcpl/index.d.ts +7 -1
- package/dist/src/mcpl/index.d.ts.map +1 -1
- package/dist/src/mcpl/index.js +5 -1
- package/dist/src/mcpl/index.js.map +1 -1
- package/dist/src/mcpl/inference-router.d.ts +19 -13
- package/dist/src/mcpl/inference-router.d.ts.map +1 -1
- package/dist/src/mcpl/inference-router.js +155 -87
- package/dist/src/mcpl/inference-router.js.map +1 -1
- package/dist/src/mcpl/log-value.d.ts +7 -0
- package/dist/src/mcpl/log-value.d.ts.map +1 -1
- package/dist/src/mcpl/log-value.js +9 -0
- package/dist/src/mcpl/log-value.js.map +1 -1
- package/dist/src/mcpl/modern-connection.d.ts +227 -0
- package/dist/src/mcpl/modern-connection.d.ts.map +1 -0
- package/dist/src/mcpl/modern-connection.js +1088 -0
- package/dist/src/mcpl/modern-connection.js.map +1 -0
- package/dist/src/mcpl/prefix-rule.d.ts +18 -0
- package/dist/src/mcpl/prefix-rule.d.ts.map +1 -0
- package/dist/src/mcpl/prefix-rule.js +25 -0
- package/dist/src/mcpl/prefix-rule.js.map +1 -0
- package/dist/src/mcpl/protocol-family.d.ts +179 -0
- package/dist/src/mcpl/protocol-family.d.ts.map +1 -0
- package/dist/src/mcpl/protocol-family.js +697 -0
- package/dist/src/mcpl/protocol-family.js.map +1 -0
- package/dist/src/mcpl/push-coalescer.d.ts +58 -17
- package/dist/src/mcpl/push-coalescer.d.ts.map +1 -1
- package/dist/src/mcpl/push-coalescer.js +93 -32
- package/dist/src/mcpl/push-coalescer.js.map +1 -1
- package/dist/src/mcpl/push-handler.d.ts +16 -9
- package/dist/src/mcpl/push-handler.d.ts.map +1 -1
- package/dist/src/mcpl/push-handler.js +18 -83
- package/dist/src/mcpl/push-handler.js.map +1 -1
- package/dist/src/mcpl/reference-fetcher.d.ts +76 -13
- package/dist/src/mcpl/reference-fetcher.d.ts.map +1 -1
- package/dist/src/mcpl/reference-fetcher.js +275 -66
- package/dist/src/mcpl/reference-fetcher.js.map +1 -1
- package/dist/src/mcpl/references.d.ts +98 -18
- package/dist/src/mcpl/references.d.ts.map +1 -1
- package/dist/src/mcpl/references.js +170 -32
- package/dist/src/mcpl/references.js.map +1 -1
- package/dist/src/mcpl/server-connection.d.ts +406 -31
- package/dist/src/mcpl/server-connection.d.ts.map +1 -1
- package/dist/src/mcpl/server-connection.js +1331 -272
- package/dist/src/mcpl/server-connection.js.map +1 -1
- package/dist/src/mcpl/server-registry.d.ts +35 -6
- package/dist/src/mcpl/server-registry.d.ts.map +1 -1
- package/dist/src/mcpl/server-registry.js +63 -13
- package/dist/src/mcpl/server-registry.js.map +1 -1
- package/dist/src/mcpl/skip-reply-wake.d.ts +36 -0
- package/dist/src/mcpl/skip-reply-wake.d.ts.map +1 -0
- package/dist/src/mcpl/skip-reply-wake.js +55 -0
- package/dist/src/mcpl/skip-reply-wake.js.map +1 -0
- package/dist/src/mcpl/tool-result-normalize.d.ts +54 -0
- package/dist/src/mcpl/tool-result-normalize.d.ts.map +1 -0
- package/dist/src/mcpl/tool-result-normalize.js +232 -0
- package/dist/src/mcpl/tool-result-normalize.js.map +1 -0
- package/dist/src/mcpl/transport.d.ts +104 -12
- package/dist/src/mcpl/transport.d.ts.map +1 -1
- package/dist/src/mcpl/transport.js +315 -85
- package/dist/src/mcpl/transport.js.map +1 -1
- package/dist/src/mcpl/types.d.ts +76 -19
- package/dist/src/mcpl/types.d.ts.map +1 -1
- package/dist/src/mcpl/types.js.map +1 -1
- package/dist/src/mcpl/visible-content.d.ts +16 -0
- package/dist/src/mcpl/visible-content.d.ts.map +1 -1
- package/dist/src/mcpl/visible-content.js +26 -0
- package/dist/src/mcpl/visible-content.js.map +1 -1
- package/dist/src/module-registry.d.ts +34 -6
- package/dist/src/module-registry.d.ts.map +1 -1
- package/dist/src/module-registry.js +119 -31
- package/dist/src/module-registry.js.map +1 -1
- package/dist/src/modules/api/index.d.ts +1 -1
- package/dist/src/modules/api/index.d.ts.map +1 -1
- package/dist/src/modules/api/index.js +3 -2
- package/dist/src/modules/api/index.js.map +1 -1
- package/dist/src/modules/discord/discord-js-client.d.ts +43 -2
- package/dist/src/modules/discord/discord-js-client.d.ts.map +1 -1
- package/dist/src/modules/discord/discord-js-client.js +286 -67
- package/dist/src/modules/discord/discord-js-client.js.map +1 -1
- package/dist/src/modules/discord/index.d.ts +53 -5
- package/dist/src/modules/discord/index.d.ts.map +1 -1
- package/dist/src/modules/discord/index.js +712 -186
- package/dist/src/modules/discord/index.js.map +1 -1
- package/dist/src/modules/discord/refusal.d.ts +14 -0
- package/dist/src/modules/discord/refusal.d.ts.map +1 -0
- package/dist/src/modules/discord/refusal.js +14 -0
- package/dist/src/modules/discord/refusal.js.map +1 -0
- package/dist/src/modules/discord/types.d.ts +27 -4
- package/dist/src/modules/discord/types.d.ts.map +1 -1
- package/dist/src/modules/health/index.d.ts.map +1 -1
- package/dist/src/modules/health/index.js +8 -3
- package/dist/src/modules/health/index.js.map +1 -1
- package/dist/src/modules/history/index.d.ts +3 -1
- package/dist/src/modules/history/index.d.ts.map +1 -1
- package/dist/src/modules/history/index.js +359 -127
- package/dist/src/modules/history/index.js.map +1 -1
- package/dist/src/modules/history/semantic.d.ts +28 -1
- package/dist/src/modules/history/semantic.d.ts.map +1 -1
- package/dist/src/modules/history/semantic.js +177 -32
- package/dist/src/modules/history/semantic.js.map +1 -1
- package/dist/src/modules/index.d.ts +1 -1
- package/dist/src/modules/index.d.ts.map +1 -1
- package/dist/src/modules/index.js +1 -1
- package/dist/src/modules/index.js.map +1 -1
- package/dist/src/modules/unknown-tool.d.ts +10 -0
- package/dist/src/modules/unknown-tool.d.ts.map +1 -0
- package/dist/src/modules/unknown-tool.js +17 -0
- package/dist/src/modules/unknown-tool.js.map +1 -0
- package/dist/src/modules/workspace/disk-agreement.d.ts +57 -4
- package/dist/src/modules/workspace/disk-agreement.d.ts.map +1 -1
- package/dist/src/modules/workspace/disk-agreement.js +75 -7
- package/dist/src/modules/workspace/disk-agreement.js.map +1 -1
- package/dist/src/modules/workspace/effects.d.ts +66 -7
- package/dist/src/modules/workspace/effects.d.ts.map +1 -1
- package/dist/src/modules/workspace/effects.js +303 -46
- package/dist/src/modules/workspace/effects.js.map +1 -1
- package/dist/src/modules/workspace/index.d.ts +313 -45
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +1404 -304
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/modules/workspace/observe.d.ts +315 -16
- package/dist/src/modules/workspace/observe.d.ts.map +1 -1
- package/dist/src/modules/workspace/observe.js +727 -37
- package/dist/src/modules/workspace/observe.js.map +1 -1
- package/dist/src/modules/workspace/reconcile.d.ts +58 -7
- package/dist/src/modules/workspace/reconcile.d.ts.map +1 -1
- package/dist/src/modules/workspace/reconcile.js +521 -56
- package/dist/src/modules/workspace/reconcile.js.map +1 -1
- package/dist/src/modules/workspace/types.d.ts +28 -5
- package/dist/src/modules/workspace/types.d.ts.map +1 -1
- package/dist/src/modules/workspace/types.js.map +1 -1
- package/dist/src/modules/workspace/watcher.d.ts +49 -2
- package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
- package/dist/src/modules/workspace/watcher.js +158 -29
- package/dist/src/modules/workspace/watcher.js.map +1 -1
- package/dist/src/prose-drafts.d.ts +240 -0
- package/dist/src/prose-drafts.d.ts.map +1 -0
- package/dist/src/prose-drafts.js +362 -0
- package/dist/src/prose-drafts.js.map +1 -0
- package/dist/src/prose-segments.d.ts +21 -2
- package/dist/src/prose-segments.d.ts.map +1 -1
- package/dist/src/prose-segments.js +46 -9
- package/dist/src/prose-segments.js.map +1 -1
- package/dist/src/recovery/offline-branch.d.ts +1 -0
- package/dist/src/recovery/offline-branch.d.ts.map +1 -1
- package/dist/src/recovery/offline-branch.js +3 -1
- package/dist/src/recovery/offline-branch.js.map +1 -1
- package/dist/src/safe-slice.d.ts +5 -1
- package/dist/src/safe-slice.d.ts.map +1 -1
- package/dist/src/safe-slice.js +9 -1
- package/dist/src/safe-slice.js.map +1 -1
- package/dist/src/silent-heartbeat.d.ts +112 -39
- package/dist/src/silent-heartbeat.d.ts.map +1 -1
- package/dist/src/silent-heartbeat.js +100 -29
- package/dist/src/silent-heartbeat.js.map +1 -1
- package/dist/src/tool-args.d.ts +40 -0
- package/dist/src/tool-args.d.ts.map +1 -0
- package/dist/src/tool-args.js +207 -0
- package/dist/src/tool-args.js.map +1 -0
- package/dist/src/tool-image-ledger.d.ts +87 -19
- package/dist/src/tool-image-ledger.d.ts.map +1 -1
- package/dist/src/tool-image-ledger.js +135 -32
- package/dist/src/tool-image-ledger.js.map +1 -1
- package/dist/src/tool-presentation.d.ts +9 -0
- package/dist/src/tool-presentation.d.ts.map +1 -1
- package/dist/src/tool-presentation.js +266 -62
- package/dist/src/tool-presentation.js.map +1 -1
- package/dist/src/tool-result-guard.d.ts.map +1 -1
- package/dist/src/tool-result-guard.js +7 -10
- package/dist/src/tool-result-guard.js.map +1 -1
- package/dist/src/tool-result-history.d.ts +32 -3
- package/dist/src/tool-result-history.d.ts.map +1 -1
- package/dist/src/tool-result-history.js +106 -19
- package/dist/src/tool-result-history.js.map +1 -1
- package/dist/src/tune-out/coordinator.d.ts +25 -1
- package/dist/src/tune-out/coordinator.d.ts.map +1 -1
- package/dist/src/tune-out/coordinator.js +260 -65
- package/dist/src/tune-out/coordinator.js.map +1 -1
- package/dist/src/types/agent.d.ts +44 -22
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/events.d.ts +25 -0
- package/dist/src/types/events.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +38 -7
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/inference-log.d.ts +1 -1
- package/dist/src/types/inference-log.d.ts.map +1 -1
- package/dist/src/types/module.d.ts +77 -14
- package/dist/src/types/module.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +97 -8
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.d.ts +5 -0
- package/dist/src/usage/usage-tracker.d.ts.map +1 -1
- package/dist/src/usage/usage-tracker.js +35 -8
- package/dist/src/usage/usage-tracker.js.map +1 -1
- package/package.json +5 -4
- package/src/agent.ts +257 -72
- package/src/api/mcp-server-core.ts +1 -1
- package/src/api/server.ts +4 -1
- package/src/api/types.ts +1 -1
- package/src/branch-names.ts +19 -0
- package/src/closest-names.ts +94 -0
- package/src/code-execution/index.ts +1 -0
- package/src/code-execution/py-runner.ts +304 -93
- package/src/code-execution/runtime-py.ts +94 -8
- package/src/code-execution/tool-definition.ts +85 -7
- package/src/config-checks.ts +50 -0
- package/src/deadline-timer.ts +44 -0
- package/src/error-message.ts +48 -0
- package/src/framework.ts +8625 -1984
- package/src/gate/event-gate.ts +38 -5
- package/src/held-writes.ts +59 -0
- package/src/index.ts +29 -5
- package/src/mcpl/capability-grant.ts +1 -1
- package/src/mcpl/channel-registry.ts +1095 -411
- package/src/mcpl/checkpoint-manager.ts +104 -29
- package/src/mcpl/conversation-router.ts +28 -8
- package/src/mcpl/convert-block.ts +105 -0
- package/src/mcpl/errors.ts +28 -0
- package/src/mcpl/hook-orchestrator.ts +84 -77
- package/src/mcpl/inbound-source.ts +156 -0
- package/src/mcpl/index.ts +23 -1
- package/src/mcpl/inference-router.ts +179 -103
- package/src/mcpl/log-value.ts +10 -0
- package/src/mcpl/modern-connection.ts +1182 -0
- package/src/mcpl/prefix-rule.ts +32 -0
- package/src/mcpl/protocol-family.ts +691 -0
- package/src/mcpl/push-coalescer.ts +110 -36
- package/src/mcpl/push-handler.ts +20 -90
- package/src/mcpl/reference-fetcher.ts +318 -67
- package/src/mcpl/references.ts +183 -34
- package/src/mcpl/server-connection.ts +1404 -280
- package/src/mcpl/server-registry.ts +63 -14
- package/src/mcpl/skip-reply-wake.ts +73 -0
- package/src/mcpl/tool-result-normalize.ts +294 -0
- package/src/mcpl/transport.ts +320 -76
- package/src/mcpl/types.ts +77 -19
- package/src/mcpl/visible-content.ts +28 -0
- package/src/module-registry.ts +126 -36
- package/src/modules/api/index.ts +3 -2
- package/src/modules/discord/discord-js-client.ts +306 -74
- package/src/modules/discord/index.ts +737 -201
- package/src/modules/discord/refusal.ts +13 -0
- package/src/modules/discord/types.ts +27 -6
- package/src/modules/health/index.ts +8 -3
- package/src/modules/history/index.ts +410 -120
- package/src/modules/history/semantic.ts +189 -32
- package/src/modules/index.ts +1 -1
- package/src/modules/unknown-tool.ts +16 -0
- package/src/modules/workspace/disk-agreement.ts +97 -8
- package/src/modules/workspace/effects.ts +291 -36
- package/src/modules/workspace/index.ts +1469 -321
- package/src/modules/workspace/observe.ts +784 -41
- package/src/modules/workspace/reconcile.ts +619 -64
- package/src/modules/workspace/types.ts +28 -5
- package/src/modules/workspace/watcher.ts +154 -30
- package/src/prose-drafts.ts +481 -0
- package/src/prose-segments.ts +51 -8
- package/src/recovery/offline-branch.ts +4 -1
- package/src/safe-slice.ts +9 -1
- package/src/silent-heartbeat.ts +184 -59
- package/src/tool-args.ts +213 -0
- package/src/tool-image-ledger.ts +153 -34
- package/src/tool-presentation.ts +233 -42
- package/src/tool-result-guard.ts +7 -8
- package/src/tool-result-history.ts +124 -20
- package/src/tune-out/coordinator.ts +259 -65
- package/src/types/agent.ts +44 -24
- package/src/types/events.ts +25 -0
- package/src/types/framework.ts +38 -7
- package/src/types/inference-log.ts +1 -1
- package/src/types/module.ts +79 -14
- package/src/types/trace.ts +103 -8
- package/src/usage/usage-tracker.ts +32 -8
- package/dist/test/activation-request-sanitize.test.d.ts +0 -2
- package/dist/test/activation-request-sanitize.test.d.ts.map +0 -1
- package/dist/test/activation-request-sanitize.test.js +0 -89
- package/dist/test/activation-request-sanitize.test.js.map +0 -1
- package/dist/test/agent-cache-ttl.test.d.ts +0 -2
- package/dist/test/agent-cache-ttl.test.d.ts.map +0 -1
- package/dist/test/agent-cache-ttl.test.js +0 -41
- package/dist/test/agent-cache-ttl.test.js.map +0 -1
- package/dist/test/agent-runtime-settings.test.d.ts +0 -2
- package/dist/test/agent-runtime-settings.test.d.ts.map +0 -1
- package/dist/test/agent-runtime-settings.test.js +0 -1598
- package/dist/test/agent-runtime-settings.test.js.map +0 -1
- package/dist/test/api-admin-gate.test.d.ts +0 -2
- package/dist/test/api-admin-gate.test.d.ts.map +0 -1
- package/dist/test/api-admin-gate.test.js +0 -116
- package/dist/test/api-admin-gate.test.js.map +0 -1
- package/dist/test/assistant-persist-refusal.test.d.ts +0 -2
- package/dist/test/assistant-persist-refusal.test.d.ts.map +0 -1
- package/dist/test/assistant-persist-refusal.test.js +0 -63
- package/dist/test/assistant-persist-refusal.test.js.map +0 -1
- package/dist/test/batched-wake-locus.test.d.ts +0 -2
- package/dist/test/batched-wake-locus.test.d.ts.map +0 -1
- package/dist/test/batched-wake-locus.test.js +0 -166
- package/dist/test/batched-wake-locus.test.js.map +0 -1
- package/dist/test/busy-agent-scheduler.test.d.ts +0 -2
- package/dist/test/busy-agent-scheduler.test.d.ts.map +0 -1
- package/dist/test/busy-agent-scheduler.test.js +0 -92
- package/dist/test/busy-agent-scheduler.test.js.map +0 -1
- package/dist/test/channel-incoming-targeting.test.d.ts +0 -2
- package/dist/test/channel-incoming-targeting.test.d.ts.map +0 -1
- package/dist/test/channel-incoming-targeting.test.js +0 -81
- package/dist/test/channel-incoming-targeting.test.js.map +0 -1
- package/dist/test/channel-label-history.test.d.ts +0 -2
- package/dist/test/channel-label-history.test.d.ts.map +0 -1
- package/dist/test/channel-label-history.test.js +0 -424
- package/dist/test/channel-label-history.test.js.map +0 -1
- package/dist/test/channel-lifecycle-provenance.test.d.ts +0 -2
- package/dist/test/channel-lifecycle-provenance.test.d.ts.map +0 -1
- package/dist/test/channel-lifecycle-provenance.test.js +0 -47
- package/dist/test/channel-lifecycle-provenance.test.js.map +0 -1
- package/dist/test/channel-registry-routing.test.d.ts +0 -2
- package/dist/test/channel-registry-routing.test.d.ts.map +0 -1
- package/dist/test/channel-registry-routing.test.js +0 -446
- package/dist/test/channel-registry-routing.test.js.map +0 -1
- package/dist/test/channel-registry-typing.test.d.ts +0 -2
- package/dist/test/channel-registry-typing.test.d.ts.map +0 -1
- package/dist/test/channel-registry-typing.test.js +0 -91
- package/dist/test/channel-registry-typing.test.js.map +0 -1
- package/dist/test/channels-changed-respond-first.test.d.ts +0 -2
- package/dist/test/channels-changed-respond-first.test.d.ts.map +0 -1
- package/dist/test/channels-changed-respond-first.test.js +0 -74
- package/dist/test/channels-changed-respond-first.test.js.map +0 -1
- package/dist/test/checkpoint-attribution.test.d.ts +0 -2
- package/dist/test/checkpoint-attribution.test.d.ts.map +0 -1
- package/dist/test/checkpoint-attribution.test.js +0 -200
- package/dist/test/checkpoint-attribution.test.js.map +0 -1
- package/dist/test/code-execution.test.d.ts +0 -11
- package/dist/test/code-execution.test.d.ts.map +0 -1
- package/dist/test/code-execution.test.js +0 -1272
- package/dist/test/code-execution.test.js.map +0 -1
- package/dist/test/component-defaults.test.d.ts +0 -2
- package/dist/test/component-defaults.test.d.ts.map +0 -1
- package/dist/test/component-defaults.test.js +0 -54
- package/dist/test/component-defaults.test.js.map +0 -1
- package/dist/test/conversation-fork-injection-scoping.test.d.ts +0 -2
- package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +0 -1
- package/dist/test/conversation-fork-injection-scoping.test.js +0 -200
- package/dist/test/conversation-fork-injection-scoping.test.js.map +0 -1
- package/dist/test/conversation-router.test.d.ts +0 -2
- package/dist/test/conversation-router.test.d.ts.map +0 -1
- package/dist/test/conversation-router.test.js +0 -174
- package/dist/test/conversation-router.test.js.map +0 -1
- package/dist/test/conversation-routing.test.d.ts +0 -7
- package/dist/test/conversation-routing.test.d.ts.map +0 -1
- package/dist/test/conversation-routing.test.js +0 -621
- package/dist/test/conversation-routing.test.js.map +0 -1
- package/dist/test/deferred-wake-integrity.test.d.ts +0 -29
- package/dist/test/deferred-wake-integrity.test.d.ts.map +0 -1
- package/dist/test/deferred-wake-integrity.test.js +0 -320
- package/dist/test/deferred-wake-integrity.test.js.map +0 -1
- package/dist/test/discord-awareness-outbox.test.d.ts +0 -2
- package/dist/test/discord-awareness-outbox.test.d.ts.map +0 -1
- package/dist/test/discord-awareness-outbox.test.js +0 -371
- package/dist/test/discord-awareness-outbox.test.js.map +0 -1
- package/dist/test/discord-history-delete-window.test.d.ts +0 -2
- package/dist/test/discord-history-delete-window.test.d.ts.map +0 -1
- package/dist/test/discord-history-delete-window.test.js +0 -81
- package/dist/test/discord-history-delete-window.test.js.map +0 -1
- package/dist/test/discord-history-sync.test.d.ts +0 -2
- package/dist/test/discord-history-sync.test.d.ts.map +0 -1
- package/dist/test/discord-history-sync.test.js +0 -56
- package/dist/test/discord-history-sync.test.js.map +0 -1
- package/dist/test/discord-typing-keepalive.test.d.ts +0 -2
- package/dist/test/discord-typing-keepalive.test.d.ts.map +0 -1
- package/dist/test/discord-typing-keepalive.test.js +0 -77
- package/dist/test/discord-typing-keepalive.test.js.map +0 -1
- package/dist/test/ephemeral-settle.test.d.ts +0 -2
- package/dist/test/ephemeral-settle.test.d.ts.map +0 -1
- package/dist/test/ephemeral-settle.test.js +0 -354
- package/dist/test/ephemeral-settle.test.js.map +0 -1
- package/dist/test/event-gate-passthrough.test.d.ts +0 -15
- package/dist/test/event-gate-passthrough.test.d.ts.map +0 -1
- package/dist/test/event-gate-passthrough.test.js +0 -289
- package/dist/test/event-gate-passthrough.test.js.map +0 -1
- package/dist/test/event-gate-policy-mutation.test.d.ts +0 -2
- package/dist/test/event-gate-policy-mutation.test.d.ts.map +0 -1
- package/dist/test/event-gate-policy-mutation.test.js +0 -137
- package/dist/test/event-gate-policy-mutation.test.js.map +0 -1
- package/dist/test/event-gate-rate-limit.test.d.ts +0 -2
- package/dist/test/event-gate-rate-limit.test.d.ts.map +0 -1
- package/dist/test/event-gate-rate-limit.test.js +0 -627
- package/dist/test/event-gate-rate-limit.test.js.map +0 -1
- package/dist/test/event-gate-script.test.d.ts +0 -2
- package/dist/test/event-gate-script.test.d.ts.map +0 -1
- package/dist/test/event-gate-script.test.js +0 -95
- package/dist/test/event-gate-script.test.js.map +0 -1
- package/dist/test/event-gate-selfwake.test.d.ts +0 -15
- package/dist/test/event-gate-selfwake.test.d.ts.map +0 -1
- package/dist/test/event-gate-selfwake.test.js +0 -125
- package/dist/test/event-gate-selfwake.test.js.map +0 -1
- package/dist/test/event-gate-tags.test.d.ts +0 -2
- package/dist/test/event-gate-tags.test.d.ts.map +0 -1
- package/dist/test/event-gate-tags.test.js +0 -76
- package/dist/test/event-gate-tags.test.js.map +0 -1
- package/dist/test/event-gate.test.d.ts +0 -2
- package/dist/test/event-gate.test.d.ts.map +0 -1
- package/dist/test/event-gate.test.js +0 -919
- package/dist/test/event-gate.test.js.map +0 -1
- package/dist/test/explicit-prose-routing.test.d.ts +0 -11
- package/dist/test/explicit-prose-routing.test.d.ts.map +0 -1
- package/dist/test/explicit-prose-routing.test.js +0 -1715
- package/dist/test/explicit-prose-routing.test.js.map +0 -1
- package/dist/test/framework.test.d.ts +0 -5
- package/dist/test/framework.test.d.ts.map +0 -1
- package/dist/test/framework.test.js +0 -1048
- package/dist/test/framework.test.js.map +0 -1
- package/dist/test/gather-context-timeout.test.d.ts +0 -2
- package/dist/test/gather-context-timeout.test.d.ts.map +0 -1
- package/dist/test/gather-context-timeout.test.js +0 -120
- package/dist/test/gather-context-timeout.test.js.map +0 -1
- package/dist/test/health-snapshot.test.d.ts +0 -2
- package/dist/test/health-snapshot.test.d.ts.map +0 -1
- package/dist/test/health-snapshot.test.js +0 -74
- package/dist/test/health-snapshot.test.js.map +0 -1
- package/dist/test/helpers/coalescing-fixture.d.ts +0 -74
- package/dist/test/helpers/coalescing-fixture.d.ts.map +0 -1
- package/dist/test/helpers/coalescing-fixture.js +0 -152
- package/dist/test/helpers/coalescing-fixture.js.map +0 -1
- package/dist/test/helpers/coalescing-kill-child.d.ts +0 -2
- package/dist/test/helpers/coalescing-kill-child.d.ts.map +0 -1
- package/dist/test/helpers/coalescing-kill-child.js +0 -24
- package/dist/test/helpers/coalescing-kill-child.js.map +0 -1
- package/dist/test/helpers/mock-membrane.d.ts +0 -53
- package/dist/test/helpers/mock-membrane.d.ts.map +0 -1
- package/dist/test/helpers/mock-membrane.js +0 -168
- package/dist/test/helpers/mock-membrane.js.map +0 -1
- package/dist/test/helpers/pytc-stop-rows.d.ts +0 -11
- package/dist/test/helpers/pytc-stop-rows.d.ts.map +0 -1
- package/dist/test/helpers/pytc-stop-rows.js +0 -143
- package/dist/test/helpers/pytc-stop-rows.js.map +0 -1
- package/dist/test/helpers/quiesce-crash-child.d.ts +0 -2
- package/dist/test/helpers/quiesce-crash-child.d.ts.map +0 -1
- package/dist/test/helpers/quiesce-crash-child.js +0 -156
- package/dist/test/helpers/quiesce-crash-child.js.map +0 -1
- package/dist/test/hide-then-turn.test.d.ts +0 -2
- package/dist/test/hide-then-turn.test.d.ts.map +0 -1
- package/dist/test/hide-then-turn.test.js +0 -101
- package/dist/test/hide-then-turn.test.js.map +0 -1
- package/dist/test/history-module-overview.test.d.ts +0 -2
- package/dist/test/history-module-overview.test.d.ts.map +0 -1
- package/dist/test/history-module-overview.test.js +0 -711
- package/dist/test/history-module-overview.test.js.map +0 -1
- package/dist/test/history-module-realstore.test.d.ts +0 -2
- package/dist/test/history-module-realstore.test.d.ts.map +0 -1
- package/dist/test/history-module-realstore.test.js +0 -363
- package/dist/test/history-module-realstore.test.js.map +0 -1
- package/dist/test/history-module-semantic.test.d.ts +0 -2
- package/dist/test/history-module-semantic.test.d.ts.map +0 -1
- package/dist/test/history-module-semantic.test.js +0 -213
- package/dist/test/history-module-semantic.test.js.map +0 -1
- package/dist/test/history-module-ux.test.d.ts +0 -2
- package/dist/test/history-module-ux.test.d.ts.map +0 -1
- package/dist/test/history-module-ux.test.js +0 -304
- package/dist/test/history-module-ux.test.js.map +0 -1
- package/dist/test/history-module.test.d.ts +0 -2
- package/dist/test/history-module.test.d.ts.map +0 -1
- package/dist/test/history-module.test.js +0 -619
- package/dist/test/history-module.test.js.map +0 -1
- package/dist/test/history-semantic-review-findings.test.d.ts +0 -2
- package/dist/test/history-semantic-review-findings.test.d.ts.map +0 -1
- package/dist/test/history-semantic-review-findings.test.js +0 -338
- package/dist/test/history-semantic-review-findings.test.js.map +0 -1
- package/dist/test/history-semantic-sync-converges.test.d.ts +0 -2
- package/dist/test/history-semantic-sync-converges.test.d.ts.map +0 -1
- package/dist/test/history-semantic-sync-converges.test.js +0 -109
- package/dist/test/history-semantic-sync-converges.test.js.map +0 -1
- package/dist/test/host-quiesce.test.d.ts +0 -2
- package/dist/test/host-quiesce.test.d.ts.map +0 -1
- package/dist/test/host-quiesce.test.js +0 -988
- package/dist/test/host-quiesce.test.js.map +0 -1
- package/dist/test/inference-exhaustion-rewind.test.d.ts +0 -2
- package/dist/test/inference-exhaustion-rewind.test.d.ts.map +0 -1
- package/dist/test/inference-exhaustion-rewind.test.js +0 -387
- package/dist/test/inference-exhaustion-rewind.test.js.map +0 -1
- package/dist/test/inference-failure-bounds.test.d.ts +0 -2
- package/dist/test/inference-failure-bounds.test.d.ts.map +0 -1
- package/dist/test/inference-failure-bounds.test.js +0 -1202
- package/dist/test/inference-failure-bounds.test.js.map +0 -1
- package/dist/test/inference-failure-observability.test.d.ts +0 -2
- package/dist/test/inference-failure-observability.test.d.ts.map +0 -1
- package/dist/test/inference-failure-observability.test.js +0 -84
- package/dist/test/inference-failure-observability.test.js.map +0 -1
- package/dist/test/journal-tool.test.d.ts +0 -2
- package/dist/test/journal-tool.test.d.ts.map +0 -1
- package/dist/test/journal-tool.test.js +0 -33
- package/dist/test/journal-tool.test.js.map +0 -1
- package/dist/test/kv-unified-open-flight-retry.test.d.ts +0 -2
- package/dist/test/kv-unified-open-flight-retry.test.d.ts.map +0 -1
- package/dist/test/kv-unified-open-flight-retry.test.js +0 -189
- package/dist/test/kv-unified-open-flight-retry.test.js.map +0 -1
- package/dist/test/kv-unified-wiring.test.d.ts +0 -2
- package/dist/test/kv-unified-wiring.test.d.ts.map +0 -1
- package/dist/test/kv-unified-wiring.test.js +0 -95
- package/dist/test/kv-unified-wiring.test.js.map +0 -1
- package/dist/test/late-events-after-stop.test.d.ts +0 -2
- package/dist/test/late-events-after-stop.test.d.ts.map +0 -1
- package/dist/test/late-events-after-stop.test.js +0 -122
- package/dist/test/late-events-after-stop.test.js.map +0 -1
- package/dist/test/liveness-watchdog.test.d.ts +0 -2
- package/dist/test/liveness-watchdog.test.d.ts.map +0 -1
- package/dist/test/liveness-watchdog.test.js +0 -94
- package/dist/test/liveness-watchdog.test.js.map +0 -1
- package/dist/test/machine-close-provenance.test.d.ts +0 -2
- package/dist/test/machine-close-provenance.test.d.ts.map +0 -1
- package/dist/test/machine-close-provenance.test.js +0 -116
- package/dist/test/machine-close-provenance.test.js.map +0 -1
- package/dist/test/maintenance-timer.test.d.ts +0 -2
- package/dist/test/maintenance-timer.test.d.ts.map +0 -1
- package/dist/test/maintenance-timer.test.js +0 -1827
- package/dist/test/maintenance-timer.test.js.map +0 -1
- package/dist/test/mcp-server-bin.test.d.ts +0 -2
- package/dist/test/mcp-server-bin.test.d.ts.map +0 -1
- package/dist/test/mcp-server-bin.test.js +0 -142
- package/dist/test/mcp-server-bin.test.js.map +0 -1
- package/dist/test/mcpl-access-provider.test.d.ts +0 -2
- package/dist/test/mcpl-access-provider.test.d.ts.map +0 -1
- package/dist/test/mcpl-access-provider.test.js +0 -20
- package/dist/test/mcpl-access-provider.test.js.map +0 -1
- package/dist/test/mcpl-awareness-barrier.test.d.ts +0 -2
- package/dist/test/mcpl-awareness-barrier.test.d.ts.map +0 -1
- package/dist/test/mcpl-awareness-barrier.test.js +0 -769
- package/dist/test/mcpl-awareness-barrier.test.js.map +0 -1
- package/dist/test/mcpl-capability-grant.test.d.ts +0 -10
- package/dist/test/mcpl-capability-grant.test.d.ts.map +0 -1
- package/dist/test/mcpl-capability-grant.test.js +0 -111
- package/dist/test/mcpl-capability-grant.test.js.map +0 -1
- package/dist/test/mcpl-capability-scoping.test.d.ts +0 -2
- package/dist/test/mcpl-capability-scoping.test.d.ts.map +0 -1
- package/dist/test/mcpl-capability-scoping.test.js +0 -266
- package/dist/test/mcpl-capability-scoping.test.js.map +0 -1
- package/dist/test/mcpl-child-env.test.d.ts +0 -2
- package/dist/test/mcpl-child-env.test.d.ts.map +0 -1
- package/dist/test/mcpl-child-env.test.js +0 -158
- package/dist/test/mcpl-child-env.test.js.map +0 -1
- package/dist/test/mcpl-coalesced-content-parity.test.d.ts +0 -2
- package/dist/test/mcpl-coalesced-content-parity.test.d.ts.map +0 -1
- package/dist/test/mcpl-coalesced-content-parity.test.js +0 -532
- package/dist/test/mcpl-coalesced-content-parity.test.js.map +0 -1
- package/dist/test/mcpl-coalescing.test.d.ts +0 -2
- package/dist/test/mcpl-coalescing.test.d.ts.map +0 -1
- package/dist/test/mcpl-coalescing.test.js +0 -1125
- package/dist/test/mcpl-coalescing.test.js.map +0 -1
- package/dist/test/mcpl-config-diagnostics.test.d.ts +0 -2
- package/dist/test/mcpl-config-diagnostics.test.d.ts.map +0 -1
- package/dist/test/mcpl-config-diagnostics.test.js +0 -452
- package/dist/test/mcpl-config-diagnostics.test.js.map +0 -1
- package/dist/test/mcpl-empty-content.test.d.ts +0 -2
- package/dist/test/mcpl-empty-content.test.d.ts.map +0 -1
- package/dist/test/mcpl-empty-content.test.js +0 -368
- package/dist/test/mcpl-empty-content.test.js.map +0 -1
- package/dist/test/mcpl-gate-roundtrip.test.d.ts +0 -2
- package/dist/test/mcpl-gate-roundtrip.test.d.ts.map +0 -1
- package/dist/test/mcpl-gate-roundtrip.test.js +0 -285
- package/dist/test/mcpl-gate-roundtrip.test.js.map +0 -1
- package/dist/test/mcpl-list-status.test.d.ts +0 -2
- package/dist/test/mcpl-list-status.test.d.ts.map +0 -1
- package/dist/test/mcpl-list-status.test.js +0 -82
- package/dist/test/mcpl-list-status.test.js.map +0 -1
- package/dist/test/mcpl-manifest-changed.test.d.ts +0 -2
- package/dist/test/mcpl-manifest-changed.test.d.ts.map +0 -1
- package/dist/test/mcpl-manifest-changed.test.js +0 -178
- package/dist/test/mcpl-manifest-changed.test.js.map +0 -1
- package/dist/test/mcpl-push-convert.test.d.ts +0 -2
- package/dist/test/mcpl-push-convert.test.d.ts.map +0 -1
- package/dist/test/mcpl-push-convert.test.js +0 -42
- package/dist/test/mcpl-push-convert.test.js.map +0 -1
- package/dist/test/mcpl-reconnect-events.test.d.ts +0 -2
- package/dist/test/mcpl-reconnect-events.test.d.ts.map +0 -1
- package/dist/test/mcpl-reconnect-events.test.js +0 -144
- package/dist/test/mcpl-reconnect-events.test.js.map +0 -1
- package/dist/test/mcpl-reconnect-reregistration.test.d.ts +0 -2
- package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +0 -1
- package/dist/test/mcpl-reconnect-reregistration.test.js +0 -238
- package/dist/test/mcpl-reconnect-reregistration.test.js.map +0 -1
- package/dist/test/mcpl-reference-fetcher.test.d.ts +0 -2
- package/dist/test/mcpl-reference-fetcher.test.d.ts.map +0 -1
- package/dist/test/mcpl-reference-fetcher.test.js +0 -427
- package/dist/test/mcpl-reference-fetcher.test.js.map +0 -1
- package/dist/test/mcpl-reference-fields.test.d.ts +0 -2
- package/dist/test/mcpl-reference-fields.test.d.ts.map +0 -1
- package/dist/test/mcpl-reference-fields.test.js +0 -149
- package/dist/test/mcpl-reference-fields.test.js.map +0 -1
- package/dist/test/mcpl-rejection-log-lines.test.d.ts +0 -2
- package/dist/test/mcpl-rejection-log-lines.test.d.ts.map +0 -1
- package/dist/test/mcpl-rejection-log-lines.test.js +0 -349
- package/dist/test/mcpl-rejection-log-lines.test.js.map +0 -1
- package/dist/test/mcpl-request-timeout.test.d.ts +0 -2
- package/dist/test/mcpl-request-timeout.test.d.ts.map +0 -1
- package/dist/test/mcpl-request-timeout.test.js +0 -138
- package/dist/test/mcpl-request-timeout.test.js.map +0 -1
- package/dist/test/mcpl-runtime-lifecycle.test.d.ts +0 -7
- package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +0 -1
- package/dist/test/mcpl-runtime-lifecycle.test.js +0 -142
- package/dist/test/mcpl-runtime-lifecycle.test.js.map +0 -1
- package/dist/test/mcpl-stderr-tail.test.d.ts +0 -2
- package/dist/test/mcpl-stderr-tail.test.d.ts.map +0 -1
- package/dist/test/mcpl-stderr-tail.test.js +0 -210
- package/dist/test/mcpl-stderr-tail.test.js.map +0 -1
- package/dist/test/mcpl-tool-class-listing.test.d.ts +0 -2
- package/dist/test/mcpl-tool-class-listing.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-class-listing.test.js +0 -147
- package/dist/test/mcpl-tool-class-listing.test.js.map +0 -1
- package/dist/test/mcpl-tool-classes.test.d.ts +0 -7
- package/dist/test/mcpl-tool-classes.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-classes.test.js +0 -80
- package/dist/test/mcpl-tool-classes.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts +0 -2
- package/dist/test/mcpl-tool-lifecycle-e2e.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-e2e.test.js +0 -237
- package/dist/test/mcpl-tool-lifecycle-e2e.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts +0 -11
- package/dist/test/mcpl-tool-lifecycle-emitter.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-emitter.test.js +0 -412
- package/dist/test/mcpl-tool-lifecycle-emitter.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-script.test.d.ts +0 -2
- package/dist/test/mcpl-tool-lifecycle-script.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle-script.test.js +0 -288
- package/dist/test/mcpl-tool-lifecycle-script.test.js.map +0 -1
- package/dist/test/mcpl-tool-lifecycle.test.d.ts +0 -11
- package/dist/test/mcpl-tool-lifecycle.test.d.ts.map +0 -1
- package/dist/test/mcpl-tool-lifecycle.test.js +0 -270
- package/dist/test/mcpl-tool-lifecycle.test.js.map +0 -1
- package/dist/test/mcpl-transport-close.test.d.ts +0 -2
- package/dist/test/mcpl-transport-close.test.d.ts.map +0 -1
- package/dist/test/mcpl-transport-close.test.js +0 -373
- package/dist/test/mcpl-transport-close.test.js.map +0 -1
- package/dist/test/mcpl-transport-spawn.test.d.ts +0 -2
- package/dist/test/mcpl-transport-spawn.test.d.ts.map +0 -1
- package/dist/test/mcpl-transport-spawn.test.js +0 -58
- package/dist/test/mcpl-transport-spawn.test.js.map +0 -1
- package/dist/test/mcpl-ws-transport.test.d.ts +0 -2
- package/dist/test/mcpl-ws-transport.test.d.ts.map +0 -1
- package/dist/test/mcpl-ws-transport.test.js +0 -259
- package/dist/test/mcpl-ws-transport.test.js.map +0 -1
- package/dist/test/module-context-integration.test.d.ts +0 -18
- package/dist/test/module-context-integration.test.d.ts.map +0 -1
- package/dist/test/module-context-integration.test.js +0 -181
- package/dist/test/module-context-integration.test.js.map +0 -1
- package/dist/test/offline-recovery-branch.test.d.ts +0 -2
- package/dist/test/offline-recovery-branch.test.d.ts.map +0 -1
- package/dist/test/offline-recovery-branch.test.js +0 -570
- package/dist/test/offline-recovery-branch.test.js.map +0 -1
- package/dist/test/operator-surgery.test.d.ts +0 -2
- package/dist/test/operator-surgery.test.d.ts.map +0 -1
- package/dist/test/operator-surgery.test.js +0 -595
- package/dist/test/operator-surgery.test.js.map +0 -1
- package/dist/test/ops-alert.test.d.ts +0 -2
- package/dist/test/ops-alert.test.d.ts.map +0 -1
- package/dist/test/ops-alert.test.js +0 -153
- package/dist/test/ops-alert.test.js.map +0 -1
- package/dist/test/overbudget-drain-breaker.test.d.ts +0 -2
- package/dist/test/overbudget-drain-breaker.test.d.ts.map +0 -1
- package/dist/test/overbudget-drain-breaker.test.js +0 -198
- package/dist/test/overbudget-drain-breaker.test.js.map +0 -1
- package/dist/test/pack-installs-alone.test.d.ts +0 -2
- package/dist/test/pack-installs-alone.test.d.ts.map +0 -1
- package/dist/test/pack-installs-alone.test.js +0 -284
- package/dist/test/pack-installs-alone.test.js.map +0 -1
- package/dist/test/per-agent-delivery.test.d.ts +0 -2
- package/dist/test/per-agent-delivery.test.d.ts.map +0 -1
- package/dist/test/per-agent-delivery.test.js +0 -108
- package/dist/test/per-agent-delivery.test.js.map +0 -1
- package/dist/test/physical-window-restart.test.d.ts +0 -16
- package/dist/test/physical-window-restart.test.d.ts.map +0 -1
- package/dist/test/physical-window-restart.test.js +0 -487
- package/dist/test/physical-window-restart.test.js.map +0 -1
- package/dist/test/placed-reaction-baseline.test.d.ts +0 -2
- package/dist/test/placed-reaction-baseline.test.d.ts.map +0 -1
- package/dist/test/placed-reaction-baseline.test.js +0 -312
- package/dist/test/placed-reaction-baseline.test.js.map +0 -1
- package/dist/test/present-while-acting.test.d.ts +0 -19
- package/dist/test/present-while-acting.test.d.ts.map +0 -1
- package/dist/test/present-while-acting.test.js +0 -1649
- package/dist/test/present-while-acting.test.js.map +0 -1
- package/dist/test/prose-segments.test.d.ts +0 -2
- package/dist/test/prose-segments.test.d.ts.map +0 -1
- package/dist/test/prose-segments.test.js +0 -52
- package/dist/test/prose-segments.test.js.map +0 -1
- package/dist/test/prose-stream-router.test.d.ts +0 -2
- package/dist/test/prose-stream-router.test.d.ts.map +0 -1
- package/dist/test/prose-stream-router.test.js +0 -171
- package/dist/test/prose-stream-router.test.js.map +0 -1
- package/dist/test/provider-acceleration-cooldown.test.d.ts +0 -2
- package/dist/test/provider-acceleration-cooldown.test.d.ts.map +0 -1
- package/dist/test/provider-acceleration-cooldown.test.js +0 -435
- package/dist/test/provider-acceleration-cooldown.test.js.map +0 -1
- package/dist/test/provider-waits.test.d.ts +0 -2
- package/dist/test/provider-waits.test.d.ts.map +0 -1
- package/dist/test/provider-waits.test.js +0 -2259
- package/dist/test/provider-waits.test.js.map +0 -1
- package/dist/test/puppet-tool-call.test.d.ts +0 -2
- package/dist/test/puppet-tool-call.test.d.ts.map +0 -1
- package/dist/test/puppet-tool-call.test.js +0 -226
- package/dist/test/puppet-tool-call.test.js.map +0 -1
- package/dist/test/puppet-turn-reservation.test.d.ts +0 -2
- package/dist/test/puppet-turn-reservation.test.d.ts.map +0 -1
- package/dist/test/puppet-turn-reservation.test.js +0 -139
- package/dist/test/puppet-turn-reservation.test.js.map +0 -1
- package/dist/test/reaction-baseline-platform.test.d.ts +0 -2
- package/dist/test/reaction-baseline-platform.test.d.ts.map +0 -1
- package/dist/test/reaction-baseline-platform.test.js +0 -124
- package/dist/test/reaction-baseline-platform.test.js.map +0 -1
- package/dist/test/record-journal.test.d.ts +0 -6
- package/dist/test/record-journal.test.d.ts.map +0 -1
- package/dist/test/record-journal.test.js +0 -269
- package/dist/test/record-journal.test.js.map +0 -1
- package/dist/test/refusal-reaction-baseline.test.d.ts +0 -2
- package/dist/test/refusal-reaction-baseline.test.d.ts.map +0 -1
- package/dist/test/refusal-reaction-baseline.test.js +0 -81
- package/dist/test/refusal-reaction-baseline.test.js.map +0 -1
- package/dist/test/refusal-rewind.test.d.ts +0 -2
- package/dist/test/refusal-rewind.test.d.ts.map +0 -1
- package/dist/test/refusal-rewind.test.js +0 -117
- package/dist/test/refusal-rewind.test.js.map +0 -1
- package/dist/test/refusal-single-call.test.d.ts +0 -2
- package/dist/test/refusal-single-call.test.d.ts.map +0 -1
- package/dist/test/refusal-single-call.test.js +0 -177
- package/dist/test/refusal-single-call.test.js.map +0 -1
- package/dist/test/release-bump.test.d.ts +0 -2
- package/dist/test/release-bump.test.d.ts.map +0 -1
- package/dist/test/release-bump.test.js +0 -248
- package/dist/test/release-bump.test.js.map +0 -1
- package/dist/test/release-changelog.test.d.ts +0 -2
- package/dist/test/release-changelog.test.d.ts.map +0 -1
- package/dist/test/release-changelog.test.js +0 -159
- package/dist/test/release-changelog.test.js.map +0 -1
- package/dist/test/release-holds.test.d.ts +0 -2
- package/dist/test/release-holds.test.d.ts.map +0 -1
- package/dist/test/release-holds.test.js +0 -456
- package/dist/test/release-holds.test.js.map +0 -1
- package/dist/test/same-round-think-policy.test.d.ts +0 -2
- package/dist/test/same-round-think-policy.test.d.ts.map +0 -1
- package/dist/test/same-round-think-policy.test.js +0 -853
- package/dist/test/same-round-think-policy.test.js.map +0 -1
- package/dist/test/save-recent-image.test.d.ts +0 -26
- package/dist/test/save-recent-image.test.d.ts.map +0 -1
- package/dist/test/save-recent-image.test.js +0 -974
- package/dist/test/save-recent-image.test.js.map +0 -1
- package/dist/test/shutdown-errors.test.d.ts +0 -2
- package/dist/test/shutdown-errors.test.d.ts.map +0 -1
- package/dist/test/shutdown-errors.test.js +0 -662
- package/dist/test/shutdown-errors.test.js.map +0 -1
- package/dist/test/silent-heartbeat-rows.test.d.ts +0 -2
- package/dist/test/silent-heartbeat-rows.test.d.ts.map +0 -1
- package/dist/test/silent-heartbeat-rows.test.js +0 -451
- package/dist/test/silent-heartbeat-rows.test.js.map +0 -1
- package/dist/test/silent-heartbeat.test.d.ts +0 -2
- package/dist/test/silent-heartbeat.test.d.ts.map +0 -1
- package/dist/test/silent-heartbeat.test.js +0 -165
- package/dist/test/silent-heartbeat.test.js.map +0 -1
- package/dist/test/state-scaling-e2e.test.d.ts +0 -22
- package/dist/test/state-scaling-e2e.test.d.ts.map +0 -1
- package/dist/test/state-scaling-e2e.test.js +0 -206
- package/dist/test/state-scaling-e2e.test.js.map +0 -1
- package/dist/test/state-scaling.test.d.ts +0 -12
- package/dist/test/state-scaling.test.d.ts.map +0 -1
- package/dist/test/state-scaling.test.js +0 -251
- package/dist/test/state-scaling.test.js.map +0 -1
- package/dist/test/stop-with-host-operations.test.d.ts +0 -20
- package/dist/test/stop-with-host-operations.test.d.ts.map +0 -1
- package/dist/test/stop-with-host-operations.test.js +0 -1174
- package/dist/test/stop-with-host-operations.test.js.map +0 -1
- package/dist/test/stop-with-work-in-flight.test.d.ts +0 -23
- package/dist/test/stop-with-work-in-flight.test.d.ts.map +0 -1
- package/dist/test/stop-with-work-in-flight.test.js +0 -784
- package/dist/test/stop-with-work-in-flight.test.js.map +0 -1
- package/dist/test/surgery-marks-receipt.test.d.ts +0 -2
- package/dist/test/surgery-marks-receipt.test.d.ts.map +0 -1
- package/dist/test/surgery-marks-receipt.test.js +0 -540
- package/dist/test/surgery-marks-receipt.test.js.map +0 -1
- package/dist/test/thinking-token-stamp.test.d.ts +0 -12
- package/dist/test/thinking-token-stamp.test.d.ts.map +0 -1
- package/dist/test/thinking-token-stamp.test.js +0 -129
- package/dist/test/thinking-token-stamp.test.js.map +0 -1
- package/dist/test/timezone.test.d.ts +0 -2
- package/dist/test/timezone.test.d.ts.map +0 -1
- package/dist/test/timezone.test.js +0 -18
- package/dist/test/timezone.test.js.map +0 -1
- package/dist/test/tool-batch-hook.test.d.ts +0 -8
- package/dist/test/tool-batch-hook.test.d.ts.map +0 -1
- package/dist/test/tool-batch-hook.test.js +0 -275
- package/dist/test/tool-batch-hook.test.js.map +0 -1
- package/dist/test/tool-policy.test.d.ts +0 -2
- package/dist/test/tool-policy.test.d.ts.map +0 -1
- package/dist/test/tool-policy.test.js +0 -51
- package/dist/test/tool-policy.test.js.map +0 -1
- package/dist/test/tool-presentation.test.d.ts +0 -2
- package/dist/test/tool-presentation.test.d.ts.map +0 -1
- package/dist/test/tool-presentation.test.js +0 -268
- package/dist/test/tool-presentation.test.js.map +0 -1
- package/dist/test/tool-result-content.test.d.ts +0 -2
- package/dist/test/tool-result-content.test.d.ts.map +0 -1
- package/dist/test/tool-result-content.test.js +0 -37
- package/dist/test/tool-result-content.test.js.map +0 -1
- package/dist/test/tool-result-guard.test.d.ts +0 -2
- package/dist/test/tool-result-guard.test.d.ts.map +0 -1
- package/dist/test/tool-result-guard.test.js +0 -3729
- package/dist/test/tool-result-guard.test.js.map +0 -1
- package/dist/test/tool-result-history.test.d.ts +0 -7
- package/dist/test/tool-result-history.test.d.ts.map +0 -1
- package/dist/test/tool-result-history.test.js +0 -156
- package/dist/test/tool-result-history.test.js.map +0 -1
- package/dist/test/tool-result-spill.test.d.ts +0 -13
- package/dist/test/tool-result-spill.test.d.ts.map +0 -1
- package/dist/test/tool-result-spill.test.js +0 -586
- package/dist/test/tool-result-spill.test.js.map +0 -1
- package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts +0 -2
- package/dist/test/tool-wrapper-prose-guard-integration.test.d.ts.map +0 -1
- package/dist/test/tool-wrapper-prose-guard-integration.test.js +0 -485
- package/dist/test/tool-wrapper-prose-guard-integration.test.js.map +0 -1
- package/dist/test/tool-wrapper-prose-guard.test.d.ts +0 -2
- package/dist/test/tool-wrapper-prose-guard.test.d.ts.map +0 -1
- package/dist/test/tool-wrapper-prose-guard.test.js +0 -34
- package/dist/test/tool-wrapper-prose-guard.test.js.map +0 -1
- package/dist/test/tools-observe-parser-conformance.test.d.ts +0 -2
- package/dist/test/tools-observe-parser-conformance.test.d.ts.map +0 -1
- package/dist/test/tools-observe-parser-conformance.test.js +0 -129
- package/dist/test/tools-observe-parser-conformance.test.js.map +0 -1
- package/dist/test/trunk-channel-routing.test.d.ts +0 -19
- package/dist/test/trunk-channel-routing.test.d.ts.map +0 -1
- package/dist/test/trunk-channel-routing.test.js +0 -652
- package/dist/test/trunk-channel-routing.test.js.map +0 -1
- package/dist/test/tune-out-e2e.test.d.ts +0 -2
- package/dist/test/tune-out-e2e.test.d.ts.map +0 -1
- package/dist/test/tune-out-e2e.test.js +0 -142
- package/dist/test/tune-out-e2e.test.js.map +0 -1
- package/dist/test/tune-out-gate-composition.test.d.ts +0 -2
- package/dist/test/tune-out-gate-composition.test.d.ts.map +0 -1
- package/dist/test/tune-out-gate-composition.test.js +0 -221
- package/dist/test/tune-out-gate-composition.test.js.map +0 -1
- package/dist/test/tune-out-lifecycle.test.d.ts +0 -2
- package/dist/test/tune-out-lifecycle.test.d.ts.map +0 -1
- package/dist/test/tune-out-lifecycle.test.js +0 -121
- package/dist/test/tune-out-lifecycle.test.js.map +0 -1
- package/dist/test/turn-trigger-provenance.test.d.ts +0 -2
- package/dist/test/turn-trigger-provenance.test.d.ts.map +0 -1
- package/dist/test/turn-trigger-provenance.test.js +0 -137
- package/dist/test/turn-trigger-provenance.test.js.map +0 -1
- package/dist/test/unconvertible-tool-result.test.d.ts +0 -2
- package/dist/test/unconvertible-tool-result.test.d.ts.map +0 -1
- package/dist/test/unconvertible-tool-result.test.js +0 -358
- package/dist/test/unconvertible-tool-result.test.js.map +0 -1
- package/dist/test/unsent-compiles.test.d.ts +0 -2
- package/dist/test/unsent-compiles.test.d.ts.map +0 -1
- package/dist/test/unsent-compiles.test.js +0 -139
- package/dist/test/unsent-compiles.test.js.map +0 -1
- package/dist/test/usage-accounting.test.d.ts +0 -2
- package/dist/test/usage-accounting.test.d.ts.map +0 -1
- package/dist/test/usage-accounting.test.js +0 -13
- package/dist/test/usage-accounting.test.js.map +0 -1
- package/dist/test/usage-tracker.test.d.ts +0 -2
- package/dist/test/usage-tracker.test.d.ts.map +0 -1
- package/dist/test/usage-tracker.test.js +0 -129
- package/dist/test/usage-tracker.test.js.map +0 -1
- package/dist/test/utils-surface.test.d.ts +0 -2
- package/dist/test/utils-surface.test.d.ts.map +0 -1
- package/dist/test/utils-surface.test.js +0 -145
- package/dist/test/utils-surface.test.js.map +0 -1
- package/dist/test/workspace-branch-continuation.test.d.ts +0 -15
- package/dist/test/workspace-branch-continuation.test.d.ts.map +0 -1
- package/dist/test/workspace-branch-continuation.test.js +0 -183
- package/dist/test/workspace-branch-continuation.test.js.map +0 -1
- package/dist/test/workspace-materialize-freshness.test.d.ts +0 -16
- package/dist/test/workspace-materialize-freshness.test.d.ts.map +0 -1
- package/dist/test/workspace-materialize-freshness.test.js +0 -252
- package/dist/test/workspace-materialize-freshness.test.js.map +0 -1
- package/dist/test/workspace-path-containment.test.d.ts +0 -19
- package/dist/test/workspace-path-containment.test.d.ts.map +0 -1
- package/dist/test/workspace-path-containment.test.js +0 -91
- package/dist/test/workspace-path-containment.test.js.map +0 -1
- package/dist/test/workspace-read-file-from-disk.test.d.ts +0 -17
- package/dist/test/workspace-read-file-from-disk.test.d.ts.map +0 -1
- package/dist/test/workspace-read-file-from-disk.test.js +0 -174
- package/dist/test/workspace-read-file-from-disk.test.js.map +0 -1
- package/dist/test/workspace-read-image.test.d.ts +0 -2
- package/dist/test/workspace-read-image.test.d.ts.map +0 -1
- package/dist/test/workspace-read-image.test.js +0 -597
- package/dist/test/workspace-read-image.test.js.map +0 -1
- package/dist/test/workspace-read-text.test.d.ts +0 -2
- package/dist/test/workspace-read-text.test.d.ts.map +0 -1
- package/dist/test/workspace-read-text.test.js +0 -101
- package/dist/test/workspace-read-text.test.js.map +0 -1
- package/dist/test/workspace-restore-order.test.d.ts +0 -16
- package/dist/test/workspace-restore-order.test.d.ts.map +0 -1
- package/dist/test/workspace-restore-order.test.js +0 -140
- package/dist/test/workspace-restore-order.test.js.map +0 -1
- package/dist/test/workspace-three-way.test.d.ts +0 -12
- package/dist/test/workspace-three-way.test.d.ts.map +0 -1
- package/dist/test/workspace-three-way.test.js +0 -4094
- package/dist/test/workspace-three-way.test.js.map +0 -1
- package/dist/test/workspace-watcher.test.d.ts +0 -2
- package/dist/test/workspace-watcher.test.d.ts.map +0 -1
- package/dist/test/workspace-watcher.test.js +0 -281
- package/dist/test/workspace-watcher.test.js.map +0 -1
- package/dist/test/xml-round-persist.test.d.ts +0 -19
- package/dist/test/xml-round-persist.test.d.ts.map +0 -1
- package/dist/test/xml-round-persist.test.js +0 -235
- package/dist/test/xml-round-persist.test.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,1174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* stop() and an operator's operations.
|
|
3
|
-
*
|
|
4
|
-
* Once stop() has begun, an operator's entry points refuse: quiesce, resume,
|
|
5
|
-
* the store surgeries, a branch switch, undo, redo, maintain, puppet, the
|
|
6
|
-
* awareness sync and the MCPL lifecycle calls (a host/command is refused by
|
|
7
|
-
* its listener). The marks' delivery a branch move starts isn't one of these
|
|
8
|
-
* operations: stop() doesn't wait for it, and starts none once it has begun.
|
|
9
|
-
* These tests cover those refusals and the operations admitted before them, over
|
|
10
|
-
* MCPL or from a direct call: stop() waits for each, and for what each starts
|
|
11
|
-
* while it waits, before the event gate, the modules, the MCPL connections
|
|
12
|
-
* and the store go. A budget can cut that wait short, leaving the store open.
|
|
13
|
-
*
|
|
14
|
-
* Where a test holds an operation open, it lets it go once stop() reads a
|
|
15
|
-
* nonempty set of operations to wait on, or reaches its modules' teardown.
|
|
16
|
-
* main reaches teardown without reading any such set, so the order of the
|
|
17
|
-
* two events is the verdict, and it doesn't depend on timing.
|
|
18
|
-
*/
|
|
19
|
-
import { describe, it, beforeEach, afterEach } from 'node:test';
|
|
20
|
-
import assert from 'node:assert/strict';
|
|
21
|
-
import { EventEmitter } from 'node:events';
|
|
22
|
-
import { existsSync, mkdtempSync, readFileSync, rmSync } from 'node:fs';
|
|
23
|
-
import { tmpdir } from 'node:os';
|
|
24
|
-
import { join } from 'node:path';
|
|
25
|
-
import { AgentFramework, OperatorActionError, ShutdownTimeoutError } from '../src/index.js';
|
|
26
|
-
import { ApiServer } from '../src/api/server.js';
|
|
27
|
-
import { MockMembrane } from './helpers/mock-membrane.js';
|
|
28
|
-
/** Resolve once `cond` holds; fail, naming `what`, after `ms`. */
|
|
29
|
-
async function until(cond, what, ms = 5000) {
|
|
30
|
-
const deadline = Date.now() + ms;
|
|
31
|
-
while (!cond()) {
|
|
32
|
-
if (Date.now() > deadline)
|
|
33
|
-
throw new Error(`timed out waiting for ${what}`);
|
|
34
|
-
await new Promise((r) => setTimeout(r, 5));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/** Records when stop() reaches its modules' teardown, which comes after its wait for operations. */
|
|
38
|
-
class TeardownProbe {
|
|
39
|
-
order;
|
|
40
|
-
name = 'teardown-probe';
|
|
41
|
-
constructor(order) {
|
|
42
|
-
this.order = order;
|
|
43
|
-
}
|
|
44
|
-
async start(_ctx) { }
|
|
45
|
-
async stop() { this.order.push('modules stopped'); }
|
|
46
|
-
getTools() { return []; }
|
|
47
|
-
async handleToolCall() { return { success: false, error: 'no tools' }; }
|
|
48
|
-
async onProcess() { return {}; }
|
|
49
|
-
}
|
|
50
|
-
const internals = (framework) => framework;
|
|
51
|
-
describe('stop() with an operator operation in flight', () => {
|
|
52
|
-
let tempDir;
|
|
53
|
-
let storePath;
|
|
54
|
-
let logged;
|
|
55
|
-
let rejections;
|
|
56
|
-
let order;
|
|
57
|
-
let waitReads;
|
|
58
|
-
const onRejection = (reason) => { rejections.push(reason); };
|
|
59
|
-
const consoleError = console.error;
|
|
60
|
-
const consoleWarn = console.warn;
|
|
61
|
-
beforeEach(() => {
|
|
62
|
-
tempDir = mkdtempSync(join(tmpdir(), 'af-stop-host-ops-'));
|
|
63
|
-
storePath = join(tempDir, 'store');
|
|
64
|
-
logged = [];
|
|
65
|
-
rejections = [];
|
|
66
|
-
order = [];
|
|
67
|
-
waitReads = 0;
|
|
68
|
-
process.on('unhandledRejection', onRejection);
|
|
69
|
-
console.error = (...args) => { logged.push(args.map(String).join(' ')); };
|
|
70
|
-
console.warn = (...args) => { logged.push(args.map(String).join(' ')); };
|
|
71
|
-
});
|
|
72
|
-
afterEach(() => {
|
|
73
|
-
console.error = consoleError;
|
|
74
|
-
console.warn = consoleWarn;
|
|
75
|
-
process.off('unhandledRejection', onRejection);
|
|
76
|
-
rmSync(tempDir, { recursive: true, force: true });
|
|
77
|
-
});
|
|
78
|
-
async function create() {
|
|
79
|
-
const framework = await AgentFramework.create({
|
|
80
|
-
storePath,
|
|
81
|
-
membrane: new MockMembrane().asMembrane(),
|
|
82
|
-
agents: [{ name: 'agent', model: 'test-model', systemPrompt: 'test' }],
|
|
83
|
-
modules: [new TeardownProbe(order)],
|
|
84
|
-
});
|
|
85
|
-
internals(framework).operatorOperations = new class extends Set {
|
|
86
|
-
[Symbol.iterator]() {
|
|
87
|
-
if (this.size > 0)
|
|
88
|
-
waitReads++;
|
|
89
|
-
return super[Symbol.iterator]();
|
|
90
|
-
}
|
|
91
|
-
}();
|
|
92
|
-
return framework;
|
|
93
|
-
}
|
|
94
|
-
/** A positive observation releases the hold. Main reaches module teardown
|
|
95
|
-
* without reading the set, making the wrong order observable too. */
|
|
96
|
-
async function releaseWhenStopWaits(release) {
|
|
97
|
-
try {
|
|
98
|
-
await until(() => waitReads > 0 || order.includes('modules stopped'), 'stop to read pending operations or stop its modules', 30_000);
|
|
99
|
-
}
|
|
100
|
-
finally {
|
|
101
|
-
release();
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
async function bootsQuiesced() {
|
|
105
|
-
const restarted = await create();
|
|
106
|
-
try {
|
|
107
|
-
return restarted.getHostModeStatus().quiesced;
|
|
108
|
-
}
|
|
109
|
-
finally {
|
|
110
|
-
await restarted.stop();
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
it('a quiesce waiting for its drain stops waiting when stop() begins, and stop() waits for it', { timeout: 20_000 }, async () => {
|
|
114
|
-
const framework = await create();
|
|
115
|
-
framework.start();
|
|
116
|
-
// A turn between dequeue and stream registration holds its token with no
|
|
117
|
-
// stream to cancel. Stop cuts the drain short; the token remains alive.
|
|
118
|
-
const tokens = internals(framework).activeTurnTokens;
|
|
119
|
-
tokens.set('agent', -1);
|
|
120
|
-
let settled = false;
|
|
121
|
-
const traces = [];
|
|
122
|
-
framework.onTrace((event) => { traces.push(event.type); });
|
|
123
|
-
const quiescing = framework.quiesce({ reason: 'surgery', timeoutMs: 600_000 });
|
|
124
|
-
void quiescing.then(() => { settled = true; }, () => { settled = true; });
|
|
125
|
-
const stopping = framework.stop();
|
|
126
|
-
try {
|
|
127
|
-
await until(() => settled || order.includes('modules stopped'), 'stop to interrupt the quiesce or reach teardown', 10_000);
|
|
128
|
-
await stopping;
|
|
129
|
-
assert.equal(settled, true, 'stop() returned while the quiesce was still waiting');
|
|
130
|
-
const status = await quiescing;
|
|
131
|
-
assert.equal(status.quiesced, true);
|
|
132
|
-
assert.equal(status.drained, false);
|
|
133
|
-
assert.ok(!traces.includes('host:quiesce'), 'an interrupted drain reports no completed quiesce');
|
|
134
|
-
assert.ok(logged.some((line) => line.includes('quiesce stopped waiting for its drain: the framework is stopping')), logged.join('\n'));
|
|
135
|
-
}
|
|
136
|
-
finally {
|
|
137
|
-
tokens.delete('agent');
|
|
138
|
-
await quiescing.catch(() => { });
|
|
139
|
-
await stopping;
|
|
140
|
-
}
|
|
141
|
-
assert.equal(await bootsQuiesced(), true, 'the host boots quiesced');
|
|
142
|
-
assert.deepEqual(rejections, []);
|
|
143
|
-
});
|
|
144
|
-
it("an abandon waiting on a turn it can't cancel stops waiting when stop() begins, and stop() waits for it", { timeout: 20_000 }, async () => {
|
|
145
|
-
const framework = await create();
|
|
146
|
-
framework.start();
|
|
147
|
-
const tokens = internals(framework).activeTurnTokens;
|
|
148
|
-
tokens.set('agent', -1);
|
|
149
|
-
let settled = false;
|
|
150
|
-
const quiescing = framework.quiesce({ timeoutMs: 1_000, abandon: true });
|
|
151
|
-
void quiescing.then(() => { settled = true; }, () => { settled = true; });
|
|
152
|
-
try {
|
|
153
|
-
// After its one-second window, abandon finds no stream to cancel and
|
|
154
|
-
// gives the turn ten seconds to settle on its own.
|
|
155
|
-
await until(() => logged.some((line) => line.includes('cannot abandon turn for agent')), 'abandon to find the held token');
|
|
156
|
-
const began = Date.now();
|
|
157
|
-
await framework.stop();
|
|
158
|
-
const took = Date.now() - began;
|
|
159
|
-
assert.equal(settled, true, 'stop() returned while the abandon was still waiting');
|
|
160
|
-
// Only waiting out the ten-second grace should consume this bound.
|
|
161
|
-
assert.ok(took < 8_000, `stop() took ${took} ms, waiting out the abandon's ten seconds`);
|
|
162
|
-
assert.deepEqual((await quiescing).unabandonable, ['agent']);
|
|
163
|
-
}
|
|
164
|
-
finally {
|
|
165
|
-
tokens.delete('agent');
|
|
166
|
-
await quiescing.catch(() => { });
|
|
167
|
-
}
|
|
168
|
-
assert.deepEqual(rejections, []);
|
|
169
|
-
});
|
|
170
|
-
it('a resume waiting when stop() begins refuses, and the host stays quiesced', async () => {
|
|
171
|
-
const framework = await create();
|
|
172
|
-
framework.start();
|
|
173
|
-
await framework.quiesce({ reason: 'surgery' });
|
|
174
|
-
// resume() waits for a running maintenance pass before its feasibility
|
|
175
|
-
// gate, and so does stop(): both go on when the pass ends.
|
|
176
|
-
let endPass;
|
|
177
|
-
internals(framework).maintenancePass = new Promise((resolve) => { endPass = resolve; });
|
|
178
|
-
const resuming = framework.resume();
|
|
179
|
-
const stopping = framework.stop();
|
|
180
|
-
endPass();
|
|
181
|
-
await assert.rejects(resuming, /^Error: resume refused: the framework is stopping, so the host stays quiesced$/);
|
|
182
|
-
await stopping;
|
|
183
|
-
assert.equal(await bootsQuiesced(), true, 'the host boots quiesced');
|
|
184
|
-
assert.deepEqual(rejections, []);
|
|
185
|
-
});
|
|
186
|
-
it('a quiesce called after stop() is refused, and persists nothing', async () => {
|
|
187
|
-
const framework = await create();
|
|
188
|
-
await framework.stop();
|
|
189
|
-
await assert.rejects(framework.quiesce({ reason: 'too late' }), /^Error: quiesce refused: the framework is stopping$/);
|
|
190
|
-
assert.equal(await bootsQuiesced(), false, 'the host boots serving');
|
|
191
|
-
});
|
|
192
|
-
it('a resume called after stop() is refused, and the host stays quiesced', async () => {
|
|
193
|
-
const framework = await create();
|
|
194
|
-
await framework.quiesce();
|
|
195
|
-
await framework.stop();
|
|
196
|
-
await assert.rejects(framework.resume(), /^Error: resume refused: the framework is stopping$/);
|
|
197
|
-
assert.equal(await bootsQuiesced(), true, 'the host boots quiesced');
|
|
198
|
-
});
|
|
199
|
-
it('stop() waits for a resume past its commit point, and a reopen that fails is released, not recycled', async () => {
|
|
200
|
-
const framework = await create();
|
|
201
|
-
const connection = {
|
|
202
|
-
id: 'srv',
|
|
203
|
-
recycled: 0,
|
|
204
|
-
readied: 0,
|
|
205
|
-
pauseDataPlane() { },
|
|
206
|
-
readyControlPlane() { },
|
|
207
|
-
ready() { this.readied++; },
|
|
208
|
-
async reconnectAfterFailure() { this.recycled++; },
|
|
209
|
-
};
|
|
210
|
-
const fw = internals(framework);
|
|
211
|
-
fw.mcplServerRegistry = { getAllServers: () => [connection], closeAll: async () => { } };
|
|
212
|
-
const failures = [];
|
|
213
|
-
framework.onTrace((event) => {
|
|
214
|
-
if (event.type === 'mcpl:server-error')
|
|
215
|
-
failures.push(String(event.serverId));
|
|
216
|
-
});
|
|
217
|
-
framework.start();
|
|
218
|
-
await framework.quiesce();
|
|
219
|
-
// The reopen waits on the awareness barrier, which fails while stop() waits.
|
|
220
|
-
let failBarrier;
|
|
221
|
-
fw.beginDiscordAwarenessBarrier = () => ({
|
|
222
|
-
requiresBarrier: true,
|
|
223
|
-
promise: new Promise((_, reject) => { failBarrier = reject; }),
|
|
224
|
-
});
|
|
225
|
-
const resuming = framework.resume().then((status) => { order.push('resume settled'); return status; });
|
|
226
|
-
await until(() => failBarrier !== undefined, 'the resume to reach its reopen');
|
|
227
|
-
const stopping = framework.stop();
|
|
228
|
-
await releaseWhenStopWaits(() => failBarrier(new Error('the awareness drain failed')));
|
|
229
|
-
await stopping;
|
|
230
|
-
assert.deepEqual(order, ['resume settled', 'modules stopped']);
|
|
231
|
-
assert.equal((await resuming).quiesced, false, 'past its commit point the resume completes');
|
|
232
|
-
assert.deepEqual(failures, ['srv'], 'the failure is still reported');
|
|
233
|
-
assert.equal(connection.recycled, 0, 'a stopping host recycles no connection');
|
|
234
|
-
assert.equal(fw.discordAwarenessBarrier, null, 'the failed barrier is released');
|
|
235
|
-
assert.equal(connection.readied, 1, 'its data plane opens, so the listeners answer what it held back');
|
|
236
|
-
assert.equal(await bootsQuiesced(), false, 'its durable clear landed');
|
|
237
|
-
assert.deepEqual(rejections, []);
|
|
238
|
-
});
|
|
239
|
-
it("stop() waits for a host/command, so its answer goes out before the connections close", async () => {
|
|
240
|
-
const framework = await create();
|
|
241
|
-
const connection = Object.assign(new EventEmitter(), { id: 'srv' });
|
|
242
|
-
internals(framework).wireMcplEvents(connection);
|
|
243
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
244
|
-
for (const n of [1, 2]) {
|
|
245
|
-
cm.addMessage('user', [{ type: 'text', text: `m${n}` }], { serverId: 'srv', channelId: 'discord:g1:c1', messageId: `d${n}` });
|
|
246
|
-
}
|
|
247
|
-
// hide's answer carries a preview of what the agent sees now; hold it.
|
|
248
|
-
let release;
|
|
249
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
250
|
-
const preview = framework.previewActivation.bind(framework);
|
|
251
|
-
let previewing = false;
|
|
252
|
-
framework.previewActivation = (async (...args) => {
|
|
253
|
-
previewing = true;
|
|
254
|
-
await held;
|
|
255
|
-
return preview(...args);
|
|
256
|
-
});
|
|
257
|
-
const answers = [];
|
|
258
|
-
connection.emit('host-command', { command: 'hide', agentName: 'agent', fromMessageId: 'd1' }, {
|
|
259
|
-
id: 7,
|
|
260
|
-
respond: (result) => { answers.push(result); order.push('host/command answered'); },
|
|
261
|
-
respondError: (code, message) => { answers.push({ code, message }); order.push('host/command answered'); },
|
|
262
|
-
});
|
|
263
|
-
await until(() => previewing, 'hide to reach its preview');
|
|
264
|
-
const stopping = framework.stop();
|
|
265
|
-
await releaseWhenStopWaits(release);
|
|
266
|
-
await stopping;
|
|
267
|
-
assert.deepEqual(order, ['host/command answered', 'modules stopped']);
|
|
268
|
-
assert.equal(answers[0].ok, true, JSON.stringify(answers));
|
|
269
|
-
assert.equal(answers[0].hidden, 1);
|
|
270
|
-
assert.deepEqual(rejections, []);
|
|
271
|
-
});
|
|
272
|
-
it('stop() waits for a store surgery to release the store', async () => {
|
|
273
|
-
const framework = await create();
|
|
274
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
275
|
-
const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: `m${n}` }]));
|
|
276
|
-
// The rollback moves the branch while it holds the store; hold that.
|
|
277
|
-
let release;
|
|
278
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
279
|
-
let switching = false;
|
|
280
|
-
const switchBranch = cm.switchBranch.bind(cm);
|
|
281
|
-
cm.switchBranch = async (...args) => {
|
|
282
|
-
switching = true;
|
|
283
|
-
await held;
|
|
284
|
-
const switched = await switchBranch(...args);
|
|
285
|
-
order.push('branch moved');
|
|
286
|
-
return switched;
|
|
287
|
-
};
|
|
288
|
-
const rolling = framework.rollbackToMessage('agent', { messageId: ids[0] });
|
|
289
|
-
await until(() => switching, 'the rollback to reach its branch move');
|
|
290
|
-
const stopping = framework.stop();
|
|
291
|
-
await releaseWhenStopWaits(release);
|
|
292
|
-
await stopping;
|
|
293
|
-
assert.deepEqual(order, ['branch moved', 'modules stopped']);
|
|
294
|
-
assert.equal((await rolling).messagesRemoved, 2);
|
|
295
|
-
// Its marks' delivery would race the teardown, so it's left to the next start.
|
|
296
|
-
assert.ok(logged.some((line) => line.includes('delivery after rollback agent=agent not started')), logged.join('\n'));
|
|
297
|
-
assert.deepEqual(rejections, []);
|
|
298
|
-
});
|
|
299
|
-
it('stop() waits for an awareness sync already running', async () => {
|
|
300
|
-
const framework = await create();
|
|
301
|
-
let deliver;
|
|
302
|
-
internals(framework).beginDiscordAwarenessBarrier = () => ({
|
|
303
|
-
requiresBarrier: true,
|
|
304
|
-
promise: new Promise((resolve) => {
|
|
305
|
-
deliver = () => resolve({ status: 'delivered', delivered: 1, failed: 0 });
|
|
306
|
-
}),
|
|
307
|
-
});
|
|
308
|
-
const syncing = framework.syncDiscordAwarenessMarkers().then(() => { order.push('awareness synced'); });
|
|
309
|
-
await until(() => deliver !== undefined, 'the sync to wait on its barrier');
|
|
310
|
-
const stopping = framework.stop();
|
|
311
|
-
await releaseWhenStopWaits(() => deliver());
|
|
312
|
-
await stopping;
|
|
313
|
-
await syncing;
|
|
314
|
-
assert.deepEqual(order, ['awareness synced', 'modules stopped']);
|
|
315
|
-
assert.deepEqual(rejections, []);
|
|
316
|
-
});
|
|
317
|
-
it("a stop() called from a trace inside stop()'s own start gets the same attempt, and one teardown runs", async () => {
|
|
318
|
-
const framework = await create();
|
|
319
|
-
const fw = framework;
|
|
320
|
-
// A coalescer with a render in flight reports it from suspend(), the first
|
|
321
|
-
// thing stop() does, as a trace.
|
|
322
|
-
let suspended = false;
|
|
323
|
-
fw.pushCoalescer = {
|
|
324
|
-
suspend: () => {
|
|
325
|
-
if (suspended)
|
|
326
|
-
return;
|
|
327
|
-
suspended = true;
|
|
328
|
-
fw.emitTrace({ type: 'mcpl:coalescing', phase: 'suspended' });
|
|
329
|
-
},
|
|
330
|
-
};
|
|
331
|
-
// A turn to undo, so an admitted undo would move the branch.
|
|
332
|
-
const record = framework.recordTurnCheckpoint.bind(framework);
|
|
333
|
-
record('agent');
|
|
334
|
-
framework.getAgent('agent').getContextManager().addMessage('user', [{ type: 'text', text: 'a turn' }]);
|
|
335
|
-
const connection = Object.assign(new EventEmitter(), { id: 'srv' });
|
|
336
|
-
internals(framework).wireMcplEvents(connection);
|
|
337
|
-
let barriers = 0;
|
|
338
|
-
internals(framework).beginDiscordAwarenessBarrier = () => {
|
|
339
|
-
barriers++;
|
|
340
|
-
return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
|
|
341
|
-
};
|
|
342
|
-
let inner;
|
|
343
|
-
let undoInside;
|
|
344
|
-
let syncInside;
|
|
345
|
-
let hostUndo;
|
|
346
|
-
framework.onTrace((event) => {
|
|
347
|
-
if (event.type !== 'mcpl:coalescing' || inner)
|
|
348
|
-
return;
|
|
349
|
-
inner = framework.stop();
|
|
350
|
-
// stop() has begun, though its queue isn't closed yet.
|
|
351
|
-
try {
|
|
352
|
-
framework.undoLastTurn('agent');
|
|
353
|
-
}
|
|
354
|
-
catch (error) {
|
|
355
|
-
undoInside = error;
|
|
356
|
-
}
|
|
357
|
-
syncInside = framework.syncDiscordAwarenessMarkers();
|
|
358
|
-
void syncInside.catch(() => { });
|
|
359
|
-
framework.startDiscordAwarenessDelivery('probe');
|
|
360
|
-
connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 1 }, {
|
|
361
|
-
respond: (result) => { hostUndo = { respond: result }; },
|
|
362
|
-
respondError: (code, message) => { hostUndo = { code, message }; },
|
|
363
|
-
});
|
|
364
|
-
});
|
|
365
|
-
const outer = framework.stop();
|
|
366
|
-
assert.equal(inner, outer, 'the reentrant stop() gets the attempt already running');
|
|
367
|
-
assert.match(String(undoInside), /^Error: undo refused: the framework is stopping$/);
|
|
368
|
-
await assert.rejects(syncInside, /^Error: awareness sync refused: the framework is stopping$/);
|
|
369
|
-
assert.ok(logged.some((line) => line.includes('delivery after probe agent=framework not started')), logged.join('\n'));
|
|
370
|
-
assert.equal(barriers, 0, 'neither the sync nor the delivery reached a barrier');
|
|
371
|
-
assert.deepEqual(hostUndo, { code: -32000, message: 'the host is stopping' });
|
|
372
|
-
assert.equal(framework.getStore().currentBranch().name, 'main', 'nothing moved the branch');
|
|
373
|
-
await outer;
|
|
374
|
-
assert.deepEqual(order, ['modules stopped'], 'one teardown');
|
|
375
|
-
assert.equal(framework.getStore().isClosed(), true);
|
|
376
|
-
await framework.stop();
|
|
377
|
-
assert.deepEqual(rejections, []);
|
|
378
|
-
});
|
|
379
|
-
it('an awareness sync after a stop() that failed is refused', async () => {
|
|
380
|
-
const framework = await create();
|
|
381
|
-
const fw = framework;
|
|
382
|
-
// A runner whose dispose throws fails stop() after the queue has closed,
|
|
383
|
-
// before stop() reaches its wait on the operator set.
|
|
384
|
-
fw.codeExecutionRunners.set('agent', { dispose() { throw new Error('dispose failed'); } });
|
|
385
|
-
await assert.rejects(framework.stop(), /dispose failed/);
|
|
386
|
-
await assert.rejects(framework.syncDiscordAwarenessMarkers(), /^Error: awareness sync refused: the framework is stopping$/);
|
|
387
|
-
fw.codeExecutionRunners.clear();
|
|
388
|
-
await framework.stop();
|
|
389
|
-
assert.equal(framework.getStore().isClosed(), true);
|
|
390
|
-
});
|
|
391
|
-
it('an awareness sync called once stop() has begun is refused, and installs no barrier', async () => {
|
|
392
|
-
const framework = await create();
|
|
393
|
-
let barriers = 0;
|
|
394
|
-
internals(framework).beginDiscordAwarenessBarrier = () => {
|
|
395
|
-
barriers++;
|
|
396
|
-
return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
|
|
397
|
-
};
|
|
398
|
-
let finishModules;
|
|
399
|
-
const hold = new Promise((resolve) => { finishModules = resolve; });
|
|
400
|
-
framework.getModule('teardown-probe').stop = async () => {
|
|
401
|
-
order.push('modules stopped');
|
|
402
|
-
await hold;
|
|
403
|
-
};
|
|
404
|
-
const stopping = framework.stop();
|
|
405
|
-
try {
|
|
406
|
-
await until(() => order.includes('modules stopped'), 'module teardown');
|
|
407
|
-
await assert.rejects(framework.syncDiscordAwarenessMarkers(), /^Error: awareness sync refused: the framework is stopping$/);
|
|
408
|
-
assert.equal(barriers, 0);
|
|
409
|
-
}
|
|
410
|
-
finally {
|
|
411
|
-
finishModules();
|
|
412
|
-
await stopping;
|
|
413
|
-
}
|
|
414
|
-
await assert.rejects(framework.syncDiscordAwarenessMarkers(), /^Error: awareness sync refused: the framework is stopping$/);
|
|
415
|
-
assert.equal(barriers, 0);
|
|
416
|
-
});
|
|
417
|
-
for (const action of ['rollback', 'suppress'])
|
|
418
|
-
it('a ' + action + " whose branch move outlasts stop()'s budget still finishes, and leaves its marks' delivery to the next start", { timeout: 20_000 }, async () => {
|
|
419
|
-
// The surgery was admitted before stop() began, so nothing refuses it
|
|
420
|
-
// partway. Its marks' delivery isn't started while the framework stops:
|
|
421
|
-
// the durable outbox keeps them for the next start.
|
|
422
|
-
const framework = await create();
|
|
423
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
424
|
-
const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
|
|
425
|
-
let finishMove;
|
|
426
|
-
const moveHold = new Promise((resolve) => { finishMove = resolve; });
|
|
427
|
-
if (action === 'rollback') {
|
|
428
|
-
const switchBranch = cm.switchBranch.bind(cm);
|
|
429
|
-
cm.switchBranch = async (...args) => { await moveHold; return switchBranch(...args); };
|
|
430
|
-
}
|
|
431
|
-
else {
|
|
432
|
-
const fork = cm.fork.bind(cm);
|
|
433
|
-
cm.fork = async (...args) => { await moveHold; return fork(...args); };
|
|
434
|
-
}
|
|
435
|
-
let barriers = 0;
|
|
436
|
-
internals(framework).beginDiscordAwarenessBarrier = () => {
|
|
437
|
-
barriers++;
|
|
438
|
-
return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
|
|
439
|
-
};
|
|
440
|
-
const surgery = action === 'rollback'
|
|
441
|
-
? framework.rollbackToMessage('agent', { messageId: ids[0] })
|
|
442
|
-
: framework.suppressMessages('agent', { messageIds: [ids[1]] });
|
|
443
|
-
void surgery.catch(() => { });
|
|
444
|
-
try {
|
|
445
|
-
await assert.rejects(framework.stop(100), (error) => error instanceof ShutdownTimeoutError && error.pending.includes('surgery:' + (action === 'rollback' ? 'roll back' : 'suppress')));
|
|
446
|
-
}
|
|
447
|
-
finally {
|
|
448
|
-
finishMove();
|
|
449
|
-
}
|
|
450
|
-
const result = await surgery;
|
|
451
|
-
assert.ok(result.messagesRemoved > 0, JSON.stringify(result));
|
|
452
|
-
assert.equal(barriers, 0, 'no delivery started while the framework stops');
|
|
453
|
-
assert.ok(logged.some((line) => line.includes('delivery after ' + action + ' agent=agent not started')), logged.join('\n'));
|
|
454
|
-
await framework.stop();
|
|
455
|
-
assert.equal(framework.getStore().isClosed(), true);
|
|
456
|
-
assert.deepEqual(rejections, []);
|
|
457
|
-
});
|
|
458
|
-
it("an operation that outlasts stop()'s budget fails the stop and keeps the store open for a retry", async () => {
|
|
459
|
-
const framework = await create();
|
|
460
|
-
let deliver;
|
|
461
|
-
internals(framework).beginDiscordAwarenessBarrier = () => ({
|
|
462
|
-
requiresBarrier: true,
|
|
463
|
-
promise: new Promise((resolve) => {
|
|
464
|
-
deliver = () => resolve({ status: 'delivered', delivered: 1, failed: 0 });
|
|
465
|
-
}),
|
|
466
|
-
});
|
|
467
|
-
const syncing = framework.syncDiscordAwarenessMarkers();
|
|
468
|
-
await until(() => deliver !== undefined, 'the sync to wait on its barrier');
|
|
469
|
-
await assert.rejects(framework.stop(100), (error) => error instanceof ShutdownTimeoutError
|
|
470
|
-
&& error.pending.includes('awareness:sync')
|
|
471
|
-
&& /^Shutdown timed out after 100 ms; pending: awareness:sync$/.test(error.message));
|
|
472
|
-
assert.equal(framework.getStore().isClosed(), false, 'the operation may still write');
|
|
473
|
-
assert.ok(order.includes('modules stopped'), 'timeout still proceeds with teardown');
|
|
474
|
-
// Bounded: a sync admitted here would wait on a barrier of its own, so it
|
|
475
|
-
// fails the test rather than hanging it.
|
|
476
|
-
const late = framework.syncDiscordAwarenessMarkers().then(() => 'admitted', (error) => String(error));
|
|
477
|
-
const stillRunning = new Promise((resolve) => { setTimeout(() => resolve('still running'), 1_000).unref(); });
|
|
478
|
-
assert.equal(await Promise.race([late, stillRunning]), 'Error: awareness sync refused: the framework is stopping', 'no stop() is waiting now, so a new sync is refused');
|
|
479
|
-
await assert.rejects(framework.stop(100), (error) => error instanceof ShutdownTimeoutError && error.pending.includes('awareness:sync'));
|
|
480
|
-
assert.equal(framework.getStore().isClosed(), false, 'a still-running retry keeps the store open too');
|
|
481
|
-
deliver();
|
|
482
|
-
await syncing;
|
|
483
|
-
await framework.stop();
|
|
484
|
-
assert.equal(framework.getStore().isClosed(), true);
|
|
485
|
-
assert.deepEqual(rejections, []);
|
|
486
|
-
});
|
|
487
|
-
const lateCalls = [
|
|
488
|
-
['quiesce', (f) => f.quiesce()],
|
|
489
|
-
['resume', (f) => f.resume()],
|
|
490
|
-
['roll back', (f) => f.rollbackToMessage('agent', { messageId: 'invalid' })],
|
|
491
|
-
['suppress', (f) => f.suppressMessages('agent', { messageIds: ['invalid'] })],
|
|
492
|
-
['undo', (f) => f.undoLastTurn('agent')],
|
|
493
|
-
['redo', (f) => f.redo('agent')],
|
|
494
|
-
['maintain', (f) => f.maintenanceTick()],
|
|
495
|
-
['puppet', (f) => f.puppetToolCall('agent', 'unused', {})],
|
|
496
|
-
['switch branch', (f) => f.switchBranch('main')],
|
|
497
|
-
['connect MCPL server', (f) => f.connectMcplServer({ id: 'late', command: 'unused' })],
|
|
498
|
-
['disconnect MCPL server', (f) => f.disconnectMcplServer('late')],
|
|
499
|
-
['restart MCPL server', (f) => f.restartMcplServer('late')],
|
|
500
|
-
['awareness sync', (f) => f.syncDiscordAwarenessMarkers()],
|
|
501
|
-
];
|
|
502
|
-
for (const [verb, call] of lateCalls) {
|
|
503
|
-
it(verb + ' is refused during teardown and after stop(), with no writes and no operator log', async () => {
|
|
504
|
-
const framework = await create();
|
|
505
|
-
let backendCalls = 0;
|
|
506
|
-
Object.assign(internals(framework), {
|
|
507
|
-
mcplHostCapabilities: {},
|
|
508
|
-
mcplServerRegistry: {
|
|
509
|
-
getAllServers: () => [], closeAll: async () => { },
|
|
510
|
-
removeServer: async () => { backendCalls++; },
|
|
511
|
-
},
|
|
512
|
-
connectMcplServerInternal: async () => { backendCalls++; },
|
|
513
|
-
refreshMcplTools: async () => { backendCalls++; },
|
|
514
|
-
emitMcplToolDiff: () => { backendCalls++; },
|
|
515
|
-
});
|
|
516
|
-
let finishModules;
|
|
517
|
-
const hold = new Promise((resolve) => { finishModules = resolve; });
|
|
518
|
-
framework.getModule('teardown-probe').stop = async () => {
|
|
519
|
-
order.push('modules stopped');
|
|
520
|
-
await hold;
|
|
521
|
-
};
|
|
522
|
-
const stopping = framework.stop();
|
|
523
|
-
await until(() => order.includes('modules stopped'), 'module teardown');
|
|
524
|
-
const sequence = framework.getStore().currentSequence();
|
|
525
|
-
const branch = framework.getStore().currentBranch().name;
|
|
526
|
-
const logPath = framework.getOperatorLogPath();
|
|
527
|
-
const log = () => existsSync(logPath) ? readFileSync(logPath, 'utf8') : '';
|
|
528
|
-
const beforeLog = log();
|
|
529
|
-
const refused = async () => assert.rejects(Promise.resolve().then(() => call(framework)), (error) => error instanceof Error && error.message === verb + ' refused: the framework is stopping');
|
|
530
|
-
try {
|
|
531
|
-
await refused();
|
|
532
|
-
assert.equal(framework.getStore().currentSequence(), sequence);
|
|
533
|
-
assert.equal(framework.getStore().currentBranch().name, branch);
|
|
534
|
-
assert.equal(log(), beforeLog);
|
|
535
|
-
assert.equal(backendCalls, 0);
|
|
536
|
-
}
|
|
537
|
-
finally {
|
|
538
|
-
finishModules();
|
|
539
|
-
await stopping;
|
|
540
|
-
}
|
|
541
|
-
await refused();
|
|
542
|
-
assert.equal(log(), beforeLog);
|
|
543
|
-
});
|
|
544
|
-
}
|
|
545
|
-
it('a resume called once stop() has begun refuses before a held maintenance pass ends', async () => {
|
|
546
|
-
const framework = await create();
|
|
547
|
-
await framework.quiesce();
|
|
548
|
-
let endPass;
|
|
549
|
-
internals(framework).maintenancePass = new Promise((resolve) => { endPass = resolve; });
|
|
550
|
-
const stopping = framework.stop();
|
|
551
|
-
let settled = false;
|
|
552
|
-
const resuming = framework.resume().finally(() => { settled = true; });
|
|
553
|
-
void resuming.catch(() => { });
|
|
554
|
-
try {
|
|
555
|
-
// Admission is synchronous; promise settlement needs only its microtasks.
|
|
556
|
-
await Promise.resolve();
|
|
557
|
-
await Promise.resolve();
|
|
558
|
-
assert.equal(settled, true, 'refusal must not wait for maintenance');
|
|
559
|
-
await assert.rejects(resuming, /resume refused: the framework is stopping/);
|
|
560
|
-
}
|
|
561
|
-
finally {
|
|
562
|
-
endPass();
|
|
563
|
-
await stopping;
|
|
564
|
-
await resuming.catch(() => { });
|
|
565
|
-
}
|
|
566
|
-
});
|
|
567
|
-
it('a resume checks again after its preview retries, and refuses when stop() began during them', async () => {
|
|
568
|
-
const framework = await create();
|
|
569
|
-
await framework.quiesce();
|
|
570
|
-
let previewed = false;
|
|
571
|
-
framework.previewAgentRuntimeSettings = (() => {
|
|
572
|
-
previewed = true;
|
|
573
|
-
return { available: false, reason: 'preview_in_flight', path: 'none', liveBudgetTokens: 0, transition: 'stable' };
|
|
574
|
-
});
|
|
575
|
-
const resuming = framework.resume();
|
|
576
|
-
void resuming.catch(() => { });
|
|
577
|
-
assert.equal(previewed, true);
|
|
578
|
-
const stopping = framework.stop();
|
|
579
|
-
await assert.rejects(resuming, /resume refused: the framework is stopping/);
|
|
580
|
-
await stopping;
|
|
581
|
-
assert.equal(await bootsQuiesced(), true);
|
|
582
|
-
});
|
|
583
|
-
it('a resume whose reopen succeeds while stop() waits releases the barrier and opens the data plane', async () => {
|
|
584
|
-
// The listeners answer whatever the pause held back with their stopping
|
|
585
|
-
// refusal, so the stopping host opens its planes as a serving one does.
|
|
586
|
-
const framework = await create();
|
|
587
|
-
let ready = 0;
|
|
588
|
-
const connection = {
|
|
589
|
-
id: 'srv', pauseDataPlane() { }, readyControlPlane() { },
|
|
590
|
-
ready() { ready++; },
|
|
591
|
-
};
|
|
592
|
-
const fw = internals(framework);
|
|
593
|
-
fw.mcplServerRegistry = { getAllServers: () => [connection], closeAll: async () => { } };
|
|
594
|
-
await framework.quiesce();
|
|
595
|
-
let deliver;
|
|
596
|
-
fw.beginDiscordAwarenessBarrier = () => ({
|
|
597
|
-
requiresBarrier: true,
|
|
598
|
-
promise: new Promise((resolve) => { deliver = () => resolve({ status: 'delivered', delivered: 0, failed: 0 }); }),
|
|
599
|
-
});
|
|
600
|
-
const resuming = framework.resume();
|
|
601
|
-
await until(() => deliver !== undefined, 'resume barrier');
|
|
602
|
-
const stopping = framework.stop();
|
|
603
|
-
await releaseWhenStopWaits(deliver);
|
|
604
|
-
await resuming;
|
|
605
|
-
await stopping;
|
|
606
|
-
assert.equal(ready, 1);
|
|
607
|
-
assert.equal(fw.discordAwarenessBarrier, null);
|
|
608
|
-
assert.ok(logged.some((line) => line.includes("parked wake(s) won't run") && line.includes('stopping')));
|
|
609
|
-
assert.equal(await bootsQuiesced(), false);
|
|
610
|
-
});
|
|
611
|
-
it('stop() waits for a puppet tool call, so it finishes before the modules stop', { timeout: 20_000 }, async () => {
|
|
612
|
-
const framework = await create();
|
|
613
|
-
const fw = framework;
|
|
614
|
-
let release;
|
|
615
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
616
|
-
let called = false;
|
|
617
|
-
fw.getToolsForAgent = () => [{ name: 'probe' }];
|
|
618
|
-
fw.executeToolCall = async () => {
|
|
619
|
-
called = true;
|
|
620
|
-
await held;
|
|
621
|
-
order.push('tool returned');
|
|
622
|
-
return { success: true, data: 'done' };
|
|
623
|
-
};
|
|
624
|
-
// The pair's two writes are what the wait protects.
|
|
625
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
626
|
-
const addMessage = cm.addMessage.bind(cm);
|
|
627
|
-
cm.addMessage = ((...args) => {
|
|
628
|
-
const id = addMessage(...args);
|
|
629
|
-
order.push('message stored');
|
|
630
|
-
return id;
|
|
631
|
-
});
|
|
632
|
-
const puppeting = framework.puppetToolCall('agent', 'probe', {});
|
|
633
|
-
void puppeting.catch(() => { });
|
|
634
|
-
await until(() => called, 'the puppet call to reach its tool');
|
|
635
|
-
const stopping = framework.stop();
|
|
636
|
-
await releaseWhenStopWaits(release);
|
|
637
|
-
const { toolUseId } = await puppeting;
|
|
638
|
-
await stopping;
|
|
639
|
-
assert.match(toolUseId, /^toolu_01/);
|
|
640
|
-
assert.deepEqual(order, ['tool returned', 'message stored', 'message stored', 'modules stopped']);
|
|
641
|
-
assert.deepEqual(rejections, []);
|
|
642
|
-
});
|
|
643
|
-
it("stop() waits for a branch switch from the API server, its config mount included", { timeout: 20_000 }, async () => {
|
|
644
|
-
const framework = await create();
|
|
645
|
-
const api = new ApiServer(framework);
|
|
646
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
647
|
-
const fw = internals(framework);
|
|
648
|
-
let release;
|
|
649
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
650
|
-
let mounting = false;
|
|
651
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
652
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
653
|
-
materializeMount: async () => { mounting = true; await held; order.push('config materialized'); },
|
|
654
|
-
} : getModule(name);
|
|
655
|
-
const switching = api.cmdBranchSwitch({ name: 'side' });
|
|
656
|
-
void switching.catch(() => { });
|
|
657
|
-
await until(() => mounting, 'the switch to reach its config mount');
|
|
658
|
-
const stopping = framework.stop();
|
|
659
|
-
await releaseWhenStopWaits(release);
|
|
660
|
-
await switching;
|
|
661
|
-
await stopping;
|
|
662
|
-
assert.deepEqual(order, ['config materialized', 'modules stopped']);
|
|
663
|
-
assert.deepEqual(rejections, []);
|
|
664
|
-
});
|
|
665
|
-
it("the API server's current branch follows the store when a switch fails after moving it, and clients hear of the move", async () => {
|
|
666
|
-
const framework = await create();
|
|
667
|
-
try {
|
|
668
|
-
const api = new ApiServer(framework);
|
|
669
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
670
|
-
const broadcasts = [];
|
|
671
|
-
api.broadcast = (event, data) => { broadcasts.push([event, data]); };
|
|
672
|
-
const fw = internals(framework);
|
|
673
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
674
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
675
|
-
materializeMount: async () => { throw new Error('disk full'); },
|
|
676
|
-
} : getModule(name);
|
|
677
|
-
await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /disk full/);
|
|
678
|
-
assert.equal(framework.getStore().currentBranch().name, 'side');
|
|
679
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'side');
|
|
680
|
-
assert.deepEqual(broadcasts, [['branch:switched', { from: 'main', to: 'side' }]]);
|
|
681
|
-
}
|
|
682
|
-
finally {
|
|
683
|
-
await framework.stop();
|
|
684
|
-
}
|
|
685
|
-
});
|
|
686
|
-
it("a successful switch from the API server names the store's branch as where it moved from, even with a stale cache", async () => {
|
|
687
|
-
const framework = await create();
|
|
688
|
-
try {
|
|
689
|
-
const api = new ApiServer(framework);
|
|
690
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
691
|
-
const broadcasts = [];
|
|
692
|
-
api.broadcast = (event, data) => { broadcasts.push([event, data]); };
|
|
693
|
-
// As after a rollback made outside the API server.
|
|
694
|
-
api.lastKnownBranch = 'stale';
|
|
695
|
-
await api.cmdBranchSwitch({ name: 'side' });
|
|
696
|
-
assert.deepEqual(broadcasts, [['branch:switched', { from: 'main', to: 'side' }]]);
|
|
697
|
-
}
|
|
698
|
-
finally {
|
|
699
|
-
await framework.stop();
|
|
700
|
-
}
|
|
701
|
-
});
|
|
702
|
-
it('a switch from the API server that waits for running maintenance names the branch it moved to, and the current branch is the store\'s throughout', async () => {
|
|
703
|
-
const framework = await create();
|
|
704
|
-
try {
|
|
705
|
-
const api = new ApiServer(framework);
|
|
706
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
707
|
-
const broadcasts = [];
|
|
708
|
-
api.broadcast = (event, data) => { broadcasts.push([event, data]); };
|
|
709
|
-
// A maintenance pass still running: the switch moves the store once it ends.
|
|
710
|
-
let finish;
|
|
711
|
-
internals(framework).maintenancePass = new Promise((resolve) => { finish = resolve; });
|
|
712
|
-
const switching = api.cmdBranchSwitch({ name: 'side' });
|
|
713
|
-
await new Promise((resolve) => setTimeout(resolve, 20));
|
|
714
|
-
assert.equal(framework.getStore().currentBranch().name, 'main', 'the switch waits for the pass');
|
|
715
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'main');
|
|
716
|
-
assert.deepEqual(broadcasts, []);
|
|
717
|
-
finish();
|
|
718
|
-
internals(framework).maintenancePass = null;
|
|
719
|
-
await switching;
|
|
720
|
-
assert.equal(framework.getStore().currentBranch().name, 'side');
|
|
721
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'side');
|
|
722
|
-
assert.deepEqual(broadcasts, [['branch:switched', { from: 'main', to: 'side' }]]);
|
|
723
|
-
}
|
|
724
|
-
finally {
|
|
725
|
-
await framework.stop();
|
|
726
|
-
}
|
|
727
|
-
});
|
|
728
|
-
it('two API switches handled together each announce their own move', async () => {
|
|
729
|
-
// With no workspace module, a switch holds the store for no await, so a
|
|
730
|
-
// second one can move the store before the first's continuation runs.
|
|
731
|
-
const framework = await create();
|
|
732
|
-
try {
|
|
733
|
-
const api = new ApiServer(framework);
|
|
734
|
-
await api.cmdBranchCreate({ name: 'a' });
|
|
735
|
-
await api.cmdBranchCreate({ name: 'b' });
|
|
736
|
-
const broadcasts = [];
|
|
737
|
-
api.broadcast = (event, data) => { broadcasts.push([event, data]); };
|
|
738
|
-
await Promise.all([api.cmdBranchSwitch({ name: 'a' }), api.cmdBranchSwitch({ name: 'b' })]);
|
|
739
|
-
assert.deepEqual(broadcasts, [
|
|
740
|
-
['branch:switched', { from: 'main', to: 'a' }],
|
|
741
|
-
['branch:switched', { from: 'a', to: 'b' }],
|
|
742
|
-
]);
|
|
743
|
-
assert.equal(framework.getStore().currentBranch().name, 'b');
|
|
744
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'b');
|
|
745
|
-
}
|
|
746
|
-
finally {
|
|
747
|
-
await framework.stop();
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
|
-
it("the API server's current branch is the store's while a switch is still running", { timeout: 20_000 }, async () => {
|
|
751
|
-
const framework = await create();
|
|
752
|
-
try {
|
|
753
|
-
const api = new ApiServer(framework);
|
|
754
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
755
|
-
const fw = internals(framework);
|
|
756
|
-
let release;
|
|
757
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
758
|
-
let mounting = false;
|
|
759
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
760
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
761
|
-
materializeMount: async () => { mounting = true; await held; },
|
|
762
|
-
} : getModule(name);
|
|
763
|
-
const switching = api.cmdBranchSwitch({ name: 'side' });
|
|
764
|
-
try {
|
|
765
|
-
await until(() => mounting, 'the switch to reach its config mount');
|
|
766
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'side');
|
|
767
|
-
await assert.rejects(api.cmdBranchDelete({ name: 'side' }), /Cannot delete current branch/);
|
|
768
|
-
// The switch holds the store through its mount.
|
|
769
|
-
assert.throws(() => framework.undoLastTurn('agent'), (error) => error instanceof OperatorActionError
|
|
770
|
-
&& error.code === 'agent-busy' && error.message === 'Cannot undo: the store is under live switch branch for every agent');
|
|
771
|
-
assert.throws(() => framework.redo('agent'), (error) => error instanceof OperatorActionError
|
|
772
|
-
&& error.code === 'agent-busy' && error.message === 'Cannot redo: the store is under live switch branch for every agent');
|
|
773
|
-
// A host/command undo in turns mode answers the refusal with its code.
|
|
774
|
-
const connection = Object.assign(new EventEmitter(), { id: 'srv' });
|
|
775
|
-
fw.wireMcplEvents(connection);
|
|
776
|
-
let answer;
|
|
777
|
-
connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 1 }, {
|
|
778
|
-
id: 11,
|
|
779
|
-
respond: (result) => { answer = result; },
|
|
780
|
-
respondError: (error) => { answer = { respondError: String(error) }; },
|
|
781
|
-
});
|
|
782
|
-
await until(() => answer !== undefined, 'the host/command undo to answer');
|
|
783
|
-
assert.deepEqual(answer, {
|
|
784
|
-
ok: false,
|
|
785
|
-
error: 'Cannot undo: the store is under live switch branch for every agent',
|
|
786
|
-
code: 'agent-busy',
|
|
787
|
-
});
|
|
788
|
-
}
|
|
789
|
-
finally {
|
|
790
|
-
release();
|
|
791
|
-
}
|
|
792
|
-
await switching;
|
|
793
|
-
}
|
|
794
|
-
finally {
|
|
795
|
-
await framework.stop();
|
|
796
|
-
}
|
|
797
|
-
});
|
|
798
|
-
it("switchBranch() starts the marks' delivery on the branch it moved to", async () => {
|
|
799
|
-
const framework = await create();
|
|
800
|
-
try {
|
|
801
|
-
const api = new ApiServer(framework);
|
|
802
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
803
|
-
const reconciledOn = [];
|
|
804
|
-
internals(framework).beginDiscordAwarenessBarrier = () => {
|
|
805
|
-
reconciledOn.push(framework.getStore().currentBranch().name);
|
|
806
|
-
return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
|
|
807
|
-
};
|
|
808
|
-
await framework.switchBranch('side');
|
|
809
|
-
assert.deepEqual(reconciledOn, ['side']);
|
|
810
|
-
}
|
|
811
|
-
finally {
|
|
812
|
-
await framework.stop();
|
|
813
|
-
}
|
|
814
|
-
});
|
|
815
|
-
it("stop() doesn't wait for the marks' delivery a branch switch started", { timeout: 20_000 }, async () => {
|
|
816
|
-
const framework = await create();
|
|
817
|
-
const api = new ApiServer(framework);
|
|
818
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
819
|
-
let delivering = false;
|
|
820
|
-
internals(framework).beginDiscordAwarenessBarrier = () => {
|
|
821
|
-
delivering = true;
|
|
822
|
-
// A delivery that never ends, as a drain to an unreachable server might.
|
|
823
|
-
return { requiresBarrier: true, promise: new Promise(() => { }) };
|
|
824
|
-
};
|
|
825
|
-
await framework.switchBranch('side');
|
|
826
|
-
assert.equal(delivering, true, 'the switch started the delivery and answered without it');
|
|
827
|
-
// A budget, so a stop() that waited for the delivery would fail rather than
|
|
828
|
-
// hang, with room for an ordinary teardown on a loaded runner.
|
|
829
|
-
await framework.stop(5_000);
|
|
830
|
-
assert.ok(order.includes('modules stopped'));
|
|
831
|
-
assert.equal(framework.getStore().isClosed(), true);
|
|
832
|
-
assert.deepEqual(rejections, []);
|
|
833
|
-
});
|
|
834
|
-
it('a branch switch during a live turn is refused, and the branch stays', async () => {
|
|
835
|
-
const framework = await create();
|
|
836
|
-
const api = new ApiServer(framework);
|
|
837
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
838
|
-
const broadcasts = [];
|
|
839
|
-
api.broadcast = (event, data) => { broadcasts.push([event, data]); };
|
|
840
|
-
// A stale cache, as after a rollback made outside the API server.
|
|
841
|
-
api.lastKnownBranch = 'stale';
|
|
842
|
-
// A turn holds its token from dequeue, before its stream registers.
|
|
843
|
-
const tokens = internals(framework).activeTurnTokens;
|
|
844
|
-
tokens.set('agent', -1);
|
|
845
|
-
try {
|
|
846
|
-
await assert.rejects(framework.switchBranch('side'), /^OperatorActionError: Cannot switch branch while agent is idle\+turn-alive/);
|
|
847
|
-
await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /Cannot switch branch while agent is idle\+turn-alive/);
|
|
848
|
-
assert.equal(framework.getStore().currentBranch().name, 'main');
|
|
849
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'main');
|
|
850
|
-
assert.deepEqual(broadcasts, [], 'a refused switch moved nothing, so it announces nothing');
|
|
851
|
-
}
|
|
852
|
-
finally {
|
|
853
|
-
tokens.delete('agent');
|
|
854
|
-
}
|
|
855
|
-
await framework.stop();
|
|
856
|
-
});
|
|
857
|
-
it('a branch switch from the API server once stop() has begun is refused, and the branch stays', async () => {
|
|
858
|
-
const framework = await create();
|
|
859
|
-
const api = new ApiServer(framework);
|
|
860
|
-
await api.cmdBranchCreate({ name: 'side' });
|
|
861
|
-
let finishModules;
|
|
862
|
-
const hold = new Promise((resolve) => { finishModules = resolve; });
|
|
863
|
-
framework.getModule('teardown-probe').stop = async () => {
|
|
864
|
-
order.push('modules stopped');
|
|
865
|
-
await hold;
|
|
866
|
-
};
|
|
867
|
-
const stopping = framework.stop();
|
|
868
|
-
try {
|
|
869
|
-
await until(() => order.includes('modules stopped'), 'module teardown');
|
|
870
|
-
await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /^Error: switch branch refused: the framework is stopping$/);
|
|
871
|
-
assert.equal(framework.getStore().currentBranch().name, 'main');
|
|
872
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'main');
|
|
873
|
-
}
|
|
874
|
-
finally {
|
|
875
|
-
finishModules();
|
|
876
|
-
await stopping;
|
|
877
|
-
}
|
|
878
|
-
// With the store closed too, the refusal is what the caller sees.
|
|
879
|
-
await assert.rejects(api.cmdBranchSwitch({ name: 'side' }), /^Error: switch branch refused: the framework is stopping$/);
|
|
880
|
-
assert.equal((await api.cmdBranchCurrent()).name, 'main');
|
|
881
|
-
});
|
|
882
|
-
for (const action of ['connect', 'disconnect', 'restart']) {
|
|
883
|
-
it('stop() waits for an MCPL ' + action + ' already running before it closes the connections', async () => {
|
|
884
|
-
const framework = await create();
|
|
885
|
-
const fw = framework;
|
|
886
|
-
let release;
|
|
887
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
888
|
-
let entered = false;
|
|
889
|
-
let connected = action !== 'connect';
|
|
890
|
-
fw.mcplHostCapabilities = {};
|
|
891
|
-
fw.mcplServerConfigs.set('srv', { id: 'srv', command: 'unused' });
|
|
892
|
-
fw.connectMcplServerInternal = async () => {
|
|
893
|
-
entered = true;
|
|
894
|
-
await held;
|
|
895
|
-
connected = true;
|
|
896
|
-
order.push('connection opened');
|
|
897
|
-
};
|
|
898
|
-
fw.refreshMcplTools = async () => { };
|
|
899
|
-
fw.emitMcplToolDiff = () => { };
|
|
900
|
-
fw.mcplServerRegistry = {
|
|
901
|
-
getAllServers: () => [],
|
|
902
|
-
removeServer: async () => {
|
|
903
|
-
entered = true;
|
|
904
|
-
await held;
|
|
905
|
-
connected = false;
|
|
906
|
-
order.push('connection removed');
|
|
907
|
-
},
|
|
908
|
-
closeAll: async () => { connected = false; order.push('connections closed'); },
|
|
909
|
-
};
|
|
910
|
-
const running = action === 'connect' ? framework.connectMcplServer({ id: 'srv', command: 'unused' })
|
|
911
|
-
: action === 'disconnect' ? framework.disconnectMcplServer('srv') : framework.restartMcplServer('srv');
|
|
912
|
-
void running.catch(() => { });
|
|
913
|
-
await until(() => entered, 'MCPL operation');
|
|
914
|
-
const stopping = framework.stop();
|
|
915
|
-
await releaseWhenStopWaits(release);
|
|
916
|
-
await running;
|
|
917
|
-
await stopping;
|
|
918
|
-
assert.equal(connected, false);
|
|
919
|
-
const settled = action === 'disconnect' ? 'connection removed' : 'connection opened';
|
|
920
|
-
assert.ok(order.includes(settled) && order.indexOf(settled) < order.indexOf('modules stopped'), order.join(', '));
|
|
921
|
-
});
|
|
922
|
-
}
|
|
923
|
-
for (const action of ['undo', 'redo', 'rollback', 'suppress']) {
|
|
924
|
-
it(action + "'s config materialization doesn't hold its caller, and stop() waits for it", { timeout: 20_000 }, async () => {
|
|
925
|
-
const framework = await create();
|
|
926
|
-
const fw = internals(framework);
|
|
927
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
928
|
-
const sequenceBefore = framework.getStore().currentSequence();
|
|
929
|
-
const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
|
|
930
|
-
fw.saveTurnCheckpoints('agent', [{ agentName: 'agent', turnIndex: 1, sequenceBefore, branchName: 'main', timestamp: Date.now() }]);
|
|
931
|
-
if (action === 'redo')
|
|
932
|
-
framework.undoLastTurn('agent');
|
|
933
|
-
let release;
|
|
934
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
935
|
-
let materializing = false;
|
|
936
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
937
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
938
|
-
materializeMount: async () => { materializing = true; await held; order.push('config materialized'); },
|
|
939
|
-
} : getModule(name);
|
|
940
|
-
if (action === 'undo')
|
|
941
|
-
framework.undoLastTurn('agent');
|
|
942
|
-
else if (action === 'redo')
|
|
943
|
-
framework.redo('agent');
|
|
944
|
-
else if (action === 'rollback')
|
|
945
|
-
await framework.rollbackToMessage('agent', { messageId: ids[0] });
|
|
946
|
-
else
|
|
947
|
-
await framework.suppressMessages('agent', { messageIds: [ids[1]] });
|
|
948
|
-
assert.equal(materializing, true, 'the caller returned before file IO settled');
|
|
949
|
-
const stopping = framework.stop();
|
|
950
|
-
await releaseWhenStopWaits(release);
|
|
951
|
-
await stopping;
|
|
952
|
-
assert.deepEqual(order, ['config materialized', 'modules stopped']);
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
it('a config materialization that fails is logged, and its undo still succeeds', async () => {
|
|
956
|
-
const framework = await create();
|
|
957
|
-
const fw = internals(framework);
|
|
958
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
959
|
-
const sequenceBefore = framework.getStore().currentSequence();
|
|
960
|
-
cm.addMessage('user', [{ type: 'text', text: 'a turn' }]);
|
|
961
|
-
fw.saveTurnCheckpoints('agent', [{ agentName: 'agent', turnIndex: 1, sequenceBefore, branchName: 'main', timestamp: Date.now() }]);
|
|
962
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
963
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
964
|
-
materializeMount: async () => { throw new Error('disk full'); },
|
|
965
|
-
} : getModule(name);
|
|
966
|
-
assert.equal(framework.undoLastTurn('agent').undone, true);
|
|
967
|
-
await framework.stop();
|
|
968
|
-
assert.ok(logged.some((line) => line.includes('re-materializing the config mount after a branch switch failed') && line.includes('disk full')), logged.join('\n'));
|
|
969
|
-
assert.deepEqual(rejections, []);
|
|
970
|
-
});
|
|
971
|
-
for (const action of ['rollback', 'suppress'])
|
|
972
|
-
it('stop() also waits for the materialization a ' + action + ' in flight starts after stop() first reads the set', { timeout: 20_000 }, async () => {
|
|
973
|
-
const framework = await create();
|
|
974
|
-
const fw = internals(framework);
|
|
975
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
976
|
-
const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
|
|
977
|
-
let finishSwitch;
|
|
978
|
-
const switchHold = new Promise((resolve) => { finishSwitch = resolve; });
|
|
979
|
-
if (action === 'rollback') {
|
|
980
|
-
const switchBranch = cm.switchBranch.bind(cm);
|
|
981
|
-
cm.switchBranch = async (...args) => { await switchHold; return switchBranch(...args); };
|
|
982
|
-
}
|
|
983
|
-
else {
|
|
984
|
-
const fork = cm.fork.bind(cm);
|
|
985
|
-
cm.fork = async (...args) => { await switchHold; return fork(...args); };
|
|
986
|
-
}
|
|
987
|
-
let finishMaterialize;
|
|
988
|
-
const materializeHold = new Promise((resolve) => { finishMaterialize = resolve; });
|
|
989
|
-
let materializing = false;
|
|
990
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
991
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
992
|
-
materializeMount: async () => { materializing = true; await materializeHold; order.push('config materialized'); },
|
|
993
|
-
} : getModule(name);
|
|
994
|
-
const rolling = action === 'rollback'
|
|
995
|
-
? framework.rollbackToMessage('agent', { messageId: ids[0] })
|
|
996
|
-
: framework.suppressMessages('agent', { messageIds: [ids[1]] });
|
|
997
|
-
void rolling.catch(() => { });
|
|
998
|
-
const stopping = framework.stop();
|
|
999
|
-
await releaseWhenStopWaits(finishSwitch);
|
|
1000
|
-
try {
|
|
1001
|
-
await rolling;
|
|
1002
|
-
assert.equal(materializing, true);
|
|
1003
|
-
await until(() => waitReads >= 2 || order.includes('modules stopped'), 'stop to discover child work', 30_000);
|
|
1004
|
-
assert.equal(order.includes('modules stopped'), false, 'the original snapshot is not the whole wait');
|
|
1005
|
-
}
|
|
1006
|
-
finally {
|
|
1007
|
-
finishMaterialize();
|
|
1008
|
-
await stopping;
|
|
1009
|
-
}
|
|
1010
|
-
assert.deepEqual(order, ['config materialized', 'modules stopped']);
|
|
1011
|
-
});
|
|
1012
|
-
it("a trace listener that calls stop() doesn't lose the operation whose trace it heard", async () => {
|
|
1013
|
-
const framework = await create();
|
|
1014
|
-
const fw = internals(framework);
|
|
1015
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
1016
|
-
const sequenceBefore = framework.getStore().currentSequence();
|
|
1017
|
-
cm.addMessage('user', [{ type: 'text', text: 'a turn' }]);
|
|
1018
|
-
fw.saveTurnCheckpoints('agent', [{ agentName: 'agent', turnIndex: 1, sequenceBefore, branchName: 'main', timestamp: Date.now() }]);
|
|
1019
|
-
// Hold the undo's preview, the last thing it does before it answers.
|
|
1020
|
-
let release;
|
|
1021
|
-
const held = new Promise((resolve) => { release = resolve; });
|
|
1022
|
-
let previewing = false;
|
|
1023
|
-
fw.lastVisiblePreview = async () => {
|
|
1024
|
-
previewing = true;
|
|
1025
|
-
await held;
|
|
1026
|
-
return null;
|
|
1027
|
-
};
|
|
1028
|
-
let stopping;
|
|
1029
|
-
framework.onTrace((event) => {
|
|
1030
|
-
if (event.type === 'undo:completed')
|
|
1031
|
-
stopping = framework.stop();
|
|
1032
|
-
});
|
|
1033
|
-
const connection = Object.assign(new EventEmitter(), { id: 'srv' });
|
|
1034
|
-
fw.wireMcplEvents(connection);
|
|
1035
|
-
connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 1 }, {
|
|
1036
|
-
id: 9,
|
|
1037
|
-
respond: () => { order.push('undo answered'); },
|
|
1038
|
-
respondError: () => { order.push('undo failed'); },
|
|
1039
|
-
});
|
|
1040
|
-
await until(() => stopping !== undefined && (previewing || order.includes('undo failed')), 'reentrant stop and the undo\'s preview');
|
|
1041
|
-
await releaseWhenStopWaits(release);
|
|
1042
|
-
await stopping;
|
|
1043
|
-
await until(() => order.includes('undo answered') || order.includes('undo failed'), 'undo answer');
|
|
1044
|
-
assert.ok(order.indexOf('undo answered') >= 0 && order.indexOf('undo answered') < order.indexOf('modules stopped'), order.join(', '));
|
|
1045
|
-
assert.deepEqual(rejections, []);
|
|
1046
|
-
});
|
|
1047
|
-
it("the API server's undo whose trace starts stop() answers, and leaves its marks' delivery to the next start", async () => {
|
|
1048
|
-
const framework = await create();
|
|
1049
|
-
const fw = internals(framework);
|
|
1050
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
1051
|
-
const record = fw.recordTurnCheckpoint.bind(fw);
|
|
1052
|
-
record('agent');
|
|
1053
|
-
cm.addMessage('user', [{ type: 'text', text: 'a turn' }]);
|
|
1054
|
-
let barriers = 0;
|
|
1055
|
-
fw.beginDiscordAwarenessBarrier = () => {
|
|
1056
|
-
barriers++;
|
|
1057
|
-
return { requiresBarrier: false, promise: Promise.resolve({ status: 'delivered', delivered: 0, failed: 0 }) };
|
|
1058
|
-
};
|
|
1059
|
-
let stopping;
|
|
1060
|
-
framework.onTrace((event) => {
|
|
1061
|
-
if (event.type === 'undo:completed' && !stopping)
|
|
1062
|
-
stopping = framework.stop();
|
|
1063
|
-
});
|
|
1064
|
-
const api = new ApiServer(framework);
|
|
1065
|
-
api.broadcast = () => { };
|
|
1066
|
-
assert.equal((await api.cmdUndo({ agentName: 'agent' })).undone, true);
|
|
1067
|
-
assert.ok(stopping, "the undo's trace started stop()");
|
|
1068
|
-
await stopping;
|
|
1069
|
-
assert.equal(barriers, 0, 'no delivery started while the framework stops');
|
|
1070
|
-
assert.ok(logged.some((line) => line.includes('delivery after undo agent=agent not started')), logged.join('\n'));
|
|
1071
|
-
assert.deepEqual(rejections, []);
|
|
1072
|
-
});
|
|
1073
|
-
it('a multi-turn host/command undo whose first turn starts stop() still undoes every turn it was asked for', async () => {
|
|
1074
|
-
const framework = await create();
|
|
1075
|
-
const fw = internals(framework);
|
|
1076
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
1077
|
-
// Two turns, each checkpointed as a real turn's start records it.
|
|
1078
|
-
const record = fw.recordTurnCheckpoint.bind(fw);
|
|
1079
|
-
record('agent');
|
|
1080
|
-
cm.addMessage('user', [{ type: 'text', text: 'turn one' }]);
|
|
1081
|
-
record('agent');
|
|
1082
|
-
cm.addMessage('user', [{ type: 'text', text: 'turn two' }]);
|
|
1083
|
-
let stopping;
|
|
1084
|
-
framework.onTrace((event) => {
|
|
1085
|
-
if (event.type === 'undo:completed' && !stopping)
|
|
1086
|
-
stopping = framework.stop();
|
|
1087
|
-
});
|
|
1088
|
-
const connection = Object.assign(new EventEmitter(), { id: 'srv' });
|
|
1089
|
-
fw.wireMcplEvents(connection);
|
|
1090
|
-
let answer;
|
|
1091
|
-
// Read as the answer goes out: stop() closes the store once the undo is done.
|
|
1092
|
-
let checkpoints;
|
|
1093
|
-
let texts = [];
|
|
1094
|
-
connection.emit('host-command', { command: 'undo', agentName: 'agent', turns: 2 }, {
|
|
1095
|
-
id: 10,
|
|
1096
|
-
respond: (result) => {
|
|
1097
|
-
answer = result;
|
|
1098
|
-
checkpoints = fw.getTurnCheckpoints('agent');
|
|
1099
|
-
texts = cm.getAllMessages().map((m) => JSON.stringify(m.content));
|
|
1100
|
-
},
|
|
1101
|
-
respondError: () => { order.push('undo failed'); },
|
|
1102
|
-
});
|
|
1103
|
-
await until(() => answer !== undefined || order.includes('undo failed'), 'the undo to answer');
|
|
1104
|
-
assert.equal(answer?.ok, true, JSON.stringify(answer));
|
|
1105
|
-
assert.equal(answer?.undone, 2, JSON.stringify(answer));
|
|
1106
|
-
assert.deepEqual(checkpoints, [], 'both turns were rolled back');
|
|
1107
|
-
assert.ok(!texts.some((t) => t.includes('turn one') || t.includes('turn two')), texts.join(' | '));
|
|
1108
|
-
assert.ok(stopping, 'the first turn started stop()');
|
|
1109
|
-
await stopping;
|
|
1110
|
-
assert.deepEqual(rejections, []);
|
|
1111
|
-
});
|
|
1112
|
-
for (const elapsed of [6_000, 9_999, 11_000])
|
|
1113
|
-
it("work an operation starts shares stop()'s deadline, " + elapsed + ' ms in', async () => {
|
|
1114
|
-
const framework = await create();
|
|
1115
|
-
const fw = internals(framework);
|
|
1116
|
-
const cm = framework.getAgent('agent').getContextManager();
|
|
1117
|
-
const ids = [1, 2, 3].map((n) => cm.addMessage('user', [{ type: 'text', text: 'm' + n }]));
|
|
1118
|
-
let finishSwitch;
|
|
1119
|
-
const switchHold = new Promise((resolve) => { finishSwitch = resolve; });
|
|
1120
|
-
const switchBranch = cm.switchBranch.bind(cm);
|
|
1121
|
-
cm.switchBranch = async (...args) => { await switchHold; return switchBranch(...args); };
|
|
1122
|
-
let finishMaterialize;
|
|
1123
|
-
const materializeHold = new Promise((resolve) => { finishMaterialize = resolve; });
|
|
1124
|
-
const getModule = fw.moduleRegistry.getModule.bind(fw.moduleRegistry);
|
|
1125
|
-
fw.moduleRegistry.getModule = (name) => name === 'workspace' ? {
|
|
1126
|
-
materializeMount: async () => { await materializeHold; order.push('config materialized'); },
|
|
1127
|
-
} : getModule(name);
|
|
1128
|
-
const rolling = framework.rollbackToMessage('agent', { messageId: ids[0] });
|
|
1129
|
-
void rolling.catch(() => { });
|
|
1130
|
-
const nowProperty = Object.getOwnPropertyDescriptor(performance, 'now');
|
|
1131
|
-
const timer = globalThis.setTimeout;
|
|
1132
|
-
const budgets = [];
|
|
1133
|
-
let now = 0;
|
|
1134
|
-
let stopping;
|
|
1135
|
-
try {
|
|
1136
|
-
Object.defineProperty(performance, 'now', { configurable: true, value: () => now });
|
|
1137
|
-
globalThis.setTimeout = ((...args) => {
|
|
1138
|
-
if (args[1] !== undefined && args[1] > 100)
|
|
1139
|
-
budgets.push(args[1]);
|
|
1140
|
-
return timer(...args);
|
|
1141
|
-
});
|
|
1142
|
-
stopping = framework.stop(10_000);
|
|
1143
|
-
void stopping.catch(() => { });
|
|
1144
|
-
await releaseWhenStopWaits(() => { now = elapsed; finishSwitch(); });
|
|
1145
|
-
await rolling;
|
|
1146
|
-
await until(() => waitReads >= 2 || order.includes('modules stopped'), 'the second operator wait');
|
|
1147
|
-
// Clock input controls the remaining budget. In the timeout cases,
|
|
1148
|
-
// work stays held until the assertion, so elapsed wall time is no verdict.
|
|
1149
|
-
if (elapsed === 6_000) {
|
|
1150
|
-
assert.deepEqual(budgets.slice(0, 2), [10_000, 4_000]);
|
|
1151
|
-
finishMaterialize();
|
|
1152
|
-
await stopping;
|
|
1153
|
-
}
|
|
1154
|
-
else {
|
|
1155
|
-
await assert.rejects(stopping, (error) => error instanceof ShutdownTimeoutError && error.pending.includes('config:materialize')
|
|
1156
|
-
&& error.message.startsWith('Shutdown timed out after 10000 ms;'));
|
|
1157
|
-
assert.equal(framework.getStore().isClosed(), false);
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
finally {
|
|
1161
|
-
finishSwitch();
|
|
1162
|
-
finishMaterialize();
|
|
1163
|
-
globalThis.setTimeout = timer;
|
|
1164
|
-
if (nowProperty)
|
|
1165
|
-
Object.defineProperty(performance, 'now', nowProperty);
|
|
1166
|
-
else
|
|
1167
|
-
Reflect.deleteProperty(performance, 'now');
|
|
1168
|
-
await rolling.catch(() => { });
|
|
1169
|
-
await stopping?.catch(() => { });
|
|
1170
|
-
await framework.stop();
|
|
1171
|
-
}
|
|
1172
|
-
});
|
|
1173
|
-
});
|
|
1174
|
-
//# sourceMappingURL=stop-with-host-operations.test.js.map
|