@skaile/workspaces 5.1.2 → 5.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/dist/app-sdk/index.js +1 -1
- package/dist/{asset-feeds-EVS3WPWS.js → asset-feeds-WDIB3E6H.js} +11 -11
- package/dist/{asset-feeds-EVS3WPWS.js.map → asset-feeds-WDIB3E6H.js.map} +1 -1
- package/dist/asset-manager/catalog-deployer.js +8 -8
- package/dist/asset-manager/index.js +12 -12
- package/dist/asset-manager/installer.js +8 -8
- package/dist/asset-manager/src/index.d.ts +27 -1
- package/dist/asset-manager/src/index.d.ts.map +1 -1
- package/dist/bridge/drivers/claude-sdk.js +110 -23
- package/dist/bridge/drivers/claude-sdk.js.map +1 -1
- package/dist/bridge/drivers/codex.js +11 -10
- package/dist/bridge/drivers/codex.js.map +1 -1
- package/dist/bridge/drivers/continue.js +10 -10
- package/dist/bridge/drivers/echo.js +3 -3
- package/dist/bridge/drivers/gemini.js +5 -5
- package/dist/bridge/drivers/goose.js +10 -10
- package/dist/bridge/drivers/omp.js +6 -5
- package/dist/bridge/drivers/omp.js.map +1 -1
- package/dist/bridge/drivers/opencode.js +10 -10
- package/dist/bridge/drivers/qwen.js +5 -5
- package/dist/bridge/index.js +13 -13
- package/dist/bridge/src/driver-capabilities.d.ts +66 -0
- package/dist/bridge/src/driver-capabilities.d.ts.map +1 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts +16 -0
- package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
- package/dist/bridge/src/drivers/codex.d.ts.map +1 -1
- package/dist/bridge/src/drivers/omp.d.ts.map +1 -1
- package/dist/bridge/src/index.d.ts +1 -0
- package/dist/bridge/src/index.d.ts.map +1 -1
- package/dist/bridge/src/registry.d.ts.map +1 -1
- package/dist/{chunk-CJB5HUY6.js → chunk-2MEMXBLC.js} +8 -7
- package/dist/chunk-2MEMXBLC.js.map +1 -0
- package/dist/{chunk-TVOODIZE.js → chunk-2QZG5VJQ.js} +3 -3
- package/dist/{chunk-TVOODIZE.js.map → chunk-2QZG5VJQ.js.map} +1 -1
- package/dist/{chunk-7SAWDPUT.js → chunk-37GBJLF5.js} +5 -55
- package/dist/chunk-37GBJLF5.js.map +1 -0
- package/dist/{chunk-RDTHJSGY.js → chunk-3E2TIPBZ.js} +56 -7
- package/dist/chunk-3E2TIPBZ.js.map +1 -0
- package/dist/{chunk-H4EGUQ7M.js → chunk-4YE7OYTB.js} +5 -5
- package/dist/chunk-4YE7OYTB.js.map +1 -0
- package/dist/{chunk-K5GBV4SA.js → chunk-5BEFNLOR.js} +6 -5
- package/dist/chunk-5BEFNLOR.js.map +1 -0
- package/dist/{chunk-UO5CWEHZ.js → chunk-6OWIEFZ2.js} +5 -5
- package/dist/{chunk-UO5CWEHZ.js.map → chunk-6OWIEFZ2.js.map} +1 -1
- package/dist/{chunk-EPHQWHOH.js → chunk-6ZCVROWW.js} +6 -6
- package/dist/{chunk-EPHQWHOH.js.map → chunk-6ZCVROWW.js.map} +1 -1
- package/dist/{chunk-TB6GDL6Q.js → chunk-77GKEZ2R.js} +21 -4
- package/dist/chunk-77GKEZ2R.js.map +1 -0
- package/dist/{chunk-TYUJB336.js → chunk-7Y43UXKA.js} +3 -3
- package/dist/{chunk-TYUJB336.js.map → chunk-7Y43UXKA.js.map} +1 -1
- package/dist/{chunk-YV4J7V53.js → chunk-ANWHAGM7.js} +3 -3
- package/dist/{chunk-YV4J7V53.js.map → chunk-ANWHAGM7.js.map} +1 -1
- package/dist/{chunk-SP47UJKE.js → chunk-B4J4RGNY.js} +231 -114
- package/dist/chunk-B4J4RGNY.js.map +1 -0
- package/dist/{chunk-IWCCZL7C.js → chunk-BIMEKYOE.js} +91 -25
- package/dist/chunk-BIMEKYOE.js.map +1 -0
- package/dist/{chunk-WCQMXBO5.js → chunk-BJQUSAGB.js} +4 -4
- package/dist/{chunk-WCQMXBO5.js.map → chunk-BJQUSAGB.js.map} +1 -1
- package/dist/{chunk-RDYI4MML.js → chunk-BNUZEYC3.js} +3 -3
- package/dist/{chunk-RDYI4MML.js.map → chunk-BNUZEYC3.js.map} +1 -1
- package/dist/{chunk-P5UQ56RA.js → chunk-BUNBKRJZ.js} +3 -3
- package/dist/{chunk-P5UQ56RA.js.map → chunk-BUNBKRJZ.js.map} +1 -1
- package/dist/{chunk-KDH74UWB.js → chunk-BWOLP6KQ.js} +3 -3
- package/dist/{chunk-KDH74UWB.js.map → chunk-BWOLP6KQ.js.map} +1 -1
- package/dist/chunk-BZXR6SW5.js +15 -0
- package/dist/{chunk-XUQBVK4R.js.map → chunk-BZXR6SW5.js.map} +1 -1
- package/dist/{chunk-ZMMFBID4.js → chunk-DD3OZLRD.js} +3 -3
- package/dist/{chunk-ZMMFBID4.js.map → chunk-DD3OZLRD.js.map} +1 -1
- package/dist/{chunk-56IWSMSD.js → chunk-EOGNW74K.js} +9 -8
- package/dist/chunk-EOGNW74K.js.map +1 -0
- package/dist/{chunk-RNNUYFFD.js → chunk-FJTC5YFO.js} +3 -3
- package/dist/{chunk-RNNUYFFD.js.map → chunk-FJTC5YFO.js.map} +1 -1
- package/dist/{chunk-THPQ6J3U.js → chunk-IOUIC2ZD.js} +8 -8
- package/dist/{chunk-THPQ6J3U.js.map → chunk-IOUIC2ZD.js.map} +1 -1
- package/dist/{chunk-YMOZC2D3.js → chunk-JPR7EPIM.js} +4 -4
- package/dist/{chunk-YMOZC2D3.js.map → chunk-JPR7EPIM.js.map} +1 -1
- package/dist/{chunk-IDEA6CYI.js → chunk-K2K7OF4P.js} +95 -3
- package/dist/chunk-K2K7OF4P.js.map +1 -0
- package/dist/{chunk-AGWYBS2E.js → chunk-KGGT6MUM.js} +4 -4
- package/dist/{chunk-AGWYBS2E.js.map → chunk-KGGT6MUM.js.map} +1 -1
- package/dist/{chunk-YJACHPI7.js → chunk-L257BENF.js} +73 -54
- package/dist/chunk-L257BENF.js.map +1 -0
- package/dist/{chunk-UVOJSWD2.js → chunk-LZ5RH6LD.js} +24 -13
- package/dist/chunk-LZ5RH6LD.js.map +1 -0
- package/dist/{chunk-N2X7DK2S.js → chunk-MGHUSFYQ.js} +2472 -2265
- package/dist/chunk-MGHUSFYQ.js.map +1 -0
- package/dist/{chunk-43ZBF3WH.js → chunk-OABIGSUY.js} +16 -3
- package/dist/chunk-OABIGSUY.js.map +1 -0
- package/dist/{chunk-YIVB7GIP.js → chunk-OFNXRI4L.js} +4 -4
- package/dist/{chunk-YIVB7GIP.js.map → chunk-OFNXRI4L.js.map} +1 -1
- package/dist/{chunk-MXXKTQXJ.js → chunk-P2EM6FNQ.js} +5 -5
- package/dist/{chunk-MXXKTQXJ.js.map → chunk-P2EM6FNQ.js.map} +1 -1
- package/dist/{chunk-KAYH6AXN.js → chunk-PHKFFJ4I.js} +3 -3
- package/dist/{chunk-KAYH6AXN.js.map → chunk-PHKFFJ4I.js.map} +1 -1
- package/dist/{chunk-YDJZRLGN.js → chunk-PU5VY7KF.js} +4 -4
- package/dist/{chunk-YDJZRLGN.js.map → chunk-PU5VY7KF.js.map} +1 -1
- package/dist/{chunk-KC3OF6B2.js → chunk-QMWMSZQ4.js} +3 -3
- package/dist/{chunk-KC3OF6B2.js.map → chunk-QMWMSZQ4.js.map} +1 -1
- package/dist/{chunk-52PFJLBJ.js → chunk-R3QW7CA5.js} +5 -5
- package/dist/{chunk-52PFJLBJ.js.map → chunk-R3QW7CA5.js.map} +1 -1
- package/dist/{chunk-UMSWQKCY.js → chunk-RXPC4KBW.js} +3 -3
- package/dist/{chunk-UMSWQKCY.js.map → chunk-RXPC4KBW.js.map} +1 -1
- package/dist/{chunk-X6IELFVB.js → chunk-S6KNDUAU.js} +4 -4
- package/dist/{chunk-X6IELFVB.js.map → chunk-S6KNDUAU.js.map} +1 -1
- package/dist/{chunk-6CSSFLGC.js → chunk-TVJBJLXR.js} +14 -15
- package/dist/chunk-TVJBJLXR.js.map +1 -0
- package/dist/{chunk-WKIOWDLQ.js → chunk-UDBN3LZU.js} +4 -4
- package/dist/{chunk-WKIOWDLQ.js.map → chunk-UDBN3LZU.js.map} +1 -1
- package/dist/{chunk-E67J56FJ.js → chunk-WMEPS6S4.js} +3 -3
- package/dist/{chunk-E67J56FJ.js.map → chunk-WMEPS6S4.js.map} +1 -1
- package/dist/{chunk-CXGHL75R.js → chunk-XIYXBHLN.js} +5 -4
- package/dist/chunk-XIYXBHLN.js.map +1 -0
- package/dist/{chunk-VDJKWKH2.js → chunk-XOTJVCJB.js} +3 -3
- package/dist/{chunk-VDJKWKH2.js.map → chunk-XOTJVCJB.js.map} +1 -1
- package/dist/{chunk-DXUQCMVT.js → chunk-YANDJSMN.js} +3 -3
- package/dist/{chunk-DXUQCMVT.js.map → chunk-YANDJSMN.js.map} +1 -1
- package/dist/{chunk-AG44ZJ7W.js → chunk-YRF5CYHR.js} +5 -14
- package/dist/chunk-YRF5CYHR.js.map +1 -0
- package/dist/{chunk-VFAJZE45.js → chunk-ZSFTCMZL.js} +907 -785
- package/dist/chunk-ZSFTCMZL.js.map +1 -0
- package/dist/cli/index.js +506 -434
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/asset-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/catalog.d.ts.map +1 -1
- package/dist/cli/src/commands/config.d.ts.map +1 -1
- package/dist/cli/src/commands/library-cmd.d.ts.map +1 -1
- package/dist/cli/src/commands/library-publish.d.ts.map +1 -1
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/run.d.ts.map +1 -1
- package/dist/cli/src/commands/skailify-lib.d.ts +0 -45
- package/dist/cli/src/commands/skailify-lib.d.ts.map +1 -1
- package/dist/cli/src/commands/source.d.ts.map +1 -1
- package/dist/cli/src/commands/validate.d.ts.map +1 -1
- package/dist/cli/src/flow-discovery.d.ts +9 -0
- package/dist/cli/src/flow-discovery.d.ts.map +1 -1
- package/dist/cli/src/helpers.d.ts +13 -0
- package/dist/cli/src/helpers.d.ts.map +1 -1
- package/dist/cli/src/setup.d.ts.map +1 -1
- package/dist/connectors/config.js +5 -5
- package/dist/connectors/index.js +17 -17
- package/dist/connectors/src/connector-manager.d.ts +8 -27
- package/dist/connectors/src/connector-manager.d.ts.map +1 -1
- package/dist/connectors/src/index.d.ts +1 -1
- package/dist/connectors/src/index.d.ts.map +1 -1
- package/dist/connectors/src/mount-ledger.d.ts +61 -0
- package/dist/connectors/src/mount-ledger.d.ts.map +1 -0
- package/dist/{connectors-KSVPVYCA.js → connectors-GUN4MRWR.js} +20 -20
- package/dist/{connectors-KSVPVYCA.js.map → connectors-GUN4MRWR.js.map} +1 -1
- package/dist/connectors-shared/index.js +2 -2
- package/dist/core/framework.js +1 -1
- package/dist/core/index.js +7 -7
- package/dist/core/manifest.js +2 -2
- package/dist/core/models.js +1 -1
- package/dist/core/publish-manifest.js +2 -2
- package/dist/core/ref.js +1 -1
- package/dist/core/runtime-assets.js +5 -5
- package/dist/core/src/framework.d.ts +7 -0
- package/dist/core/src/framework.d.ts.map +1 -1
- package/dist/core/src/index.d.ts +4 -4
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/lock.d.ts +12 -0
- package/dist/core/src/lock.d.ts.map +1 -1
- package/dist/core/src/manifest-yaml-editor.d.ts +14 -6
- package/dist/core/src/manifest-yaml-editor.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +15 -0
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/publish-manifest.d.ts +4 -6
- package/dist/core/src/publish-manifest.d.ts.map +1 -1
- package/dist/core/src/settings.d.ts.map +1 -1
- package/dist/core/workspace-config.js +4 -4
- package/dist/deploy/index.js +7 -7
- package/dist/discovery/index.js +4 -4
- package/dist/discovery/src/discover-manifest.d.ts +5 -0
- package/dist/discovery/src/discover-manifest.d.ts.map +1 -1
- package/dist/discovery/src/index.d.ts +1 -1
- package/dist/discovery/src/index.d.ts.map +1 -1
- package/dist/{ensure-sources-KVV72WRP.js → ensure-sources-VCPA762L.js} +15 -15
- package/dist/{ensure-sources-KVV72WRP.js.map → ensure-sources-VCPA762L.js.map} +1 -1
- package/dist/factory-assets/connectors/box.js +17 -17
- package/dist/factory-assets/connectors/deploy.js +17 -17
- package/dist/factory-assets/connectors/devserver.js +17 -17
- package/dist/factory-assets/connectors/flow/adapter.d.ts +28 -4
- package/dist/factory-assets/connectors/flow/adapter.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/adapter.js +17 -17
- package/dist/factory-assets/connectors/flow/engine.js +8 -8
- package/dist/factory-assets/connectors/flow/index.d.ts +1 -1
- package/dist/factory-assets/connectors/flow/index.d.ts.map +1 -1
- package/dist/factory-assets/connectors/flow/run-flow.js +19 -19
- package/dist/factory-assets/connectors/flow.js +17 -17
- package/dist/factory-assets/connectors/git/checkout.d.ts +161 -0
- package/dist/factory-assets/connectors/git/checkout.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git/config.d.ts +78 -0
- package/dist/factory-assets/connectors/git/config.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git/credentials.d.ts +93 -0
- package/dist/factory-assets/connectors/git/credentials.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git/driver.d.ts +39 -598
- package/dist/factory-assets/connectors/git/driver.d.ts.map +1 -1
- package/dist/factory-assets/connectors/git/exec.d.ts +177 -0
- package/dist/factory-assets/connectors/git/exec.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git/inspect.d.ts +120 -0
- package/dist/factory-assets/connectors/git/inspect.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git/lifecycle.d.ts +107 -0
- package/dist/factory-assets/connectors/git/lifecycle.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git/repo.d.ts +496 -0
- package/dist/factory-assets/connectors/git/repo.d.ts.map +1 -0
- package/dist/factory-assets/connectors/git.js +17 -17
- package/dist/factory-assets/connectors/gmail.js +17 -17
- package/dist/factory-assets/connectors/googledrive.js +17 -17
- package/dist/factory-assets/connectors/local.js +17 -17
- package/dist/factory-assets/connectors/mattermost.js +17 -17
- package/dist/factory-assets/connectors/memory.js +17 -17
- package/dist/factory-assets/connectors/minio.js +17 -17
- package/dist/factory-assets/connectors/postgres.js +17 -17
- package/dist/factory-assets/connectors/s3.js +17 -17
- package/dist/factory-assets/connectors/sharepoint.js +17 -17
- package/dist/factory-assets/connectors/sqlite.js +17 -17
- package/dist/factory-assets/connectors/static-server.js +17 -17
- package/dist/factory-assets/connectors/tunnel.js +17 -17
- package/dist/factory-assets/connectors/webdav.js +17 -17
- package/dist/factory-assets/connectors/xstate-store.js +17 -17
- package/dist/factory-assets/connectors/xstate.js +17 -17
- package/dist/{flows-SVCCADGE.js → flows-BOB5YA5R.js} +12 -12
- package/dist/{flows-SVCCADGE.js.map → flows-BOB5YA5R.js.map} +1 -1
- package/dist/{helpers-4NT7UX6I.js → helpers-ZGK4R5MZ.js} +15 -15
- package/dist/{helpers-4NT7UX6I.js.map → helpers-ZGK4R5MZ.js.map} +1 -1
- package/dist/library/index.js +10 -10
- package/dist/library/install.js +2 -2
- package/dist/library/src/index.d.ts +6 -3
- package/dist/library/src/index.d.ts.map +1 -1
- package/dist/library/src/install/install-from-manifest.d.ts +21 -0
- package/dist/library/src/install/install-from-manifest.d.ts.map +1 -1
- package/dist/library/src/local/install-library-asset.d.ts +64 -0
- package/dist/library/src/local/install-library-asset.d.ts.map +1 -0
- package/dist/library/src/local/local-catalog-source.d.ts +30 -0
- package/dist/library/src/local/local-catalog-source.d.ts.map +1 -1
- package/dist/library/src/local/store-paths.d.ts +6 -0
- package/dist/library/src/local/store-paths.d.ts.map +1 -1
- package/dist/library/src/manifest-writer.d.ts +73 -0
- package/dist/library/src/manifest-writer.d.ts.map +1 -0
- package/dist/library/src/sync/manifest-writeback.d.ts +2 -17
- package/dist/library/src/sync/manifest-writeback.d.ts.map +1 -1
- package/dist/{library-publish-GHIWWEEY.js → library-publish-RIP6NBYA.js} +20 -21
- package/dist/library-publish-RIP6NBYA.js.map +1 -0
- package/dist/{open-library-XKWTUYU2.js → open-library-4IJTBVTR.js} +18 -18
- package/dist/{open-library-XKWTUYU2.js.map → open-library-4IJTBVTR.js.map} +1 -1
- package/dist/{open-registry-CHCWKV5W.js → open-registry-G5DI4RPU.js} +14 -14
- package/dist/{open-registry-CHCWKV5W.js.map → open-registry-G5DI4RPU.js.map} +1 -1
- package/dist/paths-L5XLUC3D.js +22 -0
- package/dist/{paths-MKSI52PF.js.map → paths-L5XLUC3D.js.map} +1 -1
- package/dist/plugin-registry/src/targets.d.ts +3 -1
- package/dist/plugin-registry/src/targets.d.ts.map +1 -1
- package/dist/{plugin-store-SVYV7L4C.js → plugin-store-QENDYZ63.js} +9 -9
- package/dist/{plugin-store-SVYV7L4C.js.map → plugin-store-QENDYZ63.js.map} +1 -1
- package/dist/{project-P2QS3GNG.js → project-4INCIIZI.js} +16 -16
- package/dist/{project-P2QS3GNG.js.map → project-4INCIIZI.js.map} +1 -1
- package/dist/resolver/index.js +8 -8
- package/dist/runner/index.js +27 -27
- package/dist/runner/src/agent.d.ts +1 -1
- package/dist/runner/src/agent.d.ts.map +1 -1
- package/dist/runner/src/ai-provider-switch.d.ts +10 -0
- package/dist/runner/src/ai-provider-switch.d.ts.map +1 -1
- package/dist/runner/src/codex-init.d.ts.map +1 -1
- package/dist/runner/src/compaction-gate.d.ts +9 -33
- package/dist/runner/src/compaction-gate.d.ts.map +1 -1
- package/dist/runner/src/managed-codex-bootstrap.d.ts.map +1 -1
- package/dist/runner/src/pending-turns.d.ts +7 -2
- package/dist/runner/src/pending-turns.d.ts.map +1 -1
- package/dist/runner/src/resources.d.ts +2 -2
- package/dist/runner/src/resources.d.ts.map +1 -1
- package/dist/runner/src/serve-credentials.d.ts +2 -1
- package/dist/runner/src/serve-credentials.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts +19 -35
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/session-builder.d.ts.map +1 -1
- package/dist/runner/src/turn-scheduler.d.ts +158 -0
- package/dist/runner/src/turn-scheduler.d.ts.map +1 -0
- package/dist/sdk/asset-manager.js +12 -12
- package/dist/sdk/bridge.js +13 -13
- package/dist/sdk/core.js +7 -7
- package/dist/sdk/flow.js +8 -8
- package/dist/sdk/index.js +27 -27
- package/dist/sdk/resolver.js +8 -8
- package/dist/sdk/runner.js +27 -27
- package/dist/sdk/session.js +2 -2
- package/dist/sdk/types.js +1 -1
- package/dist/session/index.js +2 -2
- package/dist/session/src/dispatcher.d.ts.map +1 -1
- package/dist/{setup-RVP74D37.js → setup-RG4PJJUW.js} +23 -23
- package/dist/setup-RG4PJJUW.js.map +1 -0
- package/dist/{skills-7K2YO3KN.js → skills-CL45F7AG.js} +13 -13
- package/dist/{skills-7K2YO3KN.js.map → skills-CL45F7AG.js.map} +1 -1
- package/dist/{source-VBROLEFB.js → source-LJOI5AXU.js} +19 -19
- package/dist/{source-VBROLEFB.js.map → source-LJOI5AXU.js.map} +1 -1
- package/dist/{source-manifest-publish-7XDLJRLX.js → source-manifest-publish-QEJML4VS.js} +21 -21
- package/dist/{source-manifest-publish-7XDLJRLX.js.map → source-manifest-publish-QEJML4VS.js.map} +1 -1
- package/dist/tui/index.js +28 -28
- package/dist/tui/index.js.map +1 -1
- package/dist/types/index.js +1 -1
- package/dist/types/src/delivery.d.ts +26 -0
- package/dist/types/src/delivery.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/runtime.d.ts +51 -0
- package/dist/types/src/runtime.d.ts.map +1 -1
- package/dist/workspace-plugin/adapters/mcp.js +24 -24
- package/dist/workspace-plugin/adapters/omp.js +18 -17
- package/dist/workspace-plugin/adapters/omp.js.map +1 -1
- package/dist/workspace-plugin/index.js +2 -1
- package/dist/workspace-plugin/src/adapters/mcp.d.ts.map +1 -1
- package/dist/workspace-plugin/src/adapters/omp.d.ts.map +1 -1
- package/dist/workspace-plugin/src/plugin.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-43ZBF3WH.js.map +0 -1
- package/dist/chunk-56IWSMSD.js.map +0 -1
- package/dist/chunk-6CSSFLGC.js.map +0 -1
- package/dist/chunk-7SAWDPUT.js.map +0 -1
- package/dist/chunk-AG44ZJ7W.js.map +0 -1
- package/dist/chunk-CJB5HUY6.js.map +0 -1
- package/dist/chunk-CXGHL75R.js.map +0 -1
- package/dist/chunk-F7JHP7JV.js +0 -122
- package/dist/chunk-F7JHP7JV.js.map +0 -1
- package/dist/chunk-H4EGUQ7M.js.map +0 -1
- package/dist/chunk-IDEA6CYI.js.map +0 -1
- package/dist/chunk-IWCCZL7C.js.map +0 -1
- package/dist/chunk-K5GBV4SA.js.map +0 -1
- package/dist/chunk-N2X7DK2S.js.map +0 -1
- package/dist/chunk-RDTHJSGY.js.map +0 -1
- package/dist/chunk-SP47UJKE.js.map +0 -1
- package/dist/chunk-TB6GDL6Q.js.map +0 -1
- package/dist/chunk-UVOJSWD2.js.map +0 -1
- package/dist/chunk-VFAJZE45.js.map +0 -1
- package/dist/chunk-XUQBVK4R.js +0 -15
- package/dist/chunk-YJACHPI7.js.map +0 -1
- package/dist/library-publish-GHIWWEEY.js.map +0 -1
- package/dist/paths-MKSI52PF.js +0 -22
- package/dist/runner/src/flow-turn-dispatch.d.ts +0 -41
- package/dist/runner/src/flow-turn-dispatch.d.ts.map +0 -1
- package/dist/runner/src/reply-routing.d.ts +0 -54
- package/dist/runner/src/reply-routing.d.ts.map +0 -1
- package/dist/setup-RVP74D37.js.map +0 -1
|
@@ -1,32 +1,32 @@
|
|
|
1
|
-
import { WorkspacePlugin } from './chunk-
|
|
2
|
-
import { buildWorkspaceToolDefs } from './chunk-
|
|
3
|
-
import { findAiAssetsRoot } from './chunk-
|
|
1
|
+
import { WorkspacePlugin } from './chunk-XIYXBHLN.js';
|
|
2
|
+
import { buildWorkspaceToolDefs } from './chunk-2MEMXBLC.js';
|
|
3
|
+
import { findAiAssetsRoot } from './chunk-7Y43UXKA.js';
|
|
4
4
|
import { WebSocketServerTransport } from './chunk-5LKOAX7I.js';
|
|
5
5
|
import { assembleSystemPrompt, buildCapabilitiesPromptSection } from './chunk-W3UDISS2.js';
|
|
6
6
|
import { prepareNativePolicy, codexInstanceEnvironment, parseCodexCredential, parseCodexRefreshInput, parseCodexRefreshResult } from './chunk-HCYS7GFP.js';
|
|
7
|
-
import { resolveFlowPath } from './chunk-
|
|
8
|
-
import { findAiAssetsRoot as findAiAssetsRoot$1, deployCatalogEntry, undeployCatalogEntry } from './chunk-
|
|
9
|
-
import { ConnectFailureCarryOver, registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, buildSdkConnectorTools, buildLazySdkFlowTools, describeFlowOperations, buildConnectorToolDefs, buildFlowToolDefs, SessionNodeExecutor, SessionSubpromptRunner, ClassifierSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn, buildSdkFlowTools } from './chunk-
|
|
10
|
-
import { loadYamlConnectorDeclarations, withMaterializedConnectorDeclarations, SecretProviderChain, ConnectorStartupError, isKnownSecretRef, EnvSecretProvider, PreMintedSecretProvider, InMemorySecretProvider, resolvedConfigToDeclarations, deriveSingleMaterializedConnectorDeclaration } from './chunk-
|
|
11
|
-
import { EventNormalizer } from './chunk-
|
|
12
|
-
import { probeResumeTranscript, transcriptStoreForRuntime } from './chunk-
|
|
7
|
+
import { resolveFlowPath } from './chunk-IOUIC2ZD.js';
|
|
8
|
+
import { findAiAssetsRoot as findAiAssetsRoot$1, deployCatalogEntry, undeployCatalogEntry } from './chunk-XOTJVCJB.js';
|
|
9
|
+
import { ConnectFailureCarryOver, registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, buildSdkConnectorTools, buildLazySdkFlowTools, describeFlowOperations, buildConnectorToolDefs, buildFlowToolDefs, SessionNodeExecutor, SessionSubpromptRunner, ClassifierSubpromptRunner, SessionInlineSubFlowRunner, driveOrchestratorTurn, buildSdkFlowTools } from './chunk-MGHUSFYQ.js';
|
|
10
|
+
import { loadYamlConnectorDeclarations, withMaterializedConnectorDeclarations, SecretProviderChain, ConnectorStartupError, isKnownSecretRef, EnvSecretProvider, PreMintedSecretProvider, InMemorySecretProvider, resolvedConfigToDeclarations, deriveSingleMaterializedConnectorDeclaration } from './chunk-UDBN3LZU.js';
|
|
11
|
+
import { EventNormalizer } from './chunk-OFNXRI4L.js';
|
|
12
|
+
import { probeResumeTranscript, transcriptStoreForRuntime } from './chunk-2QZG5VJQ.js';
|
|
13
13
|
import { scopeReconfigureModel } from './chunk-EINLFFP6.js';
|
|
14
14
|
import { CodexNativeStateUnavailable } from './chunk-LOO5CB5M.js';
|
|
15
|
-
import { dispatchCapability } from './chunk-
|
|
15
|
+
import { dispatchCapability } from './chunk-BNUZEYC3.js';
|
|
16
16
|
import { classifyClaudeSdkError } from './chunk-XBSQ4KMC.js';
|
|
17
17
|
import { agentExecRequested } from './chunk-YROR332M.js';
|
|
18
|
-
import { toAgentEffort, createDriver, catalogLayer, providerCredentialEnvName, toMergedRegistry, registryCredentialEnv, AI_PROVIDER_PRESETS, AgentDriver } from './chunk-
|
|
19
|
-
import { loadFlow } from './chunk-
|
|
18
|
+
import { driverCapabilities, toAgentEffort, createDriver, catalogLayer, providerCredentialEnvName, toMergedRegistry, registryCredentialEnv, AI_PROVIDER_PRESETS, supportsLiveToolUpdates, AgentDriver } from './chunk-3E2TIPBZ.js';
|
|
19
|
+
import { loadFlow } from './chunk-RXPC4KBW.js';
|
|
20
20
|
import { parseFlowDefinition } from './chunk-QZLWJETK.js';
|
|
21
21
|
import { renderStimulusPrompt } from './chunk-XUUYAS3Z.js';
|
|
22
|
-
import { withActivityLabelJsonSchema, TOOL_ACTIVITY_PROMPT_SECTION, SESSION_ROOT_CONNECTOR_ID, PROTOCOL_VERSION } from './chunk-
|
|
23
|
-
import { resolveLibraryDir, resolveSettings, loadProviderRegistry } from './chunk-
|
|
24
|
-
import { resolveRuntimeAssets } from './chunk-
|
|
25
|
-
import { resolveDriverPaths } from './chunk-
|
|
26
|
-
import { resolveSkWorkspaceConfig, resolveAgentDir, loadMcpServerDeclarations, COMPACTION_DEFAULTS, resolveCompactionThresholdPercent, validateAssetRecipeAttr, deriveSingleMaterializedMcpDeclaration, stageMaterializedSkills, readSkillAllowList, isStagedSkillMarkerFor, unstageSkill, STAGED_SKILL_MARKER } from './chunk-
|
|
22
|
+
import { withActivityLabelJsonSchema, TOOL_ACTIVITY_PROMPT_SECTION, SESSION_ROOT_CONNECTOR_ID, PROTOCOL_VERSION, deliveryClassOf } from './chunk-K2K7OF4P.js';
|
|
23
|
+
import { resolveLibraryDir, resolveSettings, loadProviderRegistry } from './chunk-BIMEKYOE.js';
|
|
24
|
+
import { resolveRuntimeAssets } from './chunk-PU5VY7KF.js';
|
|
25
|
+
import { DEFAULT_DRIVER_ID, resolveDriverPaths } from './chunk-5BEFNLOR.js';
|
|
26
|
+
import { resolveSkWorkspaceConfig, resolveAgentDir, loadMcpServerDeclarations, COMPACTION_DEFAULTS, resolveCompactionThresholdPercent, validateAssetRecipeAttr, deriveSingleMaterializedMcpDeclaration, stageMaterializedSkills, readSkillAllowList, isStagedSkillMarkerFor, unstageSkill, STAGED_SKILL_MARKER } from './chunk-P2EM6FNQ.js';
|
|
27
27
|
import { globalSkaileDir } from './chunk-TLKM4M47.js';
|
|
28
|
-
import { withFsDeadline, FsDeadlineError, fsDeadlineMs, parseFrontmatter, tryWithFsDeadline } from './chunk-
|
|
29
|
-
import { parseAssetRef } from './chunk-
|
|
28
|
+
import { withFsDeadline, FsDeadlineError, fsDeadlineMs, parseFrontmatter, tryWithFsDeadline } from './chunk-YANDJSMN.js';
|
|
29
|
+
import { parseAssetRef } from './chunk-OABIGSUY.js';
|
|
30
30
|
import { resolveLogStoreConfig, createLogStoreFromConfig, OnLogBridgeSink, WsLogSink, resolveLogsRetention, enforceLogsRetention } from './chunk-JMKB7IB4.js';
|
|
31
31
|
import { pickRegistryEntries, registryEntries, resolveEntryBaseUrl, parseModelRef, isEntryEnabled, parseCredentialRef } from './chunk-MJHSLODD.js';
|
|
32
32
|
import { getLogStore, registerLogStore, createLogger, resetLogStore, isUnwritableStreamError, markStreamBroken, isBrokenPipeError, redactCredentials } from './chunk-BOFL7GIF.js';
|
|
@@ -2332,6 +2332,7 @@ function parsePresignResult(raw, op) {
|
|
|
2332
2332
|
// runner/src/resources.ts
|
|
2333
2333
|
async function buildAgentResources(projectDir, driverType, _onLog, watch, secretProvider, sessionMeta, tokenMediator, preMintedSecrets, deferFilesystemMounts, capabilityRegistry, fallbackConnectorDeclarations, extraMcpDeclarations, s3Presigner) {
|
|
2334
2334
|
const managedProjectMcp = sessionMeta?.managedCodex ? await resolveExternalMcpDeclarations(projectDir, sessionMeta.sessionId, true) : void 0;
|
|
2335
|
+
const inProcessMcp = driverCapabilities(driverType).inProcessMcpServers;
|
|
2335
2336
|
const resLog = createLogger({
|
|
2336
2337
|
kind: "runner",
|
|
2337
2338
|
subkind: "resources",
|
|
@@ -2415,7 +2416,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
2415
2416
|
}
|
|
2416
2417
|
return externalMcpManager;
|
|
2417
2418
|
};
|
|
2418
|
-
if (
|
|
2419
|
+
if (inProcessMcp) {
|
|
2419
2420
|
const inProcess = await buildInProcessMcpServers(
|
|
2420
2421
|
resourceManager,
|
|
2421
2422
|
projectDir,
|
|
@@ -2442,7 +2443,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
2442
2443
|
mcpSecretChain,
|
|
2443
2444
|
sessionMeta
|
|
2444
2445
|
);
|
|
2445
|
-
} else if (
|
|
2446
|
+
} else if (inProcessMcp) {
|
|
2446
2447
|
externalMcpDeclarations = await resolveExternalMcpDeclarations(
|
|
2447
2448
|
projectDir,
|
|
2448
2449
|
sessionMeta?.sessionId
|
|
@@ -2454,7 +2455,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
2454
2455
|
sessionMeta
|
|
2455
2456
|
);
|
|
2456
2457
|
}
|
|
2457
|
-
if (!resourceManager &&
|
|
2458
|
+
if (!resourceManager && !inProcessMcp && !externalMcpManager?.hasServers() && !capabilityRegistry)
|
|
2458
2459
|
return noopResult;
|
|
2459
2460
|
let coalescer = null;
|
|
2460
2461
|
const startWatching = () => {
|
|
@@ -2724,7 +2725,7 @@ function toSdkMcpServerConfig(decl, secrets) {
|
|
|
2724
2725
|
// runner/src/session-builder.ts
|
|
2725
2726
|
async function createAgentSession(config) {
|
|
2726
2727
|
const managed = config.managedCodex;
|
|
2727
|
-
if (managed && (config.driver
|
|
2728
|
+
if (managed && (!driverCapabilities(config.driver).managedSession || !config.model || !config.aiProviderConfigId || !config.capabilityRegistry || !config.capabilities))
|
|
2728
2729
|
throw new Error("AI_PROFILE_INVALID");
|
|
2729
2730
|
const {
|
|
2730
2731
|
projectDir,
|
|
@@ -2763,7 +2764,7 @@ async function createAgentSession(config) {
|
|
|
2763
2764
|
driver: driverOverride,
|
|
2764
2765
|
model: modelOverride
|
|
2765
2766
|
});
|
|
2766
|
-
const driverType = managed ?
|
|
2767
|
+
const driverType = (managed ? config.driver : settings.driver) ?? DEFAULT_DRIVER_ID;
|
|
2767
2768
|
const model = managed ? config.model : settings.model;
|
|
2768
2769
|
const registry = loadSessionRegistry(projectDir, config.registry, config.providers, sessionLog);
|
|
2769
2770
|
const modelRef = config.modelRef?.trim() || model?.trim() || void 0;
|
|
@@ -2867,7 +2868,7 @@ async function createAgentSession(config) {
|
|
|
2867
2868
|
const maxTurns = maxTurnsOverride ?? manifest?.runtime?.max_turns;
|
|
2868
2869
|
let driver;
|
|
2869
2870
|
try {
|
|
2870
|
-
const extraMcpServers = driverType
|
|
2871
|
+
const extraMcpServers = driverCapabilities(driverType).inProcessMcpServers ? await config.extraInProcessMcpServers?.() : void 0;
|
|
2871
2872
|
const driverMcpServers = extraMcpServers ? { ...mcpServers, ...extraMcpServers } : mcpServers;
|
|
2872
2873
|
driver = await createSessionDriver({
|
|
2873
2874
|
config,
|
|
@@ -4502,7 +4503,7 @@ function validateCodexInit(cmd, supported, previous) {
|
|
|
4502
4503
|
if (requirements !== void 0 && (!Array.isArray(requirements) || requirements.some((item) => typeof item !== "string" || !supported.includes(item))))
|
|
4503
4504
|
throw new Error("Unsupported runtime: required features are unavailable");
|
|
4504
4505
|
const profile = cmd.resolvedConfig.agentConfig;
|
|
4505
|
-
const managed = profile
|
|
4506
|
+
const managed = profile !== void 0 && driverCapabilities(profile.driver).managedSession && (profile.authMode !== void 0 || requirements?.includes("codex-app-server-v1"));
|
|
4506
4507
|
if ((managed || cmd.credentials.ai !== void 0) && !supported.includes("codex-app-server-v1"))
|
|
4507
4508
|
throw new Error("Unsupported runtime: codex-app-server-v1 is unavailable");
|
|
4508
4509
|
if (!managed && cmd.credentials.ai === void 0) return;
|
|
@@ -4605,7 +4606,7 @@ function loadManagedCodexHostConfig(file, projectDir) {
|
|
|
4605
4606
|
function bindManagedCodexInit(host, cmd, refreshCredential) {
|
|
4606
4607
|
const profile = cmd.resolvedConfig.agentConfig;
|
|
4607
4608
|
const credential = parseCodexCredential(cmd.credentials.ai);
|
|
4608
|
-
if (!profile?.authMode || !["subscription", "api-key"].includes(profile.authMode) || cmd.identity.sessionId !== host.sessionId || profile
|
|
4609
|
+
if (!profile?.authMode || !["subscription", "api-key"].includes(profile.authMode) || cmd.identity.sessionId !== host.sessionId || !driverCapabilities(profile.driver).managedSession || !profile.model || !host.subpromptModels.available.includes(profile.model) || credential.configId !== cmd.resolvedConfig.aiProviderConfigId || profile.authMode === "subscription" !== (credential.kind === "codex-subscription"))
|
|
4609
4610
|
throw refused();
|
|
4610
4611
|
const reasoningEffort = profile.effort ?? host.reasoningEffort;
|
|
4611
4612
|
if (!["minimal", "low", "medium", "high", "xhigh"].includes(reasoningEffort)) throw refused();
|
|
@@ -4870,6 +4871,10 @@ function createAiProviderConfigSwitcher(deps) {
|
|
|
4870
4871
|
}
|
|
4871
4872
|
};
|
|
4872
4873
|
}
|
|
4874
|
+
function movedOffBlockedSeat(blockedConfigId, outcome) {
|
|
4875
|
+
if (!blockedConfigId || !outcome.mint.ok || !outcome.configId) return false;
|
|
4876
|
+
return outcome.configId !== blockedConfigId;
|
|
4877
|
+
}
|
|
4873
4878
|
|
|
4874
4879
|
// runner/src/provider-quota-forwarder.ts
|
|
4875
4880
|
function createProviderQuotaForwarder(deps) {
|
|
@@ -5008,167 +5013,470 @@ function planRuntimeSessionEmit(input) {
|
|
|
5008
5013
|
return { type: "runtime_session", driverSessionId, model, capabilitySignature };
|
|
5009
5014
|
}
|
|
5010
5015
|
|
|
5011
|
-
// runner/src/
|
|
5012
|
-
var
|
|
5013
|
-
|
|
5014
|
-
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
|
|
5022
|
-
|
|
5023
|
-
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
* Mark a compaction as occupying the driver. The returned handle is the only
|
|
5029
|
-
* thing that can release it.
|
|
5030
|
-
*/
|
|
5031
|
-
begin() {
|
|
5032
|
-
const hold = /* @__PURE__ */ Symbol("compaction");
|
|
5033
|
-
if (this.held.size === 0) {
|
|
5034
|
-
this.opened = new Promise((resolve4) => {
|
|
5035
|
-
this.release = resolve4;
|
|
5036
|
-
});
|
|
5037
|
-
}
|
|
5038
|
-
this.held.add(hold);
|
|
5039
|
-
return hold;
|
|
5040
|
-
}
|
|
5041
|
-
/**
|
|
5042
|
-
* Release one hold, opening the gate once none remain. Unknown and null
|
|
5043
|
-
* handles are ignored, so a settle signal that fires without a matching
|
|
5044
|
-
* `begin()` is harmless.
|
|
5045
|
-
*
|
|
5046
|
-
* Call this from a signal the orchestrator emits unconditionally. A `begin()`
|
|
5047
|
-
* whose `settle()` can be skipped holds user turns forever, which is a worse
|
|
5048
|
-
* failure than the discarded reply this gate exists to prevent.
|
|
5049
|
-
*/
|
|
5050
|
-
settle(hold) {
|
|
5051
|
-
if (hold == null || !this.held.delete(hold)) return;
|
|
5052
|
-
if (this.held.size > 0) return;
|
|
5053
|
-
const release2 = this.release;
|
|
5054
|
-
this.opened = null;
|
|
5055
|
-
this.release = null;
|
|
5056
|
-
release2?.();
|
|
5057
|
-
}
|
|
5058
|
-
/** Whether no compaction holds the driver right now. */
|
|
5059
|
-
isIdle() {
|
|
5060
|
-
return this.held.size === 0;
|
|
5061
|
-
}
|
|
5062
|
-
/**
|
|
5063
|
-
* Wait for the driver to be free.
|
|
5064
|
-
*
|
|
5065
|
-
* Returns `idle` when nothing was in flight, `waited` when every compaction
|
|
5066
|
-
* settled within the bound, and `timeout` when they did not. A caller that
|
|
5067
|
-
* gets `timeout` must surface it rather than dispatch: a compaction still
|
|
5068
|
-
* holding the driver past this bound is stuck, and dispatching into it
|
|
5069
|
-
* reproduces the silent loss.
|
|
5070
|
-
*
|
|
5071
|
-
* Re-checks in a loop, as `DriverSwapGate.awaitSwap` does, so a compaction
|
|
5072
|
-
* armed while this turn was already waiting is also awaited. `timeoutMs`
|
|
5073
|
-
* bounds the whole wait, not each iteration.
|
|
5074
|
-
*/
|
|
5075
|
-
async awaitIdle(timeoutMs) {
|
|
5076
|
-
if (this.held.size === 0) return "idle";
|
|
5077
|
-
const deadline = Date.now() + timeoutMs;
|
|
5078
|
-
let waited = false;
|
|
5079
|
-
while (this.held.size > 0) {
|
|
5080
|
-
const opened = this.opened;
|
|
5081
|
-
if (!opened) break;
|
|
5082
|
-
const remaining = deadline - Date.now();
|
|
5083
|
-
if (remaining <= 0) return "timeout";
|
|
5084
|
-
if (await raceDeadline(opened, remaining) === "timeout") return "timeout";
|
|
5085
|
-
waited = true;
|
|
5016
|
+
// runner/src/init-build-hold.ts
|
|
5017
|
+
var DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS = 1e4;
|
|
5018
|
+
function resolveConnectorMutateInitHoldMs(env = process.env) {
|
|
5019
|
+
const parsed = Number.parseInt(env.SKAILE_CONNECTOR_MUTATE_INIT_HOLD_MS ?? "", 10);
|
|
5020
|
+
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS;
|
|
5021
|
+
}
|
|
5022
|
+
function createInitBuildHold(now = Date.now) {
|
|
5023
|
+
let current = null;
|
|
5024
|
+
let tail = Promise.resolve();
|
|
5025
|
+
let held = 0;
|
|
5026
|
+
const building = () => current !== null && !current.done;
|
|
5027
|
+
async function awaitNewestBuild() {
|
|
5028
|
+
for (; ; ) {
|
|
5029
|
+
const build = current;
|
|
5030
|
+
if (!build) return null;
|
|
5031
|
+
if (!build.done) await build.settled;
|
|
5032
|
+
if (current === build) return build.error;
|
|
5086
5033
|
}
|
|
5087
|
-
return waited ? "waited" : "idle";
|
|
5088
|
-
}
|
|
5089
|
-
};
|
|
5090
|
-
async function raceDeadline(opened, ms) {
|
|
5091
|
-
let timer;
|
|
5092
|
-
const expired = new Promise((resolve4) => {
|
|
5093
|
-
timer = setTimeout(() => resolve4("timeout"), ms);
|
|
5094
|
-
timer.unref?.();
|
|
5095
|
-
});
|
|
5096
|
-
try {
|
|
5097
|
-
return await Promise.race([opened.then(() => "opened"), expired]);
|
|
5098
|
-
} finally {
|
|
5099
|
-
if (timer) clearTimeout(timer);
|
|
5100
5034
|
}
|
|
5035
|
+
return {
|
|
5036
|
+
beginBuild() {
|
|
5037
|
+
let resolve4;
|
|
5038
|
+
const build = {
|
|
5039
|
+
done: false,
|
|
5040
|
+
error: null,
|
|
5041
|
+
settled: new Promise((r) => {
|
|
5042
|
+
resolve4 = r;
|
|
5043
|
+
})
|
|
5044
|
+
};
|
|
5045
|
+
current = build;
|
|
5046
|
+
const settle = (error) => {
|
|
5047
|
+
if (build.done) return;
|
|
5048
|
+
build.done = true;
|
|
5049
|
+
build.error = error;
|
|
5050
|
+
resolve4();
|
|
5051
|
+
};
|
|
5052
|
+
return { succeed: () => settle(null), fail: (error) => settle(error) };
|
|
5053
|
+
},
|
|
5054
|
+
run(task, deadlineMs) {
|
|
5055
|
+
if (held === 0 && !building()) {
|
|
5056
|
+
if (current?.error) return task({ kind: "failed", error: current.error });
|
|
5057
|
+
return task({ kind: "ready", remainingMs: void 0 });
|
|
5058
|
+
}
|
|
5059
|
+
held++;
|
|
5060
|
+
const arrivedAt = now();
|
|
5061
|
+
const previous = tail;
|
|
5062
|
+
const turn = previous.then(awaitNewestBuild);
|
|
5063
|
+
let timer;
|
|
5064
|
+
const deadline = deadlineMs === void 0 ? null : new Promise((resolve4) => {
|
|
5065
|
+
timer = setTimeout(() => resolve4("timeout"), deadlineMs);
|
|
5066
|
+
timer.unref?.();
|
|
5067
|
+
});
|
|
5068
|
+
let markStarted;
|
|
5069
|
+
const started = new Promise((resolve4) => {
|
|
5070
|
+
markStarted = resolve4;
|
|
5071
|
+
});
|
|
5072
|
+
const result = (async () => {
|
|
5073
|
+
const first = deadline ? await Promise.race([turn, deadline]) : await turn;
|
|
5074
|
+
clearTimeout(timer);
|
|
5075
|
+
if (first === "timeout") {
|
|
5076
|
+
void turn.then(markStarted);
|
|
5077
|
+
return task({ kind: "timeout", waitedMs: now() - arrivedAt });
|
|
5078
|
+
}
|
|
5079
|
+
markStarted();
|
|
5080
|
+
if (first) return task({ kind: "failed", error: first });
|
|
5081
|
+
return task({
|
|
5082
|
+
kind: "ready",
|
|
5083
|
+
remainingMs: deadlineMs === void 0 ? void 0 : Math.max(0, deadlineMs - (now() - arrivedAt))
|
|
5084
|
+
});
|
|
5085
|
+
})();
|
|
5086
|
+
tail = started;
|
|
5087
|
+
void Promise.allSettled([turn, result]).then(() => {
|
|
5088
|
+
held--;
|
|
5089
|
+
});
|
|
5090
|
+
return result;
|
|
5091
|
+
},
|
|
5092
|
+
held: () => held
|
|
5093
|
+
};
|
|
5101
5094
|
}
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
|
|
5109
|
-
|
|
5110
|
-
|
|
5111
|
-
}
|
|
5112
|
-
var PLATFORM_COMPACTION_TURN_WAIT_MS = 3e4;
|
|
5113
|
-
function compactionTurnWaitFor(trigger) {
|
|
5114
|
-
return trigger === "threshold" ? compactionTurnWaitMs() : PLATFORM_COMPACTION_TURN_WAIT_MS;
|
|
5095
|
+
|
|
5096
|
+
// runner/src/serial-lock.ts
|
|
5097
|
+
function createSerialLock() {
|
|
5098
|
+
let tail = Promise.resolve();
|
|
5099
|
+
return (fn) => {
|
|
5100
|
+
const run = tail.then(fn, fn);
|
|
5101
|
+
tail = run.catch(() => void 0);
|
|
5102
|
+
return run;
|
|
5103
|
+
};
|
|
5115
5104
|
}
|
|
5116
|
-
|
|
5117
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5105
|
+
function createCoalescedTask(lock, fn) {
|
|
5106
|
+
let waiting = null;
|
|
5107
|
+
return (...args) => {
|
|
5108
|
+
if (waiting) return waiting;
|
|
5109
|
+
const run = lock(() => {
|
|
5110
|
+
waiting = null;
|
|
5111
|
+
return fn(...args);
|
|
5112
|
+
});
|
|
5113
|
+
waiting = run;
|
|
5114
|
+
return run;
|
|
5123
5115
|
};
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5116
|
+
}
|
|
5117
|
+
async function recordStagedSkills(staged, projectDir, skillsDir, names, timeoutMs) {
|
|
5118
|
+
for (const name of names) {
|
|
5119
|
+
const path6 = join(projectDir, skillsDir, name);
|
|
5120
|
+
const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
|
|
5121
|
+
staged.set(
|
|
5122
|
+
name,
|
|
5123
|
+
st?.isDirectory() && st.birthtimeMs > 0 ? { path: path6, dev: st.dev, ino: st.ino, birthtimeMs: st.birthtimeMs } : null
|
|
5129
5124
|
);
|
|
5130
|
-
return null;
|
|
5131
|
-
}
|
|
5132
|
-
if (deps.isSwapping?.()) {
|
|
5133
|
-
release2();
|
|
5134
|
-
deps.log("[serve] compaction skipped: a driver swap is pending");
|
|
5135
|
-
return null;
|
|
5136
5125
|
}
|
|
5137
|
-
const endTurn = deps.claimTurnSlot?.();
|
|
5138
|
-
return () => {
|
|
5139
|
-
endTurn?.();
|
|
5140
|
-
release2();
|
|
5141
|
-
};
|
|
5142
5126
|
}
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
const endTurn = await deps.claimTurn();
|
|
5148
|
-
if (deps.gate.isIdle()) return endTurn;
|
|
5149
|
-
endTurn();
|
|
5150
|
-
}
|
|
5151
|
-
throw new Error(`turn overtaken by a compaction ${maxAttempts} times running`);
|
|
5127
|
+
async function isStillOurs(record2, path6, timeoutMs) {
|
|
5128
|
+
if (!record2 || record2.path !== path6) return false;
|
|
5129
|
+
const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
|
|
5130
|
+
return st?.isDirectory() === true && st.dev === record2.dev && st.ino === record2.ino && st.birthtimeMs === record2.birthtimeMs;
|
|
5152
5131
|
}
|
|
5153
|
-
|
|
5154
|
-
|
|
5155
|
-
|
|
5156
|
-
|
|
5157
|
-
|
|
5158
|
-
|
|
5159
|
-
deps.sendEvent({ type: "error", message: COMPACTION_GATE_TIMEOUT_MESSAGE, fatal: false });
|
|
5160
|
-
return false;
|
|
5132
|
+
async function recordLoadedSkillDigests(loaded, projectDir, skillsDir, names, opts) {
|
|
5133
|
+
for (const name of names) {
|
|
5134
|
+
if (opts.driverUp && opts.previouslyStaged.has(name)) continue;
|
|
5135
|
+
const path6 = join(projectDir, skillsDir, name);
|
|
5136
|
+
loaded.set(name, { path: path6, digest: await stagedSkillDigest(path6) });
|
|
5137
|
+
}
|
|
5161
5138
|
}
|
|
5162
|
-
|
|
5163
|
-
|
|
5164
|
-
var
|
|
5165
|
-
var
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5139
|
+
var DIGEST_DEADLINE_FACTOR = 4;
|
|
5140
|
+
var DIGEST_MAX_BYTES = 64 * 1024 * 1024;
|
|
5141
|
+
var DIGEST_CHUNK_BYTES = 64 * 1024;
|
|
5142
|
+
var DIGEST_OPEN_FLAGS = constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK;
|
|
5143
|
+
async function stagedSkillDigest(dir, timeoutMs) {
|
|
5144
|
+
return tryWithFsDeadline(
|
|
5145
|
+
`digest ${dir}`,
|
|
5146
|
+
async () => {
|
|
5147
|
+
const hash = createHash("sha256");
|
|
5148
|
+
let budget = DIGEST_MAX_BYTES;
|
|
5149
|
+
const hashFile = async (path6) => {
|
|
5150
|
+
const fh = await open(path6, DIGEST_OPEN_FLAGS);
|
|
5151
|
+
try {
|
|
5152
|
+
const st = await fh.stat();
|
|
5153
|
+
if (!st.isFile()) throw new Error(`not a regular file: ${path6}`);
|
|
5154
|
+
if (st.size > budget) throw new Error("skill too large to digest");
|
|
5155
|
+
const buf = Buffer.alloc(DIGEST_CHUNK_BYTES);
|
|
5156
|
+
let total = 0;
|
|
5157
|
+
for (; ; ) {
|
|
5158
|
+
const { bytesRead } = await fh.read(buf, 0, buf.length, null);
|
|
5159
|
+
if (bytesRead === 0) break;
|
|
5160
|
+
total += bytesRead;
|
|
5161
|
+
if (total > budget) throw new Error("skill too large to digest");
|
|
5162
|
+
hash.update(buf.subarray(0, bytesRead));
|
|
5163
|
+
}
|
|
5164
|
+
budget -= total;
|
|
5165
|
+
hash.update(`\0${total}\0`);
|
|
5166
|
+
} finally {
|
|
5167
|
+
await fh.close();
|
|
5168
|
+
}
|
|
5169
|
+
};
|
|
5170
|
+
const walk = async (rel) => {
|
|
5171
|
+
const here = rel ? join(dir, rel) : dir;
|
|
5172
|
+
if (rel && !(await lstat(here)).isDirectory()) throw new Error(`not a dir: ${here}`);
|
|
5173
|
+
const entries = await readdir(here, { withFileTypes: true });
|
|
5174
|
+
entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
5175
|
+
for (const entry of entries) {
|
|
5176
|
+
if (!rel && entry.name === STAGED_SKILL_MARKER) continue;
|
|
5177
|
+
const path6 = rel ? `${rel}/${entry.name}` : entry.name;
|
|
5178
|
+
if (entry.isDirectory()) {
|
|
5179
|
+
hash.update(`d\0${path6}\0`);
|
|
5180
|
+
await walk(path6);
|
|
5181
|
+
} else if (entry.isSymbolicLink()) {
|
|
5182
|
+
hash.update(`l\0${path6}\0${await readlink(join(dir, path6))}\0`);
|
|
5183
|
+
} else if (entry.isFile()) {
|
|
5184
|
+
hash.update(`f\0${path6}\0`);
|
|
5185
|
+
await hashFile(join(dir, path6));
|
|
5186
|
+
} else {
|
|
5187
|
+
hash.update(`o\0${path6}\0`);
|
|
5188
|
+
}
|
|
5189
|
+
}
|
|
5190
|
+
};
|
|
5191
|
+
await walk("");
|
|
5192
|
+
return hash.digest("hex");
|
|
5193
|
+
},
|
|
5194
|
+
null,
|
|
5195
|
+
fsDeadlineMs() * DIGEST_DEADLINE_FACTOR
|
|
5196
|
+
);
|
|
5197
|
+
}
|
|
5198
|
+
async function attachStagedSkill(deps, name) {
|
|
5199
|
+
try {
|
|
5200
|
+
const skillsDir = deps.skillsDir();
|
|
5201
|
+
const dirName = name.includes("/") ? name.split("/").pop() : name;
|
|
5202
|
+
const { staged, unchanged } = await deps.withSkillFsLock(async () => {
|
|
5203
|
+
const dest = join(deps.projectDir, skillsDir, dirName);
|
|
5204
|
+
const loaded = deps.stagedSkillDirs.has(dirName) ? deps.loadedSkillDigests.get(dirName) : void 0;
|
|
5205
|
+
const names = await stageMaterializedSkills(deps.projectDir, skillsDir, { declared: [name] });
|
|
5206
|
+
let same = false;
|
|
5207
|
+
if (names.includes(dirName)) {
|
|
5208
|
+
const digest = await stagedSkillDigest(dest);
|
|
5209
|
+
same = digest !== null && loaded?.path === dest && loaded.digest === digest;
|
|
5210
|
+
if (!same) deps.loadedSkillDigests.set(dirName, { path: dest, digest });
|
|
5211
|
+
}
|
|
5212
|
+
await recordStagedSkills(deps.stagedSkillDirs, deps.projectDir, skillsDir, names);
|
|
5213
|
+
return { staged: names, unchanged: same ? dirName : null };
|
|
5214
|
+
});
|
|
5215
|
+
if (staged.length === 0) {
|
|
5216
|
+
return {
|
|
5217
|
+
ok: false,
|
|
5218
|
+
code: "skill_not_materialized",
|
|
5219
|
+
message: `no materialized skill matching "${name}" under .skaile/assets/skill`
|
|
5220
|
+
};
|
|
5221
|
+
}
|
|
5222
|
+
const live = deps.driverStarted();
|
|
5223
|
+
const toRestart = staged.filter((s) => s !== unchanged);
|
|
5224
|
+
if (toRestart.length === 0) {
|
|
5225
|
+
deps.log(
|
|
5226
|
+
`[serve] runner.attach_instance: skill ${staged.join(", ")} already staged and unchanged \u2014 no driver restart`
|
|
5227
|
+
);
|
|
5228
|
+
return { ok: true, id: name, live, toolCount: 0 };
|
|
5229
|
+
}
|
|
5230
|
+
deps.log(`[serve] runner.attach_instance staged skill(s): ${toRestart.join(", ")}`);
|
|
5231
|
+
deps.scheduleSkillRestart(toRestart.map((s) => ({ name: s, action: "add" })));
|
|
5232
|
+
return { ok: true, id: name, live, toolCount: 0 };
|
|
5233
|
+
} catch (err) {
|
|
5234
|
+
return {
|
|
5235
|
+
ok: false,
|
|
5236
|
+
code: "skill_attach_failed",
|
|
5237
|
+
message: err instanceof Error ? err.message : String(err)
|
|
5238
|
+
};
|
|
5239
|
+
}
|
|
5240
|
+
}
|
|
5241
|
+
async function detachStagedSkill(deps, name) {
|
|
5242
|
+
try {
|
|
5243
|
+
const skillsDir = deps.skillsDir();
|
|
5244
|
+
const dirName = name.split("/").pop() ?? name;
|
|
5245
|
+
const result = await deps.withSkillFsLock(async () => {
|
|
5246
|
+
const knownStaged = await isStillOurs(
|
|
5247
|
+
deps.stagedSkillDirs.get(dirName),
|
|
5248
|
+
join(deps.projectDir, skillsDir, dirName)
|
|
5249
|
+
);
|
|
5250
|
+
return unstageSkill(deps.projectDir, skillsDir, name, { knownStaged });
|
|
5251
|
+
});
|
|
5252
|
+
const live = deps.driverStarted();
|
|
5253
|
+
if ("reason" in result) {
|
|
5254
|
+
deps.log(
|
|
5255
|
+
`[serve] runner.detach_instance: "${result.name}" exists but was not staged by the runner \u2014 left in place`
|
|
5256
|
+
);
|
|
5257
|
+
return { ok: true, id: result.name, removed: false, live, reason: result.reason };
|
|
5258
|
+
}
|
|
5259
|
+
const wasTracked = deps.stagedSkillDirs.delete(result.name);
|
|
5260
|
+
if (!result.removedStaged && !wasTracked) {
|
|
5261
|
+
deps.log(`[serve] runner.detach_instance: skill "${result.name}" was not staged`);
|
|
5262
|
+
return { ok: true, id: result.name, removed: result.removedAsset, live };
|
|
5263
|
+
}
|
|
5264
|
+
deps.log(`[serve] runner.detach_instance unstaged skill: ${result.name}`);
|
|
5265
|
+
deps.scheduleSkillRestart([{ name: result.name, action: "remove" }]);
|
|
5266
|
+
return { ok: true, id: result.name, removed: true, live };
|
|
5267
|
+
} catch (err) {
|
|
5268
|
+
return {
|
|
5269
|
+
ok: false,
|
|
5270
|
+
code: "skill_detach_failed",
|
|
5271
|
+
message: err instanceof Error ? err.message : String(err)
|
|
5272
|
+
};
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
async function pathState(path6) {
|
|
5276
|
+
try {
|
|
5277
|
+
await withFsDeadline(`lstat ${path6}`, () => lstat(path6));
|
|
5278
|
+
return "present";
|
|
5279
|
+
} catch (err) {
|
|
5280
|
+
return err?.code === "ENOENT" ? "absent" : "unknown";
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
async function removeUnlistedStagedSkills(deps, skillsDir) {
|
|
5284
|
+
const allowed = await readSkillAllowList(deps.projectDir);
|
|
5285
|
+
if (!allowed) return [];
|
|
5286
|
+
const root = join(deps.projectDir, skillsDir);
|
|
5287
|
+
const entries = await tryWithFsDeadline(
|
|
5288
|
+
`readdir ${root}`,
|
|
5289
|
+
() => readdir(root, { withFileTypes: true }),
|
|
5290
|
+
[]
|
|
5291
|
+
);
|
|
5292
|
+
const removed = [];
|
|
5293
|
+
for (const entry of entries) {
|
|
5294
|
+
if (!entry.isDirectory() || allowed.has(entry.name)) continue;
|
|
5295
|
+
try {
|
|
5296
|
+
const dir = join(root, entry.name);
|
|
5297
|
+
if (await pathState(join(deps.projectDir, ".skaile/assets/skill", entry.name)) !== "absent") {
|
|
5298
|
+
continue;
|
|
5299
|
+
}
|
|
5300
|
+
const knownStaged = await isStillOurs(deps.stagedSkillDirs.get(entry.name), dir);
|
|
5301
|
+
if (!knownStaged && !await isStagedSkillMarkerFor(dir, entry.name).catch(() => false))
|
|
5302
|
+
continue;
|
|
5303
|
+
const result = await unstageSkill(deps.projectDir, skillsDir, entry.name, {
|
|
5304
|
+
knownStaged,
|
|
5305
|
+
keepAsset: true
|
|
5306
|
+
});
|
|
5307
|
+
if ("reason" in result || !result.removedStaged) continue;
|
|
5308
|
+
deps.stagedSkillDirs.delete(result.name);
|
|
5309
|
+
removed.push(result.name);
|
|
5310
|
+
} catch (err) {
|
|
5311
|
+
deps.log(
|
|
5312
|
+
`[serve] could not remove unlisted skill "${entry.name}" (left in place): ${err instanceof Error ? err.message : String(err)}`
|
|
5313
|
+
);
|
|
5314
|
+
}
|
|
5315
|
+
}
|
|
5316
|
+
return removed;
|
|
5317
|
+
}
|
|
5318
|
+
|
|
5319
|
+
// runner/src/compaction-gate.ts
|
|
5320
|
+
var CompactionGate = class {
|
|
5321
|
+
/**
|
|
5322
|
+
* Every compaction currently holding the driver.
|
|
5323
|
+
*
|
|
5324
|
+
* A set rather than a boolean because holds can overlap: a driver swap
|
|
5325
|
+
* rebuilds the orchestrator, and the new instance carries its own
|
|
5326
|
+
* `_isCompacting`, so it can start a compaction while the previous
|
|
5327
|
+
* instance's call is still unwinding. Keyed by handle so the older one
|
|
5328
|
+
* settling cannot open the gate under the newer one — the same identity
|
|
5329
|
+
* check `DriverSwapGate.beginSwap` makes for swaps.
|
|
5330
|
+
*/
|
|
5331
|
+
held = /* @__PURE__ */ new Set();
|
|
5332
|
+
/** Resolves when the last hold is released. Null whenever the driver is free. */
|
|
5333
|
+
opened = null;
|
|
5334
|
+
release = null;
|
|
5335
|
+
/**
|
|
5336
|
+
* Mark a compaction as occupying the driver. The returned handle is the only
|
|
5337
|
+
* thing that can release it.
|
|
5338
|
+
*/
|
|
5339
|
+
begin() {
|
|
5340
|
+
const hold = /* @__PURE__ */ Symbol("compaction");
|
|
5341
|
+
if (this.held.size === 0) {
|
|
5342
|
+
this.opened = new Promise((resolve4) => {
|
|
5343
|
+
this.release = resolve4;
|
|
5344
|
+
});
|
|
5345
|
+
}
|
|
5346
|
+
this.held.add(hold);
|
|
5347
|
+
return hold;
|
|
5348
|
+
}
|
|
5349
|
+
/**
|
|
5350
|
+
* Release one hold, opening the gate once none remain. Unknown and null
|
|
5351
|
+
* handles are ignored, so a settle signal that fires without a matching
|
|
5352
|
+
* `begin()` is harmless.
|
|
5353
|
+
*
|
|
5354
|
+
* Call this from a signal the orchestrator emits unconditionally. A `begin()`
|
|
5355
|
+
* whose `settle()` can be skipped holds user turns forever, which is a worse
|
|
5356
|
+
* failure than the discarded reply this gate exists to prevent.
|
|
5357
|
+
*/
|
|
5358
|
+
settle(hold) {
|
|
5359
|
+
if (hold == null || !this.held.delete(hold)) return;
|
|
5360
|
+
if (this.held.size > 0) return;
|
|
5361
|
+
const release2 = this.release;
|
|
5362
|
+
this.opened = null;
|
|
5363
|
+
this.release = null;
|
|
5364
|
+
release2?.();
|
|
5365
|
+
}
|
|
5366
|
+
/** Whether no compaction holds the driver right now. */
|
|
5367
|
+
isIdle() {
|
|
5368
|
+
return this.held.size === 0;
|
|
5369
|
+
}
|
|
5370
|
+
/**
|
|
5371
|
+
* Wait for the driver to be free.
|
|
5372
|
+
*
|
|
5373
|
+
* Returns `idle` when nothing was in flight, `waited` when every compaction
|
|
5374
|
+
* settled within the bound, and `timeout` when they did not. A caller that
|
|
5375
|
+
* gets `timeout` must surface it rather than dispatch: a compaction still
|
|
5376
|
+
* holding the driver past this bound is stuck, and dispatching into it
|
|
5377
|
+
* reproduces the silent loss.
|
|
5378
|
+
*
|
|
5379
|
+
* Re-checks in a loop, as `DriverSwapGate.awaitSwap` does, so a compaction
|
|
5380
|
+
* armed while this turn was already waiting is also awaited. `timeoutMs`
|
|
5381
|
+
* bounds the whole wait, not each iteration.
|
|
5382
|
+
*/
|
|
5383
|
+
async awaitIdle(timeoutMs) {
|
|
5384
|
+
if (this.held.size === 0) return "idle";
|
|
5385
|
+
const deadline = Date.now() + timeoutMs;
|
|
5386
|
+
let waited = false;
|
|
5387
|
+
while (this.held.size > 0) {
|
|
5388
|
+
const opened = this.opened;
|
|
5389
|
+
if (!opened) break;
|
|
5390
|
+
const remaining = deadline - Date.now();
|
|
5391
|
+
if (remaining <= 0) return "timeout";
|
|
5392
|
+
if (await raceDeadline(opened, remaining) === "timeout") return "timeout";
|
|
5393
|
+
waited = true;
|
|
5394
|
+
}
|
|
5395
|
+
return waited ? "waited" : "idle";
|
|
5396
|
+
}
|
|
5397
|
+
};
|
|
5398
|
+
async function raceDeadline(opened, ms) {
|
|
5399
|
+
let timer;
|
|
5400
|
+
const expired = new Promise((resolve4) => {
|
|
5401
|
+
timer = setTimeout(() => resolve4("timeout"), ms);
|
|
5402
|
+
timer.unref?.();
|
|
5403
|
+
});
|
|
5404
|
+
try {
|
|
5405
|
+
return await Promise.race([opened.then(() => "opened"), expired]);
|
|
5406
|
+
} finally {
|
|
5407
|
+
if (timer) clearTimeout(timer);
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
var DEFAULT_COMPACTION_GATE_TIMEOUT_MS = 60 * 6e4;
|
|
5411
|
+
function compactionGateTimeoutMs() {
|
|
5412
|
+
const raw = Number(process.env.SKAILE_COMPACTION_GATE_TIMEOUT_MS);
|
|
5413
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_GATE_TIMEOUT_MS;
|
|
5414
|
+
}
|
|
5415
|
+
var DEFAULT_COMPACTION_TURN_WAIT_MS = 10 * 6e4;
|
|
5416
|
+
function compactionTurnWaitMs() {
|
|
5417
|
+
const raw = Number(process.env.SKAILE_COMPACTION_TURN_WAIT_MS);
|
|
5418
|
+
return Number.isFinite(raw) && raw > 0 ? raw : DEFAULT_COMPACTION_TURN_WAIT_MS;
|
|
5419
|
+
}
|
|
5420
|
+
var PLATFORM_COMPACTION_TURN_WAIT_MS = 3e4;
|
|
5421
|
+
function compactionTurnWaitFor(trigger) {
|
|
5422
|
+
return trigger === "threshold" ? compactionTurnWaitMs() : PLATFORM_COMPACTION_TURN_WAIT_MS;
|
|
5423
|
+
}
|
|
5424
|
+
async function claimDriverForCompaction(deps) {
|
|
5425
|
+
const hold = deps.gate.begin();
|
|
5426
|
+
let released = false;
|
|
5427
|
+
const release2 = () => {
|
|
5428
|
+
if (released) return;
|
|
5429
|
+
released = true;
|
|
5430
|
+
deps.gate.settle(hold);
|
|
5431
|
+
};
|
|
5432
|
+
const { timeoutMs } = deps;
|
|
5433
|
+
if (await raceDeadline(deps.awaitClaimedTurns(), timeoutMs) !== "opened") {
|
|
5434
|
+
release2();
|
|
5435
|
+
deps.log(
|
|
5436
|
+
`[serve] compaction skipped: a turn still held the driver after ${Math.round(timeoutMs / 1e3)}s`
|
|
5437
|
+
);
|
|
5438
|
+
return null;
|
|
5439
|
+
}
|
|
5440
|
+
if (deps.isDriverReplaced()) {
|
|
5441
|
+
release2();
|
|
5442
|
+
deps.log("[serve] compaction skipped: its driver is being or has been replaced");
|
|
5443
|
+
return null;
|
|
5444
|
+
}
|
|
5445
|
+
const endTurn = deps.claimTurnSlot();
|
|
5446
|
+
return () => {
|
|
5447
|
+
endTurn();
|
|
5448
|
+
release2();
|
|
5449
|
+
};
|
|
5450
|
+
}
|
|
5451
|
+
var TURN_COMPACTION_YIELD_ATTEMPTS = 3;
|
|
5452
|
+
async function beginTurnClearOfCompaction(deps) {
|
|
5453
|
+
for (let attempt = 0; attempt < TURN_COMPACTION_YIELD_ATTEMPTS; attempt += 1) {
|
|
5454
|
+
if (!await deps.awaitIdle()) return null;
|
|
5455
|
+
const endTurn = await deps.claimTurn();
|
|
5456
|
+
if (deps.gate.isIdle()) return endTurn;
|
|
5457
|
+
endTurn();
|
|
5458
|
+
}
|
|
5459
|
+
throw new Error(`turn overtaken by a compaction ${TURN_COMPACTION_YIELD_ATTEMPTS} times running`);
|
|
5460
|
+
}
|
|
5461
|
+
var COMPACTION_GATE_TIMEOUT_MESSAGE = "The session is still compacting its history and could not take this message. Send it again in a moment.";
|
|
5462
|
+
async function guardTurnAgainstCompaction(deps) {
|
|
5463
|
+
const outcome = await deps.gate.awaitIdle(compactionGateTimeoutMs());
|
|
5464
|
+
if (outcome === "waited") deps.log(`[serve] ${deps.what} released after compaction settled`);
|
|
5465
|
+
if (outcome !== "timeout") return true;
|
|
5466
|
+
deps.log(`[serve] ${deps.what} abandoned: a compaction has held the driver past its bound`);
|
|
5467
|
+
deps.sendEvent({ type: "error", message: COMPACTION_GATE_TIMEOUT_MESSAGE, fatal: false });
|
|
5468
|
+
return false;
|
|
5469
|
+
}
|
|
5470
|
+
|
|
5471
|
+
// runner/src/driver-swap-gate.ts
|
|
5472
|
+
var TURN_BIND_ATTEMPTS = 3;
|
|
5473
|
+
var DriverSwapGate = class {
|
|
5474
|
+
/** Resolves when the in-flight driver recreate settles (resolve or reject). */
|
|
5475
|
+
activeDriverSwap = null;
|
|
5476
|
+
/** FIFO chain; resolves once every started turn has settled. */
|
|
5477
|
+
turnTail = Promise.resolve();
|
|
5478
|
+
/** FIFO chain of swaps; never rejects, resolves once every queued swap settled. */
|
|
5479
|
+
swapTail = Promise.resolve();
|
|
5172
5480
|
/**
|
|
5173
5481
|
* Mark a turn as in flight. Call at the real `driver.prompt()` dispatch — not
|
|
5174
5482
|
* earlier — so a same-handler restart (e.g. restaging skills before the turn)
|
|
@@ -5273,103 +5581,23 @@ var DriverSwapGate = class {
|
|
|
5273
5581
|
beginSwap(recreate) {
|
|
5274
5582
|
this.activeDriverSwap = recreate;
|
|
5275
5583
|
const clear = () => {
|
|
5276
|
-
if (this.activeDriverSwap === recreate) this.activeDriverSwap = null;
|
|
5277
|
-
};
|
|
5278
|
-
recreate.then(clear, clear);
|
|
5279
|
-
}
|
|
5280
|
-
/**
|
|
5281
|
-
* Await the in-flight swap before reading the live driver. Re-checks in a loop
|
|
5282
|
-
* so a second swap starting during the wait is also awaited.
|
|
5283
|
-
*/
|
|
5284
|
-
async awaitSwap() {
|
|
5285
|
-
while (this.activeDriverSwap) {
|
|
5286
|
-
try {
|
|
5287
|
-
await this.activeDriverSwap;
|
|
5288
|
-
} catch {
|
|
5289
|
-
}
|
|
5290
|
-
}
|
|
5291
|
-
}
|
|
5292
|
-
};
|
|
5293
|
-
|
|
5294
|
-
// runner/src/init-build-hold.ts
|
|
5295
|
-
var DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS = 1e4;
|
|
5296
|
-
function resolveConnectorMutateInitHoldMs(env = process.env) {
|
|
5297
|
-
const parsed = Number.parseInt(env.SKAILE_CONNECTOR_MUTATE_INIT_HOLD_MS ?? "", 10);
|
|
5298
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : DEFAULT_CONNECTOR_MUTATE_INIT_HOLD_MS;
|
|
5299
|
-
}
|
|
5300
|
-
function createInitBuildHold(now = Date.now) {
|
|
5301
|
-
let current = null;
|
|
5302
|
-
let tail = Promise.resolve();
|
|
5303
|
-
let held = 0;
|
|
5304
|
-
const building = () => current !== null && !current.done;
|
|
5305
|
-
async function awaitNewestBuild() {
|
|
5306
|
-
for (; ; ) {
|
|
5307
|
-
const build = current;
|
|
5308
|
-
if (!build) return null;
|
|
5309
|
-
if (!build.done) await build.settled;
|
|
5310
|
-
if (current === build) return build.error;
|
|
5311
|
-
}
|
|
5584
|
+
if (this.activeDriverSwap === recreate) this.activeDriverSwap = null;
|
|
5585
|
+
};
|
|
5586
|
+
recreate.then(clear, clear);
|
|
5312
5587
|
}
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
};
|
|
5323
|
-
current = build;
|
|
5324
|
-
const settle = (error) => {
|
|
5325
|
-
if (build.done) return;
|
|
5326
|
-
build.done = true;
|
|
5327
|
-
build.error = error;
|
|
5328
|
-
resolve4();
|
|
5329
|
-
};
|
|
5330
|
-
return { succeed: () => settle(null), fail: (error) => settle(error) };
|
|
5331
|
-
},
|
|
5332
|
-
run(task, deadlineMs) {
|
|
5333
|
-
if (held === 0 && !building()) {
|
|
5334
|
-
if (current?.error) return task({ kind: "failed", error: current.error });
|
|
5335
|
-
return task({ kind: "ready", remainingMs: void 0 });
|
|
5588
|
+
/**
|
|
5589
|
+
* Await the in-flight swap before reading the live driver. Re-checks in a loop
|
|
5590
|
+
* so a second swap starting during the wait is also awaited.
|
|
5591
|
+
*/
|
|
5592
|
+
async awaitSwap() {
|
|
5593
|
+
while (this.activeDriverSwap) {
|
|
5594
|
+
try {
|
|
5595
|
+
await this.activeDriverSwap;
|
|
5596
|
+
} catch {
|
|
5336
5597
|
}
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
const turn = previous.then(awaitNewestBuild);
|
|
5341
|
-
let timer;
|
|
5342
|
-
const deadline = deadlineMs === void 0 ? null : new Promise((resolve4) => {
|
|
5343
|
-
timer = setTimeout(() => resolve4("timeout"), deadlineMs);
|
|
5344
|
-
timer.unref?.();
|
|
5345
|
-
});
|
|
5346
|
-
let markStarted;
|
|
5347
|
-
const started = new Promise((resolve4) => {
|
|
5348
|
-
markStarted = resolve4;
|
|
5349
|
-
});
|
|
5350
|
-
const result = (async () => {
|
|
5351
|
-
const first = deadline ? await Promise.race([turn, deadline]) : await turn;
|
|
5352
|
-
clearTimeout(timer);
|
|
5353
|
-
if (first === "timeout") {
|
|
5354
|
-
void turn.then(markStarted);
|
|
5355
|
-
return task({ kind: "timeout", waitedMs: now() - arrivedAt });
|
|
5356
|
-
}
|
|
5357
|
-
markStarted();
|
|
5358
|
-
if (first) return task({ kind: "failed", error: first });
|
|
5359
|
-
return task({
|
|
5360
|
-
kind: "ready",
|
|
5361
|
-
remainingMs: deadlineMs === void 0 ? void 0 : Math.max(0, deadlineMs - (now() - arrivedAt))
|
|
5362
|
-
});
|
|
5363
|
-
})();
|
|
5364
|
-
tail = started;
|
|
5365
|
-
void Promise.allSettled([turn, result]).then(() => {
|
|
5366
|
-
held--;
|
|
5367
|
-
});
|
|
5368
|
-
return result;
|
|
5369
|
-
},
|
|
5370
|
-
held: () => held
|
|
5371
|
-
};
|
|
5372
|
-
}
|
|
5598
|
+
}
|
|
5599
|
+
}
|
|
5600
|
+
};
|
|
5373
5601
|
|
|
5374
5602
|
// runner/src/pending-turns.ts
|
|
5375
5603
|
var PendingTurns = class {
|
|
@@ -5393,9 +5621,15 @@ var PendingTurns = class {
|
|
|
5393
5621
|
}
|
|
5394
5622
|
};
|
|
5395
5623
|
}
|
|
5396
|
-
/**
|
|
5397
|
-
|
|
5398
|
-
|
|
5624
|
+
/**
|
|
5625
|
+
* Whether to report idle now, at the end of something that ran on the driver.
|
|
5626
|
+
* A `"turn"` end belongs to a counted turn, which is still counted when it
|
|
5627
|
+
* fires. A `"compaction"` end (the compaction turn, or the snapshot turn after
|
|
5628
|
+
* it) is no counted turn, so every counted turn is waiting behind it.
|
|
5629
|
+
*/
|
|
5630
|
+
shouldReportIdle(endedBy) {
|
|
5631
|
+
const own = endedBy === "turn" ? 1 : 0;
|
|
5632
|
+
if (this.count > own) {
|
|
5399
5633
|
this.idleOwed = true;
|
|
5400
5634
|
return false;
|
|
5401
5635
|
}
|
|
@@ -5463,248 +5697,298 @@ var PromptTurnQueue = class {
|
|
|
5463
5697
|
}
|
|
5464
5698
|
};
|
|
5465
5699
|
|
|
5466
|
-
// runner/src/
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5700
|
+
// runner/src/turn-scheduler.ts
|
|
5701
|
+
var FLOW_TURN_COMPACTION_TIMEOUT = "Flow turn abandoned: a compaction held the driver";
|
|
5702
|
+
var TurnScheduler = class {
|
|
5703
|
+
constructor(deps) {
|
|
5704
|
+
this.deps = deps;
|
|
5705
|
+
}
|
|
5706
|
+
deps;
|
|
5707
|
+
swaps = new DriverSwapGate();
|
|
5708
|
+
compactions = new CompactionGate();
|
|
5709
|
+
pending = new PendingTurns(() => this.sendIdle());
|
|
5710
|
+
queue = new PromptTurnQueue();
|
|
5711
|
+
/** The compaction that armed the event suppression; null while none runs. */
|
|
5712
|
+
suppressedBy = null;
|
|
5713
|
+
/** Compactions past their end callback and not yet settled: a snapshot turn may still run. */
|
|
5714
|
+
snapshotTurns = /* @__PURE__ */ new Set();
|
|
5715
|
+
/** Counts {@link compactionHooks} calls; only the latest hooks may start a compaction. */
|
|
5716
|
+
hooksGeneration = 0;
|
|
5717
|
+
/** Run a chat prompt: queue it, wait out swaps and compactions, claim the driver, dispatch. */
|
|
5718
|
+
prompt(turn) {
|
|
5719
|
+
return this.counted(async () => {
|
|
5720
|
+
const place = this.queue.join(turn.owner);
|
|
5721
|
+
try {
|
|
5722
|
+
if (place.queued) {
|
|
5723
|
+
turn.onQueued?.();
|
|
5724
|
+
const queuedAt = Date.now();
|
|
5725
|
+
await place.ready;
|
|
5726
|
+
this.deps.logPhase("prompt_queue_wait", queuedAt, { dropped: place.dropped });
|
|
5727
|
+
if (place.dropped) return;
|
|
5728
|
+
}
|
|
5729
|
+
await this.runPrompt(turn, place.leave);
|
|
5730
|
+
} finally {
|
|
5731
|
+
place.leave();
|
|
5732
|
+
}
|
|
5482
5733
|
});
|
|
5483
|
-
waiting = run;
|
|
5484
|
-
return run;
|
|
5485
|
-
};
|
|
5486
|
-
}
|
|
5487
|
-
async function recordStagedSkills(staged, projectDir, skillsDir, names, timeoutMs) {
|
|
5488
|
-
for (const name of names) {
|
|
5489
|
-
const path6 = join(projectDir, skillsDir, name);
|
|
5490
|
-
const st = await tryWithFsDeadline(`lstat ${path6}`, () => lstat(path6), null, timeoutMs);
|
|
5491
|
-
staged.set(
|
|
5492
|
-
name,
|
|
5493
|
-
st?.isDirectory() && st.birthtimeMs > 0 ? { path: path6, dev: st.dev, ino: st.ino, birthtimeMs: st.birthtimeMs } : null
|
|
5494
|
-
);
|
|
5495
5734
|
}
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
|
|
5503
|
-
|
|
5504
|
-
|
|
5505
|
-
|
|
5506
|
-
|
|
5735
|
+
/**
|
|
5736
|
+
* Run a question reply. A paused question takes the answer at once, ahead of
|
|
5737
|
+
* every wait. A recreate waits for the paused turn, and that turn waits for
|
|
5738
|
+
* this answer, so gating the answer on the swap wedges the session for good.
|
|
5739
|
+
* Anything else is a fresh turn and queues like a prompt.
|
|
5740
|
+
*/
|
|
5741
|
+
reply(turn) {
|
|
5742
|
+
return this.counted(async () => {
|
|
5743
|
+
if (!await turn.admit()) return;
|
|
5744
|
+
const paused = this.deps.getDriver();
|
|
5745
|
+
if (paused.hasPendingQuestion()) {
|
|
5746
|
+
if (paused.answerQuestion(turn.answer, turn.question, turn.requestId)) {
|
|
5747
|
+
turn.onAnswered?.();
|
|
5748
|
+
return;
|
|
5749
|
+
}
|
|
5750
|
+
} else {
|
|
5751
|
+
await this.swaps.awaitSwap();
|
|
5752
|
+
}
|
|
5753
|
+
if (!this.deps.getDriver().acceptsReplyAsPrompt) {
|
|
5754
|
+
if (!this.deps.getDriver().hasPendingQuestion()) {
|
|
5755
|
+
this.deps.log("[serve] reply: driver takes no reply as a prompt; answer not delivered");
|
|
5756
|
+
this.deps.sendEvent({
|
|
5757
|
+
type: "error",
|
|
5758
|
+
message: "This question is no longer open, so the agent did not get your answer. Send it as a new message.",
|
|
5759
|
+
fatal: false
|
|
5760
|
+
});
|
|
5761
|
+
}
|
|
5762
|
+
return;
|
|
5763
|
+
}
|
|
5764
|
+
let endTurn;
|
|
5765
|
+
try {
|
|
5766
|
+
endTurn = await this.claim("reply", () => this.deps.ensureDriverStarted());
|
|
5767
|
+
} catch (err) {
|
|
5768
|
+
this.deps.sendEvent(replyFailed(err));
|
|
5769
|
+
return;
|
|
5770
|
+
}
|
|
5771
|
+
if (!endTurn) return;
|
|
5772
|
+
try {
|
|
5773
|
+
await this.deps.getDriver().prompt(freshTurnReplyPrompt(turn.answer, turn.question));
|
|
5774
|
+
} catch (err) {
|
|
5775
|
+
this.deps.sendEvent(replyFailed(err));
|
|
5776
|
+
} finally {
|
|
5777
|
+
endTurn();
|
|
5778
|
+
}
|
|
5779
|
+
});
|
|
5507
5780
|
}
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5781
|
+
/**
|
|
5782
|
+
* Run one flow turn and resolve on its `agent_end`.
|
|
5783
|
+
*
|
|
5784
|
+
* Waits out a pending swap, any compaction, and every turn already in flight.
|
|
5785
|
+
* The in-flight wait is what makes the `agent_end` listener safe: a flow
|
|
5786
|
+
* started from inside a chat turn would otherwise resolve on that turn's end.
|
|
5787
|
+
* The slot is held for the whole turn, never across a wait, which would stall
|
|
5788
|
+
* a swap behind a compaction.
|
|
5789
|
+
*/
|
|
5790
|
+
flowTurn(prompt, timeoutMs) {
|
|
5791
|
+
return this.counted(async () => {
|
|
5792
|
+
for (; ; ) {
|
|
5793
|
+
await this.swaps.awaitSwap();
|
|
5794
|
+
if (!await this.awaitCompactionIdle("flow turn"))
|
|
5795
|
+
throw new Error(FLOW_TURN_COMPACTION_TIMEOUT);
|
|
5796
|
+
const endTurn = await this.swaps.beginQueuedTurn();
|
|
5797
|
+
if (this.swaps.isSwapping() || !this.compactions.isIdle()) {
|
|
5798
|
+
endTurn();
|
|
5799
|
+
continue;
|
|
5800
|
+
}
|
|
5521
5801
|
try {
|
|
5522
|
-
|
|
5523
|
-
|
|
5524
|
-
|
|
5525
|
-
const buf = Buffer.alloc(DIGEST_CHUNK_BYTES);
|
|
5526
|
-
let total = 0;
|
|
5527
|
-
for (; ; ) {
|
|
5528
|
-
const { bytesRead } = await fh.read(buf, 0, buf.length, null);
|
|
5529
|
-
if (bytesRead === 0) break;
|
|
5530
|
-
total += bytesRead;
|
|
5531
|
-
if (total > budget) throw new Error("skill too large to digest");
|
|
5532
|
-
hash.update(buf.subarray(0, bytesRead));
|
|
5533
|
-
}
|
|
5534
|
-
budget -= total;
|
|
5535
|
-
hash.update(`\0${total}\0`);
|
|
5802
|
+
await this.deps.ensureDriverStarted();
|
|
5803
|
+
await awaitAgentEnd(this.deps.getDriver(), prompt, timeoutMs);
|
|
5804
|
+
return;
|
|
5536
5805
|
} finally {
|
|
5537
|
-
|
|
5538
|
-
}
|
|
5539
|
-
};
|
|
5540
|
-
const walk = async (rel) => {
|
|
5541
|
-
const here = rel ? join(dir, rel) : dir;
|
|
5542
|
-
if (rel && !(await lstat(here)).isDirectory()) throw new Error(`not a dir: ${here}`);
|
|
5543
|
-
const entries = await readdir(here, { withFileTypes: true });
|
|
5544
|
-
entries.sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
5545
|
-
for (const entry of entries) {
|
|
5546
|
-
if (!rel && entry.name === STAGED_SKILL_MARKER) continue;
|
|
5547
|
-
const path6 = rel ? `${rel}/${entry.name}` : entry.name;
|
|
5548
|
-
if (entry.isDirectory()) {
|
|
5549
|
-
hash.update(`d\0${path6}\0`);
|
|
5550
|
-
await walk(path6);
|
|
5551
|
-
} else if (entry.isSymbolicLink()) {
|
|
5552
|
-
hash.update(`l\0${path6}\0${await readlink(join(dir, path6))}\0`);
|
|
5553
|
-
} else if (entry.isFile()) {
|
|
5554
|
-
hash.update(`f\0${path6}\0`);
|
|
5555
|
-
await hashFile(join(dir, path6));
|
|
5556
|
-
} else {
|
|
5557
|
-
hash.update(`o\0${path6}\0`);
|
|
5558
|
-
}
|
|
5806
|
+
endTurn();
|
|
5559
5807
|
}
|
|
5560
|
-
};
|
|
5561
|
-
await walk("");
|
|
5562
|
-
return hash.digest("hex");
|
|
5563
|
-
},
|
|
5564
|
-
null,
|
|
5565
|
-
fsDeadlineMs() * DIGEST_DEADLINE_FACTOR
|
|
5566
|
-
);
|
|
5567
|
-
}
|
|
5568
|
-
async function attachStagedSkill(deps, name) {
|
|
5569
|
-
try {
|
|
5570
|
-
const skillsDir = deps.skillsDir();
|
|
5571
|
-
const dirName = name.includes("/") ? name.split("/").pop() : name;
|
|
5572
|
-
const { staged, unchanged } = await deps.withSkillFsLock(async () => {
|
|
5573
|
-
const dest = join(deps.projectDir, skillsDir, dirName);
|
|
5574
|
-
const loaded = deps.stagedSkillDirs.has(dirName) ? deps.loadedSkillDigests.get(dirName) : void 0;
|
|
5575
|
-
const names = await stageMaterializedSkills(deps.projectDir, skillsDir, { declared: [name] });
|
|
5576
|
-
let same = false;
|
|
5577
|
-
if (names.includes(dirName)) {
|
|
5578
|
-
const digest = await stagedSkillDigest(dest);
|
|
5579
|
-
same = digest !== null && loaded?.path === dest && loaded.digest === digest;
|
|
5580
|
-
if (!same) deps.loadedSkillDigests.set(dirName, { path: dest, digest });
|
|
5581
5808
|
}
|
|
5582
|
-
await recordStagedSkills(deps.stagedSkillDirs, deps.projectDir, skillsDir, names);
|
|
5583
|
-
return { staged: names, unchanged: same ? dirName : null };
|
|
5584
5809
|
});
|
|
5585
|
-
if (staged.length === 0) {
|
|
5586
|
-
return {
|
|
5587
|
-
ok: false,
|
|
5588
|
-
code: "skill_not_materialized",
|
|
5589
|
-
message: `no materialized skill matching "${name}" under .skaile/assets/skill`
|
|
5590
|
-
};
|
|
5591
|
-
}
|
|
5592
|
-
const live = deps.driverStarted();
|
|
5593
|
-
const toRestart = staged.filter((s) => s !== unchanged);
|
|
5594
|
-
if (toRestart.length === 0) {
|
|
5595
|
-
deps.log(
|
|
5596
|
-
`[serve] runner.attach_instance: skill ${staged.join(", ")} already staged and unchanged \u2014 no driver restart`
|
|
5597
|
-
);
|
|
5598
|
-
return { ok: true, id: name, live, toolCount: 0 };
|
|
5599
|
-
}
|
|
5600
|
-
deps.log(`[serve] runner.attach_instance staged skill(s): ${toRestart.join(", ")}`);
|
|
5601
|
-
deps.scheduleSkillRestart(toRestart.map((s) => ({ name: s, action: "add" })));
|
|
5602
|
-
return { ok: true, id: name, live, toolCount: 0 };
|
|
5603
|
-
} catch (err) {
|
|
5604
|
-
return {
|
|
5605
|
-
ok: false,
|
|
5606
|
-
code: "skill_attach_failed",
|
|
5607
|
-
message: err instanceof Error ? err.message : String(err)
|
|
5608
|
-
};
|
|
5609
5810
|
}
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
|
|
5624
|
-
|
|
5625
|
-
|
|
5626
|
-
|
|
5627
|
-
|
|
5628
|
-
|
|
5629
|
-
|
|
5630
|
-
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
|
|
5811
|
+
/**
|
|
5812
|
+
* Run a driver swap (recreate): queued behind every earlier swap, then behind
|
|
5813
|
+
* every turn holding a slot. Prompts defer to it from the moment it is
|
|
5814
|
+
* registered. Never call from inside a swap: it would wait on itself.
|
|
5815
|
+
*/
|
|
5816
|
+
runSwap(swap) {
|
|
5817
|
+
return this.swaps.runSwap(swap);
|
|
5818
|
+
}
|
|
5819
|
+
/**
|
|
5820
|
+
* The driver ended a turn. Reports idle unless a compaction suppresses it, or
|
|
5821
|
+
* more turns are queued behind this one, in which case it is owed and goes
|
|
5822
|
+
* out when the last of them settles.
|
|
5823
|
+
*/
|
|
5824
|
+
reportTurnEnd() {
|
|
5825
|
+
this.reportIdleIfDrained(this.snapshotTurns.size > 0 ? "compaction" : "turn");
|
|
5826
|
+
}
|
|
5827
|
+
/**
|
|
5828
|
+
* Drop every prompt `senderId` has waiting, in queue order. The prompt whose
|
|
5829
|
+
* turn is running is not waiting, and a prompt with no sender is nobody's to drop.
|
|
5830
|
+
*/
|
|
5831
|
+
dropQueuedPromptsFrom(senderId) {
|
|
5832
|
+
return this.queue.dropQueuedFrom(senderId);
|
|
5833
|
+
}
|
|
5834
|
+
/** Turns taken on and not yet settled, waiting ones included. */
|
|
5835
|
+
get pendingTurns() {
|
|
5836
|
+
return this.pending.size;
|
|
5837
|
+
}
|
|
5838
|
+
/**
|
|
5839
|
+
* Whether a compaction is running, from its start until its end callback: the
|
|
5840
|
+
* host must not see the compaction turn's events, `status: idle` included.
|
|
5841
|
+
*/
|
|
5842
|
+
get isCompacting() {
|
|
5843
|
+
return this.suppressedBy !== null;
|
|
5844
|
+
}
|
|
5845
|
+
/**
|
|
5846
|
+
* The hooks one compaction orchestrator wires to take part in scheduling: it
|
|
5847
|
+
* claims the driver before it starts, holds user turns off from its start
|
|
5848
|
+
* until it has settled, and suppresses turn events from its start until its
|
|
5849
|
+
* end. Call once per orchestrator; a newer call retires the hooks before it,
|
|
5850
|
+
* so a stale orchestrator (its driver replaced by a swap) can no longer
|
|
5851
|
+
* start a compaction.
|
|
5852
|
+
*/
|
|
5853
|
+
compactionHooks() {
|
|
5854
|
+
const generation = ++this.hooksGeneration;
|
|
5855
|
+
const superseded = () => generation !== this.hooksGeneration;
|
|
5856
|
+
let hold = null;
|
|
5638
5857
|
return {
|
|
5639
|
-
|
|
5640
|
-
|
|
5641
|
-
|
|
5858
|
+
// A user turn that already holds a slot keeps the driver; the compaction
|
|
5859
|
+
// waits for it rather than prompting the driver under it. A platform call
|
|
5860
|
+
// waits briefly: a turn paused on a question can hold its slot for hours.
|
|
5861
|
+
claimDriver: async (trigger) => {
|
|
5862
|
+
if (superseded()) {
|
|
5863
|
+
this.deps.log("[serve] compaction skipped: its driver has been replaced");
|
|
5864
|
+
return null;
|
|
5865
|
+
}
|
|
5866
|
+
return claimDriverForCompaction({
|
|
5867
|
+
gate: this.compactions,
|
|
5868
|
+
awaitClaimedTurns: () => this.swaps.awaitActiveTurn(),
|
|
5869
|
+
isDriverReplaced: () => this.swaps.isSwapping() || superseded(),
|
|
5870
|
+
claimTurnSlot: () => this.swaps.beginTurn(),
|
|
5871
|
+
log: this.deps.log,
|
|
5872
|
+
timeoutMs: compactionTurnWaitFor(trigger)
|
|
5873
|
+
});
|
|
5874
|
+
},
|
|
5875
|
+
onCompactionStart: (trigger) => {
|
|
5876
|
+
hold = this.compactions.begin();
|
|
5877
|
+
this.suppressedBy = hold;
|
|
5878
|
+
this.deps.sendEvent({ type: "status", phase: "compacting" });
|
|
5879
|
+
this.deps.log(`[serve] compaction started (trigger=${trigger})`);
|
|
5880
|
+
},
|
|
5881
|
+
onCompactionEnd: () => {
|
|
5882
|
+
if (hold === null || this.suppressedBy !== hold) return;
|
|
5883
|
+
this.suppressedBy = null;
|
|
5884
|
+
this.snapshotTurns.add(hold);
|
|
5885
|
+
this.reportIdleIfDrained("compaction");
|
|
5886
|
+
},
|
|
5887
|
+
onCompactionSettled: () => {
|
|
5888
|
+
if (hold !== null && this.suppressedBy === hold) this.suppressedBy = null;
|
|
5889
|
+
if (hold !== null) this.snapshotTurns.delete(hold);
|
|
5890
|
+
this.compactions.settle(hold);
|
|
5891
|
+
hold = null;
|
|
5892
|
+
}
|
|
5642
5893
|
};
|
|
5643
5894
|
}
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
|
|
5652
|
-
|
|
5653
|
-
|
|
5654
|
-
|
|
5655
|
-
|
|
5656
|
-
const root = join(deps.projectDir, skillsDir);
|
|
5657
|
-
const entries = await tryWithFsDeadline(
|
|
5658
|
-
`readdir ${root}`,
|
|
5659
|
-
() => readdir(root, { withFileTypes: true }),
|
|
5660
|
-
[]
|
|
5661
|
-
);
|
|
5662
|
-
const removed = [];
|
|
5663
|
-
for (const entry of entries) {
|
|
5664
|
-
if (!entry.isDirectory() || allowed.has(entry.name)) continue;
|
|
5665
|
-
try {
|
|
5666
|
-
const dir = join(root, entry.name);
|
|
5667
|
-
if (await pathState(join(deps.projectDir, ".skaile/assets/skill", entry.name)) !== "absent") {
|
|
5668
|
-
continue;
|
|
5895
|
+
async runPrompt(turn, leaveQueue) {
|
|
5896
|
+
if (!await turn.admit()) return;
|
|
5897
|
+
await this.swaps.awaitSwap();
|
|
5898
|
+
if (!await this.awaitCompactionIdle("prompt")) return;
|
|
5899
|
+
const handOff = await turn.route();
|
|
5900
|
+
if (handOff === false) return;
|
|
5901
|
+
if (handOff) {
|
|
5902
|
+
leaveQueue();
|
|
5903
|
+
try {
|
|
5904
|
+
await handOff();
|
|
5905
|
+
} finally {
|
|
5906
|
+
this.reportIdleIfDrained("turn");
|
|
5669
5907
|
}
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5908
|
+
return;
|
|
5909
|
+
}
|
|
5910
|
+
const startedAt = Date.now();
|
|
5911
|
+
let ok = false;
|
|
5912
|
+
let attempts = 0;
|
|
5913
|
+
let endTurn;
|
|
5914
|
+
try {
|
|
5915
|
+
endTurn = await this.claim("prompt", () => {
|
|
5916
|
+
attempts += 1;
|
|
5917
|
+
return this.deps.ensureDriverStarted();
|
|
5676
5918
|
});
|
|
5677
|
-
|
|
5678
|
-
deps.stagedSkillDirs.delete(result.name);
|
|
5679
|
-
removed.push(result.name);
|
|
5919
|
+
ok = endTurn !== null;
|
|
5680
5920
|
} catch (err) {
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5921
|
+
const message = errorMessage2(err);
|
|
5922
|
+
this.deps.log(`[serve] driver start failed: ${message}`);
|
|
5923
|
+
this.deps.sendEvent({
|
|
5924
|
+
type: "error",
|
|
5925
|
+
message: `Driver start failed: ${message}`,
|
|
5926
|
+
fatal: true
|
|
5927
|
+
});
|
|
5928
|
+
return;
|
|
5929
|
+
} finally {
|
|
5930
|
+
this.deps.logPhase("driver_start", startedAt, { ok, attempts });
|
|
5684
5931
|
}
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
await deps.gate.awaitSwap();
|
|
5694
|
-
if (!await deps.awaitCompactionIdle()) throw new Error(FLOW_TURN_COMPACTION_TIMEOUT);
|
|
5695
|
-
const endTurn = await deps.gate.beginQueuedTurn();
|
|
5696
|
-
if (deps.gate.isSwapping() || deps.isCompacting()) {
|
|
5932
|
+
if (!endTurn) return;
|
|
5933
|
+
try {
|
|
5934
|
+
await turn.dispatch();
|
|
5935
|
+
} catch (err) {
|
|
5936
|
+
const message = errorMessage2(err);
|
|
5937
|
+
this.deps.log(`[serve] prompt failed: ${message}`);
|
|
5938
|
+
this.deps.sendEvent({ type: "error", message: `Prompt failed: ${message}`, fatal: true });
|
|
5939
|
+
} finally {
|
|
5697
5940
|
endTurn();
|
|
5698
|
-
continue;
|
|
5699
5941
|
}
|
|
5942
|
+
}
|
|
5943
|
+
/** Claim a turn slot on a live driver no swap or compaction occupies. `null`: turn abandoned. */
|
|
5944
|
+
claim(what, prepare) {
|
|
5945
|
+
return beginTurnClearOfCompaction({
|
|
5946
|
+
gate: this.compactions,
|
|
5947
|
+
awaitIdle: () => this.awaitCompactionIdle(what),
|
|
5948
|
+
claimTurn: () => this.swaps.beginTurnOnLiveDriver(prepare)
|
|
5949
|
+
});
|
|
5950
|
+
}
|
|
5951
|
+
/** `false` when a compaction held the driver past its bound; the abandon is already reported. */
|
|
5952
|
+
awaitCompactionIdle(what) {
|
|
5953
|
+
return guardTurnAgainstCompaction({
|
|
5954
|
+
gate: this.compactions,
|
|
5955
|
+
what,
|
|
5956
|
+
log: this.deps.log,
|
|
5957
|
+
sendEvent: this.deps.sendEvent
|
|
5958
|
+
});
|
|
5959
|
+
}
|
|
5960
|
+
/** Count a turn from receipt until its handler settles, so waiting turns count as queued. */
|
|
5961
|
+
async counted(run) {
|
|
5962
|
+
const end = this.pending.begin();
|
|
5700
5963
|
try {
|
|
5701
|
-
await
|
|
5702
|
-
await awaitAgentEnd(deps.getDriver(), prompt, timeoutMs);
|
|
5703
|
-
return;
|
|
5964
|
+
return await run();
|
|
5704
5965
|
} finally {
|
|
5705
|
-
|
|
5966
|
+
end();
|
|
5706
5967
|
}
|
|
5707
5968
|
}
|
|
5969
|
+
/** Idle unless a compaction suppresses events or more turns are queued, in which case it is owed. */
|
|
5970
|
+
reportIdleIfDrained(endedBy) {
|
|
5971
|
+
if (this.suppressedBy) return;
|
|
5972
|
+
if (this.pending.shouldReportIdle(endedBy)) this.sendIdle();
|
|
5973
|
+
}
|
|
5974
|
+
/** The only `status: idle` emit site. Silent while a compaction suppresses turn events. */
|
|
5975
|
+
sendIdle() {
|
|
5976
|
+
if (this.suppressedBy) return;
|
|
5977
|
+
this.deps.sendEvent({ type: "status", phase: "idle" });
|
|
5978
|
+
}
|
|
5979
|
+
};
|
|
5980
|
+
function errorMessage2(err) {
|
|
5981
|
+
return err instanceof Error ? err.message : String(err);
|
|
5982
|
+
}
|
|
5983
|
+
function replyFailed(err) {
|
|
5984
|
+
return { type: "error", message: `Reply failed: ${errorMessage2(err)}`, fatal: false };
|
|
5985
|
+
}
|
|
5986
|
+
function freshTurnReplyPrompt(answer, question) {
|
|
5987
|
+
const asked = question?.replace(/\s+/g, " ").trim();
|
|
5988
|
+
if (!asked) return answer;
|
|
5989
|
+
return `${answer}
|
|
5990
|
+
|
|
5991
|
+
(The answer above is to your question "${asked}")`;
|
|
5708
5992
|
}
|
|
5709
5993
|
function awaitAgentEnd(driver, prompt, timeoutMs) {
|
|
5710
5994
|
return new Promise((resolve4, reject) => {
|
|
@@ -5733,25 +6017,6 @@ function awaitAgentEnd(driver, prompt, timeoutMs) {
|
|
|
5733
6017
|
});
|
|
5734
6018
|
}
|
|
5735
6019
|
|
|
5736
|
-
// runner/src/reply-routing.ts
|
|
5737
|
-
async function routeReply(deps) {
|
|
5738
|
-
const current = deps.getDriver();
|
|
5739
|
-
if (current.hasPendingQuestion()) {
|
|
5740
|
-
if (!current.answerQuestion(deps.answer, deps.question, deps.requestId)) return "fresh-turn";
|
|
5741
|
-
deps.onAnswered?.();
|
|
5742
|
-
return "answered";
|
|
5743
|
-
}
|
|
5744
|
-
await deps.awaitSwap();
|
|
5745
|
-
return "fresh-turn";
|
|
5746
|
-
}
|
|
5747
|
-
function freshTurnReplyPrompt(answer, question) {
|
|
5748
|
-
const asked = question?.replace(/\s+/g, " ").trim();
|
|
5749
|
-
if (!asked) return answer;
|
|
5750
|
-
return `${answer}
|
|
5751
|
-
|
|
5752
|
-
(The answer above is to your question "${asked}")`;
|
|
5753
|
-
}
|
|
5754
|
-
|
|
5755
6020
|
// runner/src/event-gap-buffer.ts
|
|
5756
6021
|
var EVENT_GAP_BUFFER_MAX_EVENTS = 1e4;
|
|
5757
6022
|
var EVENT_GAP_BUFFER_MAX_BYTES = 16 * 1024 * 1024;
|
|
@@ -6734,7 +6999,8 @@ function selectClaudeCodeCredentialsSecret(secrets, selection) {
|
|
|
6734
6999
|
const legacy = secrets[CLAUDE_CODE_CREDENTIALS_KEY];
|
|
6735
7000
|
if (legacy) return { key: CLAUDE_CODE_CREDENTIALS_KEY, value: legacy };
|
|
6736
7001
|
if (!selection?.registry) return void 0;
|
|
6737
|
-
if (selection.driver && selection.driver
|
|
7002
|
+
if (selection.driver && !driverCapabilities(selection.driver).claudeCodeCredentials)
|
|
7003
|
+
return void 0;
|
|
6738
7004
|
const entries = registryEntries(selection.registry).map(
|
|
6739
7005
|
([id, entry2]) => [id, { ...entry2, kind: entryKind(entry2) }]
|
|
6740
7006
|
);
|
|
@@ -8476,9 +8742,6 @@ function pickRepointedManager(next, current, disposed) {
|
|
|
8476
8742
|
if (current !== null && current === disposed) return null;
|
|
8477
8743
|
return current;
|
|
8478
8744
|
}
|
|
8479
|
-
function supportsLiveToolUpdates(driverType, managedCodex = false) {
|
|
8480
|
-
return driverType !== "claude-sdk" && !(driverType === "codex" && managedCodex);
|
|
8481
|
-
}
|
|
8482
8745
|
function buildResourcesAvailablePayload(manager, mcpManager, driverLive, bakedServerIds) {
|
|
8483
8746
|
const { mounts, connectors } = splitConnectorsForWire(manager);
|
|
8484
8747
|
const mcp_servers = (mcpManager?.listServers() ?? []).map((s) => ({
|
|
@@ -8487,19 +8750,16 @@ function buildResourcesAvailablePayload(manager, mcpManager, driverLive, bakedSe
|
|
|
8487
8750
|
}));
|
|
8488
8751
|
return { type: "resources_available", mounts, connectors, mcp_servers, sessionRoot: true };
|
|
8489
8752
|
}
|
|
8490
|
-
function isTerminalFlowStatus(status) {
|
|
8491
|
-
return status === "complete" || status === "cancelled";
|
|
8492
|
-
}
|
|
8493
8753
|
function hasNonTerminalFlow(flows) {
|
|
8494
8754
|
for (const f of flows) {
|
|
8495
|
-
if (!
|
|
8755
|
+
if (!f.adapter.turnRule(f.handle).terminal) return true;
|
|
8496
8756
|
}
|
|
8497
8757
|
return false;
|
|
8498
8758
|
}
|
|
8499
8759
|
function registerActiveFlow(flows, runId, entry) {
|
|
8500
8760
|
const removed = [];
|
|
8501
8761
|
for (const [key, existing] of flows) {
|
|
8502
|
-
if (
|
|
8762
|
+
if (existing.adapter.turnRule(existing.handle).terminal) {
|
|
8503
8763
|
flows.delete(key);
|
|
8504
8764
|
removed.push(key);
|
|
8505
8765
|
}
|
|
@@ -8511,21 +8771,18 @@ function pickFlowToolTarget(flows, manager) {
|
|
|
8511
8771
|
let latest;
|
|
8512
8772
|
for (const entry of flows) latest = entry;
|
|
8513
8773
|
if (!latest || !manager) return null;
|
|
8514
|
-
if (
|
|
8774
|
+
if (latest.adapter.turnRule(latest.handle).terminal) return null;
|
|
8515
8775
|
return { manager, connectorId: latest.connectorId };
|
|
8516
8776
|
}
|
|
8517
|
-
function flowRunDrivesTurns(execution) {
|
|
8518
|
-
return !(execution.done || execution.status === "failed" || isTerminalFlowStatus(execution.status));
|
|
8519
|
-
}
|
|
8520
8777
|
function pickChatFlowTarget(flows) {
|
|
8521
8778
|
let latest;
|
|
8522
8779
|
for (const entry of flows) latest = entry;
|
|
8523
8780
|
if (!latest) return null;
|
|
8524
|
-
if (!
|
|
8781
|
+
if (!latest.adapter.turnRule(latest.handle).acceptsTurn) return null;
|
|
8525
8782
|
return latest;
|
|
8526
8783
|
}
|
|
8527
8784
|
function flowStartNeedsDriverRestart(state) {
|
|
8528
|
-
return state.driverStarted && state.driverType
|
|
8785
|
+
return state.driverStarted && driverCapabilities(state.driverType).inProcessMcpServers && !state.flowToolsBaked;
|
|
8529
8786
|
}
|
|
8530
8787
|
async function setUpFlowConnector(deps) {
|
|
8531
8788
|
const recreated = await deps.recreateForFlowTools();
|
|
@@ -8536,8 +8793,8 @@ async function setUpFlowConnector(deps) {
|
|
|
8536
8793
|
async function recreateKeepingLiveFlows(flows, deps) {
|
|
8537
8794
|
const live = [];
|
|
8538
8795
|
for (const { runId, connectorId, flowDef, adapter, handle } of flows) {
|
|
8796
|
+
if (adapter.turnRule(handle).terminal) continue;
|
|
8539
8797
|
const execution = adapter.getExecution(handle);
|
|
8540
|
-
if (isTerminalFlowStatus(execution.status)) continue;
|
|
8541
8798
|
live.push({ runId, connectorId, flowDef, execution: structuredClone(execution) });
|
|
8542
8799
|
}
|
|
8543
8800
|
await deps.recreate();
|
|
@@ -8558,7 +8815,7 @@ async function recreateKeepingLiveFlows(flows, deps) {
|
|
|
8558
8815
|
return reconnected;
|
|
8559
8816
|
}
|
|
8560
8817
|
function reconnectedRunNeedsAgentTurn(state) {
|
|
8561
|
-
return state.cutDriverWork && state.
|
|
8818
|
+
return state.cutDriverWork && state.restoreKick === "agent_work" && !state.busHasTurn && !state.promptQueuedForRun;
|
|
8562
8819
|
}
|
|
8563
8820
|
var DRIVER_ACTIVITY_EVENTS = /* @__PURE__ */ new Set([
|
|
8564
8821
|
"message_start",
|
|
@@ -8961,11 +9218,11 @@ function toActiveFlowTarget(entry) {
|
|
|
8961
9218
|
runId: entry.runId,
|
|
8962
9219
|
connectorId: entry.connectorId,
|
|
8963
9220
|
hydratedStateChanged: entry.hydratedStateChanged,
|
|
8964
|
-
|
|
9221
|
+
restoreKick: entry.adapter.turnRule(entry.handle).restoreKick
|
|
8965
9222
|
};
|
|
8966
9223
|
}
|
|
8967
9224
|
function restoredRunHasWorkToResume(target) {
|
|
8968
|
-
return target.hydratedStateChanged === true || target.
|
|
9225
|
+
return target.hydratedStateChanged === true || target.restoreKick === "runtime_work";
|
|
8969
9226
|
}
|
|
8970
9227
|
async function executeConnectorMutate(cmd, deps) {
|
|
8971
9228
|
let acked = false;
|
|
@@ -9154,7 +9411,7 @@ async function applyConnectorMutate(cmd, deps, respond, connectorWaitMs) {
|
|
|
9154
9411
|
} else if (cmd.op === "hydrate") {
|
|
9155
9412
|
const active = deps.flowState().activeFlow;
|
|
9156
9413
|
const changed = typeof result === "string" && JSON.stringify(payload.state) !== result;
|
|
9157
|
-
if (active && (changed || active.
|
|
9414
|
+
if (active && (changed || active.restoreKick === "runtime_work")) {
|
|
9158
9415
|
deps.signalStimulus(active, { kind: "resumed_after_hibernation" });
|
|
9159
9416
|
}
|
|
9160
9417
|
}
|
|
@@ -9438,7 +9695,7 @@ async function startAgentServer(opts) {
|
|
|
9438
9695
|
reason: "retry-401",
|
|
9439
9696
|
rejection: "usage-limit"
|
|
9440
9697
|
});
|
|
9441
|
-
if (outcome.switched) {
|
|
9698
|
+
if (outcome.switched || movedOffBlockedSeat(ctx.configId, outcome)) {
|
|
9442
9699
|
return { switched: true, ...outcome.configId ? { configId: outcome.configId } : {} };
|
|
9443
9700
|
}
|
|
9444
9701
|
return {
|
|
@@ -9573,7 +9830,7 @@ async function startAgentServer(opts) {
|
|
|
9573
9830
|
return {
|
|
9574
9831
|
projectDir: opts.projectDir,
|
|
9575
9832
|
agentDir,
|
|
9576
|
-
driver: managedCodex ?
|
|
9833
|
+
driver: managedCodex ? wireAgentConfig?.driver : opts.driver ?? wireAgentConfig?.driver,
|
|
9577
9834
|
model: managedCodex ? wireAgentConfig?.model : opts.model ?? wireAgentConfig?.model,
|
|
9578
9835
|
// The control-plane registry layer, normalized to the bare `id → entry`
|
|
9579
9836
|
// map the session builder layers `providers.yml` under.
|
|
@@ -9889,18 +10146,17 @@ async function startAgentServer(opts) {
|
|
|
9889
10146
|
}
|
|
9890
10147
|
const normalizer = new EventNormalizer();
|
|
9891
10148
|
function forwardNormalizedEvent(event) {
|
|
9892
|
-
if (
|
|
10149
|
+
if (turnScheduler.isCompacting) return;
|
|
9893
10150
|
contextUsage.observeEvent(event);
|
|
9894
|
-
|
|
9895
|
-
if (!isTransient) {
|
|
10151
|
+
if (deliveryClassOf(event.type) === "persisted") {
|
|
9896
10152
|
eventSeq++;
|
|
9897
10153
|
compactionOrchestrator?.trackMessage(eventSeq);
|
|
9898
10154
|
}
|
|
9899
10155
|
if (event.type === "finished") {
|
|
9900
10156
|
scheduleContextUsageEmit("turn-end");
|
|
9901
|
-
if (!
|
|
10157
|
+
if (!turnScheduler.isCompacting && compactionOrchestrator?.shouldCompact()) {
|
|
9902
10158
|
const compactionTimer = setTimeout(() => {
|
|
9903
|
-
if (
|
|
10159
|
+
if (turnScheduler.isCompacting || !compactionOrchestrator?.shouldCompact()) return;
|
|
9904
10160
|
compactionOrchestrator.compact("threshold").catch((err) => {
|
|
9905
10161
|
log(
|
|
9906
10162
|
`[serve] auto-compaction failed: ${err instanceof Error ? err.message : String(err)}`
|
|
@@ -9923,12 +10179,13 @@ async function startAgentServer(opts) {
|
|
|
9923
10179
|
}
|
|
9924
10180
|
let driverStarted = false;
|
|
9925
10181
|
let driverStartInFlight = null;
|
|
9926
|
-
const
|
|
9927
|
-
|
|
9928
|
-
|
|
9929
|
-
|
|
10182
|
+
const turnScheduler = new TurnScheduler({
|
|
10183
|
+
ensureDriverStarted,
|
|
10184
|
+
getDriver: () => driver,
|
|
10185
|
+
sendEvent,
|
|
10186
|
+
log,
|
|
10187
|
+
logPhase
|
|
9930
10188
|
});
|
|
9931
|
-
const promptTurns = new PromptTurnQueue();
|
|
9932
10189
|
let driverRestartChain = Promise.resolve();
|
|
9933
10190
|
let liveDriverActiveAfterTurn = false;
|
|
9934
10191
|
let driver = secretsMode === "env" ? agentSession.driver : void 0;
|
|
@@ -9971,8 +10228,6 @@ async function startAgentServer(opts) {
|
|
|
9971
10228
|
};
|
|
9972
10229
|
sendEvent(runtimeSessionEvent);
|
|
9973
10230
|
}
|
|
9974
|
-
let compacting = false;
|
|
9975
|
-
let suppressedBy = null;
|
|
9976
10231
|
let compactionOrchestrator = null;
|
|
9977
10232
|
const compactionConfig = wsConfig.compaction;
|
|
9978
10233
|
function scheduleContextUsageEmit(trigger) {
|
|
@@ -9987,18 +10242,13 @@ async function startAgentServer(opts) {
|
|
|
9987
10242
|
}
|
|
9988
10243
|
function rebuildCompactionOrchestrator() {
|
|
9989
10244
|
if (!driver) return;
|
|
9990
|
-
let gateHold = null;
|
|
9991
10245
|
compactionOrchestrator = new CompactionOrchestrator({
|
|
9992
10246
|
driver,
|
|
9993
10247
|
config: compactionConfig,
|
|
9994
10248
|
contextWindows,
|
|
9995
|
-
|
|
9996
|
-
|
|
9997
|
-
|
|
9998
|
-
suppressedBy = gateHold;
|
|
9999
|
-
sendEvent({ type: "status", phase: "compacting" });
|
|
10000
|
-
log(`[serve] compaction started (trigger=${trigger})`);
|
|
10001
|
-
},
|
|
10249
|
+
// Start, end, settled and the driver claim: the scheduler owns the holds,
|
|
10250
|
+
// the event suppression and the `status` phases around a compaction.
|
|
10251
|
+
...turnScheduler.compactionHooks(),
|
|
10002
10252
|
onSnapshot: (snapshot) => {
|
|
10003
10253
|
sendEvent(snapshot);
|
|
10004
10254
|
contextUsage.onCompaction(snapshot.summary);
|
|
@@ -10007,27 +10257,6 @@ async function startAgentServer(opts) {
|
|
|
10007
10257
|
onCompactionAttempt: (event) => {
|
|
10008
10258
|
sendEvent(event);
|
|
10009
10259
|
},
|
|
10010
|
-
onCompactionEnd: () => {
|
|
10011
|
-
if (suppressedBy !== gateHold) return;
|
|
10012
|
-
compacting = false;
|
|
10013
|
-
suppressedBy = null;
|
|
10014
|
-
sendEvent({ type: "status", phase: "idle" });
|
|
10015
|
-
},
|
|
10016
|
-
onCompactionSettled: () => {
|
|
10017
|
-
compactionGate.settle(gateHold);
|
|
10018
|
-
gateHold = null;
|
|
10019
|
-
},
|
|
10020
|
-
// A user turn that already holds a slot keeps the driver; the compaction
|
|
10021
|
-
// waits for it rather than prompting the driver under it. A platform call
|
|
10022
|
-
// waits briefly: a turn paused on a question can hold its slot for hours.
|
|
10023
|
-
claimDriver: (trigger) => claimDriverForCompaction({
|
|
10024
|
-
gate: compactionGate,
|
|
10025
|
-
awaitClaimedTurns: () => driverSwapGate.awaitActiveTurn(),
|
|
10026
|
-
isSwapping: () => driverSwapGate.isSwapping(),
|
|
10027
|
-
claimTurnSlot: () => driverSwapGate.beginTurn(),
|
|
10028
|
-
log,
|
|
10029
|
-
timeoutMs: compactionTurnWaitFor(trigger)
|
|
10030
|
-
}),
|
|
10031
10260
|
onLog: (line) => log(`[serve] ${line}`),
|
|
10032
10261
|
// Phase 3: stamp every CompactionAttemptEvent with the registry's
|
|
10033
10262
|
// current signature so wake-time tier-1 selection has the input it
|
|
@@ -10074,7 +10303,8 @@ async function startAgentServer(opts) {
|
|
|
10074
10303
|
const normalized = normalizer.normalize(event);
|
|
10075
10304
|
const turnEnded = event.type === "agent_end";
|
|
10076
10305
|
for (const e of normalized) {
|
|
10077
|
-
if (turnEnded &&
|
|
10306
|
+
if (turnEnded && e.type === "status" && e.phase === "idle") {
|
|
10307
|
+
turnScheduler.reportTurnEnd();
|
|
10078
10308
|
continue;
|
|
10079
10309
|
}
|
|
10080
10310
|
forwardNormalizedEvent(e);
|
|
@@ -10114,7 +10344,6 @@ async function startAgentServer(opts) {
|
|
|
10114
10344
|
const stimulus = stimulusFromMetas(metas);
|
|
10115
10345
|
await entry.adapter.drainRuntimeNodes(entry.handle);
|
|
10116
10346
|
const execution = entry.adapter.getExecution(entry.handle);
|
|
10117
|
-
if (!flowRunDrivesTurns(execution)) return;
|
|
10118
10347
|
if (!entry.adapter.shouldDriveAgentTurn(entry.handle, stimulus)) return;
|
|
10119
10348
|
await ensureFlowDriverStarted();
|
|
10120
10349
|
await driveOrchestratorTurn({
|
|
@@ -10122,42 +10351,13 @@ async function startAgentServer(opts) {
|
|
|
10122
10351
|
execution,
|
|
10123
10352
|
stimulus,
|
|
10124
10353
|
emit: sendEvent,
|
|
10125
|
-
deliver: (prompt) =>
|
|
10354
|
+
deliver: (prompt) => turnScheduler.flowTurn(prompt, FLOW_TURN_TIMEOUT_MS)
|
|
10126
10355
|
});
|
|
10127
10356
|
},
|
|
10128
10357
|
log: serverLog
|
|
10129
10358
|
});
|
|
10130
10359
|
return stimulusBus;
|
|
10131
10360
|
}
|
|
10132
|
-
function awaitFlowAgentEnd(prompt, timeoutMs) {
|
|
10133
|
-
return countPendingTurn(
|
|
10134
|
-
() => dispatchFlowTurn(
|
|
10135
|
-
{
|
|
10136
|
-
gate: driverSwapGate,
|
|
10137
|
-
awaitCompactionIdle: () => awaitCompactionIdle("flow turn"),
|
|
10138
|
-
isCompacting: () => !compactionGate.isIdle(),
|
|
10139
|
-
ensureDriverStarted,
|
|
10140
|
-
getDriver: () => driver
|
|
10141
|
-
},
|
|
10142
|
-
prompt,
|
|
10143
|
-
timeoutMs
|
|
10144
|
-
)
|
|
10145
|
-
);
|
|
10146
|
-
}
|
|
10147
|
-
function activeFlowWantsAgentTurn(runId) {
|
|
10148
|
-
const entry = activeFlows.get(runId);
|
|
10149
|
-
if (!entry) return false;
|
|
10150
|
-
if (!flowRunDrivesTurns(entry.adapter.getExecution(entry.handle))) return false;
|
|
10151
|
-
return entry.adapter.shouldDriveAgentTurn(entry.handle, { kind: "resumed_after_hibernation" });
|
|
10152
|
-
}
|
|
10153
|
-
async function countPendingTurn(run) {
|
|
10154
|
-
const end = pendingTurns.begin();
|
|
10155
|
-
try {
|
|
10156
|
-
return await run();
|
|
10157
|
-
} finally {
|
|
10158
|
-
end();
|
|
10159
|
-
}
|
|
10160
|
-
}
|
|
10161
10361
|
function ensureResourceManagerForFlow() {
|
|
10162
10362
|
if (!resourceManager) {
|
|
10163
10363
|
registerBuiltinConnectors();
|
|
@@ -10255,7 +10455,7 @@ async function startAgentServer(opts) {
|
|
|
10255
10455
|
execution,
|
|
10256
10456
|
stimulus,
|
|
10257
10457
|
emit: sendEvent,
|
|
10258
|
-
deliver: (prompt) =>
|
|
10458
|
+
deliver: (prompt) => turnScheduler.flowTurn(prompt, FLOW_TURN_TIMEOUT_MS)
|
|
10259
10459
|
});
|
|
10260
10460
|
}
|
|
10261
10461
|
});
|
|
@@ -10301,7 +10501,7 @@ async function startAgentServer(opts) {
|
|
|
10301
10501
|
execute: (op, args) => adapter.executeOp(handle, op, args),
|
|
10302
10502
|
mandatoryGates: () => adapter.getMandatoryAgentApprovalNodeIds(handle)
|
|
10303
10503
|
};
|
|
10304
|
-
if (agentSession?.driverType
|
|
10504
|
+
if (driverCapabilities(agentSession?.driverType).inProcessMcpServers) {
|
|
10305
10505
|
try {
|
|
10306
10506
|
const server = await buildSdkConnectorTools(manager, { z: z });
|
|
10307
10507
|
const flowServer = flowToolsBaked ? null : await buildSdkFlowTools(manager, connectorId, { z: z });
|
|
@@ -10323,7 +10523,7 @@ async function startAgentServer(opts) {
|
|
|
10323
10523
|
log(`[serve] failed to rebuild MCP tools for flow: ${errMsg}`);
|
|
10324
10524
|
}
|
|
10325
10525
|
}
|
|
10326
|
-
if (agentSession?.driverType
|
|
10526
|
+
if (driverCapabilities(agentSession?.driverType).managedSession && !driver.acceptsReplyAsPrompt) {
|
|
10327
10527
|
removeCodexFlowTools?.();
|
|
10328
10528
|
removeCodexFlowTools = registerCodexFlowTools(capabilityRegistry, manager, connectorId);
|
|
10329
10529
|
}
|
|
@@ -10588,7 +10788,7 @@ async function startAgentServer(opts) {
|
|
|
10588
10788
|
return { needsWireFallbackRecreate, needsWireAgentConfigRecreate };
|
|
10589
10789
|
}
|
|
10590
10790
|
async function recreateAgentSession(overrides) {
|
|
10591
|
-
return
|
|
10791
|
+
return turnScheduler.runSwap(async () => {
|
|
10592
10792
|
const resolved = typeof overrides === "function" ? overrides() : overrides;
|
|
10593
10793
|
if (!resolved) return false;
|
|
10594
10794
|
await recreateAgentSessionInner(resolved);
|
|
@@ -10612,10 +10812,10 @@ async function startAgentServer(opts) {
|
|
|
10612
10812
|
needsAgentTurn: (run) => {
|
|
10613
10813
|
const needed = reconnectedRunNeedsAgentTurn({
|
|
10614
10814
|
cutDriverWork,
|
|
10615
|
-
|
|
10815
|
+
restoreKick: run.restoreKick ?? null,
|
|
10616
10816
|
busHasTurn: stimulusBus?.hasTurn(run.connectorId) ?? false,
|
|
10617
10817
|
// Approximate: a waiting reply counts too. A prompt reaches one run only.
|
|
10618
|
-
promptQueuedForRun: pendingTurns
|
|
10818
|
+
promptQueuedForRun: turnScheduler.pendingTurns > 0 && pickChatFlowTarget(activeFlows.values())?.runId === run.runId
|
|
10619
10819
|
});
|
|
10620
10820
|
if (needed) redriven.push(run.runId);
|
|
10621
10821
|
return needed;
|
|
@@ -10818,7 +11018,7 @@ async function startAgentServer(opts) {
|
|
|
10818
11018
|
}
|
|
10819
11019
|
}
|
|
10820
11020
|
async function rebuildMcpToolsForNewStores(storesRegistered) {
|
|
10821
|
-
if (!(storesRegistered > 0 && !driverStarted && agentSession?.driverType
|
|
11021
|
+
if (!(storesRegistered > 0 && !driverStarted && driverCapabilities(agentSession?.driverType).inProcessMcpServers)) {
|
|
10822
11022
|
return;
|
|
10823
11023
|
}
|
|
10824
11024
|
try {
|
|
@@ -10970,13 +11170,15 @@ async function startAgentServer(opts) {
|
|
|
10970
11170
|
}
|
|
10971
11171
|
try {
|
|
10972
11172
|
validateCodexInit(cmd, supportedRuntimeFeatures, runtimeIdentity ?? void 0);
|
|
10973
|
-
const wantsManaged =
|
|
11173
|
+
const wantsManaged = driverCapabilities(
|
|
11174
|
+
cmd.resolvedConfig.agentConfig?.driver
|
|
11175
|
+
).managedSession;
|
|
10974
11176
|
if (managedHost && !wantsManaged) throw new Error("AI_PROFILE_INVALID");
|
|
10975
11177
|
if (managedHost && wantsManaged) {
|
|
10976
11178
|
if (managedBootstrapClosed || agentSession && !managedInitFingerprint || cmd.secrets && CLAUDE_CODE_CREDENTIALS_KEY in cmd.secrets)
|
|
10977
11179
|
throw new Error("AI_PROFILE_INVALID");
|
|
10978
11180
|
const profile2 = cmd.resolvedConfig.agentConfig;
|
|
10979
|
-
if (opts.driver && opts.driver !==
|
|
11181
|
+
if (opts.driver && opts.driver !== profile2.driver || opts.provider && opts.provider !== "openai" || opts.model && opts.model !== profile2.model)
|
|
10980
11182
|
throw new Error("AI_PROFILE_INVALID");
|
|
10981
11183
|
const initialCredential = parseCodexCredential(cmd.credentials.ai);
|
|
10982
11184
|
const binding = bindManagedCodexInit(managedHost, cmd, async (input, signal) => {
|
|
@@ -11085,7 +11287,7 @@ async function startAgentServer(opts) {
|
|
|
11085
11287
|
settings = { driver: driver2 ?? profile?.driver, model: model ?? profile?.model };
|
|
11086
11288
|
}
|
|
11087
11289
|
credentialsSelection = {
|
|
11088
|
-
driver: settings.driver ??
|
|
11290
|
+
driver: settings.driver ?? DEFAULT_DRIVER_ID,
|
|
11089
11291
|
registry: wireAgentConfig?.registry,
|
|
11090
11292
|
modelRef: wireAgentConfig?.modelRef?.trim() || settings.model?.trim() || void 0
|
|
11091
11293
|
};
|
|
@@ -11134,7 +11336,7 @@ async function startAgentServer(opts) {
|
|
|
11134
11336
|
let pendingResumeSessionId;
|
|
11135
11337
|
const cfgResumeSessionId = cfg.resumeSessionId;
|
|
11136
11338
|
const cfgExpectedSig = cfg.expectedCapabilitySignature;
|
|
11137
|
-
const resumeTargetDriver = managedCodex ?
|
|
11339
|
+
const resumeTargetDriver = (managedCodex ? void 0 : opts.driver) ?? wireAgentConfig?.driver ?? agentSession?.driverType;
|
|
11138
11340
|
if (cfgResumeSessionId) {
|
|
11139
11341
|
const currentSig = computeCapabilitySignature(capabilityRegistry.list());
|
|
11140
11342
|
if (cfgExpectedSig && cfgExpectedSig !== currentSig) {
|
|
@@ -11149,7 +11351,7 @@ async function startAgentServer(opts) {
|
|
|
11149
11351
|
resumeSessionId: cfgResumeSessionId,
|
|
11150
11352
|
reason: "signature_mismatch"
|
|
11151
11353
|
});
|
|
11152
|
-
} else if (resumeProbe === "jsonl_lost" && resumeTargetDriver
|
|
11354
|
+
} else if (resumeProbe === "jsonl_lost" && driverCapabilities(resumeTargetDriver).resumeNeedsTranscript) {
|
|
11153
11355
|
log(`[serve] tier-1 resume skipped: no transcript for ${cfgResumeSessionId}`);
|
|
11154
11356
|
sendEvent({
|
|
11155
11357
|
type: "resume_failed",
|
|
@@ -11246,129 +11448,88 @@ async function startAgentServer(opts) {
|
|
|
11246
11448
|
}
|
|
11247
11449
|
});
|
|
11248
11450
|
}
|
|
11249
|
-
const awaitCompactionIdle = (what) => guardTurnAgainstCompaction({ gate: compactionGate, what, log, sendEvent });
|
|
11250
11451
|
async function handlePrompt(cmd) {
|
|
11251
11452
|
if (cmd.messageId) sendEvent({ type: "prompt_ack", messageId: cmd.messageId });
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11265
|
-
|
|
11266
|
-
|
|
11267
|
-
|
|
11268
|
-
|
|
11269
|
-
|
|
11270
|
-
|
|
11271
|
-
|
|
11272
|
-
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11299
|
-
|
|
11300
|
-
|
|
11301
|
-
|
|
11302
|
-
|
|
11303
|
-
|
|
11304
|
-
|
|
11305
|
-
|
|
11306
|
-
|
|
11307
|
-
|
|
11308
|
-
|
|
11309
|
-
|
|
11310
|
-
|
|
11311
|
-
|
|
11312
|
-
|
|
11313
|
-
|
|
11314
|
-
|
|
11315
|
-
|
|
11316
|
-
text: cmd.prompt,
|
|
11317
|
-
senderId: "user"
|
|
11453
|
+
await turnScheduler.prompt({
|
|
11454
|
+
owner: { senderId: cmd.senderId, messageId: cmd.messageId },
|
|
11455
|
+
// The turn ahead may be paused on a question it can only leave through
|
|
11456
|
+
// this driver's rule for a new prompt; apply it now, not after that turn.
|
|
11457
|
+
onQueued: () => driver?.supersedePendingQuestion?.(),
|
|
11458
|
+
admit: async () => {
|
|
11459
|
+
const promptReceivedAt = Date.now();
|
|
11460
|
+
const sessionIsReady = await awaitSessionReadyOrFail();
|
|
11461
|
+
logPhase("prompt_gate_wait", promptReceivedAt, { ready: sessionIsReady });
|
|
11462
|
+
if (!sessionIsReady) return false;
|
|
11463
|
+
if (!secretsProvisioned) {
|
|
11464
|
+
log("[serve] prompt received before secrets provisioned \u2014 rejecting");
|
|
11465
|
+
sendEvent({
|
|
11466
|
+
type: "error",
|
|
11467
|
+
message: "Secrets not yet provisioned \u2014 send provision_secrets first",
|
|
11468
|
+
fatal: false
|
|
11469
|
+
});
|
|
11470
|
+
return false;
|
|
11471
|
+
}
|
|
11472
|
+
log(`[serve] prompt: ${cmd.prompt.slice(0, 80)}...`);
|
|
11473
|
+
contextUsage.observeUserPrompt(cmd.prompt);
|
|
11474
|
+
return true;
|
|
11475
|
+
},
|
|
11476
|
+
route: async () => {
|
|
11477
|
+
await restageMaterializedSkills(true);
|
|
11478
|
+
try {
|
|
11479
|
+
await rebuildForLateMcpDeclarations({
|
|
11480
|
+
driverStarted: () => driverStarted,
|
|
11481
|
+
unloadedMcpDeclarationIds: () => agentSession.unloadedMcpDeclarationIds(),
|
|
11482
|
+
resumeSessionId: () => agentSession.resumeSessionId,
|
|
11483
|
+
recreate: (overrides) => recreateAgentSession(overrides),
|
|
11484
|
+
log,
|
|
11485
|
+
warn: (line) => serverLog.warn(line)
|
|
11486
|
+
});
|
|
11487
|
+
} catch (err) {
|
|
11488
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
11489
|
+
serverLog.warn(`[serve] session rebuild for late MCP servers failed: ${errMsg}`);
|
|
11490
|
+
sendEvent({ type: "error", message: `Session rebuild failed: ${errMsg}`, fatal: true });
|
|
11491
|
+
return false;
|
|
11492
|
+
}
|
|
11493
|
+
const activeFlow = pickChatFlowTarget(activeFlows.values());
|
|
11494
|
+
if (!activeFlow) return null;
|
|
11495
|
+
return async () => {
|
|
11496
|
+
sendEvent({ type: "status", phase: "thinking" });
|
|
11497
|
+
try {
|
|
11498
|
+
const bus = getOrCreateStimulusBus();
|
|
11499
|
+
const userStimulus = {
|
|
11500
|
+
kind: "user_message",
|
|
11501
|
+
text: cmd.prompt,
|
|
11502
|
+
senderId: "user"
|
|
11503
|
+
};
|
|
11504
|
+
await bus.signal(activeFlow.connectorId, {
|
|
11505
|
+
promptFragment: renderStimulusPrompt(userStimulus),
|
|
11506
|
+
meta: {
|
|
11507
|
+
kind: "user_message",
|
|
11508
|
+
runId: activeFlow.runId,
|
|
11509
|
+
text: cmd.prompt,
|
|
11510
|
+
senderId: "user"
|
|
11511
|
+
}
|
|
11512
|
+
});
|
|
11513
|
+
} catch (err) {
|
|
11514
|
+
const errMsg = err instanceof Error ? err.message : String(err);
|
|
11515
|
+
log(`[serve] flow user-message turn failed: ${errMsg}`);
|
|
11516
|
+
sendEvent({ type: "error", message: `Flow turn failed: ${errMsg}`, fatal: false });
|
|
11318
11517
|
}
|
|
11319
|
-
}
|
|
11320
|
-
}
|
|
11321
|
-
|
|
11322
|
-
|
|
11323
|
-
|
|
11324
|
-
} finally {
|
|
11325
|
-
if (pendingTurns.shouldReportIdle()) sendEvent({ type: "status", phase: "idle" });
|
|
11518
|
+
};
|
|
11519
|
+
},
|
|
11520
|
+
dispatch: async () => {
|
|
11521
|
+
sendEvent({ type: "status", phase: "thinking" });
|
|
11522
|
+
await driver.promptInput({ text: cmd.prompt, attachments: cmd.attachments });
|
|
11326
11523
|
}
|
|
11327
|
-
|
|
11328
|
-
}
|
|
11329
|
-
const driverStartStartedAt = Date.now();
|
|
11330
|
-
let driverStartOk = false;
|
|
11331
|
-
let driverStartAttempts = 0;
|
|
11332
|
-
let endTurn;
|
|
11333
|
-
try {
|
|
11334
|
-
endTurn = await beginTurnClearOfCompaction({
|
|
11335
|
-
gate: compactionGate,
|
|
11336
|
-
awaitIdle: () => awaitCompactionIdle("prompt"),
|
|
11337
|
-
claimTurn: () => driverSwapGate.beginTurnOnLiveDriver(() => {
|
|
11338
|
-
driverStartAttempts += 1;
|
|
11339
|
-
return ensureDriverStarted();
|
|
11340
|
-
})
|
|
11341
|
-
});
|
|
11342
|
-
driverStartOk = endTurn !== null;
|
|
11343
|
-
} catch (err) {
|
|
11344
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
11345
|
-
log(`[serve] driver start failed: ${errMsg}`);
|
|
11346
|
-
sendEvent({ type: "error", message: `Driver start failed: ${errMsg}`, fatal: true });
|
|
11347
|
-
return;
|
|
11348
|
-
} finally {
|
|
11349
|
-
logPhase("driver_start", driverStartStartedAt, {
|
|
11350
|
-
ok: driverStartOk,
|
|
11351
|
-
attempts: driverStartAttempts
|
|
11352
|
-
});
|
|
11353
|
-
}
|
|
11354
|
-
if (!endTurn) return;
|
|
11355
|
-
sendEvent({ type: "status", phase: "thinking" });
|
|
11356
|
-
try {
|
|
11357
|
-
await driver.promptInput({ text: cmd.prompt, attachments: cmd.attachments });
|
|
11358
|
-
} catch (err) {
|
|
11359
|
-
const errMsg = err instanceof Error ? err.message : String(err);
|
|
11360
|
-
log(`[serve] prompt failed: ${errMsg}`);
|
|
11361
|
-
sendEvent({ type: "error", message: `Prompt failed: ${errMsg}`, fatal: true });
|
|
11362
|
-
} finally {
|
|
11363
|
-
endTurn();
|
|
11364
|
-
}
|
|
11524
|
+
});
|
|
11365
11525
|
}
|
|
11366
11526
|
async function handleReply(cmd) {
|
|
11367
|
-
|
|
11368
|
-
|
|
11369
|
-
|
|
11370
|
-
|
|
11371
|
-
|
|
11527
|
+
await turnScheduler.reply({
|
|
11528
|
+
admit: async () => {
|
|
11529
|
+
if (!await awaitSessionReadyOrFail()) return false;
|
|
11530
|
+
log(`[serve] reply: ${cmd.answer.slice(0, 80)}...`);
|
|
11531
|
+
return true;
|
|
11532
|
+
},
|
|
11372
11533
|
answer: cmd.answer,
|
|
11373
11534
|
question: cmd.question,
|
|
11374
11535
|
requestId: cmd.requestId,
|
|
@@ -11381,49 +11542,10 @@ async function startAgentServer(opts) {
|
|
|
11381
11542
|
...cmd.requestId !== void 0 ? { requestId: cmd.requestId } : {}
|
|
11382
11543
|
})
|
|
11383
11544
|
});
|
|
11384
|
-
if (routed === "answered") return;
|
|
11385
|
-
if (!driver.acceptsReplyAsPrompt) {
|
|
11386
|
-
if (!driver.hasPendingQuestion()) {
|
|
11387
|
-
log("[serve] reply: driver takes no reply as a prompt; answer not delivered");
|
|
11388
|
-
sendEvent({
|
|
11389
|
-
type: "error",
|
|
11390
|
-
message: "This question is no longer open, so the agent did not get your answer. Send it as a new message.",
|
|
11391
|
-
fatal: false
|
|
11392
|
-
});
|
|
11393
|
-
}
|
|
11394
|
-
return;
|
|
11395
|
-
}
|
|
11396
|
-
let endTurn;
|
|
11397
|
-
try {
|
|
11398
|
-
endTurn = await beginTurnClearOfCompaction({
|
|
11399
|
-
gate: compactionGate,
|
|
11400
|
-
awaitIdle: () => awaitCompactionIdle("reply"),
|
|
11401
|
-
claimTurn: () => driverSwapGate.beginTurnOnLiveDriver(ensureDriverStarted)
|
|
11402
|
-
});
|
|
11403
|
-
} catch (err) {
|
|
11404
|
-
sendEvent({
|
|
11405
|
-
type: "error",
|
|
11406
|
-
message: `Reply failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
11407
|
-
fatal: false
|
|
11408
|
-
});
|
|
11409
|
-
return;
|
|
11410
|
-
}
|
|
11411
|
-
if (!endTurn) return;
|
|
11412
|
-
try {
|
|
11413
|
-
await driver.prompt(freshTurnReplyPrompt(cmd.answer, cmd.question));
|
|
11414
|
-
} catch (err) {
|
|
11415
|
-
sendEvent({
|
|
11416
|
-
type: "error",
|
|
11417
|
-
message: `Reply failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
11418
|
-
fatal: false
|
|
11419
|
-
});
|
|
11420
|
-
} finally {
|
|
11421
|
-
endTurn();
|
|
11422
|
-
}
|
|
11423
11545
|
}
|
|
11424
11546
|
async function handleCancel(cmd) {
|
|
11425
11547
|
if (cmd.senderId) {
|
|
11426
|
-
const dropped =
|
|
11548
|
+
const dropped = turnScheduler.dropQueuedPromptsFrom(cmd.senderId);
|
|
11427
11549
|
if (dropped.length > 0) {
|
|
11428
11550
|
log(`[serve] cancel dropped ${dropped.length} queued prompt(s) of the presser`);
|
|
11429
11551
|
sendEvent({
|
|
@@ -11699,10 +11821,10 @@ async function startAgentServer(opts) {
|
|
|
11699
11821
|
await handleSessionInit(cmd);
|
|
11700
11822
|
break;
|
|
11701
11823
|
case "prompt":
|
|
11702
|
-
await
|
|
11824
|
+
await handlePrompt(cmd);
|
|
11703
11825
|
break;
|
|
11704
11826
|
case "reply":
|
|
11705
|
-
await
|
|
11827
|
+
await handleReply(cmd);
|
|
11706
11828
|
break;
|
|
11707
11829
|
case "cancel":
|
|
11708
11830
|
await handleCancel(cmd);
|
|
@@ -11811,7 +11933,7 @@ async function startAgentServer(opts) {
|
|
|
11811
11933
|
}
|
|
11812
11934
|
function emitAvailability() {
|
|
11813
11935
|
if (resourceManager || agentSession?.getExternalMcpManager()) {
|
|
11814
|
-
const driverLive = agentSession?.driverType
|
|
11936
|
+
const driverLive = driverCapabilities(agentSession?.driverType).liveToolUpdates;
|
|
11815
11937
|
const payload = buildResourcesAvailablePayload(
|
|
11816
11938
|
resourceManager,
|
|
11817
11939
|
agentSession?.getExternalMcpManager() ?? null,
|
|
@@ -12011,6 +12133,6 @@ function touchSession(state) {
|
|
|
12011
12133
|
return { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
12012
12134
|
}
|
|
12013
12135
|
|
|
12014
|
-
export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CONNECTOR_MUTATE_NOT_READY, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, DEFAULT_FLOW_MUTATE_CONNECTOR_WAIT_MS, MOUNT_LIST_MAX_DEPTH, MOUNT_LIST_MAX_ENTRIES, MOUNT_READ_DEADLINE_FACTOR, MOUNT_READ_MAX_CHUNK_BYTES, MOUNT_STAT_BUDGET_MS, MOUNT_STAT_MAX_ENTRIES, MOUNT_TREE_OP_DEADLINE_FACTOR, MOUNT_WRITE_MAX_CHUNK_BYTES, MarkdownStreamer, PreInitRingSink, ResourceOperationError, SESSION_ROOT_WRITABLE_DIRS, SESSION_ROOT_WRITABLE_FILES, WRITE_RANGE_PARTIAL_TTL_MS, WS_AUTH_TOKEN_ENV, WS_AUTH_TOKEN_FILE_ENV, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildConnectorTokenMediator, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, buildStoreSnapshotReplay, builtinCapabilities, capabilityLogInstance, capabilitySignatureInputs, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, computeDirectoryTotals, connectorRefreshKind, createAgentSession, createFlowConnectorReadiness, createManagedCodexSubpromptDriver, createSessionStimulusBus, defineCapability, deleteSession, dispatchResourceRequest, dispatchRunnerCapabilityInvocation, driverActiveAfterTurnEnd, emitSystemPromptComposed, ensureClaudeSettingsDisablesConnectors, ensureGitConfigInclude, executeConnectorMutate, extractClaudeAiOauthExpiresAt,
|
|
12015
|
-
//# sourceMappingURL=chunk-
|
|
12016
|
-
//# sourceMappingURL=chunk-
|
|
12136
|
+
export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CONNECTOR_MUTATE_NOT_READY, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, DEFAULT_FLOW_MUTATE_CONNECTOR_WAIT_MS, MOUNT_LIST_MAX_DEPTH, MOUNT_LIST_MAX_ENTRIES, MOUNT_READ_DEADLINE_FACTOR, MOUNT_READ_MAX_CHUNK_BYTES, MOUNT_STAT_BUDGET_MS, MOUNT_STAT_MAX_ENTRIES, MOUNT_TREE_OP_DEADLINE_FACTOR, MOUNT_WRITE_MAX_CHUNK_BYTES, MarkdownStreamer, PreInitRingSink, ResourceOperationError, SESSION_ROOT_WRITABLE_DIRS, SESSION_ROOT_WRITABLE_FILES, WRITE_RANGE_PARTIAL_TTL_MS, WS_AUTH_TOKEN_ENV, WS_AUTH_TOKEN_FILE_ENV, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildConnectorTokenMediator, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, buildStoreSnapshotReplay, builtinCapabilities, capabilityLogInstance, capabilitySignatureInputs, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, computeDirectoryTotals, connectorRefreshKind, createAgentSession, createFlowConnectorReadiness, createManagedCodexSubpromptDriver, createSessionStimulusBus, defineCapability, deleteSession, dispatchResourceRequest, dispatchRunnerCapabilityInvocation, driverActiveAfterTurnEnd, emitSystemPromptComposed, ensureClaudeSettingsDisablesConnectors, ensureGitConfigInclude, executeConnectorMutate, extractClaudeAiOauthExpiresAt, flowStartNeedsDriverRestart, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, handleSessionRootResourceRequest, hasNonTerminalFlow, hostOpResumeStimulus, installPreInitRingSink, isSessionRootPathAllowed, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadManagedCodexHostConfig, loadSession, loadSessionById, mcpAuthSecretKey, newSession, nulTailPaddingLength, pickChatFlowTarget, pickFlowToolTarget, pickRepointedManager, planFlowMutate, prepareCodexTools, reconcilePendingDecisions, reconnectedRunNeedsAgentTurn, recreateKeepingLiveFlows, registerActiveFlow, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, rejectPendingCapabilityCallsOnDisconnect, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveFlowMutateConnectorWaitMs, resolveMixin, restoredRunHasWorkToResume, runAgentChat, saveSession, setCurrentSession, setUpFlowConnector, startAgentServer, stimulusFromMetas, takeRunnerWsAuthToken, toActiveFlowTarget, touchSession, validateInputResponse, writeClaudeCodeCredentialsFile, writeRangeChunk, writeRangePartialPath };
|
|
12137
|
+
//# sourceMappingURL=chunk-ZSFTCMZL.js.map
|
|
12138
|
+
//# sourceMappingURL=chunk-ZSFTCMZL.js.map
|