diff --git a/docs/.generated/plugin-sdk-api-baseline.sha256 b/docs/.generated/plugin-sdk-api-baseline.sha256 index 92f606896133..3ef8b0e1121f 100644 --- a/docs/.generated/plugin-sdk-api-baseline.sha256 +++ b/docs/.generated/plugin-sdk-api-baseline.sha256 @@ -3,22 +3,22 @@ b41e6e6f7a1197d85922d010de1abf1de64f25c535200f6506a8c9b4334952f1 module/account 71522995185b956a0cc4927a472cc8d1153e5e998874bfd9a750513175174713 module/account-id 1f9b6f85f7886fcca451930f5be6898ba917f9a9c01973fc7cc0c76929bdcc76 module/account-resolution 4fbb1c87e99399f842a20d75d5e35a4b7064a1b7f02115c23f9a2a7cdcfb57ee module/agent-config-primitives -8791c48864f7d5b3aa4a9202741c252dbf8c36a901d575d47ab02830c8c2edf1 module/agent-harness -0125b0c97adb16e6db96e4098a0b18008679ad454b9f036dd780f28da2269d93 module/agent-harness-runtime +ca0b30b341c82b818df80be3e8e69f29ea1d141386c213194010493baa285268 module/agent-harness +e39b68a5403a5e9fde5a9017861e269f17cd25efd8bd3f585e04340d1c3504de module/agent-harness-runtime d6097cfa1b410f4b5267a56a7bd19c2a33fbaf6642683dae6aec68e998e48f6c module/agent-media-payload -076faadad74fd3cb2d2527a9693ed163c9fa178b6f5e8c1d5fe907e24fe8336d module/agent-runtime +b7c45b591d7993e678b8dd93bb7c8d6b8607b3820cffddea1c27e9c91ce3ebed module/agent-runtime cbcd1201250087b16f41e87cd5b9d3be303620dd27e945b619e7117a5dbc069f module/agent-scope-runtime 8fecb210e22bce4532b6ab649b09465f0bd2c857a44abf40db7d683d6491e6da module/allow-from af6c69278be1aaab26d97dcc27cdfd73f56b3f18df327e71f346a75882a09436 module/allowlist-config-edit -846e6be23e110ed8591775e09f66d4c860a7e88517a1e5d84b9af9d7ab9518b5 module/approval-auth-runtime -b0f0ad13a668a79e99e754cb0938186224ff4c86d683d22f12f2f35c96032cfc module/approval-client-runtime -12bbfe2e88289fa12ba0dde237f001cd5c0725ada0908152657b4e2f9b3c95c9 module/approval-delivery-runtime +7114945de449cba61d7526d2afd7910fe7a09f36123498b4594757a33b15a000 module/approval-auth-runtime +2d048b1bc89e8919cdfb55919b6549e47facf8bf3de50fb46b9499d8e505c34d module/approval-client-runtime +134fbf72b52e66074f65ce0514c7ad5fb1618eb92d4da5f50b1d64db5ce7169f module/approval-delivery-runtime ba39ac4f12fa4f2579e65bec93e0504395f988cc25a797c7441193bd652d9a0f module/approval-gateway-runtime 00583c41e60108630d09a5f6d22404fdc005156026d7f912141f126c5b2d9e37 module/approval-handler-adapter-runtime f58b20c83ee79dc0a6d51e33907829f31962ed11f40a4c318810ea1565e6d71d module/approval-handler-runtime -9e3063fdec75eaf73960130ca60f93bb54a00fedc553f94a46d2774b27a45fa3 module/approval-native-runtime +fb4c51474507ec63a9de2755ad3c15911c652d5f0d44ca387cbe4aac7f0ecc6f module/approval-native-runtime 1ec6ff040213d9cdfcc3e871b408e2c98ae5bc7bbdb7a9d847095df70050cbab module/approval-reply-runtime -649645f4cdcf1e2b17eafd696b3478dfdfe8a5e369e71c9074b6d6835681161a module/approval-runtime +20fd8ffb99d1cc5dabd7c5682cfddc78ca36786223fe504325d32e321a01da64 module/approval-runtime 01ca912836b8dec672f705e294f72d346e778557e4c591317d67558ea7669c0b module/archive d7e53de63b0ac11a266e4abdc18ba6e9401b80309f5c8f5f6a72a00f65dfe3bd module/boolean-param b11b9d8fb991e26acd6e7efcb96b77635455d2c9b94d0a7e840dbdac94ad5b85 module/channel-actions @@ -26,57 +26,57 @@ b33ade7748d6818914a6e9b9a23b98d0140432f5dcbe1f000a84d76617e9f639 module/channel c2cc71d5070b6071c51248b0648d1ad1a9468d3737df890adc77ec02025e8853 module/channel-config-primitives a6cca5706f3aba6abb2178b175a0986d921ade98c2c05d2a54451e2fb7e16825 module/channel-config-schema e4e4a5e78619abf1c8d78dd00d90e9bc8fe748adbf8a0dadbf0d9052bfcf5ab1 module/channel-contract -cf098ed89f10e92a275ec49146dc718baad919dfcada10aa59fad1f6b0a887b9 module/channel-core +6db0bd55d63376227259c40c25a8044ae097069d75eeec4d46f30a2f628572fc module/channel-core f6596a8bcf85e9cfeb29e785c0f3b21fe438e07b1a4f179b9ec49c624516ed72 module/channel-dm-policy -c412bffcd394dc07d559527c26e31f466a2aa76a900bc7a78c16c7afb906c6e3 module/channel-entry-contract +bbd52585511338a135aca271314dc4bb89ce59b6f6fe4f04b7302b6f74021e29 module/channel-entry-contract 47cf8765e76c151ae7d2991d41beca62922a8837c1521e10a3fd23f9992c2d7c module/channel-feedback -d06b10a06868e5793c4f20f6ec6c4c0264c1217767cef607608a82d39dd738ed module/channel-inbound +1992d42383ed31d77af0d6bcf315c9d9df7da758759b6fb7483a5010b0a43784 module/channel-inbound 3115366026efa38e07bfe0bfecd483e93454cc7bcad432385139c956777accff module/channel-inbound-debounce bc59c696ee45fb500d105c619c0ec81b8186bebe99135f23dc818ac16004deb0 module/channel-ingress-runtime bf81078cfeebe50ac260a3b6e56d842756f24ed2dd9af1a29f00a3ff2039be93 module/channel-lifecycle 0e47457e38d1df0bd572e1408cde2ca6a788b65205f43c585316b5ad3a8f2f16 module/channel-logging -757fca9e3889f35e3f81980a0f7d559a8231000e7427bf59fc847a0c720cb291 module/channel-message -059710480d2c728609a8fdbb6b1a8012f32c1c08a88460f3a2f34bcacb67d525 module/channel-outbound -55e38ea1273e37c0f035cc36e352170498b521ab20a4a93d25d6cdb6acbf15df module/channel-pairing -746e8a837f7aff515215157270c6fe3207eeba309186e9bf20f10a0d72f1b6c4 module/channel-plugin-common +5982cb0209ac7a6cada238403c2239f53241f19d185d5258fa003cad624da2dd module/channel-message +d0543fac4cb2125ec3d74b9d9a08e8e921c838c92402d2d311c2191bc63c9bc8 module/channel-outbound +b919a6cc5cf7a3ee3ec2a1ed69480a03564bf4dfff790256c997f8530db42517 module/channel-pairing +f2415aaf9039ea1d1bf1597757e0587cfa01cef28561ade788fc8e9ae99a0dff module/channel-plugin-common e9f6fa5006304028e54f4ee84f1b006c14356b9f64b9c8508491cdae5290ccfd module/channel-policy -3c454d34f2c70b1741c2c977bd1367004c5d0e79ee44f3aece7345e40bc84394 module/channel-reply-pipeline +717d673996642914794c0fc8916a20c41f54859df5b9a7330f3f8f4b7b1033d4 module/channel-reply-pipeline 482370e60135db9bfaf07f24bab549e5fde09ab265a6061a1f587c5d93929e91 module/channel-runtime-context 241050b8979ed905727789e99011535631dd8c205aa6967401677d78281900de module/channel-secret-basic-runtime 2edd63d294a8ee128a18c1815f6ae53be915569c49ebbad0dd139eb60475b0e6 module/channel-secret-runtime -306c4dcb4d88bd6a4f8f8636184670d995c3bba8bc8a9b6463d3d5d1b2e49d65 module/channel-send-result +eddfe96aba576a02288de7bced470677337ec75964f71e2fe45cec2339007af2 module/channel-send-result 1c6dc79f7cc591b1d043f48d0b726cd989f4b3e15665962bc31f1cb6b1c5e9c0 module/channel-setup d9dc27767e1d3496fb7a8a8e36796815d0ed582034daf393a655a10378e7abaf module/channel-status f6c25ae55d49d90431682ca53c9dd836304942a738425d6ff028146a0c6d2c97 module/channel-streaming b2f920ff4a6b4190e6d6ea0a3effb001751e092f0e3ac0cf296721ff8c383d86 module/channel-streaming-config fdeffe356c7c4edeec9f8fd03edcadc375eabc7a9412e582b10c3180e3ef40fc module/cli-argv ad12670dbfe538f8d0ebf4fb2b68080e93a760278278e6b1ce9bb129d4b2d533 module/collection-runtime -b2e8c02d09eb3bd3c7645bc37ba0785be1c0fbbd742eeafdf6e9e109b4377fc1 module/command-auth -1ab2991c220b55cd96041c3dc70956cf1e01b8aa45a8d8b130d32a6683001ac5 module/command-auth-native +586fb21bb836210bb0d96d59553088afc97fa138fbd9134c920b02a102116c2d module/command-auth +e91ae6a361d75d6600426dd5cbc5a4fb1b21a23aa506703600bc4646dfee38ea module/command-auth-native 50c24235bca2c1d3c011f6bc266b57078b78a76d2d27ee12e7b3245f2947b493 module/command-detection e24382c2cca7fd2cf69ac353e258153dab80b279daf9f0ef54a727981a7dff3c module/command-primitives-runtime 1d6ebcdc843b7072a7fc4475eadadb90a1111d49c1da1e4326775800873cf9f1 module/command-status 064ac3096df6265c46610082286d233b1806fc73fe02acd12daf784bd8eab243 module/config-contracts 0d99f5cb8c4978ed760e5fb4e476543759fbd8fd5bf73cc50a50c1d550203826 module/config-mutation -5153d66e931ca8c9c5a6102460da637fcb9e6c7e1db94d67ef7e5970b6a8d42d module/config-runtime +4a4a980be74abdf1c189246d1644934f6c1b6b2d31b718769562d5c3e1a3a426 module/config-runtime a87d663700604d7ca14a2b3f7e047c67633182cbe60f1f18bb78782240a4886b module/conversation-runtime -8d188be6c7a095fba512eed9d89a8fc1f0a1d307d388df2fda74eed73d36d59b module/core -7c0e4d56dab3c0239e4a1904e6a5ef1bef07ad8a1efe40a973ba11e1b14a91d0 module/dedupe-runtime +7a55a300f44c92f6c04271fc77c34e60aa8df75b3c6dfd79f4e798a1827c3aaa module/core +982b6d874212df168af043ac067a468ab27ca2407c2c3839cf519619bedfe233 module/dedupe-runtime ebef0e650ab45e44c9335e2b3e15588c968cea6dadd125364a076f9c50ad1e8c module/device-bootstrap 21d86413166ef815581d606f678b6a216a1cc73ffe470b841f5bc4a131bff6df module/diagnostic-runtime 6c697283dd82402fd84b97b5226086575a23ec36ba5bf915b650fb9ee21df9ad module/directory-runtime -b4581ed2ac4eccf395b7c052178621ef06879226f73cdd1722dc42e790deb9e6 module/discord +0c7af6a67531ddf4b623cd2b362c3f954fc8300384a99356821fffb4b22805ea module/discord 39fe343ed2119de714757c365eef2ccec89c2c82a0876c60a4bef8ce469f8c8a module/error-runtime ce4f1602bf5b5de968ca97cede4f498b6ae709a0a59393b5ce9255cf0e6a9d5e module/extension-shared dd9f6e0fd33cc88b22543c1ee30cc09cf4de4d8f30dff7b7f9cebef885c21543 module/gateway-method-runtime -74315bc4642a583d3dc21d09e2e179d414384f691672d1816f65321d2e466fc7 module/gateway-runtime +b9494ae460096cdb30ff10f0fa6ae0fde70887038c83c9a484aed8a4d7e0b7aa module/gateway-runtime 1b1c6bd5bfc0cfb0c5bb9bd97f8ac1928750cb87232a3415dd066cc21d7b48b7 module/group-access edcc13362193d3bb0b16fc48a3d96122e6efa236cfdec3760e57e2c6d85ee8b8 module/health -69d49c9cd6cf270df7dc1c6babb0c53c7ed1e60e9e2da102eecbda0226b2278e module/hook-runtime +07a63fe100a985a690db0f739de87611186297b5928ec1fd305f43f5ead7e48e module/hook-runtime a953bd0c23c562e29fc512bc2354ed45c497728169d8201cb2cdb75d9e056073 module/inbound-envelope 4928af5d2509f696b896f53ac790303a0742202dbcdae3e44fe6d1b434a9c1ba module/inbound-event-delivery -271c40917a54400de91b269f1f95c381dbecc8f98113f6d9828eeebd3e83ebfd module/inbound-reply-dispatch -f0247897efdea3bff60314e68a0ad41aff9d6835b43a4c443044eb5fade503f8 module/infra-runtime +f234740cf866255bb805e194d3da0d18129c7f90956ed3d57b0e1b8131c19098 module/inbound-reply-dispatch +4b3e492ab53f62a42a7ddaf73bbca780a444e6b26d2656db8f40a7ad361e4363 module/infra-runtime ce73721421f1b903dd04ead4df173582e59ea3e9990248102c448b419cc6d272 module/ingress-effect-once 9c6e3796569c6a27762946281a5c1a792158505651ae5e9434e5d18ebd9ee947 module/interactive-runtime 408d257ab5cc4b88a22b7e7595039cb8fc524b261c44141b294fbd0100ba62ee module/json-store @@ -85,32 +85,32 @@ cc2d0e1c1e7b9491eb254f314ed2c081a33256936781017eb5d8f9f11808f35b module/logging f1ca4ced4305d0769c2d8cc1291137ac7002fe0e6eaec2c1a71edad2204c8311 module/matrix 4d18b3bcec2c4291085e6001ed444198fe74f12708956e1c40c964d84e53bec8 module/media-local-roots f74d7295fe716aa140aa0bc9300d6259d71dab826de0808fca6bb02592bf5d6e module/media-mime -38ae5fdcae1c1fb795f1dc63b5b822020894ea1ce0264beb6bd25b995719cb50 module/media-runtime +a7c26ae23c130c992cfa0a6fd531f57721111f7833e38ff816a44ce3e4e01898 module/media-runtime 6a52f93107335f88751704352cc01e62add06f854a5b7d765e2a5ee87c0313b6 module/media-store 3bdcc734f6ea5f59320708cb2b87de9c5422a8b70745774ea0cc8a01cf656924 module/media-understanding 4e64c47aed06c23796a07f099b7ab52ee68feeb7c934c749c5cdcd7cb9ef6e7b module/media-understanding-runtime -73ae8562bcda4f26b44348302f9169b2ce15b282bc19d2065128c267ef9164d3 module/meeting-runtime +3e7192e47b89dcbd767cec6bc783002f13291e5a4368e129e63e38bc88f65ca5 module/meeting-runtime 3312468e2e8f3423b765fac6bb17944b800ea2c84acffeb64342c99040b2f482 module/memory-core-host-engine-foundation -b57de21d9676dc0df41d59b895c434700e767bbcab454fa8fac0379b5c066967 module/memory-host-core +3e3f360bf5b4dc4f2585c148b946f900a6789d6a9736dcaed5d39d0f891de380 module/memory-host-core 1efa0aadc4261d1c6073058cbf3dcc9fa681424819bdd14333e19b249bbc4b18 module/messaging-targets -8a43f27e4b4cc71aa92d0fdde83c9374ad155f74bb2ec7db1d48559065a8772d module/model-session-runtime -2902259327d96199b4753b871251edec12265dbf70a7c12d8f5f863db5743b6a module/models-provider-runtime +f265b47539cb1c8e205723638ee634fd14ce94694c2bb6d5455d92d1ea7d36fb module/model-session-runtime +bc5f40c86c375013561df101ed33fc32c00e7adfbc47af9168456fe5ea4e2fa4 module/models-provider-runtime a3eaaf99e2ac5e83f0e14b83ae54a2d99488a6597df0c4421a0d58cdc1bd3fd7 module/native-command-config-runtime f6ffada942145ca2fcec4df90740b4578afa09e81d46cc09122a65d6e345fe02 module/native-command-registry a6b5532576fa4cfd609d0966927eec12806424f2e1efce9fe47d903dfeb8e4dd module/param-readers ca7a56bb1a6169b4cf9befbf5aa21da280a8086fdc49fca4eec520a7a7c98549 module/persistent-dedupe b31f5d86904097993a55377fed7973cd298b0e1f49cade7e37a1e28f6e724108 module/plugin-config-runtime -a2f3f20742849b14599685bd98b083f1454b2f56c8363f30f0d49789b41d612d module/plugin-entry -fd39068d4eefdc8804ce84d4621cc94877047dccf07c9092a40020cfc2e5f9de module/plugin-runtime -f7770b96b0a1b152d7aa9619d2e19f9a637ce25e36cab9c23ce030565eea870a module/provider-auth -d2a40746f617fbeb758c4606a299b5f00be13aa86676de26b249a9abf291a775 module/provider-catalog-runtime +4c4a03635aed82aa3e63f14ce475c8acef302c4e398d9d3b7f86ee0ad58cdc1c module/plugin-entry +b6f54e0cd9dea64c62caa18676074756ccfb910a4f1e55298266e0b6abd7cbe7 module/plugin-runtime +a60fe7ebb2a1245e51d798956399d1e3b5b9f4498589c41f186067aa3aec5c68 module/provider-auth +0ccf4aabd80263e252912b6d2605124e266df68aa353aa0555994165012443bd module/provider-catalog-runtime 8131147d699394bd06503e2ea2f5f1a50b1594a87dded6d118b74a8d0328c8f6 module/proxy-capture a6c6462326817540b9d654f0254bf561a340ba058851e958fd0367aaa9198b9a module/question-gateway-runtime 50e250d810a9936ae468710698a61e8e569f728f2f3f55fb57ea1e401b3a37be module/reply-chunking -54c342c161d75b85b992f1aeb798c98ded01555411a48edad80dc30c24ba1ad8 module/reply-dispatch-runtime +26bd09f241930b744f54a8e60a6f59e4ecc74eb7f9c57b1035553c3ac1247f55 module/reply-dispatch-runtime 73f861fa3179d5af1159853c5acab0eec7a6c8f9398dcb75ea770e784fca6727 module/reply-history 321f9ecc06267499c7700c17f96d58bfd1e56d09fd765bb8ce4b6664427720ff module/reply-payload -3453ad8d356b46b6ff7fca1ed6bb1b096373dcc74d6e212915f3efc2063bdd43 module/reply-runtime +555f9f3917d260af1e8934fe362ae680bdce007a16e0878738cced6e38ec8a36 module/reply-runtime aa07d85d99fdd2b1e0cbe9975fb6dcae66b8bdce2607c6bd5402ae68bb15118c module/root-walk ad6c5c5b16e22f8b06994f69ecfafbc9a9622b07c14670f3c4e8ee81cf3b8c4d module/routing 7877a7e58fa32a64107154e5b714c6d165e96989d4aa5f43e0afac085a187af0 module/run-command @@ -118,20 +118,20 @@ ad6c5c5b16e22f8b06994f69ecfafbc9a9622b07c14670f3c4e8ee81cf3b8c4d module/routing 0570a20fac6020880900a0cf9a889d8f28f47b89d0e1d17862265b557236d440 module/runtime-config-snapshot bfe087e249a3c0adda4d24727220a65bcc159f53d6a4d6d8cd9b252627ef8e98 module/runtime-env 49e9b6a8195c89704eaa80656f176444af7cacbf639b759f41f2c78ae6bfcfd9 module/runtime-group-policy -c57fba7d4e6eca193cf6896eb7ace28683733e192404fe0f6d7421a2b2aa6852 module/runtime-store +feda681a44e76ed58a8ef1530f703b7dfa1b2bc77546d76289bea289ece29b82 module/runtime-store d17862c40825af1ddf0257b44f1e1cbb9c375e8e5ed668fae75d530d1a465cf9 module/secret-file 8e2ac4d3973d8d8ce4478e3440d66ee5c0d9213b0fe9e927c421d14fd31e5e86 module/secret-input b1b0229280d7cc4a880e4db75130714eb6adc9d6aea31240dc9a8ff6fda55219 module/secret-input-runtime 0cbc3908bd9e1d4527585023a1692eba6c0bfe82f107f49a926a8d1c79aee2a0 module/secret-ref-runtime efac9b2e9828a4d2f45794bfea8a9c0ce92578164f6012a9d2d83418d0bd7ba8 module/security-runtime -c20154becd67047940393057af0758a287a09e052bb77f83463a6e87c1484ff9 module/session-catalog -01c150ef10d33839f86107b05fcfb7bc3dc0883c7dafd1e065758678caf7c9aa module/session-discussion -8d71e05167eb3301536e9f7e8fc14047791c28a4e32c014746db5b3dd0477242 module/session-store-runtime +b77c39b449d4e40664b2f6be40fcb515381a1c26b515f12a1c44b07aecfe8f4f module/session-catalog +3ea91a6e3edff5e50a1b24f1c4df33bd57439d171bf078f937c6bd1496995c08 module/session-discussion +7524ecfe9006c8b1699ed39e8777747532590a9cd77f570bb2d91b59010d556b module/session-store-runtime 124f36c843153cb31b85bbe061a145ee768251b82fc31ffdd0b9c7cab472f9b2 module/setup a2b1f5da3a82d501171a88f759c9dd756286df8884703168da97d8cd4aa2b1c9 module/setup-runtime d0cb4c5abb7484352088f556c1ba7c7b147d7b57977b8246e5cb7187937768b7 module/setup-tools -41cb221e60e0285e00c926af872b222ed089f745c70d3c513476f96f6736de8b module/skill-commands-runtime -ac554f41638bb2780d9b53cfc76fc9c8d361a587ddba234804cdd67a91a823de module/speech-settings +7763b2c9f4ffed3ae05b778dc0ed9210f2e743156a4bd3a6600ecb8fcd7a807f module/skill-commands-runtime +06a76f244546b513756e6b8d816378dd00b80d01b555493b90554bbf9404f788 module/speech-settings 614e35857fd3891aefd1a49955140e0e78c5bf9c4e3950268b9e28f4eeed6f9d module/ssrf-policy b84d7ab7506041897a22e3cc5ba7f62e90fdcdbea91e38a71030b79cca2d77ed module/ssrf-runtime 3855f0a23281d21063762f5b3be2b7485c8bdb3b4cd1692de4f2a17d4eeae496 module/state-paths @@ -141,11 +141,11 @@ f097d0096b21c8a052f0f649b7512ecf2aba4744ae6956f001950e053828b309 module/string- aef35bee2502cd6ed8765409b758e452aff8ac9469fd773e6a2a44c9a1bc3f66 module/temp-path 87fa81b9e58d8fc04a4b4202d2d37fca339615f5225687d9db905151439e0f4d module/text-chunking fcdaf13ecea269f1a471ba4fe14958f3c8e198eaa20f354546a648408ed74064 module/text-runtime -903548ea9a01c9f5853870a168b523028b7787253015d9a7732ce5e54480800a module/tool-plugin +cab5163967280a7da2540924306f399378fc8d34d42a2d7b6f20dc8dd21b963e module/tool-plugin dc1a073c59ab61e2789533b777b3f0cb9af689d64a97796b10e8aa82552510db module/tool-results 1aa65cefa239d5943f19c2cf2a19c37857b0b659452877fc457dbf627a28fff0 module/tool-send cda105b721d498df23a554c6b68be150b8fe66b8b9172185c31a0b3b0646b1dc module/web-media -14e040a528b00146a4df1fe994d69db028fa14b043ae7a01cce26472d7445133 module/webhook-ingress +6d2079e50605a1e7fa6b40599e39cc44a48368485bc966c7402bb834844c82bf module/webhook-ingress e3a199a9ce0b85d203e9e8a29b500db29c6b7af307e3145d0a311e29d598925b module/webhook-request-guards de59e86e126b75d13251cba7ebbe27b44d9b5588785d98df5ff4d6722374c81f module/widget-html 9161b36ec0ab062ea41b363c894fcd672a7727f21cb726739f99f9c184fce69d module/zod diff --git a/scripts/e2e/codex-npm-plugin-live-docker.sh b/scripts/e2e/codex-npm-plugin-live-docker.sh index 5da28c43bf6b..01335cabf983 100644 --- a/scripts/e2e/codex-npm-plugin-live-docker.sh +++ b/scripts/e2e/codex-npm-plugin-live-docker.sh @@ -43,7 +43,7 @@ AGENT_TURN_TIMEOUT_SECONDS="$( )" SESSION_STORE_CONTRACT="${OPENCLAW_CODEX_NPM_PLUGIN_SESSION_STORE_CONTRACT:-}" if [[ -z "$SESSION_STORE_CONTRACT" ]]; then - if [[ -f "$CANDIDATE_ROOT/src/config/sessions/session-accessor.sqlite.ts" ]]; then + if [[ -f "$CANDIDATE_ROOT/src/config/sessions/session-accessor.sqlite-contract.ts" ]]; then SESSION_STORE_CONTRACT="sqlite" else # Trusted current harnesses also validate frozen targets from before the SQLite cutover. diff --git a/src/auto-reply/reply/agent-runner-memory.test.ts b/src/auto-reply/reply/agent-runner-memory.test.ts index c5bcdc328dc4..18b2a56a761b 100644 --- a/src/auto-reply/reply/agent-runner-memory.test.ts +++ b/src/auto-reply/reply/agent-runner-memory.test.ts @@ -13,7 +13,7 @@ import { readTranscriptStatsSync, upsertSessionEntry, } from "../../config/sessions/session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "../../config/sessions/session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "../../config/sessions/session-accessor.sqlite-transcript-write.js"; import { resolveSessionStorePathForScope } from "../../config/sessions/session-store-path.js"; import { clearMemoryPluginState, diff --git a/src/auto-reply/reply/session-fork.test.ts b/src/auto-reply/reply/session-fork.test.ts index db8ba7558380..eff33d6fc8fa 100644 --- a/src/auto-reply/reply/session-fork.test.ts +++ b/src/auto-reply/reply/session-fork.test.ts @@ -8,7 +8,7 @@ import { loadTranscriptEvents, replaceSessionEntry, } from "../../config/sessions/session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "../../config/sessions/session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "../../config/sessions/session-accessor.sqlite-transcript-write.js"; import type { InternalSessionEntry } from "../../config/sessions/types.js"; import type { OpenClawConfig } from "../../config/types.openclaw.js"; import { diff --git a/src/commands/agent.worktree-race.test.ts b/src/commands/agent.worktree-race.test.ts index bf72ff1dac5d..a0249ae22059 100644 --- a/src/commands/agent.worktree-race.test.ts +++ b/src/commands/agent.worktree-race.test.ts @@ -9,7 +9,7 @@ import "./agent-command.test-mocks.js"; import { ensureAgentWorkspace } from "../agents/workspace.js"; import { getRegistryWorktree } from "../agents/worktrees/registry.js"; import { managedWorktrees } from "../agents/worktrees/service.js"; -import { upsertSqliteSessionEntry } from "../config/sessions/session-accessor.sqlite.js"; +import { upsertSqliteSessionEntry } from "../config/sessions/session-accessor.sqlite-entry.js"; import { clearSessionStoreCacheForTest } from "../config/sessions/store-writer-state.js"; import type { OpenClawConfig } from "../config/types.openclaw.js"; import { closeOpenClawStateDatabaseForTest } from "../state/openclaw-state-db.js"; diff --git a/src/commands/doctor-session-sqlite.test.ts b/src/commands/doctor-session-sqlite.test.ts index 953ae54d842f..352e9f70ad2b 100644 --- a/src/commands/doctor-session-sqlite.test.ts +++ b/src/commands/doctor-session-sqlite.test.ts @@ -9,10 +9,12 @@ import { useAutoCleanupTempDirTracker } from "../../test/helpers/temp-dir.js"; import { CURRENT_SESSION_VERSION, SessionManager } from "../agents/sessions/session-manager.js"; import { loadExactSqliteSessionEntry, + upsertSqliteSessionEntry, +} from "../config/sessions/session-accessor.sqlite-entry.js"; +import { loadSqliteTranscriptEventsSync, readSqliteTranscriptStatsSync, - upsertSqliteSessionEntry, -} from "../config/sessions/session-accessor.sqlite.js"; +} from "../config/sessions/session-accessor.sqlite-read.js"; import * as nodeSqlite from "../infra/node-sqlite.js"; import * as replaceFile from "../infra/replace-file.js"; import { resolveSqliteDatabaseFilePaths } from "../infra/sqlite-files.js"; diff --git a/src/commands/doctor-session-sqlite.ts b/src/commands/doctor-session-sqlite.ts index 1ba02652f490..cae9f11fbe6f 100644 --- a/src/commands/doctor-session-sqlite.ts +++ b/src/commands/doctor-session-sqlite.ts @@ -6,7 +6,7 @@ import { getRuntimeConfig } from "../config/config.js"; import { resolveStateDir } from "../config/paths.js"; import { parseSqliteSessionFileMarker } from "../config/sessions/legacy-sqlite-marker.js"; import { resolveSessionFilePath } from "../config/sessions/paths.js"; -import { importSqliteSessionRows } from "../config/sessions/session-accessor.sqlite.js"; +import { importSqliteSessionRows } from "../config/sessions/session-accessor.sqlite-import.js"; import { resolveUnsuffixedSqliteTargetFromSessionStorePath } from "../config/sessions/session-sqlite-target.js"; import { normalizeStoreSessionKey } from "../config/sessions/store-entry.js"; import { diff --git a/src/config/sessions/incognito-session-transcript.test.ts b/src/config/sessions/incognito-session-transcript.test.ts index a34993080698..8c8f7dd28756 100644 --- a/src/config/sessions/incognito-session-transcript.test.ts +++ b/src/config/sessions/incognito-session-transcript.test.ts @@ -15,7 +15,7 @@ import { loadTranscriptEvents, patchSessionEntry, } from "./session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite-transcript-write.js"; const sessionKey = "agent:main:dashboard:incognito-round-trip"; diff --git a/src/config/sessions/session-accessor.conformance.test.ts b/src/config/sessions/session-accessor.conformance.test.ts index 3d163992d154..57245fae2c84 100644 --- a/src/config/sessions/session-accessor.conformance.test.ts +++ b/src/config/sessions/session-accessor.conformance.test.ts @@ -46,25 +46,31 @@ import { type TranscriptUpdatePayload, } from "./session-accessor.js"; import { - appendSqliteTranscriptEvent, - appendSqliteTranscriptMessage, branchSqliteCompactionCheckpointSession, - cleanupSqliteSessionLifecycleArtifacts, - forkSqliteSessionEntryFromParentTarget, + restoreSqliteCompactionCheckpointSession, +} from "./session-accessor.sqlite-checkpoint.js"; +import { listSqliteSessionEntries, loadExactSqliteSessionEntry, loadSqliteSessionEntry, - loadSqliteTranscriptEvents, - loadSqliteTranscriptEventsSync, patchSqliteSessionEntry, - publishSqliteTranscriptUpdate, readSqliteSessionUpdatedAt, replaceSqliteSessionEntry, replaceSqliteSessionEntrySync, - replaceSqliteTranscriptEvents, - restoreSqliteCompactionCheckpointSession, upsertSqliteSessionEntry, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-entry.js"; +import { publishSqliteTranscriptUpdate } from "./session-accessor.sqlite-events.js"; +import { cleanupSqliteSessionLifecycleArtifacts } from "./session-accessor.sqlite-lifecycle.js"; +import { forkSqliteSessionEntryFromParentTarget } from "./session-accessor.sqlite-parent-session.js"; +import { + loadSqliteTranscriptEvents, + loadSqliteTranscriptEventsSync, +} from "./session-accessor.sqlite-read.js"; +import { + appendSqliteTranscriptEvent, + appendSqliteTranscriptMessage, + replaceSqliteTranscriptEvents, +} from "./session-accessor.sqlite-transcript-write.js"; import { setCanonicalSqliteSessionMainKey } from "./session-canonical-key.js"; import type { InternalSessionEntry, SessionCompactionCheckpoint, SessionEntry } from "./types.js"; diff --git a/src/config/sessions/session-accessor.entry-mutation.ts b/src/config/sessions/session-accessor.entry-mutation.ts index 653e2b21aa79..306303589797 100644 --- a/src/config/sessions/session-accessor.entry-mutation.ts +++ b/src/config/sessions/session-accessor.entry-mutation.ts @@ -13,14 +13,16 @@ import { } from "./session-accessor.entry.js"; import { applySessionEntryLifecycleMutation } from "./session-accessor.lifecycle.js"; import { - appendSqliteTranscriptEvent, - forkSqliteSessionEntryFromParentTarget, - forkSqliteSessionTranscriptFromParent, + patchSqliteSessionEntry, recordSqliteInboundSessionMeta, updateSqliteSessionLastRoute, - patchSqliteSessionEntry, +} from "./session-accessor.sqlite-entry.js"; +import { + forkSqliteSessionEntryFromParentTarget, + forkSqliteSessionTranscriptFromParent, resolveSqliteSessionParentForkDecision, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-parent-session.js"; +import { appendSqliteTranscriptEvent } from "./session-accessor.sqlite-transcript-write.js"; import type { SessionAccessScope, SessionEntryUpdateOptions, diff --git a/src/config/sessions/session-accessor.entry.ts b/src/config/sessions/session-accessor.entry.ts index 07b03ad5c40a..ef9d4b63c8fb 100644 --- a/src/config/sessions/session-accessor.entry.ts +++ b/src/config/sessions/session-accessor.entry.ts @@ -10,16 +10,18 @@ import { resolveAgentMainSessionKey } from "./main-session.js"; import { resolveStorePath } from "./paths.js"; import { clearPluginOwnedSessionState } from "./plugin-host-cleanup.js"; import { - countSqliteSessionEntryRowsReadOnly as countSessionEntryRowsReadOnly, copySqliteSessionOwnedStateForCanonicalRepair as copySessionOwnedStateForCanonicalRepair, - ensureSqliteSessionEntrySync as ensureSessionEntrySyncRaw, - hasSqliteSessionEntriesByStatusReadOnly as hasSessionEntriesByStatusReadOnly, listSqliteSessionGenerationIdsForCanonicalRepair as listSessionGenerationIdsForCanonicalRepair, - listSqliteSessionChildEntriesReadOnly as listSessionChildEntriesReadOnly, - listSqliteSessionEntries, listSqliteSessionEntriesForCanonicalRepair as listSessionEntriesForCanonicalRepair, rehomeSqliteSessionDeliveryReferencesForCanonicalRepair as rehomeSessionDeliveryReferencesForCanonicalRepair, rehomeSqliteSessionDeliveryReferencesForCanonicalRepairBatch as rehomeSessionDeliveryReferencesForCanonicalRepairBatch, +} from "./session-accessor.sqlite-canonical-repair.js"; +import { + countSqliteSessionEntryRowsReadOnly as countSessionEntryRowsReadOnly, + ensureSqliteSessionEntrySync as ensureSessionEntrySync, + hasSqliteSessionEntriesByStatusReadOnly as hasSessionEntriesByStatusReadOnly, + listSqliteSessionChildEntriesReadOnly as listSessionChildEntriesReadOnly, + listSqliteSessionEntries, listSqliteSessionEntriesReadOnly as listSessionEntriesReadOnly, listSqliteSessionEntryKeysReadOnly as listSessionEntryKeysReadOnly, loadExactSqliteSessionEntry as loadExactSessionEntry, @@ -33,7 +35,7 @@ import { replaceSqliteSessionEntrySync as replaceSessionEntrySync, resolveSqliteSessionEntry, upsertSqliteSessionEntry as upsertSessionEntry, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-entry.js"; import type { SessionAccessScope, LogicalSessionAccessScope, @@ -54,19 +56,15 @@ import { canonicalSessionKeyMigrationRequiredError } from "./session-canonical-k import { resolveSessionStorePathForScope } from "./session-store-path.js"; import { normalizeStoreSessionKey, resolveSessionStoreEntry } from "./store-entry.js"; import { resolveAllAgentSessionStoreTargetsSync, type SessionStoreTarget } from "./targets.js"; -import { - SessionTranscriptWriterClaimReboundError, - withOwnedSessionTranscriptWriterFence, -} from "./transcript-write-context.js"; import type { SessionEntry } from "./types.js"; export { clearPluginOwnedSessionState }; -// SQLite is the only runtime session store. Re-export its canonical entry -// operations directly except the sync initializer fenced below. +// SQLite is the only runtime session store. Re-export its canonical entry operations directly. export { countSessionEntryRowsReadOnly, copySessionOwnedStateForCanonicalRepair, + ensureSessionEntrySync, hasSessionEntriesByStatusReadOnly, listSessionGenerationIdsForCanonicalRepair, listSessionChildEntriesReadOnly, @@ -87,15 +85,6 @@ export { upsertSessionEntry, }; -export const ensureSessionEntrySync: typeof ensureSessionEntrySyncRaw = (scope, entry) => { - const fencedScope = withOwnedSessionTranscriptWriterFence(scope); - const ensured = ensureSessionEntrySyncRaw(fencedScope, entry); - if (fencedScope.expectedWriterRunId !== undefined && !ensured) { - throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); - } - return ensured; -}; - /** Keeps legacy store-key alias resolution behind the entry owner boundary. */ export function resolveSessionEntryFromStore(params: { store: Record; diff --git a/src/config/sessions/session-accessor.lifecycle.ts b/src/config/sessions/session-accessor.lifecycle.ts index eadbe2b9d2f7..0f8480be575c 100644 --- a/src/config/sessions/session-accessor.lifecycle.ts +++ b/src/config/sessions/session-accessor.lifecycle.ts @@ -16,18 +16,20 @@ import { replaceSessionEntry, patchSessionEntry, } from "./session-accessor.entry.js"; +import { applySqliteSessionEntryBatchProjection as applySessionEntryBatchProjection } from "./session-accessor.sqlite-batch-projection.js"; import { - applySqliteSessionEntryBatchProjection as applySessionEntryBatchProjection, - applySqliteSessionEntryLifecycleMutation as applySessionEntryLifecycleMutation, - applySqliteSessionEntryReplacements as applySessionEntryReplacements, - applySqliteSessionStoreProjection as applySessionStoreProjection, cleanupSqliteSessionLifecycleArtifacts as cleanupSessionLifecycleArtifacts, deleteSqliteSessionEntryLifecycle as deleteSessionEntryLifecycle, - purgeSqliteDeletedAgentSessionEntries as purgeDeletedAgentSessionEntries, rollbackSqliteAgentHarnessSessionEntryLifecycle as rollbackAgentHarnessSessionEntryLifecycle, rollbackSqlitePluginOwnedSessionEntryLifecycle as rollbackPluginOwnedSessionEntryLifecycle, resetSqliteSessionEntryLifecycle as resetSessionEntryLifecycle, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-lifecycle.js"; +import { + applySqliteSessionEntryLifecycleMutation as applySessionEntryLifecycleMutation, + applySqliteSessionEntryReplacements as applySessionEntryReplacements, + applySqliteSessionStoreProjection as applySessionStoreProjection, + purgeSqliteDeletedAgentSessionEntries as purgeDeletedAgentSessionEntries, +} from "./session-accessor.sqlite-projection.js"; import type { SessionAccessScope, SessionCompactionCheckpointMutationResult, diff --git a/src/config/sessions/session-accessor.message-cut.ts b/src/config/sessions/session-accessor.message-cut.ts index 996c733f4da3..44c93a94a392 100644 --- a/src/config/sessions/session-accessor.message-cut.ts +++ b/src/config/sessions/session-accessor.message-cut.ts @@ -4,7 +4,7 @@ import { resolveSessionTranscriptActiveLeafEntryId as resolveSqliteSessionTranscriptActiveLeafEntryId, rewindSqliteSessionToMessage, switchSqliteSessionBranch, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-message-cut.js"; import type { TranscriptEvent } from "./session-accessor.types.js"; import type { SessionBranchListParams, diff --git a/src/config/sessions/session-accessor.reply-init-concurrency.test.ts b/src/config/sessions/session-accessor.reply-init-concurrency.test.ts index 9f186c6d8d21..1771c7e25fd1 100644 --- a/src/config/sessions/session-accessor.reply-init-concurrency.test.ts +++ b/src/config/sessions/session-accessor.reply-init-concurrency.test.ts @@ -14,7 +14,7 @@ import { upsertSessionEntry, withTranscriptWriteLock, } from "./session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite-transcript-write.js"; vi.mock("../config.js", async () => ({ ...(await vi.importActual("../config.js")), diff --git a/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts b/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts index 25ba39dd740c..efc8b7c51e41 100644 --- a/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts +++ b/src/config/sessions/session-accessor.sqlite-archive.worker.test.ts @@ -29,7 +29,7 @@ import { planSqliteSessionStateDeleteIfUnreferenced, } from "./session-accessor.sqlite-lifecycle-state.js"; import { touchTranscriptMutationInTransaction } from "./session-accessor.sqlite-transcript-state.js"; -import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite-transcript-write.js"; import { resolveSqliteTargetFromSessionStorePath } from "./session-sqlite-target.js"; type TestTranscriptEvent = { diff --git a/src/config/sessions/session-accessor.sqlite-cleanup-race.test.ts b/src/config/sessions/session-accessor.sqlite-cleanup-race.test.ts index 44f2fde10e25..664a5141247f 100644 --- a/src/config/sessions/session-accessor.sqlite-cleanup-race.test.ts +++ b/src/config/sessions/session-accessor.sqlite-cleanup-race.test.ts @@ -14,7 +14,7 @@ import { replaceSessionEntry, } from "./session-accessor.js"; import { planSqliteSessionLifecycleArtifactCleanup } from "./session-accessor.sqlite-lifecycle-state.js"; -import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "./session-accessor.sqlite-transcript-write.js"; import { resolveSqliteTargetFromSessionStorePath } from "./session-sqlite-target.js"; import type { SessionEntry } from "./types.js"; diff --git a/src/config/sessions/session-accessor.sqlite-entry.ts b/src/config/sessions/session-accessor.sqlite-entry.ts index 944c3b68d9e8..4786fe7c4b66 100644 --- a/src/config/sessions/session-accessor.sqlite-entry.ts +++ b/src/config/sessions/session-accessor.sqlite-entry.ts @@ -76,6 +76,10 @@ import { buildSessionCreationStamp } from "./session-entry-provenance.js"; import { kickSessionHistoryDiskBudgetMaintenance } from "./session-history-eviction.js"; import { resolveSessionStorePathForScope } from "./session-store-path.js"; import { resolveDeliveryProvenCanonicalSessionKey } from "./store-entry.js"; +import { + SessionTranscriptWriterClaimReboundError, + withOwnedSessionTranscriptWriterFence, +} from "./transcript-write-context.js"; import type { GroupKeyResolution, SessionEntry } from "./types.js"; import { mergeSessionEntry, mergeSessionEntryPreserveActivity } from "./types.js"; @@ -455,7 +459,9 @@ export function ensureSqliteSessionEntrySync( Pick, entry: SessionEntry, ): boolean { - const resolved = resolveSqliteScope(scope); + // Every sync initializer inherits and enforces the admitted writer claim. + const fencedScope = withOwnedSessionTranscriptWriterFence(scope); + const resolved = resolveSqliteScope(fencedScope); assertCanonicalSessionWriteScope(resolved); let owned = false; let previous = new Map(); @@ -472,7 +478,7 @@ export function ensureSqliteSessionEntrySync( current = previous; return; } - if (scope.expectedWriterRunId !== undefined) { + if (fencedScope.expectedWriterRunId !== undefined) { current = previous; return; } @@ -483,6 +489,9 @@ export function ensureSqliteSessionEntrySync( if (current.size !== previous.size || owned) { emitCommittedSessionIdentityDiff(previous, current); } + if (fencedScope.expectedWriterRunId !== undefined && !owned) { + throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); + } return owned; } diff --git a/src/config/sessions/session-accessor.sqlite-message-cut.test.ts b/src/config/sessions/session-accessor.sqlite-message-cut.test.ts index 234741543797..2aee1d566926 100644 --- a/src/config/sessions/session-accessor.sqlite-message-cut.test.ts +++ b/src/config/sessions/session-accessor.sqlite-message-cut.test.ts @@ -24,7 +24,7 @@ import { updateSessionEntry, upsertSessionEntry, } from "./session-accessor.js"; -import { listSqliteSessionBranches } from "./session-accessor.sqlite.js"; +import { listSqliteSessionBranches } from "./session-accessor.sqlite-message-cut.js"; import type { InternalSessionEntry } from "./types.js"; const tempDirs = useAutoCleanupTempDirTracker(afterEach); diff --git a/src/config/sessions/session-accessor.sqlite-transcript-write.ts b/src/config/sessions/session-accessor.sqlite-transcript-write.ts index da799b335be1..b87f71cf2dba 100644 --- a/src/config/sessions/session-accessor.sqlite-transcript-write.ts +++ b/src/config/sessions/session-accessor.sqlite-transcript-write.ts @@ -64,6 +64,10 @@ import { } from "./session-transcript-turn-state.js"; import type { TranscriptEntryAnchor } from "./transcript-entry-anchor.js"; import { serializeJsonlLines } from "./transcript-jsonl.js"; +import { + SessionTranscriptWriterClaimReboundError, + withOwnedSessionTranscriptWriterFence, +} from "./transcript-write-context.js"; import type { InternalSessionEntry, SessionEntry } from "./types.js"; import { mergeSessionEntry } from "./types.js"; @@ -156,23 +160,28 @@ export function replaceSqliteTranscriptEventsSync( scope: SessionTranscriptWriteScope, events: TranscriptEvent[], ): boolean { - const resolved = resolveSqliteTranscriptScope(scope); + // Every sync replacement inherits and enforces the admitted writer claim. + const fencedScope = withOwnedSessionTranscriptWriterFence(scope); + const resolved = resolveSqliteTranscriptScope(fencedScope); let replaced = false; runOpenClawAgentWriteTransaction((database) => { const fresh = readSessionEntryRow(database, resolved.sessionKey); if ( !fresh || fresh.entry.sessionId !== resolved.sessionId || - (scope.expectedLifecycleRevision !== undefined && - fresh.entry.lifecycleRevision !== scope.expectedLifecycleRevision) || - (scope.expectedWriterRunId !== undefined && - (fresh.entry as InternalSessionEntry).activeWriterRunId !== scope.expectedWriterRunId) + (fencedScope.expectedLifecycleRevision !== undefined && + fresh.entry.lifecycleRevision !== fencedScope.expectedLifecycleRevision) || + (fencedScope.expectedWriterRunId !== undefined && + (fresh.entry as InternalSessionEntry).activeWriterRunId !== fencedScope.expectedWriterRunId) ) { return; } replaceSqliteTranscriptEventsInTransaction(database, resolved, events); replaced = true; }, toDatabaseOptions(resolved)); + if (fencedScope.expectedWriterRunId !== undefined && !replaced) { + throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); + } return replaced; } @@ -276,7 +285,9 @@ export function appendSqliteTranscriptEventSync( options: TranscriptEventAppendOptions = {}, ): Result { assertNonMessageTranscriptEvent(event); - const resolved = resolveSqliteTranscriptScope(scope); + // Every sync event append inherits and enforces the admitted writer claim. + const fencedScope = withOwnedSessionTranscriptWriterFence(scope); + const resolved = resolveSqliteTranscriptScope(fencedScope); let result: Result = ok(false); runOpenClawAgentWriteTransaction((database) => { const fresh = readSessionEntryRow(database, resolved.sessionKey); @@ -298,10 +309,10 @@ export function appendSqliteTranscriptEventSync( return; } if ( - (scope.expectedLifecycleRevision !== undefined && - fresh.entry.lifecycleRevision !== scope.expectedLifecycleRevision) || - (scope.expectedWriterRunId !== undefined && - (fresh.entry as InternalSessionEntry).activeWriterRunId !== scope.expectedWriterRunId) + (fencedScope.expectedLifecycleRevision !== undefined && + fresh.entry.lifecycleRevision !== fencedScope.expectedLifecycleRevision) || + (fencedScope.expectedWriterRunId !== undefined && + (fresh.entry as InternalSessionEntry).activeWriterRunId !== fencedScope.expectedWriterRunId) ) { result = err({ actualSessionId: fresh.entry.sessionId, @@ -319,6 +330,9 @@ export function appendSqliteTranscriptEventSync( ), ); }, toDatabaseOptions(resolved)); + if (fencedScope.expectedWriterRunId !== undefined && !result.ok) { + throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); + } return result; } @@ -512,22 +526,27 @@ export function appendSqliteTranscriptMessageSync( scope: SessionTranscriptWriteScope, options: TranscriptMessageAppendOptions, ): TranscriptMessageAppendResult | undefined { - const resolved = resolveSqliteTranscriptScope(scope); + // Every sync message append inherits and enforces the admitted writer claim. + const fencedScope = withOwnedSessionTranscriptWriterFence(scope); + const resolved = resolveSqliteTranscriptScope(fencedScope); let result: TranscriptMessageAppendResult | undefined; runOpenClawAgentWriteTransaction((database) => { const fresh = readSessionEntryRow(database, resolved.sessionKey); if ( !fresh || fresh.entry.sessionId !== resolved.sessionId || - (scope.expectedLifecycleRevision !== undefined && - fresh.entry.lifecycleRevision !== scope.expectedLifecycleRevision) || - (scope.expectedWriterRunId !== undefined && - (fresh.entry as InternalSessionEntry).activeWriterRunId !== scope.expectedWriterRunId) + (fencedScope.expectedLifecycleRevision !== undefined && + fresh.entry.lifecycleRevision !== fencedScope.expectedLifecycleRevision) || + (fencedScope.expectedWriterRunId !== undefined && + (fresh.entry as InternalSessionEntry).activeWriterRunId !== fencedScope.expectedWriterRunId) ) { return; } result = appendSqliteTranscriptMessageInTransaction(database, resolved, options); }, toDatabaseOptions(resolved)); + if (fencedScope.expectedWriterRunId !== undefined && result === undefined) { + throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); + } return result; } diff --git a/src/config/sessions/session-accessor.sqlite.ts b/src/config/sessions/session-accessor.sqlite.ts deleted file mode 100644 index 0ce0d0be7ad8..000000000000 --- a/src/config/sessions/session-accessor.sqlite.ts +++ /dev/null @@ -1,90 +0,0 @@ -// Stable SQLite accessor surface. Domain owners live in the focused modules below. -export { - countSqliteSessionEntryRowsReadOnly, - ensureSqliteSessionEntrySync, - hasSqliteSessionEntriesByStatusReadOnly, - listSqliteSessionEntries, - listSqliteSessionChildEntriesReadOnly, - listSqliteSessionEntriesReadOnly, - listSqliteSessionEntryKeysReadOnly, - listSqliteSessionEntriesByStatus, - listSqliteSessionTranscriptInstances, - loadExactSqliteSessionEntry, - loadExactSqliteSessionEntryReadOnly, - loadSqliteSessionEntry, - loadSqliteSessionEntryReadOnly, - patchSqliteSessionEntry, - patchSqliteSessionEntryTarget, - readSqliteSessionUpdatedAt, - recordSqliteInboundSessionMeta, - replaceSqliteSessionEntry, - replaceSqliteSessionEntrySync, - resolveSqliteSessionEntry, - resolveSqliteSessionKeyBySessionId, - updateSqliteSessionLastRoute, - upsertSqliteSessionEntry, -} from "./session-accessor.sqlite-entry.js"; -export { - copySqliteSessionOwnedStateForCanonicalRepair, - listSqliteSessionEntriesForCanonicalRepair, - listSqliteSessionGenerationIdsForCanonicalRepair, - rehomeSqliteSessionDeliveryReferencesForCanonicalRepair, - rehomeSqliteSessionDeliveryReferencesForCanonicalRepairBatch, -} from "./session-accessor.sqlite-canonical-repair.js"; -export { - cleanupSqliteSessionLifecycleArtifacts, - deleteSqliteSessionEntryLifecycle, - resetSqliteSessionEntryLifecycle, - rollbackSqliteAgentHarnessSessionEntryLifecycle, - rollbackSqlitePluginOwnedSessionEntryLifecycle, -} from "./session-accessor.sqlite-lifecycle.js"; -export { - applySqliteSessionEntryLifecycleMutation, - applySqliteSessionEntryReplacements, - applySqliteSessionStoreProjection, - purgeSqliteDeletedAgentSessionEntries, -} from "./session-accessor.sqlite-projection.js"; -export { applySqliteSessionEntryBatchProjection } from "./session-accessor.sqlite-batch-projection.js"; -export { - forkSqliteSessionEntryFromParentTarget, - forkSqliteSessionTranscriptFromParent, - resolveSqliteSessionParentForkDecision, -} from "./session-accessor.sqlite-parent-session.js"; -export { - branchSqliteCompactionCheckpointSession, - restoreSqliteCompactionCheckpointSession, -} from "./session-accessor.sqlite-checkpoint.js"; -export { - forkSqliteSessionAtMessage, - listSqliteSessionBranches, - resolveSessionTranscriptActiveLeafEntryId, - rewindSqliteSessionToMessage, - switchSqliteSessionBranch, -} from "./session-accessor.sqlite-message-cut.js"; -export { - appendSqliteExpectedSessionTranscriptTurn, - appendSqliteTranscriptEvent, - appendSqliteTranscriptEventSync, - appendSqliteTranscriptMessage, - appendSqliteTranscriptMessageSync, - replaceSqliteTranscriptEvents, - replaceSqliteTranscriptEventsSync, - rewriteSqliteTranscriptEventRowsExact, - trimSqliteTranscriptForManualCompact, - withSqliteTranscriptWriteLock, - withSqliteTranscriptWriteTransaction, -} from "./session-accessor.sqlite-transcript-write.js"; -export { importSqliteSessionRows } from "./session-accessor.sqlite-import.js"; -export { publishSqliteTranscriptUpdate } from "./session-accessor.sqlite-events.js"; -export { readSqliteTranscriptRawDelta } from "./session-accessor.sqlite-delta.js"; -export { - findSqliteTranscriptEvent, - loadLatestSqliteAssistantText, - loadSqliteTranscriptEventRowsAfterSeqSync, - loadSqliteTranscriptEvents, - loadSqliteTranscriptEventsSync, - loadSqliteTranscriptHeaderSync, - loadSqliteTranscriptTailEventsSync, - readSqliteTranscriptEventAtSeqSync, - readSqliteTranscriptStatsSync, -} from "./session-accessor.sqlite-read.js"; diff --git a/src/config/sessions/session-accessor.test.ts b/src/config/sessions/session-accessor.test.ts index b28226d7e93c..7f254637e1b8 100644 --- a/src/config/sessions/session-accessor.test.ts +++ b/src/config/sessions/session-accessor.test.ts @@ -76,17 +76,19 @@ import { readSqliteSessionEntryCount, readSqliteSessionEntryKeys, } from "./session-accessor.sqlite-entry-store.js"; -import { applySqliteSessionEntryCanonicalReplacements } from "./session-accessor.sqlite-replacement-projection.js"; import { - applySqliteSessionEntryLifecycleMutation, - appendSqliteTranscriptEventSync, - deleteSqliteSessionEntryLifecycle, - importSqliteSessionRows, loadExactSqliteSessionEntry, replaceSqliteSessionEntrySync, +} from "./session-accessor.sqlite-entry.js"; +import { importSqliteSessionRows } from "./session-accessor.sqlite-import.js"; +import { deleteSqliteSessionEntryLifecycle } from "./session-accessor.sqlite-lifecycle.js"; +import { applySqliteSessionEntryLifecycleMutation } from "./session-accessor.sqlite-projection.js"; +import { applySqliteSessionEntryCanonicalReplacements } from "./session-accessor.sqlite-replacement-projection.js"; +import { + appendSqliteTranscriptEventSync, replaceSqliteTranscriptEvents, trimSqliteTranscriptForManualCompact, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-transcript-write.js"; import { resolveSqliteTargetFromSessionStorePath } from "./session-sqlite-target.js"; import { SessionTranscriptWriterClaimReboundError, diff --git a/src/config/sessions/session-accessor.transcript-turn.ts b/src/config/sessions/session-accessor.transcript-turn.ts index e079b57b4708..95feda2098c4 100644 --- a/src/config/sessions/session-accessor.transcript-turn.ts +++ b/src/config/sessions/session-accessor.transcript-turn.ts @@ -14,7 +14,7 @@ import { rememberCommittedSqliteTranscriptMessageSequences, } from "./session-accessor.sqlite-transcript-sequences.js"; import { redactTranscriptMessageForStorage } from "./session-accessor.sqlite-transcript-store.js"; -import { appendSqliteExpectedSessionTranscriptTurn } from "./session-accessor.sqlite.js"; +import { appendSqliteExpectedSessionTranscriptTurn } from "./session-accessor.sqlite-transcript-write.js"; import { appendTranscriptMessage, emitTranscriptUpdate } from "./session-accessor.transcript.js"; import type { SessionTranscriptWriteScope, diff --git a/src/config/sessions/session-accessor.transcript.ts b/src/config/sessions/session-accessor.transcript.ts index afead50c8351..f809eeab08f7 100644 --- a/src/config/sessions/session-accessor.transcript.ts +++ b/src/config/sessions/session-accessor.transcript.ts @@ -1,9 +1,8 @@ import { emitSessionTranscriptUpdate } from "../../sessions/transcript-events.js"; +import { readSqliteTranscriptRawDelta as readTranscriptRawDelta } from "./session-accessor.sqlite-delta.js"; +import { resolveSqliteSessionKeyBySessionId as resolveTranscriptSessionKeyBySessionId } from "./session-accessor.sqlite-entry.js"; +import { publishSqliteTranscriptUpdate as publishTranscriptUpdate } from "./session-accessor.sqlite-events.js"; import { - appendSqliteTranscriptEvent as appendTranscriptEvent, - appendSqliteTranscriptEventSync, - appendSqliteTranscriptMessage as appendTranscriptMessage, - appendSqliteTranscriptMessageSync, findSqliteTranscriptEvent, loadLatestSqliteAssistantText as readLatestTranscriptAssistantText, loadSqliteTranscriptEventRowsAfterSeqSync as loadTranscriptEventRowsAfterSeqSync, @@ -13,16 +12,19 @@ import { loadSqliteTranscriptTailEventsSync as loadTranscriptTailEventsSync, readSqliteTranscriptStatsSync as readTranscriptStatsSync, readSqliteTranscriptEventAtSeqSync as readTranscriptEventAtSeqSync, - readSqliteTranscriptRawDelta as readTranscriptRawDelta, - publishSqliteTranscriptUpdate as publishTranscriptUpdate, +} from "./session-accessor.sqlite-read.js"; +import { + appendSqliteTranscriptEvent as appendTranscriptEvent, + appendSqliteTranscriptEventSync as appendTranscriptEventSync, + appendSqliteTranscriptMessage as appendTranscriptMessage, + appendSqliteTranscriptMessageSync as appendTranscriptMessageSync, replaceSqliteTranscriptEvents as replaceTranscriptEvents, - replaceSqliteTranscriptEventsSync, + replaceSqliteTranscriptEventsSync as replaceTranscriptEventsSync, rewriteSqliteTranscriptEventRowsExact as rewriteTranscriptEventRowsExact, - resolveSqliteSessionKeyBySessionId as resolveTranscriptSessionKeyBySessionId, trimSqliteTranscriptForManualCompact, withSqliteTranscriptWriteLock as withTranscriptWriteLock, withSqliteTranscriptWriteTransaction as withTranscriptWriteTransaction, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-transcript-write.js"; import type { SessionTranscriptRuntimeScope, SessionTranscriptReadScope, @@ -34,16 +36,13 @@ import { scanSessionTranscriptTree, selectSessionTranscriptTreePathNodes, } from "./transcript-tree.js"; -import { - SessionTranscriptWriterClaimReboundError, - withOwnedSessionTranscriptWriterFence, -} from "./transcript-write-context.js"; -// Persisted transcripts have one SQLite owner. Async operations keep direct -// exports; sync runtime writes use the ownership-fenced wrappers below. +// Persisted transcripts have one SQLite owner. Re-export its canonical operations directly. export { appendTranscriptEvent, + appendTranscriptEventSync, appendTranscriptMessage, + appendTranscriptMessageSync, loadTranscriptEventRowsAfterSeqSync, loadTranscriptEvents, loadTranscriptEventsSync, @@ -55,49 +54,13 @@ export { readTranscriptRawDelta, readTranscriptStatsSync, replaceTranscriptEvents, + replaceTranscriptEventsSync, rewriteTranscriptEventRowsExact, resolveTranscriptSessionKeyBySessionId, withTranscriptWriteLock, withTranscriptWriteTransaction, }; -export const appendTranscriptEventSync: typeof appendSqliteTranscriptEventSync = ( - scope, - event, - options, -) => { - const fencedScope = withOwnedSessionTranscriptWriterFence(scope); - const result = appendSqliteTranscriptEventSync(fencedScope, event, options); - if (fencedScope.expectedWriterRunId !== undefined && !result.ok) { - throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); - } - return result; -}; - -export const appendTranscriptMessageSync: typeof appendSqliteTranscriptMessageSync = ( - scope, - options, -) => { - const fencedScope = withOwnedSessionTranscriptWriterFence(scope); - const result = appendSqliteTranscriptMessageSync(fencedScope, options); - if (fencedScope.expectedWriterRunId !== undefined && result === undefined) { - throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); - } - return result; -}; - -export const replaceTranscriptEventsSync: typeof replaceSqliteTranscriptEventsSync = ( - scope, - events, -) => { - const fencedScope = withOwnedSessionTranscriptWriterFence(scope); - const replaced = replaceSqliteTranscriptEventsSync(fencedScope, events); - if (fencedScope.expectedWriterRunId !== undefined && !replaced) { - throw new SessionTranscriptWriterClaimReboundError(scope.sessionKey); - } - return replaced; -}; - /** Keeps transcript event delivery behind the transcript owner boundary. */ export function emitTranscriptUpdate( update: Parameters[0], diff --git a/src/config/sessions/session-history.ts b/src/config/sessions/session-history.ts index 610ac68fd89f..aa6f10e52ea2 100644 --- a/src/config/sessions/session-history.ts +++ b/src/config/sessions/session-history.ts @@ -6,7 +6,7 @@ import type { import { listSqliteSessionEntriesByStatus, listSqliteSessionTranscriptInstances, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-entry.js"; import type { SessionEntry } from "./types.js"; type SessionEntryListScope = Partial>; diff --git a/src/config/sessions/session-transcript-search.test.ts b/src/config/sessions/session-transcript-search.test.ts index 14f161410eee..105b930f2afe 100644 --- a/src/config/sessions/session-transcript-search.test.ts +++ b/src/config/sessions/session-transcript-search.test.ts @@ -15,7 +15,7 @@ import { appendSqliteTranscriptEvent, appendSqliteTranscriptMessage, replaceSqliteTranscriptEvents, -} from "./session-accessor.sqlite.js"; +} from "./session-accessor.sqlite-transcript-write.js"; import { listSessionsNeedingTranscriptIndexReconcile } from "./session-transcript-index.js"; import { searchSessionTranscripts } from "./session-transcript-search.js"; diff --git a/src/gateway/managed-image-attachments.ts b/src/gateway/managed-image-attachments.ts index a631656e4a9e..36e1c3204d2a 100644 --- a/src/gateway/managed-image-attachments.ts +++ b/src/gateway/managed-image-attachments.ts @@ -16,7 +16,7 @@ import type { ReplyMediaAttachment } from "../auto-reply/reply-payload.js"; import { getRuntimeConfig } from "../config/config.js"; import { resolveStateDir } from "../config/paths.js"; import { loadExactSessionEntryReadOnlyResult } from "../config/sessions/session-accessor.sqlite-entry-availability.js"; -import { resolveSqliteSessionEntry } from "../config/sessions/session-accessor.sqlite.js"; +import { resolveSqliteSessionEntry } from "../config/sessions/session-accessor.sqlite-entry.js"; import { resolveExistingAgentSessionStoreTargetsReadOnlyResult, type SessionStoreTargetsReadCache, diff --git a/src/gateway/server-methods/sessions-rewind.ts b/src/gateway/server-methods/sessions-rewind.ts index 274061bf85e8..cf7c79450016 100644 --- a/src/gateway/server-methods/sessions-rewind.ts +++ b/src/gateway/server-methods/sessions-rewind.ts @@ -20,7 +20,7 @@ import { forkSqliteSessionAtMessage as forkSessionAtMessage, rewindSqliteSessionToMessage as rewindSessionToMessage, switchSqliteSessionBranch as switchSessionBranch, -} from "../../config/sessions/session-accessor.sqlite.js"; +} from "../../config/sessions/session-accessor.sqlite-message-cut.js"; import { MEDIA_MAX_BYTES, readMediaBuffer } from "../../media/store.js"; import { isCompetingSessionWorkAdmissionActive, diff --git a/src/gateway/server.chat.gateway-server-chat.test.ts b/src/gateway/server.chat.gateway-server-chat.test.ts index 29d6d5343591..5c06b7c05255 100644 --- a/src/gateway/server.chat.gateway-server-chat.test.ts +++ b/src/gateway/server.chat.gateway-server-chat.test.ts @@ -7,7 +7,7 @@ import { beforeEach, describe, expect, test, vi } from "vitest"; import { WebSocket } from "ws"; import { createDeferred } from "../../test/helpers/promise.js"; import { loadSessionEntry } from "../config/sessions/session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "../config/sessions/session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "../config/sessions/session-accessor.sqlite-transcript-write.js"; import { emitAgentEvent } from "../infra/agent-events.js"; import { registerAgentRunContext } from "../infra/agent-run-registry.js"; import { diff --git a/src/gateway/server.sessions.delete-lifecycle.test.ts b/src/gateway/server.sessions.delete-lifecycle.test.ts index d2fc4f85bfd9..bca74a4dd62d 100644 --- a/src/gateway/server.sessions.delete-lifecycle.test.ts +++ b/src/gateway/server.sessions.delete-lifecycle.test.ts @@ -16,7 +16,7 @@ import { loadTranscriptEvents, replaceSessionEntry, } from "../config/sessions/session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "../config/sessions/session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "../config/sessions/session-accessor.sqlite-transcript-write.js"; import { beginSessionWorkAdmission, runExclusiveSessionLifecycleMutation, diff --git a/src/gateway/session-compaction-checkpoints.ts b/src/gateway/session-compaction-checkpoints.ts index 3bae86a446ad..240335fdfa7a 100644 --- a/src/gateway/session-compaction-checkpoints.ts +++ b/src/gateway/session-compaction-checkpoints.ts @@ -26,7 +26,7 @@ import { import { branchSqliteCompactionCheckpointSession, restoreSqliteCompactionCheckpointSession, -} from "../config/sessions/session-accessor.sqlite.js"; +} from "../config/sessions/session-accessor.sqlite-checkpoint.js"; import type { SessionTranscriptRuntimeTarget } from "../config/sessions/session-accessor.types.js"; import { streamSessionTranscriptLines } from "../config/sessions/transcript-stream.js"; import { scanSessionTranscriptTree } from "../config/sessions/transcript-tree.js"; diff --git a/test/helpers/sqlite-sessions-transcripts-flip-proof.ts b/test/helpers/sqlite-sessions-transcripts-flip-proof.ts index c48a09dcb8da..5f4f5136d122 100644 --- a/test/helpers/sqlite-sessions-transcripts-flip-proof.ts +++ b/test/helpers/sqlite-sessions-transcripts-flip-proof.ts @@ -19,7 +19,7 @@ import { appendTranscriptMessage, type TranscriptEvent, } from "../../src/config/sessions/session-accessor.js"; -import { importSqliteSessionRows } from "../../src/config/sessions/session-accessor.sqlite.js"; +import { importSqliteSessionRows } from "../../src/config/sessions/session-accessor.sqlite-import.js"; import type { SessionEntry } from "../../src/config/sessions/types.js"; import { connectGatewayClient, diff --git a/test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts b/test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts index 6da4c0ca6673..f4e918ac9460 100644 --- a/test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts +++ b/test/scripts/sqlite-sessions-transcripts-flip-proof.built-cli.e2e.test.ts @@ -11,7 +11,7 @@ import { loadTranscriptEvents, replaceSessionEntry, } from "../../src/config/sessions/session-accessor.js"; -import { replaceSqliteTranscriptEvents } from "../../src/config/sessions/session-accessor.sqlite.js"; +import { replaceSqliteTranscriptEvents } from "../../src/config/sessions/session-accessor.sqlite-transcript-write.js"; import { resolveSqliteTargetFromSessionStorePath } from "../../src/config/sessions/session-sqlite-target.js"; import { connectGatewayClient,