@myagentroam/agent 0.9.61 → 0.9.64
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/LICENSE +202 -0
- package/NOTICE +4 -0
- package/dist/cli/codex-auth-file.js +268 -3
- package/dist/cli/main.js +427 -2
- package/dist/error.js +66 -2
- package/dist/host/contracts.js +20 -2
- package/dist/host/local-agent-host.js +146 -2
- package/dist/host/local-process-executor.js +39 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +12 -2
- package/dist/model/anthropic-messages.js +474 -2
- package/dist/model/anthropic-thinking.js +33 -2
- package/dist/model/catalog-file.js +88 -2
- package/dist/model/configuration.js +137 -2
- package/dist/model/contracts.d.ts +2 -0
- package/dist/model/contracts.js +1 -2
- package/dist/model/http.js +529 -2
- package/dist/model/openai-responses.d.ts +2 -0
- package/dist/model/openai-responses.js +1602 -2
- package/dist/model/runtime-credential.js +35 -2
- package/dist/model/sse.js +199 -2
- package/dist/prompts/compact.js +25 -2
- package/dist/prompts/core.js +37 -2
- package/dist/prompts/execution-budget.js +10 -2
- package/dist/prompts/index.d.ts +3 -2
- package/dist/prompts/index.js +47 -2
- package/dist/prompts/modes.js +25 -2
- package/dist/prompts/output.js +1 -2
- package/dist/prompts/resources.d.ts +1 -1
- package/dist/prompts/resources.js +31 -2
- package/dist/prompts/subagent.d.ts +6 -0
- package/dist/prompts/subagent.js +29 -2
- package/dist/prompts/title.js +9 -2
- package/dist/prompts/workflow.js +32 -2
- package/dist/runtime/async-queue.js +62 -2
- package/dist/runtime/builtin-skills.js +19 -2
- package/dist/runtime/byted-ark-imagegen-skill.js +18 -2
- package/dist/runtime/codex-imagegen-skill.js +35 -2
- package/dist/runtime/compact.js +225 -2
- package/dist/runtime/context-gc-runtime.d.ts +35 -0
- package/dist/runtime/context-gc-runtime.js +163 -0
- package/dist/runtime/context-gc-tokens.d.ts +24 -0
- package/dist/runtime/context-gc-tokens.js +83 -0
- package/dist/runtime/context-gc.d.ts +66 -0
- package/dist/runtime/context-gc.js +909 -0
- package/dist/runtime/context-projection.d.ts +23 -0
- package/dist/runtime/context-projection.js +203 -0
- package/dist/runtime/environment-context.js +41 -2
- package/dist/runtime/execution-policy.js +13 -2
- package/dist/runtime/instructions.js +298 -2
- package/dist/runtime/normalize.js +40 -2
- package/dist/runtime/plan-output.js +95 -2
- package/dist/runtime/rollout-budget.d.ts +2 -0
- package/dist/runtime/rollout-budget.js +92 -2
- package/dist/runtime/token-budget.d.ts +2 -0
- package/dist/runtime/token-budget.js +44 -2
- package/dist/sdk/agent.js +1804 -2
- package/dist/sdk/types.d.ts +15 -5
- package/dist/sdk/types.js +1 -2
- package/dist/session/catalog.d.ts +5 -4
- package/dist/session/catalog.js +133 -2
- package/dist/session/context-gc-checkpoint.d.ts +148 -0
- package/dist/session/context-gc-checkpoint.js +665 -0
- package/dist/session/context-gc-replacements.d.ts +52 -0
- package/dist/session/context-gc-replacements.js +226 -0
- package/dist/session/context-gc-subagent.d.ts +43 -0
- package/dist/session/context-gc-subagent.js +267 -0
- package/dist/session/jsonl-store.d.ts +42 -4
- package/dist/session/jsonl-store.js +1657 -2
- package/dist/subagent/scheduler.d.ts +35 -2
- package/dist/subagent/scheduler.js +249 -2
- package/dist/subagent/session-controller.d.ts +94 -0
- package/dist/subagent/session-controller.js +675 -0
- package/dist/tools/agent-cancel.js +28 -2
- package/dist/tools/{task.d.ts → agent-message.d.ts} +2 -2
- package/dist/tools/agent-message.js +51 -0
- package/dist/tools/agent-start.js +84 -2
- package/dist/tools/agent-wait.js +53 -2
- package/dist/tools/apply-patch.js +478 -2
- package/dist/tools/code-mode.js +370 -2
- package/dist/tools/codex-image-gen.js +312 -2
- package/dist/tools/exec.js +455 -2
- package/dist/tools/execution-limits.d.ts +1 -0
- package/dist/tools/execution-limits.js +44 -2
- package/dist/tools/local-registry.js +233 -2
- package/dist/tools/local-workspace-tools.js +28 -2
- package/dist/tools/question.js +124 -2
- package/dist/tools/read-context.d.ts +16 -0
- package/dist/tools/read-context.js +85 -0
- package/dist/tools/read.d.ts +13 -0
- package/dist/tools/read.js +294 -2
- package/dist/tools/registry.js +76 -2
- package/dist/tools/runtime-context.d.ts +9 -2
- package/dist/tools/runtime-context.js +1 -2
- package/dist/tools/runtime.js +21 -2
- package/dist/tools/scheduler.js +41 -2
- package/dist/tools/shared/path-resolver.js +133 -2
- package/dist/tools/skill.js +37 -2
- package/dist/tools/todo-read.js +10 -2
- package/dist/tools/todo-write.js +65 -2
- package/dist/tools/todo.js +67 -2
- package/dist/tools/view-image.js +81 -2
- package/dist/tools/web-fetch.js +11 -2
- package/dist/tools/web-search.js +14 -2
- package/package.json +17 -15
- package/README.md +0 -3
- package/dist/runtime/prompt.d.ts +0 -9
- package/dist/runtime/prompt.js +0 -2
- package/dist/tools/shared/secret-redaction.d.ts +0 -4
- package/dist/tools/shared/secret-redaction.js +0 -2
- package/dist/tools/task-cancel.d.ts +0 -7
- package/dist/tools/task-cancel.js +0 -2
- package/dist/tools/task-output.d.ts +0 -7
- package/dist/tools/task-output.js +0 -2
- package/dist/tools/task-tools.d.ts +0 -36
- package/dist/tools/task-tools.js +0 -2
- package/dist/tools/task.js +0 -2
- package/dist/tools/todo-tools.d.ts +0 -25
- package/dist/tools/todo-tools.js +0 -2
|
@@ -1,2 +1,1657 @@
|
|
|
1
|
-
|
|
2
|
-
const _0xc75581=_0x2082;(function(_0x48b931,_0x4685d0){const _0x3d9a40=_0x2082,_0x1ed38f=_0x48b931();while(!![]){try{const _0x1a192c=-parseInt(_0x3d9a40(0x22c))/(-0x22d7+-0x22e8+0x45c0)*(-parseInt(_0x3d9a40(0x18a))/(0x1590+-0xb3*0x1a+-0xc*0x48))+-parseInt(_0x3d9a40(0x22f))/(-0x1*-0xffd+0x1b41+0x2b3b*-0x1)*(-parseInt(_0x3d9a40(0x201))/(-0x10ae+0x2159+-0x58d*0x3))+-parseInt(_0x3d9a40(0x1e7))/(0x4*-0x3b4+-0x208+0x1*0x10dd)*(-parseInt(_0x3d9a40(0x1c2))/(0x119*-0x1f+-0x12*-0xc7+0x403*0x5))+parseInt(_0x3d9a40(0x1f5))/(-0x22d*-0x1+-0x1c*-0x6a+-0xdbe)+parseInt(_0x3d9a40(0x1a9))/(-0x459+-0x1f9+0x65a)+-parseInt(_0x3d9a40(0x1f7))/(0x25cc+-0x2159+-0x5*0xe2)+parseInt(_0x3d9a40(0x1ad))/(-0x1211+0x231e+-0xd*0x14f)*(-parseInt(_0x3d9a40(0x1f3))/(-0x9*-0x183+0x4b2*-0x4+0x538));if(_0x1a192c===_0x4685d0)break;else _0x1ed38f['push'](_0x1ed38f['shift']());}catch(_0x4015e8){_0x1ed38f['push'](_0x1ed38f['shift']());}}}(_0x3cb3,-0x778b6+-0x41577+0x10ccb4));import{createHash,randomUUID}from'node:crypto';import{constants}from'node:fs';import{copyFile,lstat,mkdir,open,readFile,readdir,rename,rm,stat,writeFile}from'node:fs/promises';function _0x3cb3(){const _0x2e3768=['CMvMzxjLBMnLCW','CMvHza','vg9Vig1HBNKGAw1Hz2uGAw5WDxrZihDLCMuGChjVDMLKzwqU','zMLUza','zMXVB3i','C2vZC2LVBNm','yNL0zxm','CMvHzev4zwn1DgLVBLn0yxrL','C3bSAxq','Aw1Hz2vjBMrLEa','AxnbCNjHEq','BxrPBwvnCW','Dg9VBc5JB21WBgv0zwq','Dg9szxzLCNnLza','zxzLCNK','A2LSBa','C2vZC2LVBKrPCMvJDg9YEq','Aw1Hz2u','CMvTB3zLsw5WDxrjBwfNzxm','zw5KC1DPDgG','t19ot0zpteXpvW','Dg9KBW','Aw1Hz2uVCg5N','zMLYC3rtzxf1zw5Jzq','rvnsq0G','C2vXDwvUy2u','CgfKu3rHCNq','B2jQzwn0','D3jPDgvgAwXL','DhvYBI51C2vY','CMvHzeLUChv0sw1Hz2u','DhjPBq','mtmYotbQCgXereW','Dg9KB1nLCxvLBMnL','u2vZC2LVBIbYzxn1BwuGAw5KzxGGAxmGAw52ywXPzc4','u2vZC2LVBIbPBNb1DcbPBwfNzsbPCYbJB3jYDxb0lG','Dg9KB1jLDMLZAw9U','CMvHzfbHz2u','C2vZC2LVBI5JCMvHDgvK','zMLUzeXHC3q','C3vTBwfYEq','D2LUmZi','C2HHmJu2','ywnXDwLYzvnLC3nPB25mzwfZzq','mJGZndGXz2HYDxrm','C3LUyW','mJq2ntu2ofLfEwrWvW','AM9PBG','ntK1mZyYnK9NBM5KuW','tufsx0fhru5ux1nfu1njt05Fq09suLvqva','CgLK','u2vZC2LVBIb0AxrSzsbPCYbYzxf1AxjLzc4','ywrK','zMLUzeLUzgv4','y29TCgfJDc5JB21WBgv0zwq','BgLTAxq','D29YA3nWywnL','DgLTzxn0yw1W','mtqXmKXuyuvOtW','BMfTzq','DMfSDwvZ','AgfZ','lNjVBgXIywnRlwjHy2T1Ca','sw1Hz2uGAw5WDxqGzxHJzwvKCYb0AguGC3vWCg9YDgvKihnPEMuGBgLTAxqU','y2XVC2vK','Dg9KBY51CgrHDgvK','yMfZzty0DxjS','sw1Hz2uGAw5WDxqGtuLnrsb0ExbLigLZihvUC3vWCg9YDgvKlG','Dg9ju09tDhjPBMC','yM9VBgvHBG','CMvJB3jKCW','u2vZC2LVBIbYB2XSyMfJAYb0yxjNzxqGD2fZig5VDcbMB3vUzc4','BgLUzxm','y2XVC2u','u2vZC2LVBIb3yxmGBM90igzVDw5KlG','DgL0Bgu','zMLSzxm','tufsx0fhru5ux1rpt0XFsu5qvvrFsu5wquXjra','C29Tzq','BNvTyMvY','AxngAwXL','Cgf5Bg9Hza','y29TCgfJDfnLCxvLBMnL','zM9YA1nLC3nPB24','D3jPDgu','DhjHC2G','y29TCgfJDa','CMvHzeLUChv0sw1Hz2vZ','lNrTCa','zMXHDe1HCa','zxzLBNrZlq','DxrMoa','CgvYC2LZDeLUChv0sw1Hz2vZ','Aw1Hz2uVD2vICa','yM91BMrHCNLuDxjUswq','t19sre9otfK','zw52AxjVBM1LBNq','yxv0B21HDgLJvgL0Bgvqzw5KAw5N','CgfYC2u','Bw9KzwXjza','Aw5KzxHeAxj0Eq','oujPuuLKwG','CMvWBgfJzw1LBNriAxn0B3j5','AgfZt3DU','ntm3wunnsMfp','C2vZC2LVBI50AxrSzs51CgrHDgvK','C3vIyxjYyxK','zMLSDgvY','yxbWzw5K','C3bSAwnL','DxbKyxrL','ywDLBNq','u2vZC2LVBIbHBhjLywr5igHHCYbHihDYAxrLCI4','yMvMB3jLu2vXDwvUy2u','CgvUzgLUz1nLC3nPB25Z','Aw1Hz2vZ','y29Kzq','CM9SBgjHy2TtzxnZAw9U','BwLTzvr5Cgu','y3vYC29Y','u2vZC2LVBIbYzxDPBMqGDgfYz2v0ihDHCYbUB3qGzM91BMqU','y3rPBwvnCW','yNL0zuXLBMD0Aa','zgvSzxrL','tufsx0fhru5ux1nfu1njt05FtK9ux0zpvu5e','BgfZDfnLCxvLBMnL','u2vZC2LVBIbZDg9YzsbPCYbJBg9ZzwqU','yxv0B21HDgLJ','Cgf0Aa','Aw5KzxGUANnVBG','ChvZAa','u2vZC2LVBIbOAxn0B3j5igLZignVCNj1ChqU','B3bLBG','ywXSB2m','DgvZDa','Agv4','DgvTCg9Yyxj5ugf0Aa','y29UDgv4DfjLy29Yzhm','C29YDa','zMLSzu5HBwu','yxv0B21HDgLJvgL0Bgu','DhvYBKLK','zxHLy3v0Aw9Uswq','tufyx1nbrKvFsu5uruDfuG','lNjVBgXIywnRlxrTCa','CM9VDa','lMPZB25S','C2L6zq','BMv4DfnLCxvLBMnL','BgfZDefJDgL2Axr5qxq','Bg9JAW','q29TCgfJDcbZDw1Tyxj5igLZihjLCxvPCMvKlG','BgLZDa','lMjPBG','DxbKyxrLvgL0Bgu','zMLUzeXHC3rjBMrLEa','zgf0yujHC2u2na','AgfZrwfYBgLLCG','tufsx0fhru5ux0Hpu1rFteLnsvrFrvHdruveruq','lM1HCG','y3jLyxrLzef0','Aw5KzxG','CM9Szq','Bwf4','CMvHzenVBNrLEhq','tMv3ihnLC3nPB24','tufsx0fhru5ux1jfv0Lorf9uqvjhrvrFsu5wquXjra','lNjVBgXIywnRlxrYyxnO','otCXnZHQrvjlz1u','yMfJA3vW','CgXHDgzVCM0','zgLNzxn0','Aw1Hz2uVz2LM','C3rYAw5NAwz5','tufsx0fhru5ux0Loufvux0nbuefcsuXjvfLFvu5tvvbqt1juruq','C2vNBwvUDhm','tufsx0fhru5ux1jpteXcqunlx1rbuKDfvf9jtLzbteLe','y29UDgvUDa','C2v0','u2vZC2LVBIbPBMrLEcbPCYbIDxn5lG','BM93','ywXSB2nvBNnHzMu','Cg9W','Aw5V','yMfZzty0','yNL0zvnPEMu','CMv2zxjZzq','BwLU','BwfW','BgvUz3rO','A2LUza','CMfUzg9T','DhLWzq','C3rHDa','AxntywzLsw50zwDLCG','Dw5ZAgLMDa','C3rYAw5N','CMv2AxnPB24','Aw5KzxGUBg9JAW','mtiZnJu1mM9PwgzzqG','zgv2','Aw5WDxrFAw1Hz2vZ','Aw1Hz2uVANbLzW','ndbQzMfizMW','zNjVBq','DxnLCG','DMvYC2LVBG','ru5pru5u','z2vUzxjHDgvKx2LTywDLCW','DxnLCL9PBNb1Da','z2v0','y29Uy2f0','C2vZC2LVBKLK','yxj0AwzHy3rZ','tufsx0fhru5ux1nfu1njt05Fte9ds0ve','ue9tsvrjvKvFsu5gsu5jvfK','ywXS','zw50CMLLCW','tufsx0fhru5ux0rju1bpu0ve','CMvZDw1L','y3jLyxrLu2vZC2LVBG','Dg9tDhjPBMC','zxHLyW','Bg9JywXLq29TCgfYzq','mJi4B0neqKz1','C2XPy2u','y2f0y2G','yNL0zxnszwfK','z2v0u2vZC2LVBG'];_0x3cb3=function(){return _0x2e3768;};return _0x3cb3();}import{basename,join}from'node:path';import{setTimeout as _0xc63b03}from'node:timers/promises';import{MarAgentError}from'../error.js';import{todoItemsFromSnapshot}from'../tools/todo.js';const MAX_SEGMENT_BYTES=(0x23e0+-0xb8a+-0x1846)*(0x3*-0xa6b+-0xef*-0x1d+0x82e)*(-0xfd*-0x27+0xa36+-0x2cc1),REVERSE_READ_CHUNK_BYTES=(-0x2494+-0x2f9+-0x17*-0x1bb)*(-0x1*0x236+-0x1*-0x7c9+0x193*-0x1),MAX_INPUT_IMAGES=-0x1*0xac1+-0x9*0x3a7+0x1*0x2ba5,MAX_INPUT_IMAGE_BYTES=(-0xbb2+0x70*-0x11+-0x1*-0x1327)*(-0x7b4+-0x8*-0x3fd+0xc*-0x1af)*(0x22*0xfb+-0x1f8c+0x236),MAX_INPUT_IMAGES_BYTES=(-0xb53*0x3+0x1f02+0x301)*(0xf4e+0x1380+-0x1ece)*(-0xb28+-0x2*0x112b+0x317e),INPUT_IMAGE_MIME_TYPES=new Set([_0xc75581(0x1dd),_0xc75581(0x1ac),_0xc75581(0x18e),_0xc75581(0x224)]);export class JsonlSessionStore{static #instances=new Map();static #opening=new Map();#shared;#leaseClosed=![];constructor(_0x56caa8){this.#shared=_0x56caa8;}static async[_0xc75581(0x166)](_0x41f20c){const _0x8bac42=_0xc75581,_0x4ed400=join(_0x41f20c,_0x8bac42(0x181),_0x8bac42(0x236)),_0x4bac58=JsonlSessionStore.#instances[_0x8bac42(0x1b4)](_0x4ed400);if(_0x4bac58)return _0x4bac58[_0x8bac42(0x1c7)]++,new JsonlSessionStore(_0x4bac58);const _0x116a45=JsonlSessionStore.#opening[_0x8bac42(0x1b4)](_0x4ed400);if(_0x116a45){const _0x4e26a0=await _0x116a45;return _0x4e26a0[_0x8bac42(0x1c7)]++,new JsonlSessionStore(_0x4e26a0);}const _0x1c2492=JsonlSessionStore.#openExclusive(_0x4ed400);JsonlSessionStore.#opening[_0x8bac42(0x194)](_0x4ed400,_0x1c2492);try{const _0x51e6aa=await _0x1c2492;return JsonlSessionStore.#instances[_0x8bac42(0x194)](_0x4ed400,_0x51e6aa),new JsonlSessionStore(_0x51e6aa);}finally{JsonlSessionStore.#opening[_0x8bac42(0x15d)](_0x4ed400);}}static async #openExclusive(_0x4b2858){const _0x5cd7a6=_0xc75581;await mkdir(join(_0x4b2858,_0x5cd7a6(0x1cc)),{'recursive':!![]});let _0x1c3880={'version':0x1,'revision':0x0,'sessions':[]};try{_0x1c3880=JSON[_0x5cd7a6(0x229)](await readFile(join(_0x4b2858,_0x5cd7a6(0x1cc),_0x5cd7a6(0x163)),_0x5cd7a6(0x222)));}catch{}return{'root':_0x4b2858,'index':_0x1c3880,'pendingSessions':new Map(),'references':0x1,'closed':![],'indexDirty':![],'segments':new Map()};}async #saveIndex(_0x54c4f9){const _0x4c1c19=_0xc75581,_0x515947=await acquireFileLock(join(this.#shared[_0x4c1c19(0x173)],_0x4c1c19(0x1cc),_0x4c1c19(0x1a8))),_0x49fe84=join(this.#shared[_0x4c1c19(0x173)],_0x4c1c19(0x1cc),_0x4c1c19(0x163)),_0x1db30c=_0x49fe84+'.'+randomUUID()+_0x4c1c19(0x21f);try{let _0x3ccd09={'version':0x1,'revision':0x0,'sessions':[]};try{_0x3ccd09=JSON[_0x4c1c19(0x229)](await readFile(_0x49fe84,_0x4c1c19(0x222)));}catch{}const _0x5e69e4=new Map(_0x3ccd09[_0x4c1c19(0x1cc)][_0x4c1c19(0x19e)](_0x3f0a7b=>[_0x3f0a7b['id'],_0x3f0a7b]));for(const _0x450595 of this.#shared[_0x4c1c19(0x183)][_0x4c1c19(0x1cc)]){const _0x58bced=_0x5e69e4[_0x4c1c19(0x1b4)](_0x450595['id']);if(!_0x58bced||_0x58bced[_0x4c1c19(0x177)]<=_0x450595[_0x4c1c19(0x177)])_0x5e69e4[_0x4c1c19(0x194)](_0x450595['id'],_0x450595);}if(_0x54c4f9)_0x5e69e4[_0x4c1c19(0x15d)](_0x54c4f9);this.#shared[_0x4c1c19(0x183)]={'version':0x1,'revision':Math[_0x4c1c19(0x185)](_0x3ccd09[_0x4c1c19(0x1a7)],this.#shared[_0x4c1c19(0x183)][_0x4c1c19(0x1a7)])+(-0x102d*-0x1+0xb74*-0x1+-0x4b8),'sessions':[..._0x5e69e4[_0x4c1c19(0x203)]()]},await writeFile(_0x1db30c,JSON[_0x4c1c19(0x18f)](this.#shared[_0x4c1c19(0x183)]),{'mode':0x180}),await rename(_0x1db30c,_0x49fe84),this.#shared[_0x4c1c19(0x22b)]=![];}finally{await rm(_0x1db30c,{'force':!![]}),await _0x515947();}}async #refreshIndex(){const _0x3cdfd6=_0xc75581;try{const _0x334f33=JSON[_0x3cdfd6(0x229)](await readFile(join(this.#shared[_0x3cdfd6(0x173)],_0x3cdfd6(0x1cc),_0x3cdfd6(0x163)),_0x3cdfd6(0x222)));if(_0x334f33[_0x3cdfd6(0x1a7)]<=this.#shared[_0x3cdfd6(0x183)][_0x3cdfd6(0x1a7)])return;const _0x39c039=new Map(this.#shared[_0x3cdfd6(0x183)][_0x3cdfd6(0x1cc)][_0x3cdfd6(0x19e)](_0x5a129c=>[_0x5a129c['id'],_0x5a129c]));for(const _0x32e686 of _0x334f33[_0x3cdfd6(0x1cc)]){const _0x21568e=_0x39c039[_0x3cdfd6(0x1b4)](_0x32e686['id']);if(!_0x21568e||_0x21568e[_0x3cdfd6(0x177)]<_0x32e686[_0x3cdfd6(0x177)])_0x39c039[_0x3cdfd6(0x194)](_0x32e686['id'],_0x32e686);}this.#shared[_0x3cdfd6(0x183)]={..._0x334f33,'sessions':[..._0x39c039[_0x3cdfd6(0x203)]()]};}catch{}}async[_0xc75581(0x1be)](_0x5bdeb8){const _0x4f11aa=_0xc75581;this.#assertOpen();const _0x12413d=randomUUID(),_0x4cdccf=new Date()[_0x4f11aa(0x20b)](),_0x23b0ce={'id':_0x12413d,'title':_0x5bdeb8[_0x4f11aa(0x212)]??_0x4f11aa(0x187),'workspace':_0x5bdeb8[_0x4f11aa(0x1ff)],'createdAt':_0x4cdccf,'lastActivityAt':_0x4cdccf,'nextSequence':0x1,'automaticTitlePending':_0x5bdeb8[_0x4f11aa(0x212)]===undefined,'resume':{'version':0x1,'todoRevision':0x0},'segments':[]};return await mkdir(join(this.#shared[_0x4f11aa(0x173)],_0x4f11aa(0x1cc),_0x12413d),{'recursive':!![]}),this.#shared[_0x4f11aa(0x191)][_0x4f11aa(0x194)](_0x12413d,-0x5d3+-0x1d35*-0x1+-0x7*0x357),this.#shared[_0x4f11aa(0x183)]={'version':0x1,'revision':this.#shared[_0x4f11aa(0x183)][_0x4f11aa(0x1a7)]+(-0x16*-0x1ab+0xdac+-0x325d*0x1),'sessions':[_0x23b0ce,...this.#shared[_0x4f11aa(0x183)][_0x4f11aa(0x1cc)]]},await this.#saveIndex(),await this[_0x4f11aa(0x233)](_0x12413d,{'type':_0x4f11aa(0x1ed),'payload':{'title':_0x23b0ce[_0x4f11aa(0x212)],'workspace':_0x23b0ce[_0x4f11aa(0x1ff)],'automaticTitle':_0x5bdeb8[_0x4f11aa(0x212)]===undefined}}),_0x23b0ce;}[_0xc75581(0x1d7)](_0x304c4e){const _0x1aa908=_0xc75581;this.#assertOpen();if(!this.#shared[_0x1aa908(0x183)][_0x1aa908(0x1cc)][_0x1aa908(0x215)](_0x1602c8=>_0x1602c8['id']===_0x304c4e)&&!this.#shared[_0x1aa908(0x239)][_0x1aa908(0x204)](_0x304c4e))throw new MarAgentError(_0x1aa908(0x15e),_0x1aa908(0x211));return join(this.#shared[_0x1aa908(0x173)],_0x1aa908(0x1cc),_0x304c4e);}async[_0xc75581(0x223)](_0x374adb,_0x589b06){const _0x39b737=_0xc75581;this.#assertOpen();if(_0x589b06[_0x39b737(0x19f)]===0x11ab*0x1+-0xdb3+-0x3f8)return[];if(_0x589b06[_0x39b737(0x19f)]>MAX_INPUT_IMAGES)throw new MarAgentError(_0x39b737(0x180),_0x39b737(0x1c9));const _0x50fef3=join(this[_0x39b737(0x1d7)](_0x374adb),_0x39b737(0x1ab));await mkdir(_0x50fef3,{'recursive':!![],'mode':0x1c0});const _0x321374=[];let _0x41b676,_0x4dfbde=0x235*-0x9+-0x96a+0x1d47;try{const _0x10d25a=[];for(const _0x5082a4 of _0x589b06){if(!INPUT_IMAGE_MIME_TYPES[_0x39b737(0x204)](_0x5082a4[_0x39b737(0x23d)]))throw new MarAgentError(_0x39b737(0x190),_0x39b737(0x20a));const _0x4f1f4a=Buffer[_0x39b737(0x1ae)](_0x5082a4[_0x39b737(0x17e)],_0x39b737(0x19a));_0x4dfbde+=_0x4f1f4a[_0x39b737(0x15c)];if(_0x4f1f4a[_0x39b737(0x15c)]===0x440*-0x5+0xae5*0x1+0xa5b||_0x4f1f4a[_0x39b737(0x15c)]>MAX_INPUT_IMAGE_BYTES||_0x4dfbde>MAX_INPUT_IMAGES_BYTES)throw new MarAgentError(_0x39b737(0x180),_0x39b737(0x206));const _0x4275a7=randomUUID()+_0x39b737(0x17b);_0x41b676=join(_0x50fef3,'.'+_0x4275a7+'.'+randomUUID()+_0x39b737(0x21f));const _0x58097b=await open(_0x41b676,'wx',0x78b*0x1+0x5*-0x788+0x1f9d*0x1);try{await _0x58097b[_0x39b737(0x1e3)](_0x4f1f4a),await _0x58097b[_0x39b737(0x1f4)]();}finally{await _0x58097b[_0x39b737(0x210)]();}await rename(_0x41b676,join(_0x50fef3,_0x4275a7)),_0x41b676=undefined,_0x321374[_0x39b737(0x164)](_0x4275a7),_0x10d25a[_0x39b737(0x164)]({'name':_0x5082a4[_0x39b737(0x202)],'mimeType':_0x5082a4[_0x39b737(0x23d)],'byteSize':_0x4f1f4a[_0x39b737(0x15c)],'fileName':_0x4275a7,'sha256':createHash(_0x39b737(0x1f1))[_0x39b737(0x235)](_0x4f1f4a)[_0x39b737(0x18d)](_0x39b737(0x169))});}return _0x10d25a;}catch(_0x5221d9){if(_0x41b676!==undefined)await rm(_0x41b676,{'force':!![]})[_0x39b737(0x1c4)](()=>undefined);await Promise[_0x39b737(0x1ba)](_0x321374[_0x39b737(0x19e)](_0x24b673=>rm(join(_0x50fef3,_0x24b673),{'force':!![]})[_0x39b737(0x1c4)](()=>undefined)));throw _0x5221d9;}}async[_0xc75581(0x21e)](_0x1e3b94,_0x34cf0f){const _0x56847d=_0xc75581;this.#assertOpen();const _0x319db1=inputImageReferences(_0x34cf0f);if(_0x319db1[_0x56847d(0x19f)]===-0x14*-0xc5+-0x9b+-0xec9)return[];const _0xc04bdd=join(this[_0x56847d(0x1d7)](_0x1e3b94),_0x56847d(0x1ab)),_0x138781=[];for(const _0x16ddac of _0x319db1){const _0x51ce32=await readInputImageBytes(_0xc04bdd,_0x16ddac);_0x138781[_0x56847d(0x164)]({'mimeType':_0x16ddac[_0x56847d(0x23d)],'dataBase64':_0x51ce32[_0x56847d(0x1bf)](_0x56847d(0x19a))});}return _0x138781;}async[_0xc75581(0x1e5)](_0x27abe9,_0x262544){const _0x2b43e6=_0xc75581;this.#assertOpen();if(!Number[_0x2b43e6(0x1a4)](_0x262544[_0x2b43e6(0x1e0)])||_0x262544[_0x2b43e6(0x1e0)]<-0x188+-0x26e1+-0x5c6*-0x7||_0x262544[_0x2b43e6(0x1e0)]>=Number[_0x2b43e6(0x171)]||!Number[_0x2b43e6(0x1a4)](_0x262544[_0x2b43e6(0x1d0)])||_0x262544[_0x2b43e6(0x1d0)]<0x1d2d+0x1271*0x2+0x420f*-0x1)return undefined;const _0x46ee42=await this[_0x2b43e6(0x1ec)](_0x27abe9,{'limit':0x1,'beforeSequence':_0x262544[_0x2b43e6(0x1e0)]+(-0x52*-0x13+-0xf*0x5d+-0x36*0x3)}),_0x2af721=_0x46ee42[_0x2b43e6(0x20d)][-0x1a79+-0x1013+0x185*0x1c];if(_0x2af721?.[_0x2b43e6(0x1e0)]!==_0x262544[_0x2b43e6(0x1e0)]||_0x2af721[_0x2b43e6(0x1a2)]!==_0x2b43e6(0x1e4)||!isObject(_0x2af721[_0x2b43e6(0x218)]))return undefined;if(!Array[_0x2b43e6(0x1d1)](_0x2af721[_0x2b43e6(0x218)][_0x2b43e6(0x23a)])||_0x262544[_0x2b43e6(0x1d0)]>=_0x2af721[_0x2b43e6(0x218)][_0x2b43e6(0x23a)][_0x2b43e6(0x19f)])return undefined;const _0x87523e=inputImageReference(_0x2af721[_0x2b43e6(0x218)][_0x2b43e6(0x23a)][_0x262544[_0x2b43e6(0x1d0)]]);if(_0x87523e===undefined)return undefined;const _0x598530=await readInputImageBytes(join(this[_0x2b43e6(0x1d7)](_0x27abe9),_0x2b43e6(0x1ab)),_0x87523e);return{'name':_0x87523e[_0x2b43e6(0x202)],'mimeType':_0x87523e[_0x2b43e6(0x23d)],'byteSize':_0x87523e[_0x2b43e6(0x19b)],'fileName':_0x87523e[_0x2b43e6(0x16d)],'sha256':_0x87523e[_0x2b43e6(0x1f1)],'dataBase64':_0x598530[_0x2b43e6(0x1bf)](_0x2b43e6(0x19a))};}async[_0xc75581(0x1d9)](_0x3a2569,_0x49527c){const _0x579eb2=_0xc75581;this.#assertOpen();const _0x1036a3=join(this[_0x579eb2(0x1d7)](_0x3a2569),_0x579eb2(0x1ab));await Promise[_0x579eb2(0x1ba)](_0x49527c[_0x579eb2(0x220)](_0x1acc15=>validInputImageFileName(_0x1acc15[_0x579eb2(0x16d)])?[rm(join(_0x1036a3,_0x1acc15[_0x579eb2(0x16d)]),{'force':!![]})]:[]));}async[_0xc75581(0x21a)](_0x35bf0e,_0x190cbe){const _0x2a61ce=_0xc75581;this.#assertOpen();const _0x2df2f5=await this[_0x2a61ce(0x1f2)](_0x35bf0e);try{const _0x547fb9=this.#shared[_0x2a61ce(0x183)][_0x2a61ce(0x1cc)][_0x2a61ce(0x1ca)](_0x4441ee=>_0x4441ee['id']===_0x35bf0e);if(!_0x547fb9)throw new MarAgentError(_0x2a61ce(0x15e),_0x2a61ce(0x211));const _0x1726ec=await this[_0x2a61ce(0x1c8)](_0x35bf0e),_0x2dc9c6=_0x190cbe[_0x2a61ce(0x225)]===null?-(-0x1a0a+-0xbe7*-0x1+0xe24):_0x1726ec[_0x2a61ce(0x17d)](_0x4a0165=>_0x4a0165[_0x2a61ce(0x16f)]===_0x190cbe[_0x2a61ce(0x225)]);if(_0x190cbe[_0x2a61ce(0x225)]!==null&&_0x2dc9c6<0x16aa+-0xb42+-0xb68)throw new MarAgentError(_0x2a61ce(0x188),_0x2a61ce(0x15a));const _0x52d478=new Date()[_0x2a61ce(0x20b)](),_0x5f27ff={'id':randomUUID(),'title':_0x190cbe[_0x2a61ce(0x212)],'workspace':_0x547fb9[_0x2a61ce(0x1ff)],'createdAt':_0x52d478,'lastActivityAt':_0x52d478,'nextSequence':0x1,'automaticTitlePending':![],'resume':{'version':0x1,'todoRevision':0x0},'segments':[]};await mkdir(join(this.#shared[_0x2a61ce(0x173)],_0x2a61ce(0x1cc),_0x5f27ff['id']),{'recursive':!![]}),this.#shared[_0x2a61ce(0x191)][_0x2a61ce(0x194)](_0x5f27ff['id'],-0xd15*-0x1+0x977*-0x1+-0x39d),this.#shared[_0x2a61ce(0x239)][_0x2a61ce(0x194)](_0x5f27ff['id'],_0x5f27ff);try{await this[_0x2a61ce(0x233)](_0x5f27ff['id'],{'type':_0x2a61ce(0x1ed),'payload':{'title':_0x5f27ff[_0x2a61ce(0x212)],'workspace':_0x5f27ff[_0x2a61ce(0x1ff)],'automaticTitle':![]}});const _0x56c5e3=_0x190cbe[_0x2a61ce(0x225)]===null?[]:_0x1726ec[_0x2a61ce(0x1c3)](-0x40f*0x1+-0x39*0x65+-0x3cb*-0x7,_0x2dc9c6+(-0x220f+0x1635+0xbdb));for(const _0x2f3e8b of _0x56c5e3)await this[_0x2a61ce(0x233)](_0x5f27ff['id'],{'type':_0x2f3e8b[_0x2a61ce(0x1a2)],'payload':forkedPayload(_0x2f3e8b[_0x2a61ce(0x1a2)],_0x2f3e8b[_0x2a61ce(0x218)],_0x35bf0e,_0x5f27ff['id'],_0x190cbe[_0x2a61ce(0x212)]),..._0x2f3e8b[_0x2a61ce(0x170)]===undefined?{}:{'executionId':_0x2f3e8b[_0x2a61ce(0x170)]},..._0x2f3e8b[_0x2a61ce(0x16f)]===undefined?{}:{'turnId':_0x2f3e8b[_0x2a61ce(0x16f)]},'timestamp':_0x2f3e8b[_0x2a61ce(0x200)]});return await copyGeneratedImages(this[_0x2a61ce(0x1d7)](_0x35bf0e),this[_0x2a61ce(0x1d7)](_0x5f27ff['id']),generatedImageFileNames(_0x56c5e3)),await copyInputImages(this[_0x2a61ce(0x1d7)](_0x35bf0e),this[_0x2a61ce(0x1d7)](_0x5f27ff['id']),inputImageReferencesFromRecords(_0x56c5e3)),_0x5f27ff[_0x2a61ce(0x177)]=_0x5f27ff[_0x2a61ce(0x182)],this.#shared[_0x2a61ce(0x239)][_0x2a61ce(0x15d)](_0x5f27ff['id']),this.#shared[_0x2a61ce(0x183)]={'version':0x1,'revision':this.#shared[_0x2a61ce(0x183)][_0x2a61ce(0x1a7)]+(-0x954+0x714+0x241),'sessions':[_0x5f27ff,...this.#shared[_0x2a61ce(0x183)][_0x2a61ce(0x1cc)]]},this.#shared[_0x2a61ce(0x22b)]=!![],await this.#saveIndex(),{'id':_0x5f27ff['id'],'title':_0x5f27ff[_0x2a61ce(0x212)],'workspace':_0x5f27ff[_0x2a61ce(0x1ff)],'createdAt':_0x5f27ff[_0x2a61ce(0x182)],'lastActivityAt':_0x5f27ff[_0x2a61ce(0x182)]};}catch(_0x4d4e5b){this.#shared[_0x2a61ce(0x239)][_0x2a61ce(0x15d)](_0x5f27ff['id']);const _0xebfa83=this.#shared[_0x2a61ce(0x183)][_0x2a61ce(0x1cc)][_0x2a61ce(0x1fc)](_0x361f43=>_0x361f43['id']===_0x5f27ff['id']);_0xebfa83>=0x45*-0x25+-0x2d*0x5+0x6*0x1cf&&(this.#shared[_0x2a61ce(0x183)][_0x2a61ce(0x1cc)][_0x2a61ce(0x234)](_0xebfa83,-0x1d14+0x189a+-0x1f*-0x25),this.#shared[_0x2a61ce(0x183)][_0x2a61ce(0x1a7)]++,this.#shared[_0x2a61ce(0x22b)]=!![],await this.#saveIndex(_0x5f27ff['id'])[_0x2a61ce(0x1c4)](()=>undefined));this.#shared[_0x2a61ce(0x191)][_0x2a61ce(0x15d)](_0x5f27ff['id']),await rm(join(this.#shared[_0x2a61ce(0x173)],_0x2a61ce(0x1cc),_0x5f27ff['id']),{'recursive':!![],'force':!![]})[_0x2a61ce(0x1c4)](()=>undefined);throw _0x4d4e5b;}}finally{await _0x2df2f5();}}async[_0xc75581(0x23c)](_0x8db364,_0x2ffbc5){const _0x5648fe=_0xc75581;this.#assertOpen();const _0x46f23f=await this[_0x5648fe(0x1f2)](_0x8db364);try{const _0x26daa3=this.#shared[_0x5648fe(0x183)][_0x5648fe(0x1cc)][_0x5648fe(0x1ca)](_0x29f83b=>_0x29f83b['id']===_0x8db364);if(!_0x26daa3)throw new MarAgentError(_0x5648fe(0x15e),_0x5648fe(0x211));const _0xd4f71b=await this[_0x5648fe(0x1c8)](_0x8db364);if(_0xd4f71b[0x9*0x3ce+-0x2075+-0x1c9]?.[_0x5648fe(0x1a2)]!==_0x5648fe(0x1ed))throw new MarAgentError(_0x5648fe(0x1f8),_0x5648fe(0x165));const _0x3b7620=_0x2ffbc5[_0x5648fe(0x225)]===null?-0x67*-0x61+-0x1d50+-0x9b7:_0xd4f71b[_0x5648fe(0x17d)](_0x8bfa4c=>_0x8bfa4c[_0x5648fe(0x16f)]===_0x2ffbc5[_0x5648fe(0x225)]);if(_0x2ffbc5[_0x5648fe(0x225)]!==null&&_0x3b7620<-0x17a4+0xb5b*0x1+-0x25*-0x55)throw new MarAgentError(_0x5648fe(0x192),_0x5648fe(0x20e));const _0x58ade0=_0xd4f71b[_0x5648fe(0x1c3)](0x9*0x383+0xf8+-0x2093,_0x3b7620+(0x23a7*-0x1+0x119a+0x2*0x907)),_0x2ba38b=await stageRollbackSegments(this[_0x5648fe(0x1d7)](_0x8db364),_0x58ade0),_0x492ecb=randomUUID();let _0x30c15c=[],_0x2181d6=[];const _0x3e6025=structuredClone(_0x26daa3),_0x1a8da9=this.#shared[_0x5648fe(0x183)][_0x5648fe(0x1a7)],_0x3a01eb=this.#shared[_0x5648fe(0x191)][_0x5648fe(0x1b4)](_0x8db364),_0x353e57=await this.#segmentPaths(_0x8db364),_0x1b2467=_0x353e57[_0x5648fe(0x19e)](_0x415f0f=>({'path':_0x415f0f,'backup':_0x415f0f+'.'+_0x492ecb+_0x5648fe(0x205)})),_0x5011af=[];let _0x586c1d=![];try{_0x30c15c=await stageUnreferencedImages(this[_0x5648fe(0x1d7)](_0x8db364),_0x5648fe(0x1b2),new Set(generatedImageFileNames(_0x58ade0)),_0x492ecb),_0x2181d6=await stageUnreferencedImages(this[_0x5648fe(0x1d7)](_0x8db364),_0x5648fe(0x1ab),new Set(inputImageReferencesFromRecords(_0x58ade0)[_0x5648fe(0x19e)](_0x123f61=>_0x123f61[_0x5648fe(0x16d)])),_0x492ecb);for(const _0x4ab7c1 of _0x1b2467)await rename(_0x4ab7c1[_0x5648fe(0x162)],_0x4ab7c1[_0x5648fe(0x18b)]);for(const _0x30f676 of _0x2ba38b[_0x5648fe(0x213)]){await rename(_0x30f676[_0x5648fe(0x16a)],_0x30f676[_0x5648fe(0x162)]),_0x5011af[_0x5648fe(0x164)](_0x30f676[_0x5648fe(0x162)]);}const _0x5dbd3e=deriveExecutionState(_0x58ade0),_0x1b72d4=new Date()[_0x5648fe(0x20b)]();return _0x26daa3[_0x5648fe(0x212)]=retainedSessionTitle(_0x58ade0,_0x26daa3[_0x5648fe(0x212)]),_0x26daa3[_0x5648fe(0x177)]=_0x1b72d4,_0x26daa3[_0x5648fe(0x176)]=(_0x58ade0['at'](-(-0x1e5*0x11+-0x1932+-0x14e*-0x2c))?.[_0x5648fe(0x1e0)]??-0xf08+-0xabb*-0x3+-0xbf*0x17)+(-0x1*0x254d+-0x60a+0x49*0x98),_0x26daa3[_0x5648fe(0x228)]=_0x5dbd3e[_0x5648fe(0x228)],_0x26daa3[_0x5648fe(0x1bd)]=_0x5dbd3e[_0x5648fe(0x1bd)],_0x26daa3[_0x5648fe(0x191)]=_0x2ba38b[_0x5648fe(0x191)],this.#shared[_0x5648fe(0x191)][_0x5648fe(0x194)](_0x8db364,_0x2ba38b[_0x5648fe(0x191)]['at'](-(0x13c4+0x4d1+-0x625*0x4))?.[_0x5648fe(0x216)]??0x1824+-0x40e*0x4+-0x7eb),this.#shared[_0x5648fe(0x183)][_0x5648fe(0x1a7)]++,this.#shared[_0x5648fe(0x22b)]=!![],await this.#saveIndex(),_0x586c1d=!![],await Promise[_0x5648fe(0x1ba)]([..._0x1b2467[_0x5648fe(0x19e)](_0x333235=>rm(_0x333235[_0x5648fe(0x18b)],{'force':!![]})[_0x5648fe(0x1c4)](()=>undefined)),..._0x30c15c[_0x5648fe(0x19e)](_0xb21d89=>rm(_0xb21d89[_0x5648fe(0x21c)],{'force':!![]})[_0x5648fe(0x1c4)](()=>undefined)),..._0x2181d6[_0x5648fe(0x19e)](_0x3d8a77=>rm(_0x3d8a77[_0x5648fe(0x21c)],{'force':!![]})[_0x5648fe(0x1c4)](()=>undefined))])[_0x5648fe(0x1c4)](()=>undefined),{'id':_0x26daa3['id'],'title':_0x26daa3[_0x5648fe(0x212)],'workspace':_0x26daa3[_0x5648fe(0x1ff)],'createdAt':_0x26daa3[_0x5648fe(0x182)],'lastActivityAt':_0x26daa3[_0x5648fe(0x177)]};}catch(_0x4e152f){if(!_0x586c1d){await Promise[_0x5648fe(0x1ba)](_0x5011af[_0x5648fe(0x19e)](_0x5d0736=>rm(_0x5d0736,{'force':!![]})))[_0x5648fe(0x1c4)](()=>undefined),await restoreRenamedFiles(_0x1b2467[_0x5648fe(0x19e)](_0x44ff17=>({'from':_0x44ff17[_0x5648fe(0x18b)],'to':_0x44ff17[_0x5648fe(0x162)]}))),await restoreRenamedFiles([..._0x30c15c,..._0x2181d6]),restoreSessionMeta(_0x26daa3,_0x3e6025),this.#shared[_0x5648fe(0x183)][_0x5648fe(0x1a7)]=_0x1a8da9;if(_0x3a01eb===undefined)this.#shared[_0x5648fe(0x191)][_0x5648fe(0x15d)](_0x8db364);else this.#shared[_0x5648fe(0x191)][_0x5648fe(0x194)](_0x8db364,_0x3a01eb);this.#shared[_0x5648fe(0x22b)]=!![];}throw _0x4e152f;}finally{await Promise[_0x5648fe(0x1ba)](_0x2ba38b[_0x5648fe(0x213)][_0x5648fe(0x19e)](_0x22685d=>rm(_0x22685d[_0x5648fe(0x16a)],{'force':!![]})))[_0x5648fe(0x1c4)](()=>undefined);}}finally{await _0x46f23f();}}async[_0xc75581(0x17c)](_0xa5c0f,_0x39798c,_0x2e0f2e={}){const _0x39e9aa=_0xc75581;this.#assertOpen();const _0x1a7565=_0x39798c[_0x39e9aa(0x1e6)]();if(!_0x1a7565)throw new MarAgentError(_0x39e9aa(0x214),_0x39e9aa(0x1fa));const _0x52fd9c=this.#shared[_0x39e9aa(0x183)][_0x39e9aa(0x1cc)][_0x39e9aa(0x1ca)](_0x3e79c9=>_0x3e79c9['id']===_0xa5c0f);if(!_0x52fd9c)throw new MarAgentError(_0x39e9aa(0x15e),_0x39e9aa(0x211));await this[_0x39e9aa(0x233)](_0xa5c0f,{'type':_0x39e9aa(0x230),'payload':{'title':_0x1a7565,'automatic':!![]},..._0x2e0f2e[_0x39e9aa(0x170)]?{'executionId':_0x2e0f2e[_0x39e9aa(0x170)]}:{},..._0x2e0f2e[_0x39e9aa(0x16f)]?{'turnId':_0x2e0f2e[_0x39e9aa(0x16f)]}:{}}),_0x52fd9c[_0x39e9aa(0x212)]=_0x1a7565;}async[_0xc75581(0x1c6)](_0x4db87f){const _0xdf5b0=_0xc75581;this.#assertOpen(),await this.#refreshIndex();const _0x1556b7=this.#shared[_0xdf5b0(0x183)][_0xdf5b0(0x1cc)][_0xdf5b0(0x1ca)](_0x2087b3=>_0x2087b3['id']===_0x4db87f);if(!_0x1556b7)throw new MarAgentError(_0xdf5b0(0x15e),_0xdf5b0(0x211));return{'id':_0x1556b7['id'],'title':_0x1556b7[_0xdf5b0(0x212)],'workspace':_0x1556b7[_0xdf5b0(0x1ff)],'createdAt':_0x1556b7[_0xdf5b0(0x182)],'lastActivityAt':_0x1556b7[_0xdf5b0(0x177)]};}async[_0xc75581(0x233)](_0x42beeb,_0x178136){const _0x1ba649=_0xc75581;this.#assertOpen();const _0x3ad6d4=this.#shared[_0x1ba649(0x183)][_0x1ba649(0x1cc)][_0x1ba649(0x1ca)](_0x32355b=>_0x32355b['id']===_0x42beeb)??this.#shared[_0x1ba649(0x239)][_0x1ba649(0x1b4)](_0x42beeb);if(!_0x3ad6d4)throw new MarAgentError(_0x1ba649(0x15e),_0x1ba649(0x211));const _0x1e9228=!this.#shared[_0x1ba649(0x239)][_0x1ba649(0x204)](_0x42beeb),_0x3edec5={'schemaVersion':0x1,'recordId':randomUUID(),'sequence':_0x3ad6d4[_0x1ba649(0x176)]++,'timestamp':_0x178136[_0x1ba649(0x200)]??new Date()[_0x1ba649(0x20b)](),'sessionId':_0x42beeb,..._0x178136[_0x1ba649(0x170)]?{'executionId':_0x178136[_0x1ba649(0x170)]}:{},..._0x178136[_0x1ba649(0x16f)]?{'turnId':_0x178136[_0x1ba649(0x16f)]}:{},'type':_0x178136[_0x1ba649(0x1a2)],'payload':_0x178136[_0x1ba649(0x218)]},_0x489d43=JSON[_0x1ba649(0x18f)](_0x3edec5)+'\x0a';let _0x1b2af9=await this.#currentSegment(_0x42beeb),_0x401a4f=this.#segmentPath(_0x42beeb,_0x1b2af9);try{const _0xdeb4de=await stat(_0x401a4f);_0xdeb4de[_0x1ba649(0x175)]>-0x1b89+0x10*-0x1a0+-0x3589*-0x1&&_0xdeb4de[_0x1ba649(0x175)]+Buffer[_0x1ba649(0x15c)](_0x489d43)>MAX_SEGMENT_BYTES&&(_0x1b2af9+=0x3*0x1+0x1b92*0x1+-0x1b94,this.#shared[_0x1ba649(0x191)][_0x1ba649(0x194)](_0x42beeb,_0x1b2af9),_0x401a4f=this.#segmentPath(_0x42beeb,_0x1b2af9));}catch{}const _0x104610=await open(_0x401a4f,'a',0x1057+0x17*-0x71+-0x258*0x2);try{await _0x104610[_0x1ba649(0x21b)](_0x489d43),await _0x104610[_0x1ba649(0x1f4)]();}finally{await _0x104610[_0x1ba649(0x210)]();}const _0xa14a39=_0x3ad6d4[_0x1ba649(0x191)]??(_0x3ad6d4[_0x1ba649(0x191)]=[]),_0x3504e8=_0xa14a39[_0x1ba649(0x1ca)](_0x3a3fd8=>_0x3a3fd8[_0x1ba649(0x216)]===_0x1b2af9);if(_0x3504e8)_0x3504e8[_0x1ba649(0x15f)]=_0x3edec5[_0x1ba649(0x1e0)],_0x3504e8[_0x1ba649(0x1cd)]+=Buffer[_0x1ba649(0x15c)](_0x489d43);else _0xa14a39[_0x1ba649(0x164)]({'number':_0x1b2af9,'firstSequence':_0x3edec5[_0x1ba649(0x1e0)],'lastSequence':_0x3edec5[_0x1ba649(0x1e0)],'bytes':Buffer[_0x1ba649(0x15c)](_0x489d43)});return _0x3ad6d4[_0x1ba649(0x177)]=_0x3edec5[_0x1ba649(0x200)],this.#applyRecordToResumeIndex(_0x3ad6d4,_0x3edec5),_0x1e9228&&(this.#shared[_0x1ba649(0x183)][_0x1ba649(0x1a7)]++,this.#shared[_0x1ba649(0x22b)]=!![]),_0x3edec5;}async[_0xc75581(0x1c8)](_0x465be9){const _0xaccd48=_0xc75581;this.#assertOpen();try{const _0x42d51=[];for(const _0x1ebb75 of await this.#segmentPaths(_0x465be9))_0x42d51[_0xaccd48(0x164)](...await readRecords(_0x1ebb75));return _0x42d51;}catch(_0x5b192c){if(_0x5b192c instanceof MarAgentError)throw _0x5b192c;throw new MarAgentError(_0xaccd48(0x15e),_0xaccd48(0x211),{'cause':_0x5b192c});}}async[_0xc75581(0x1ce)](_0x3dc429){const _0x45211f=_0xc75581;this.#assertOpen();const _0x645e45=this.#shared[_0x45211f(0x183)][_0x45211f(0x1cc)][_0x45211f(0x1ca)](_0x52880e=>_0x52880e['id']===_0x3dc429);if(!_0x645e45)throw new MarAgentError(_0x45211f(0x15e),_0x45211f(0x211));if(_0x645e45[_0x45211f(0x1bd)]?.[_0x45211f(0x1b0)]!==0x123*-0x1f+0x1*-0x6f8+0x6*0x709||typeof _0x645e45[_0x45211f(0x228)]!==_0x45211f(0x20c)||_0x645e45[_0x45211f(0x1bd)][_0x45211f(0x219)]===undefined)return this.#rebuildExecutionState(_0x645e45);try{const _0x15391e=await this.#readFromSequence(_0x645e45,_0x645e45[_0x45211f(0x1bd)][_0x45211f(0x219)]);if(_0x15391e[0x1297+0x1334+-0x25cb]?.[_0x45211f(0x1e0)]!==_0x645e45[_0x45211f(0x1bd)][_0x45211f(0x219)]||!isCompactCheckpoint(_0x15391e[0x6b4+-0xd9*0x17+0xccb])||_0x15391e[_0x45211f(0x215)]((_0x14df87,_0x814897)=>_0x814897>0x2*0x9f0+-0x970+0x14e*-0x8&&isCompactCheckpoint(_0x14df87)))return this.#rebuildExecutionState(_0x645e45);const _0x1e5107=await this.#readIndexedTodo(_0x645e45,_0x15391e);if(!_0x1e5107)return this.#rebuildExecutionState(_0x645e45);return{'automaticTitlePending':_0x645e45[_0x45211f(0x228)],'todo':_0x1e5107,'contextRecords':_0x15391e};}catch{return this.#rebuildExecutionState(_0x645e45);}}async[_0xc75581(0x186)](_0xe1885e){const _0x15ba88=_0xc75581;return(await this[_0x15ba88(0x1ce)](_0xe1885e))[_0x15ba88(0x16b)];}async[_0xc75581(0x1ec)](_0x26cbd9,_0x4c0cd8={}){const _0x50a384=_0xc75581,_0x59e6f0=this.#shared[_0x50a384(0x183)][_0x50a384(0x1cc)][_0x50a384(0x1ca)](_0xafcc5f=>_0xafcc5f['id']===_0x26cbd9);if(!_0x59e6f0)throw new MarAgentError(_0x50a384(0x15e),_0x50a384(0x211));const _0x42a22b=_0x4c0cd8[_0x50a384(0x238)]??Number[_0x50a384(0x1b9)],_0x37e80b=Math[_0x50a384(0x19d)](-0x3a1*0x7+0x5*-0x401+0x1c3*0x1c,Math[_0x50a384(0x185)](-0x371+0x102*0x21+0x24*-0xd4,_0x4c0cd8[_0x50a384(0x1fe)]??-0x1341+-0x1*0x149f+0x2*0x1422)),_0x4fbdfb=[];let _0x436224=![];const _0x2425e6=(await this.#segmentPaths(_0x26cbd9))[_0x50a384(0x19c)]();for(const [_0x38202b,_0x594d99]of _0x2425e6[_0x50a384(0x1bb)]()){const _0x3a02a9=segmentNumberFromPath(_0x594d99),_0x4e2af2=_0x59e6f0[_0x50a384(0x191)]?.[_0x50a384(0x1ca)](_0x458de0=>_0x458de0[_0x50a384(0x216)]===_0x3a02a9);if(_0x4e2af2!==undefined&&_0x4e2af2[_0x50a384(0x1de)]>=_0x42a22b)continue;const _0x2ade4e=_0x37e80b-_0x4fbdfb[_0x50a384(0x19f)],_0xbf65a=await readRecordPageFromTail(_0x594d99,_0x42a22b,_0x2ade4e);_0x4fbdfb[_0x50a384(0x1a5)](..._0xbf65a[_0x50a384(0x20d)]);if(_0xbf65a[_0x50a384(0x17f)]){_0x436224=!![];break;}if(_0x4fbdfb[_0x50a384(0x19f)]>=_0x37e80b){_0x436224=_0x38202b<_0x2425e6[_0x50a384(0x19f)]-(-0x1*0x894+-0xf1*0x1+0x986);break;}}const _0x4f8c83=_0x436224?_0x4fbdfb[0x6*0x655+0x1890+-0x3e8e]?.[_0x50a384(0x1e0)]:undefined;return{'records':_0x4fbdfb,..._0x4f8c83?{'previousBeforeSequence':_0x4f8c83}:{}};}async[_0xc75581(0x21d)](_0x348f65,_0x5331b8){const _0x3de347=_0xc75581;if(!_0x5331b8[_0x3de347(0x1ef)][_0x3de347(0x1e6)]())throw new MarAgentError(_0x3de347(0x214),_0x3de347(0x179));const _0x210976=this.#shared[_0x3de347(0x183)][_0x3de347(0x1cc)][_0x3de347(0x1ca)](_0x32ff69=>_0x32ff69['id']===_0x348f65);if(!_0x210976)throw new MarAgentError(_0x3de347(0x15e),_0x3de347(0x211));return this[_0x3de347(0x233)](_0x348f65,{'type':_0x3de347(0x1fd),'payload':{'summary':_0x5331b8[_0x3de347(0x1ef)],..._0x5331b8[_0x3de347(0x22d)]===undefined?{}:{'replacementHistory':_0x5331b8[_0x3de347(0x22d)]},..._0x5331b8[_0x3de347(0x227)]===undefined?{}:{'environment':_0x5331b8[_0x3de347(0x227)]},'boundarySequence':_0x210976[_0x3de347(0x176)]-(0x1e59+-0x1ccb*0x1+-0x18d),'automatic':_0x5331b8[_0x3de347(0x161)]===!![],..._0x5331b8[_0x3de347(0x22a)]===undefined?{}:{'modelId':_0x5331b8[_0x3de347(0x22a)]}},..._0x5331b8[_0x3de347(0x170)]?{'executionId':_0x5331b8[_0x3de347(0x170)]}:{},..._0x5331b8[_0x3de347(0x16f)]?{'turnId':_0x5331b8[_0x3de347(0x16f)]}:{}});}async[_0xc75581(0x1f2)](_0x1ac5ef){const _0x41f969=_0xc75581;this.#assertOpen(),await this.#refreshIndex();if(!this.#shared[_0x41f969(0x183)][_0x41f969(0x1cc)][_0x41f969(0x215)](_0x48f2ba=>_0x48f2ba['id']===_0x1ac5ef))throw new MarAgentError(_0x41f969(0x15e),_0x41f969(0x211));const _0x220af3=join(this.#shared[_0x41f969(0x173)],_0x41f969(0x1cc),_0x1ac5ef,_0x41f969(0x178)),_0x4ecbe=await acquireFileLock(_0x220af3,_0x41f969(0x237),0x1310+-0xaca*0x1+-0x1*0x846);try{await this.#reconcileTail(_0x1ac5ef);}catch(_0x7e4918){await _0x4ecbe();throw _0x7e4918;}return async()=>{const _0x38d7cb=_0x41f969;try{if(this.#shared[_0x38d7cb(0x22b)])await this.#saveIndex();}finally{await _0x4ecbe();}};}async[_0xc75581(0x17a)](_0x5ddf45={}){const _0x54e77a=_0xc75581;this.#assertOpen(),await this.#refreshIndex();const _0x515db7=_0x5ddf45[_0x54e77a(0x23e)]?Number(Buffer[_0x54e77a(0x1ae)](_0x5ddf45[_0x54e77a(0x23e)],_0x54e77a(0x209))[_0x54e77a(0x1bf)](_0x54e77a(0x222))):0x1*0x135a+0x3db*0x1+0xd*-0x1c9,_0x25594e=Math[_0x54e77a(0x19d)](0xb2a+-0x742*0x1+-0x320,Math[_0x54e77a(0x185)](-0x502+0x168f+-0x118c*0x1,_0x5ddf45[_0x54e77a(0x1fe)]??-0x460+0x121e+-0xd8c)),_0x26325a=[...this.#shared[_0x54e77a(0x183)][_0x54e77a(0x1cc)]][_0x54e77a(0x16c)]((_0x35bf25,_0x52508d)=>_0x52508d[_0x54e77a(0x177)][_0x54e77a(0x1c1)](_0x35bf25[_0x54e77a(0x177)])),_0x310b36=_0x26325a[_0x54e77a(0x1c3)](_0x515db7,_0x515db7+_0x25594e)[_0x54e77a(0x19e)](_0x4e11b5=>({'id':_0x4e11b5['id'],'title':_0x4e11b5[_0x54e77a(0x212)],'workspace':_0x4e11b5[_0x54e77a(0x1ff)],'createdAt':_0x4e11b5[_0x54e77a(0x182)],'lastActivityAt':_0x4e11b5[_0x54e77a(0x177)]})),_0x19e7bc=_0x515db7+_0x25594e<_0x26325a[_0x54e77a(0x19f)]?Buffer[_0x54e77a(0x1ae)](String(_0x515db7+_0x25594e))[_0x54e77a(0x1bf)](_0x54e77a(0x209)):undefined;return{'sessions':_0x310b36,..._0x19e7bc?{'nextCursor':_0x19e7bc}:{}};}#applyRecordToResumeIndex(_0x354e7f,_0x1d0efc){const _0x154081=_0xc75581;if(_0x1d0efc[_0x154081(0x1a2)]===_0x154081(0x1e4))_0x354e7f[_0x154081(0x228)]=![];const _0x489f9c=_0x354e7f[_0x154081(0x1bd)];if(_0x489f9c?.[_0x154081(0x1b0)]!==0xc*-0x236+-0x1e74+-0x3*-0x12ff||!Number[_0x154081(0x1a4)](_0x489f9c[_0x154081(0x1eb)]))return;if(isCompactCheckpoint(_0x1d0efc))_0x489f9c[_0x154081(0x219)]=_0x1d0efc[_0x154081(0x1e0)];if(_0x1d0efc[_0x154081(0x1a2)]!==_0x154081(0x208)||!todoItemsFromSnapshot(_0x1d0efc[_0x154081(0x218)]))return;_0x489f9c[_0x154081(0x1e8)]=_0x1d0efc[_0x154081(0x1e0)],_0x489f9c[_0x154081(0x1eb)]++;}async #readIndexedTodo(_0x51816a,_0x412548){const _0xc8173=_0xc75581,_0x1f6e2c=_0x51816a[_0xc8173(0x1bd)];if(_0x1f6e2c?.[_0xc8173(0x1b0)]!==0x19*-0x10d+-0x618+0x2*0x102f||!Number[_0xc8173(0x1a4)](_0x1f6e2c[_0xc8173(0x1eb)])||_0x1f6e2c[_0xc8173(0x1eb)]<-0x1*0x147a+-0x1b69*-0x1+0x47*-0x19)return undefined;const _0x564500=_0x412548[_0xc8173(0x1ee)](_0xa3e070=>_0xa3e070[_0xc8173(0x1a2)]===_0xc8173(0x208)&&todoItemsFromSnapshot(_0xa3e070[_0xc8173(0x218)])!==undefined);if(_0x564500&&(_0x1f6e2c[_0xc8173(0x1e8)]===undefined||_0x564500[_0xc8173(0x1e0)]!==_0x1f6e2c[_0xc8173(0x1e8)]))return undefined;if(_0x1f6e2c[_0xc8173(0x1e8)]===undefined)return _0x1f6e2c[_0xc8173(0x1eb)]===0xfa0+-0x22fd+0x135d?{'revision':0x0,'items':[]}:undefined;if(_0x1f6e2c[_0xc8173(0x1eb)]===0xab9+-0xa46+0x1*-0x73)return undefined;const _0x2bf656=_0x412548[_0xc8173(0x1ca)](_0x7fc434=>_0x7fc434[_0xc8173(0x1e0)]===_0x1f6e2c[_0xc8173(0x1e8)])??await this.#readRecordAtSequence(_0x51816a,_0x1f6e2c[_0xc8173(0x1e8)]);if(_0x2bf656?.[_0xc8173(0x1a2)]!==_0xc8173(0x208))return undefined;const _0x3a1702=todoItemsFromSnapshot(_0x2bf656[_0xc8173(0x218)]);return _0x3a1702?{'revision':_0x1f6e2c[_0xc8173(0x1eb)],'items':_0x3a1702}:undefined;}async #readRecordAtSequence(_0x49f1ad,_0x210a2f){const _0x161ce3=_0xc75581,_0x55caf6=_0x49f1ad[_0x161ce3(0x191)]?.[_0x161ce3(0x1ca)](_0x5cc6a4=>_0x5cc6a4[_0x161ce3(0x1de)]<=_0x210a2f&&_0x5cc6a4[_0x161ce3(0x15f)]>=_0x210a2f);if(!_0x55caf6)return undefined;return(await readRecords(this.#segmentPath(_0x49f1ad['id'],_0x55caf6[_0x161ce3(0x216)])))[_0x161ce3(0x1ca)](_0x5815a4=>_0x5815a4[_0x161ce3(0x1e0)]===_0x210a2f);}async #readFromSequence(_0x10d9d0,_0x254e7d){const _0x3f645b=_0xc75581,_0xb8d42=(_0x10d9d0[_0x3f645b(0x191)]??[])[_0x3f645b(0x232)](_0x2706ec=>_0x2706ec[_0x3f645b(0x15f)]>=_0x254e7d)[_0x3f645b(0x16c)]((_0x3f9a2c,_0x29d07b)=>_0x3f9a2c[_0x3f645b(0x216)]-_0x29d07b[_0x3f645b(0x216)]);if(_0xb8d42[_0x3f645b(0x19f)]===-0x481*0x7+-0x128b+0x3212)throw new MarAgentError(_0x3f645b(0x1f8),_0x3f645b(0x1e9));const _0x3e71d9=[];for(const _0x194206 of _0xb8d42)_0x3e71d9[_0x3f645b(0x164)](...(await readRecords(this.#segmentPath(_0x10d9d0['id'],_0x194206[_0x3f645b(0x216)])))[_0x3f645b(0x232)](_0x10d6f0=>_0x10d6f0[_0x3f645b(0x1e0)]>=_0x254e7d));return _0x3e71d9;}async #rebuildExecutionState(_0x52c1c8){const _0x1c58be=_0xc75581,_0x1ca51d=deriveExecutionState(await this[_0x1c58be(0x1c8)](_0x52c1c8['id']));return(_0x52c1c8[_0x1c58be(0x228)]!==_0x1ca51d[_0x1c58be(0x228)]||!sameResumeIndex(_0x52c1c8[_0x1c58be(0x1bd)],_0x1ca51d[_0x1c58be(0x1bd)]))&&(_0x52c1c8[_0x1c58be(0x228)]=_0x1ca51d[_0x1c58be(0x228)],_0x52c1c8[_0x1c58be(0x1bd)]=_0x1ca51d[_0x1c58be(0x1bd)],this.#shared[_0x1c58be(0x183)][_0x1c58be(0x1a7)]++,this.#shared[_0x1c58be(0x22b)]=!![]),{'automaticTitlePending':_0x1ca51d[_0x1c58be(0x228)],'todo':_0x1ca51d[_0x1c58be(0x1dc)],'contextRecords':_0x1ca51d[_0x1c58be(0x16b)]};}async[_0xc75581(0x15d)](_0x4f91cb){const _0x8db12=_0xc75581;this.#assertOpen();const _0x11a0a5=this.#shared[_0x8db12(0x183)][_0x8db12(0x1cc)][_0x8db12(0x1fc)](_0x496fc2=>_0x496fc2['id']===_0x4f91cb);if(_0x11a0a5<0x1bc+-0x8ad*-0x1+-0xa69)throw new MarAgentError(_0x8db12(0x15e),_0x8db12(0x211));const _0x163146=join(this.#shared[_0x8db12(0x173)],_0x8db12(0x1cc),_0x4f91cb),_0xd1745c=await sessionDirectoryExists(_0x163146);return await rm(_0x163146,{'recursive':!![],'force':!![]}),this.#shared[_0x8db12(0x191)][_0x8db12(0x15d)](_0x4f91cb),this.#shared[_0x8db12(0x183)][_0x8db12(0x1cc)][_0x8db12(0x234)](_0x11a0a5,0x3bb+0xb03*0x1+-0x31*0x4d),this.#shared[_0x8db12(0x183)][_0x8db12(0x1a7)]++,await this.#saveIndex(_0x4f91cb),{'deleted':_0xd1745c};}#assertOpen(){const _0x528b16=_0xc75581;if(this.#leaseClosed||this.#shared[_0x528b16(0x207)])throw new MarAgentError(_0x528b16(0x1bc),_0x528b16(0x160));}#segmentPath(_0x3cf56d,_0x164f4d){const _0x372140=_0xc75581;return join(this.#shared[_0x372140(0x173)],_0x372140(0x1cc),_0x3cf56d,_0x372140(0x221)+String(_0x164f4d)[_0x372140(0x1e1)](-0x4*-0x887+-0x1*0x26fb+0x4e5,'0')+_0x372140(0x174));}async #segmentPaths(_0x27f670){const _0x4c5550=_0xc75581,_0x4231f5=join(this.#shared[_0x4c5550(0x173)],_0x4c5550(0x1cc),_0x27f670),_0x52b98b=(await readdir(_0x4231f5))[_0x4c5550(0x232)](_0x164785=>/^events-\d{6}\.jsonl$/[_0x4c5550(0x168)](_0x164785))[_0x4c5550(0x16c)]();if(_0x52b98b[_0x4c5550(0x19f)]===0xe6e+-0x2678+0x180a)throw new MarAgentError(_0x4c5550(0x15e),_0x4c5550(0x211));return _0x52b98b[_0x4c5550(0x19e)](_0xda2c6f=>join(_0x4231f5,_0xda2c6f));}async #currentSegment(_0xd0564c){const _0xfa9b74=_0xc75581,_0x4b550f=this.#shared[_0xfa9b74(0x191)][_0xfa9b74(0x1b4)](_0xd0564c);if(_0x4b550f!==undefined)return _0x4b550f;const _0x417b4e=this.#shared[_0xfa9b74(0x183)][_0xfa9b74(0x1cc)][_0xfa9b74(0x1ca)](_0x1a4bfb=>_0x1a4bfb['id']===_0xd0564c),_0x1e260f=_0x417b4e?.[_0xfa9b74(0x191)]?.['at'](-(-0x1*0xb87+-0x26*-0x4d+0x1a*0x1))?.[_0xfa9b74(0x216)];if(_0x1e260f!==undefined)return this.#shared[_0xfa9b74(0x191)][_0xfa9b74(0x194)](_0xd0564c,_0x1e260f),_0x1e260f;const _0x5b4ce1=await this.#segmentPaths(_0xd0564c),_0x1d22a5=/events-(\d{6})\.jsonl$/[_0xfa9b74(0x1c0)](_0x5b4ce1['at'](-(-0x1*0x6be+0x2063+0x88c*-0x3))),_0x252301=Number(_0x1d22a5?.[0x2*-0x824+0x19c9+-0x980]??0xcee*-0x1+-0x2c*-0x47+0xbb);return this.#shared[_0xfa9b74(0x191)][_0xfa9b74(0x194)](_0xd0564c,_0x252301),_0x252301;}async #reconcileTail(_0x316286){const _0x54be56=_0xc75581,_0x39d9d6=this.#shared[_0x54be56(0x183)][_0x54be56(0x1cc)][_0x54be56(0x1ca)](_0x56021b=>_0x56021b['id']===_0x316286),_0x508dcb=await this.#segmentPaths(_0x316286),_0x1804d1=_0x508dcb['at'](-(-0x201*0xb+-0x1*-0x2b3+0x1359)),_0x2ce795=await readRecords(_0x1804d1),_0x61d305=_0x2ce795['at'](-(-0x1a*-0x11d+0x125b+-0x2f4c)),_0x2cf84e=/events-(\d{6})\.jsonl$/[_0x54be56(0x1c0)](_0x1804d1),_0x1ba9e1=Number(_0x2cf84e?.[-0x2558+0x1512+0x1047]??0x1c60+-0x211f+0x4c0);this.#shared[_0x54be56(0x191)][_0x54be56(0x194)](_0x316286,_0x1ba9e1);if(_0x61d305===undefined)return;const _0xd41f21=(await stat(_0x1804d1))[_0x54be56(0x175)],_0x44a70e=_0x2ce795[0x117a+0x924+-0x1a9e][_0x54be56(0x1e0)],_0x381aea=_0x39d9d6[_0x54be56(0x191)]?.[_0x54be56(0x1ca)](_0x109466=>_0x109466[_0x54be56(0x216)]===_0x1ba9e1),_0x1aaa4d=_0x2ce795[_0x54be56(0x1ee)](_0x1382f2=>_0x1382f2[_0x54be56(0x1a2)]===_0x54be56(0x230)&&typeof _0x1382f2[_0x54be56(0x218)][_0x54be56(0x212)]===_0x54be56(0x1a6)),_0x32dafe=_0x1aaa4d?.[_0x54be56(0x218)]?.[_0x54be56(0x212)],_0x42abf7=_0x39d9d6[_0x54be56(0x176)]<=_0x61d305[_0x54be56(0x1e0)]||_0x381aea?.[_0x54be56(0x1cd)]!==_0xd41f21||_0x32dafe!==undefined&&_0x39d9d6[_0x54be56(0x212)]!==_0x32dafe;_0x39d9d6[_0x54be56(0x176)]=Math[_0x54be56(0x185)](_0x39d9d6[_0x54be56(0x176)],_0x61d305[_0x54be56(0x1e0)]+(-0x10b9*0x1+0xb3*-0x2a+0x2e18));if(_0x32dafe!==undefined)_0x39d9d6[_0x54be56(0x212)]=_0x32dafe;_0x39d9d6[_0x54be56(0x177)]=_0x39d9d6[_0x54be56(0x177)]<_0x61d305[_0x54be56(0x200)]?_0x61d305[_0x54be56(0x200)]:_0x39d9d6[_0x54be56(0x177)];if(!_0x39d9d6[_0x54be56(0x191)])_0x39d9d6[_0x54be56(0x191)]=[];if(_0x381aea)_0x381aea[_0x54be56(0x1de)]=_0x44a70e,_0x381aea[_0x54be56(0x15f)]=_0x61d305[_0x54be56(0x1e0)],_0x381aea[_0x54be56(0x1cd)]=_0xd41f21;else _0x39d9d6[_0x54be56(0x191)][_0x54be56(0x164)]({'number':_0x1ba9e1,'firstSequence':_0x44a70e,'lastSequence':_0x61d305[_0x54be56(0x1e0)],'bytes':_0xd41f21});_0x42abf7&&(delete _0x39d9d6[_0x54be56(0x228)],delete _0x39d9d6[_0x54be56(0x1bd)],this.#shared[_0x54be56(0x183)][_0x54be56(0x1a7)]++,this.#shared[_0x54be56(0x22b)]=!![]);}async[_0xc75581(0x210)](){const _0x1ffd55=_0xc75581;if(this.#leaseClosed)return;this.#leaseClosed=!![],this.#shared[_0x1ffd55(0x1c7)]--;if(this.#shared[_0x1ffd55(0x1c7)]>0x9*-0x1bb+0x1183*0x2+0xd*-0x17f)return;if(this.#shared[_0x1ffd55(0x22b)])await this.#saveIndex();this.#shared[_0x1ffd55(0x207)]=!![],JsonlSessionStore.#instances[_0x1ffd55(0x15d)](this.#shared[_0x1ffd55(0x173)]);}}async function sessionDirectoryExists(_0x31624){const _0x1fd3e0=_0xc75581;try{return await lstat(_0x31624),!![];}catch(_0x24551a){if(_0x24551a[_0x1fd3e0(0x23b)]===_0x1fd3e0(0x1b1))return![];throw _0x24551a;}}function generatedImageFileNames(_0x3735b8){const _0x6c319c=_0xc75581,_0x38141f=new Set();for(const _0x2607e2 of _0x3735b8){if(_0x2607e2[_0x6c319c(0x1a2)]!==_0x6c319c(0x1d3)||!isObject(_0x2607e2[_0x6c319c(0x218)]))continue;const _0x1ad08f=_0x2607e2[_0x6c319c(0x218)][_0x6c319c(0x1b7)];if(!Array[_0x6c319c(0x1d1)](_0x1ad08f))continue;for(const _0x5570cd of _0x1ad08f){if(!isObject(_0x5570cd)||_0x5570cd[_0x6c319c(0x1a0)]!==_0x6c319c(0x1d8)||typeof _0x5570cd[_0x6c319c(0x16d)]!==_0x6c319c(0x1a6)||basename(_0x5570cd[_0x6c319c(0x16d)])!==_0x5570cd[_0x6c319c(0x16d)]||!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}\.png$/u[_0x6c319c(0x168)](_0x5570cd[_0x6c319c(0x16d)]))continue;_0x38141f[_0x6c319c(0x1fb)](_0x5570cd[_0x6c319c(0x16d)]);}}return[..._0x38141f];}async function stageRollbackSegments(_0x5f0b25,_0x3b6277){const _0x9d8153=_0xc75581,_0x49e452=[];for(const _0x19b2a4 of _0x3b6277){const _0x40e050=JSON[_0x9d8153(0x18f)](_0x19b2a4)+'\x0a',_0x680414=Buffer[_0x9d8153(0x15c)](_0x40e050);let _0xfbbfdd=_0x49e452['at'](-(0x1867+0x1*-0x63d+0x1*-0x1229));if(_0xfbbfdd!==undefined&&_0xfbbfdd[_0x9d8153(0x1cd)]>0x6c6+-0x1670+-0x322*-0x5&&_0xfbbfdd[_0x9d8153(0x1cd)]+_0x680414>MAX_SEGMENT_BYTES)_0xfbbfdd=undefined;_0xfbbfdd===undefined&&(_0xfbbfdd={'lines':[],'bytes':0x0,'firstSequence':_0x19b2a4[_0x9d8153(0x1e0)],'lastSequence':_0x19b2a4[_0x9d8153(0x1e0)]},_0x49e452[_0x9d8153(0x164)](_0xfbbfdd)),_0xfbbfdd[_0x9d8153(0x20f)][_0x9d8153(0x164)](_0x40e050),_0xfbbfdd[_0x9d8153(0x1cd)]+=_0x680414,_0xfbbfdd[_0x9d8153(0x15f)]=_0x19b2a4[_0x9d8153(0x1e0)];}if(_0x49e452[_0x9d8153(0x19f)]===0x5ab*-0x5+-0x1a11*0x1+0x3668)throw new MarAgentError(_0x9d8153(0x1f8),_0x9d8153(0x165));const _0x3fca66=randomUUID(),_0x28af89=[];try{for(const [_0x42f085,_0x394c8b]of _0x49e452[_0x9d8153(0x1bb)]()){const _0x231c61=_0x42f085+(0x179+0x1c7b+-0x2b9*0xb),_0x19bb70=join(_0x5f0b25,_0x9d8153(0x221)+String(_0x231c61)[_0x9d8153(0x1e1)](-0x1520+0x21b6+-0xc90,'0')+_0x9d8153(0x174)),_0x17fb68=_0x19bb70+'.'+_0x3fca66+_0x9d8153(0x172),_0x76fbc=await open(_0x17fb68,'wx',-0x6*-0x259+-0x977*-0x4+-0x3272);try{await _0x76fbc[_0x9d8153(0x1e3)](_0x394c8b[_0x9d8153(0x20f)][_0x9d8153(0x1f6)]('')),await _0x76fbc[_0x9d8153(0x1f4)]();}finally{await _0x76fbc[_0x9d8153(0x210)]();}_0x28af89[_0x9d8153(0x164)]({'path':_0x19bb70,'temporaryPath':_0x17fb68});}return{'files':_0x28af89,'segments':_0x49e452[_0x9d8153(0x19e)]((_0x483eae,_0x3df70d)=>({'number':_0x3df70d+(0x711+-0x92e+0x21e),'firstSequence':_0x483eae[_0x9d8153(0x1de)],'lastSequence':_0x483eae[_0x9d8153(0x15f)],'bytes':_0x483eae[_0x9d8153(0x1cd)]}))};}catch(_0x34e505){await Promise[_0x9d8153(0x1ba)](_0x28af89[_0x9d8153(0x19e)](_0x449cad=>rm(_0x449cad[_0x9d8153(0x16a)],{'force':!![]})))[_0x9d8153(0x1c4)](()=>undefined);throw _0x34e505;}}function _0x2082(_0x436e6f,_0x21b515){_0x436e6f=_0x436e6f-(-0x13*-0xc9+-0x280*0xa+-0x1*-0xb6f);const _0x4dd07e=_0x3cb3();let _0x1ccc87=_0x4dd07e[_0x436e6f];if(_0x2082['ZeuINk']===undefined){var _0x3b85ee=function(_0x28948a){const _0x535603='abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789+/=';let _0xc9dc47='',_0x32fe86='';for(let _0xfeb40b=-0x3*-0x5d9+0x614+-0x179f,_0x4b2581,_0x28e778,_0x5c79fa=0xbd*-0x7+0x1*-0x1f41+0x246c;_0x28e778=_0x28948a['charAt'](_0x5c79fa++);~_0x28e778&&(_0x4b2581=_0xfeb40b%(0x29f*-0x1+0x268b+-0x23e8)?_0x4b2581*(-0x3ee+-0x2494+0x28c2)+_0x28e778:_0x28e778,_0xfeb40b++%(0x13e5+0x47f*-0x3+-0x664))?_0xc9dc47+=String['fromCharCode'](0x157f*0x1+-0x573+-0xf0d&_0x4b2581>>(-(-0x1*-0x1d87+0x22*-0x6d+-0xf0b)*_0xfeb40b&0x70*-0x11+-0x1*0x21eb+0x2961)):-0x8*-0x3fd+0x1*-0x13d9+-0x1b9*0x7){_0x28e778=_0x535603['indexOf'](_0x28e778);}for(let _0x4060ac=0x2eb+0x12bc+-0x15a7,_0x43a9c3=_0xc9dc47['length'];_0x4060ac<_0x43a9c3;_0x4060ac++){_0x32fe86+='%'+('00'+_0xc9dc47['charCodeAt'](_0x4060ac)['toString'](0x1f02+0xf04+-0x2df6))['slice'](-(0xf4e+0x1380+-0x22cc));}return decodeURIComponent(_0x32fe86);};_0x2082['uTLuOW']=_0x3b85ee,_0x2082['NapWLW']={},_0x2082['ZeuINk']=!![];}const _0x58d470=_0x4dd07e[-0xb28+-0x2*0x112b+0x2d7e];_0x2082['UaUuxd']!==_0x58d470&&(_0x2082['NapWLW']={},_0x2082['UaUuxd']=_0x58d470);const _0xff5e1f=_0x2082['NapWLW'][_0x436e6f];return _0xff5e1f===undefined?(_0x1ccc87=_0x2082['uTLuOW'](_0x1ccc87),_0x2082['NapWLW'][_0x436e6f]=_0x1ccc87):_0x1ccc87=_0xff5e1f,_0x1ccc87;}async function stageUnreferencedImages(_0xdb676a,_0x498f66,_0x32e566,_0x29dd03){const _0x15caf2=_0xc75581,_0x9427d8=join(_0xdb676a,_0x498f66);let _0x5c4852;try{_0x5c4852=await readdir(_0x9427d8);}catch(_0x25ed59){if(_0x25ed59[_0x15caf2(0x23b)]===_0x15caf2(0x1b1))return[];throw _0x25ed59;}const _0x2f96b6=[];try{for(const _0x596356 of _0x5c4852){if(_0x32e566[_0x15caf2(0x204)](_0x596356))continue;const _0x3911ad=join(_0x9427d8,_0x596356),_0x23a403=join(_0x9427d8,'.'+_0x596356+'.'+_0x29dd03+_0x15caf2(0x189));await rename(_0x3911ad,_0x23a403),_0x2f96b6[_0x15caf2(0x164)]({'from':_0x23a403,'to':_0x3911ad,'trash':_0x23a403});}return _0x2f96b6;}catch(_0x1c8101){await restoreRenamedFiles(_0x2f96b6);throw _0x1c8101;}}async function restoreRenamedFiles(_0x15c727){const _0x556b0f=_0xc75581;for(const _0x3b62a0 of _0x15c727[_0x556b0f(0x1d4)]())await rename(_0x3b62a0[_0x556b0f(0x1ae)],_0x3b62a0['to'])[_0x556b0f(0x1c4)](()=>undefined);}function retainedSessionTitle(_0x3a366f,_0x774fb1){const _0x1d3e64=_0xc75581;let _0x4be902=_0x774fb1;for(const _0x2a711a of _0x3a366f){if((_0x2a711a[_0x1d3e64(0x1a2)]===_0x1d3e64(0x1ed)||_0x2a711a[_0x1d3e64(0x1a2)]===_0x1d3e64(0x230))&&isObject(_0x2a711a[_0x1d3e64(0x218)])&&typeof _0x2a711a[_0x1d3e64(0x218)][_0x1d3e64(0x212)]===_0x1d3e64(0x1a6)&&_0x2a711a[_0x1d3e64(0x218)][_0x1d3e64(0x212)][_0x1d3e64(0x1e6)]()[_0x1d3e64(0x19f)]>-0x1*-0x8dd+-0x26b1+0x1dd4)_0x4be902=_0x2a711a[_0x1d3e64(0x218)][_0x1d3e64(0x212)];}return _0x4be902;}function restoreSessionMeta(_0x141dc7,_0x1b2a07){const _0x24aad1=_0xc75581;_0x141dc7['id']=_0x1b2a07['id'],_0x141dc7[_0x24aad1(0x212)]=_0x1b2a07[_0x24aad1(0x212)],_0x141dc7[_0x24aad1(0x1ff)]=_0x1b2a07[_0x24aad1(0x1ff)],_0x141dc7[_0x24aad1(0x182)]=_0x1b2a07[_0x24aad1(0x182)],_0x141dc7[_0x24aad1(0x177)]=_0x1b2a07[_0x24aad1(0x177)],_0x141dc7[_0x24aad1(0x176)]=_0x1b2a07[_0x24aad1(0x176)];if(_0x1b2a07[_0x24aad1(0x228)]===undefined)delete _0x141dc7[_0x24aad1(0x228)];else _0x141dc7[_0x24aad1(0x228)]=_0x1b2a07[_0x24aad1(0x228)];if(_0x1b2a07[_0x24aad1(0x1bd)]===undefined)delete _0x141dc7[_0x24aad1(0x1bd)];else _0x141dc7[_0x24aad1(0x1bd)]=structuredClone(_0x1b2a07[_0x24aad1(0x1bd)]);if(_0x1b2a07[_0x24aad1(0x191)]===undefined)delete _0x141dc7[_0x24aad1(0x191)];else _0x141dc7[_0x24aad1(0x191)]=structuredClone(_0x1b2a07[_0x24aad1(0x191)]);}async function copyGeneratedImages(_0x2eba34,_0x120972,_0x141dff){const _0x51d758=_0xc75581;if(_0x141dff[_0x51d758(0x19f)]===0x24dd+0x294+-0x2771)return;const _0xec26af=join(_0x2eba34,_0x51d758(0x1b2)),_0x154614=join(_0x120972,_0x51d758(0x1b2));await mkdir(_0x154614,{'recursive':!![]});for(const _0x23098f of _0x141dff)await copyFile(join(_0xec26af,_0x23098f),join(_0x154614,_0x23098f));}function inputImageReferencesFromRecords(_0x5167dd){const _0x1d04a1=_0xc75581,_0x27c78a=new Map();for(const _0x361865 of _0x5167dd){if(_0x361865[_0x1d04a1(0x1a2)]!==_0x1d04a1(0x1e4)||!isObject(_0x361865[_0x1d04a1(0x218)]))continue;for(const _0x1752cf of inputImageReferences(_0x361865[_0x1d04a1(0x218)][_0x1d04a1(0x23a)])){const _0xac2a6d=_0x27c78a[_0x1d04a1(0x1b4)](_0x1752cf[_0x1d04a1(0x16d)]);if(_0xac2a6d!==undefined&&(_0xac2a6d[_0x1d04a1(0x23d)]!==_0x1752cf[_0x1d04a1(0x23d)]||_0xac2a6d[_0x1d04a1(0x19b)]!==_0x1752cf[_0x1d04a1(0x19b)]||_0xac2a6d[_0x1d04a1(0x1f1)]!==_0x1752cf[_0x1d04a1(0x1f1)]))throw corruptInputImageReference();_0x27c78a[_0x1d04a1(0x194)](_0x1752cf[_0x1d04a1(0x16d)],_0x1752cf);}}return[..._0x27c78a[_0x1d04a1(0x203)]()];}function inputImageReferences(_0x4f2896){const _0x5251a0=_0xc75581;if(!Array[_0x5251a0(0x1d1)](_0x4f2896))return[];const _0x5854a5=[];let _0x47bd37=0x4*-0x83f+-0xb*-0x136+0x13aa;for(const _0x335ed9 of _0x4f2896){const _0x4e6364=inputImageReference(_0x335ed9);if(_0x4e6364===undefined)continue;_0x47bd37+=_0x4e6364[_0x5251a0(0x19b)];if(_0x5854a5[_0x5251a0(0x19f)]>=MAX_INPUT_IMAGES||_0x47bd37>MAX_INPUT_IMAGES_BYTES)throw corruptInputImageReference();_0x5854a5[_0x5251a0(0x164)](_0x4e6364);}return _0x5854a5;}function inputImageReference(_0x36d718){const _0x2c85eb=_0xc75581;if(!isObject(_0x36d718)||!Object[_0x2c85eb(0x22e)](_0x36d718,_0x2c85eb(0x16d)))return undefined;if(typeof _0x36d718[_0x2c85eb(0x202)]!==_0x2c85eb(0x1a6)||typeof _0x36d718[_0x2c85eb(0x23d)]!==_0x2c85eb(0x1a6)||!INPUT_IMAGE_MIME_TYPES[_0x2c85eb(0x204)](_0x36d718[_0x2c85eb(0x23d)])||typeof _0x36d718[_0x2c85eb(0x19b)]!==_0x2c85eb(0x216)||!Number[_0x2c85eb(0x1a4)](_0x36d718[_0x2c85eb(0x19b)])||_0x36d718[_0x2c85eb(0x19b)]<=-0x1108+-0x1896+0x1*0x299e||_0x36d718[_0x2c85eb(0x19b)]>MAX_INPUT_IMAGE_BYTES||typeof _0x36d718[_0x2c85eb(0x16d)]!==_0x2c85eb(0x1a6)||!validInputImageFileName(_0x36d718[_0x2c85eb(0x16d)])||typeof _0x36d718[_0x2c85eb(0x1f1)]!==_0x2c85eb(0x1a6)||!/^[a-f0-9]{64}$/u[_0x2c85eb(0x168)](_0x36d718[_0x2c85eb(0x1f1)]))throw corruptInputImageReference();return{'name':_0x36d718[_0x2c85eb(0x202)],'fileName':_0x36d718[_0x2c85eb(0x16d)],'mimeType':_0x36d718[_0x2c85eb(0x23d)],'byteSize':_0x36d718[_0x2c85eb(0x19b)],'sha256':_0x36d718[_0x2c85eb(0x1f1)]};}function validInputImageFileName(_0x4ad807){const _0x563141=_0xc75581;return basename(_0x4ad807)===_0x4ad807&&/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}\.bin$/u[_0x563141(0x168)](_0x4ad807);}async function readInputImageBytes(_0x33902e,_0x1f5b86){const _0x4cc653=_0xc75581,_0x3c209d=join(_0x33902e,_0x1f5b86[_0x4cc653(0x16d)]);for(let _0x191970=0xe2f*0x2+-0x221e+0x10*0x5c;_0x191970<-0x88c+0x1*-0x9bf+0x124d;_0x191970++){let _0x4d217d;try{const _0x2060d8=await lstat(_0x3c209d);if(!_0x2060d8[_0x4cc653(0x217)]()||_0x2060d8[_0x4cc653(0x175)]!==_0x1f5b86[_0x4cc653(0x19b)])throw corruptInputImageReference();const _0x5630e5=process[_0x4cc653(0x18c)]===_0x4cc653(0x1f0)?constants[_0x4cc653(0x226)]:constants[_0x4cc653(0x226)]|constants[_0x4cc653(0x1db)];_0x4d217d=await open(_0x3c209d,_0x5630e5);const _0x2c35e7=await _0x4d217d[_0x4cc653(0x1a3)]();if(!_0x2c35e7[_0x4cc653(0x217)]()||_0x2c35e7[_0x4cc653(0x175)]!==_0x1f5b86[_0x4cc653(0x19b)]||_0x2c35e7[_0x4cc653(0x1aa)]!==_0x2060d8[_0x4cc653(0x1aa)]||_0x2c35e7[_0x4cc653(0x199)]!==_0x2060d8[_0x4cc653(0x199)])continue;const _0x507eb9=await readExactBytes(_0x4d217d,_0x1f5b86[_0x4cc653(0x19b)]),_0x212a13=await _0x4d217d[_0x4cc653(0x1a3)]();if(_0x212a13[_0x4cc653(0x175)]!==_0x2c35e7[_0x4cc653(0x175)]||_0x212a13[_0x4cc653(0x1d2)]!==_0x2c35e7[_0x4cc653(0x1d2)]||_0x212a13[_0x4cc653(0x15b)]!==_0x2c35e7[_0x4cc653(0x15b)])continue;if(createHash(_0x4cc653(0x1f1))[_0x4cc653(0x235)](_0x507eb9)[_0x4cc653(0x18d)](_0x4cc653(0x169))!==_0x1f5b86[_0x4cc653(0x1f1)])throw corruptInputImageReference();return _0x507eb9;}catch(_0x284ff0){if(_0x284ff0 instanceof MarAgentError)throw _0x284ff0;throw corruptInputImageReference(_0x284ff0);}finally{await _0x4d217d?.[_0x4cc653(0x210)]();}}throw corruptInputImageReference();}async function readExactBytes(_0x2c6c34,_0x18ecce){const _0x8ff40c=_0xc75581,_0x390bae=Buffer[_0x8ff40c(0x167)](_0x18ecce);let _0x6ff48b=0x25ac+-0x64d*0x1+-0x1f5f;while(_0x6ff48b<_0x18ecce){const {bytesRead:_0xa3afa4}=await _0x2c6c34[_0x8ff40c(0x1c8)](_0x390bae,_0x6ff48b,_0x18ecce-_0x6ff48b,_0x6ff48b);if(_0xa3afa4===0x1fa2+0x50a+-0x1256*0x2)throw corruptInputImageReference();_0x6ff48b+=_0xa3afa4;}const _0xcd8d62=Buffer[_0x8ff40c(0x197)](0x919+0x8c4+-0x11dc);if((await _0x2c6c34[_0x8ff40c(0x1c8)](_0xcd8d62,-0x15f9+-0x205c+0x3655,0x268d+-0x1b85+0x3*-0x3ad,_0x18ecce))[_0x8ff40c(0x1c5)]!==0x1b23+-0x330*-0x6+0xd*-0x38f)throw corruptInputImageReference();return _0x390bae;}async function copyInputImages(_0x33b10f,_0x3e3a73,_0x5ef68d){const _0x40ee15=_0xc75581;if(_0x5ef68d[_0x40ee15(0x19f)]===-0x2303+-0x222+0x1*0x2525)return;const _0x4a70e9=join(_0x33b10f,_0x40ee15(0x1ab)),_0x413f96=join(_0x3e3a73,_0x40ee15(0x1ab));await mkdir(_0x413f96,{'recursive':!![],'mode':0x1c0});for(const _0xb4d58 of _0x5ef68d){const _0x41445b=await readInputImageBytes(_0x4a70e9,_0xb4d58);await writeFile(join(_0x413f96,_0xb4d58[_0x40ee15(0x16d)]),_0x41445b,{'mode':0x180,'flag':'wx'});}}function corruptInputImageReference(_0x1fc671){const _0x315f48=_0xc75581;return new MarAgentError(_0x315f48(0x1f8),_0x315f48(0x1ea),{..._0x1fc671===undefined?{}:{'cause':_0x1fc671}});}function isObject(_0x3f755d){const _0x28d9cf=_0xc75581;return _0x3f755d!==null&&typeof _0x3f755d===_0x28d9cf(0x1e2)&&!Array[_0x28d9cf(0x1d1)](_0x3f755d);}function forkedPayload(_0x405fd2,_0x6cec3a,_0x46b94f,_0x5574e8,_0x4bc835){const _0x2f64a1=_0xc75581;if(_0x6cec3a===null||typeof _0x6cec3a!==_0x2f64a1(0x1e2)||Array[_0x2f64a1(0x1d1)](_0x6cec3a))return _0x6cec3a;const _0xbcc880={..._0x6cec3a};if(_0xbcc880[_0x2f64a1(0x1b6)]===_0x46b94f)_0xbcc880[_0x2f64a1(0x1b6)]=_0x5574e8;return _0x405fd2===_0x2f64a1(0x230)&&(_0xbcc880[_0x2f64a1(0x212)]=_0x4bc835,_0xbcc880[_0x2f64a1(0x161)]=![]),_0xbcc880;}function deriveExecutionState(_0xfbf25e){const _0x56de8f=_0xc75581;let _0xc150bc=![],_0x4d6c49=![],_0x25735a,_0x4e881f,_0x55735e=0x3e*-0x6e+-0xa5b+0x4d*0x7b,_0x409571=[];for(const _0x501601 of _0xfbf25e){if(_0x501601[_0x56de8f(0x1a2)]===_0x56de8f(0x1ed))_0xc150bc=_0x501601[_0x56de8f(0x218)]?.[_0x56de8f(0x16e)]===!![];else{if(_0x501601[_0x56de8f(0x1a2)]===_0x56de8f(0x1e4))_0x4d6c49=!![];else{if(isCompactCheckpoint(_0x501601))_0x25735a=_0x501601[_0x56de8f(0x1e0)];else{if(_0x501601[_0x56de8f(0x1a2)]===_0x56de8f(0x208)){const _0x3cbdd1=todoItemsFromSnapshot(_0x501601[_0x56de8f(0x218)]);if(!_0x3cbdd1)continue;_0x4e881f=_0x501601[_0x56de8f(0x1e0)],_0x55735e++,_0x409571=_0x3cbdd1;}}}}}const _0x184b3d=_0xfbf25e[_0x56de8f(0x17d)](isCompactCheckpoint);return{'automaticTitlePending':_0xc150bc&&!_0x4d6c49,'todo':{'revision':_0x55735e,'items':_0x409571},'contextRecords':_0x184b3d<-0x1736+-0x47*0x80+0x3ab6?[..._0xfbf25e]:_0xfbf25e[_0x56de8f(0x1c3)](_0x184b3d),'resume':{'version':0x1,..._0x25735a===undefined?{}:{'compactSequence':_0x25735a},..._0x4e881f===undefined?{}:{'todoSequence':_0x4e881f},'todoRevision':_0x55735e}};}export function compactSummaryFromCheckpoint(_0x760ef1){const _0x868360=_0xc75581;if(_0x760ef1?.[_0x868360(0x1a2)]!==_0x868360(0x1fd))return undefined;const _0x657d9c=_0x760ef1[_0x868360(0x218)];if(_0x657d9c===null||typeof _0x657d9c!==_0x868360(0x1e2)||Array[_0x868360(0x1d1)](_0x657d9c))return undefined;const _0x22d8f8=_0x657d9c[_0x868360(0x1ef)];return typeof _0x22d8f8===_0x868360(0x1a6)&&_0x22d8f8[_0x868360(0x1e6)]()[_0x868360(0x19f)]>0x261d+0xeba+-0x34d7?_0x22d8f8:undefined;}export function replacementHistoryFromCheckpoint(_0x37754a){const _0x1850ae=_0xc75581;if(compactSummaryFromCheckpoint(_0x37754a)===undefined)return undefined;const _0x56aa26=_0x37754a[_0x1850ae(0x218)][_0x1850ae(0x22d)];if(!Array[_0x1850ae(0x1d1)](_0x56aa26)||!_0x56aa26[_0x1850ae(0x1d5)](_0x3e2fca=>_0x3e2fca!==null&&typeof _0x3e2fca===_0x1850ae(0x1e2)&&_0x3e2fca[_0x1850ae(0x184)]===_0x1850ae(0x1af)&&typeof _0x3e2fca[_0x1850ae(0x193)]===_0x1850ae(0x1a6)&&(_0x3e2fca[_0x1850ae(0x1a0)]===_0x1850ae(0x1b3)||_0x3e2fca[_0x1850ae(0x1a0)]===_0x1850ae(0x1ef)&&_0x3e2fca[_0x1850ae(0x193)][_0x1850ae(0x1e6)]()[_0x1850ae(0x19f)]>0x7*0x211+0x62b*-0x1+-0x213*0x4))||_0x56aa26[_0x1850ae(0x232)](_0x5395d1=>_0x5395d1[_0x1850ae(0x1a0)]===_0x1850ae(0x1ef))[_0x1850ae(0x19f)]!==-0x1ad3+0x2131+0x9*-0xb5)return undefined;return _0x56aa26[_0x1850ae(0x19e)](({role:_0x4cee38,content:_0x3a72e0,kind:_0x2e0915})=>({'role':_0x4cee38,'content':_0x3a72e0,'kind':_0x2e0915}));}function isCompactCheckpoint(_0x2200f9){return compactSummaryFromCheckpoint(_0x2200f9)!==undefined;}function sameResumeIndex(_0x280a37,_0x534ddc){const _0x280834=_0xc75581;return _0x280a37?.[_0x280834(0x1b0)]===_0x534ddc[_0x280834(0x1b0)]&&_0x280a37[_0x280834(0x219)]===_0x534ddc[_0x280834(0x219)]&&_0x280a37[_0x280834(0x1e8)]===_0x534ddc[_0x280834(0x1e8)]&&_0x280a37[_0x280834(0x1eb)]===_0x534ddc[_0x280834(0x1eb)];}async function readRecords(_0x2aabad){const _0x5d5376=_0xc75581,_0x5dd11b=await readFile(_0x2aabad,_0x5d5376(0x222)),_0x4819b8=_0x5dd11b[_0x5d5376(0x1cf)]('\x0a');if(_0x4819b8['at'](-(0x2f*0x16+-0x1*-0x22c6+-0x26cf))==='')_0x4819b8[_0x5d5376(0x198)]();const _0xbf853d=[];for(const [_0x1ec802,_0x3ca4d0]of _0x4819b8[_0x5d5376(0x1bb)]()){if(!_0x3ca4d0)continue;try{_0xbf853d[_0x5d5376(0x164)](JSON[_0x5d5376(0x229)](_0x3ca4d0));}catch(_0x1f1b6f){if(_0x1ec802===_0x4819b8[_0x5d5376(0x19f)]-(0xce6+0x19*-0x5b+-0x402)&&!_0x5dd11b[_0x5d5376(0x1da)]('\x0a'))break;throw new MarAgentError(_0x5d5376(0x1f8),_0x5d5376(0x165),{'cause':_0x1f1b6f});}}return _0xbf853d;}async function readRecordPageFromTail(_0x463153,_0x4f2c92,_0x2d00e9){const _0x30d06e=_0xc75581,_0x1b2e8f=await open(_0x463153,'r');try{const _0x23e1d4=(await _0x1b2e8f[_0x30d06e(0x1a3)]())[_0x30d06e(0x175)];let _0x2f9dd0=_0x23e1d4,_0x2efe28=[],_0x1b7366=![],_0x4f5134=![],_0xb30389=![];const _0x894bcf=[],_0x42c6df=(_0x40fb0b,_0xa673a4)=>{const _0x224082=_0x30d06e;if(_0x40fb0b[_0x224082(0x19f)]===-0x1*-0x31c+-0x2584+0x2268)return;let _0x562fd5;try{_0x562fd5=JSON[_0x224082(0x229)](_0x40fb0b[_0x224082(0x1bf)](_0x224082(0x222)));}catch(_0x2bf616){if(_0xa673a4)return;throw new MarAgentError(_0x224082(0x1f8),_0x224082(0x165),{'cause':_0x2bf616});}if(_0x562fd5[_0x224082(0x1e0)]<_0x4f2c92)_0x894bcf[_0x224082(0x164)](_0x562fd5);};while(_0x2f9dd0>-0x1808+-0x17fe+0x3006&&_0x894bcf[_0x30d06e(0x19f)]<=_0x2d00e9){const _0x1ec011=Math[_0x30d06e(0x185)](0xddc+-0x1143*0x2+-0x17*-0xe6,_0x2f9dd0-REVERSE_READ_CHUNK_BYTES),_0x3829e3=Buffer[_0x30d06e(0x197)](_0x2f9dd0-_0x1ec011);let _0x449ab5=-0x1417+0x5*0x5aa+0x12d*-0x7;while(_0x449ab5<_0x3829e3[_0x30d06e(0x19f)]){const _0x48b0f0=await _0x1b2e8f[_0x30d06e(0x1c8)](_0x3829e3,_0x449ab5,_0x3829e3[_0x30d06e(0x19f)]-_0x449ab5,_0x1ec011+_0x449ab5);if(_0x48b0f0[_0x30d06e(0x1c5)]===0x1768+-0x904*-0x3+-0x3274)break;_0x449ab5+=_0x48b0f0[_0x30d06e(0x1c5)];}const _0xfbd8ba=_0x3829e3[_0x30d06e(0x231)](-0x105+-0x25b4+0x26b9,_0x449ab5);!_0x4f5134&&(_0x4f5134=!![],_0x1b7366=_0xfbd8ba['at'](-(-0x1d7c+0x29*-0xe+-0x1*-0x1fbb))!==0x4*-0x9d+0x6*0x665+-0x23e0);let _0x41ce1e=_0xfbd8ba[_0x30d06e(0x19f)];for(let _0x58931b=_0xfbd8ba[_0x30d06e(0x19f)]-(0x14d3+0x1159*-0x1+-0x379);_0x58931b>=0x2da+0x883*0x3+-0x1c63;_0x58931b--){if(_0xfbd8ba[_0x58931b]!==-0x1c2f+-0x6*-0x266+0xdd5)continue;const _0x170421=_0xfbd8ba[_0x30d06e(0x231)](_0x58931b+(-0x171b+0x263c+-0x4*0x3c8),_0x41ce1e),_0x3fcafa=_0x2efe28[_0x30d06e(0x19f)]===0xb3*0x5+0xf59*-0x2+0x1b33?_0x170421:Buffer[_0x30d06e(0x1b5)]([_0x170421,..._0x2efe28]);_0x42c6df(_0x3fcafa,_0x1b7366),_0x1b7366=![],_0x2efe28=[],_0x41ce1e=_0x58931b;if(_0x894bcf[_0x30d06e(0x19f)]>_0x2d00e9){_0xb30389=!![];break;}}if(!_0xb30389&&_0x41ce1e>0x102c+0x2573+-0x359f)_0x2efe28[_0x30d06e(0x1a5)](Buffer[_0x30d06e(0x1ae)](_0xfbd8ba[_0x30d06e(0x231)](0x1c3c+-0x253a+0x8fe,_0x41ce1e)));_0x2f9dd0=_0x1ec011;}if(_0x2f9dd0===0x2204+0x2434+0x8c7*-0x8&&_0x894bcf[_0x30d06e(0x19f)]<=_0x2d00e9&&_0x2efe28[_0x30d06e(0x19f)]>0x12d*0x3+-0xd06*-0x1+-0x108d)_0x42c6df(Buffer[_0x30d06e(0x1b5)](_0x2efe28),_0x1b7366);const _0x3c3f13=_0x894bcf[_0x30d06e(0x19f)]>_0x2d00e9;return{'records':_0x894bcf[_0x30d06e(0x1c3)](0xcc7*-0x1+-0xb8*-0xa+-0x35*-0x1b,_0x2d00e9)[_0x30d06e(0x19c)](),'hasEarlier':_0x3c3f13};}finally{await _0x1b2e8f[_0x30d06e(0x210)]();}}function segmentNumberFromPath(_0x13c0df){const _0x3447fa=_0xc75581,_0x5cf28a=/events-(\d{6})\.jsonl$/[_0x3447fa(0x1c0)](_0x13c0df);return _0x5cf28a===null?undefined:Number(_0x5cf28a[-0x407+0x1*-0x201d+0x2425]);}async function acquireFileLock(_0x38525d,_0x142186=_0xc75581(0x195),_0x5b76a4=-0x7e4+0x1*0x124d+0x1*0x91f){const _0x107291=_0xc75581,_0x5d7d3d=Date[_0x107291(0x196)]()+_0x5b76a4;for(;;){try{const _0x171364=await open(_0x38525d,'wx',-0xcc5*-0x1+0xfa3+0x1ec*-0xe);await _0x171364[_0x107291(0x1e3)](JSON[_0x107291(0x18f)]({'pid':process[_0x107291(0x1f9)],'createdAt':new Date()[_0x107291(0x20b)]()}));let _0x1bbe83=![];return async()=>{const _0x5bd11d=_0x107291;if(_0x1bbe83)return;_0x1bbe83=!![],await _0x171364[_0x5bd11d(0x210)](),await rm(_0x38525d,{'force':!![]});};}catch(_0x33de0b){if(await removeDeadOwner(_0x38525d))continue;if(Date[_0x107291(0x196)]()>=_0x5d7d3d)throw new MarAgentError(_0x107291(0x1b8),_0x142186,{'cause':_0x33de0b});await _0xc63b03(0x1a8a+0x1472+-0x3*0xfa1+Math[_0x107291(0x1cb)](Math[_0x107291(0x1a1)]()*(-0x475+0x23b7+-0x3*0xa63)));}}}async function removeDeadOwner(_0x5b7371){const _0x38ebdd=_0xc75581;try{const _0x2740b0=JSON[_0x38ebdd(0x229)](await readFile(_0x5b7371,_0x38ebdd(0x222)));if(typeof _0x2740b0[_0x38ebdd(0x1f9)]!==_0x38ebdd(0x216)||!Number[_0x38ebdd(0x1a4)](_0x2740b0[_0x38ebdd(0x1f9)]))return![];try{return process[_0x38ebdd(0x1d6)](_0x2740b0[_0x38ebdd(0x1f9)],-0x1e*0x101+0xfa2+0xe7c),![];}catch(_0x426f83){if(_0x426f83[_0x38ebdd(0x23b)]!==_0x38ebdd(0x1df))return![];return await rm(_0x5b7371,{'force':!![]}),!![];}}catch{return![];}}
|
|
1
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
2
|
+
import { constants } from 'node:fs';
|
|
3
|
+
import { copyFile, lstat, mkdir, open, readFile, readdir, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
4
|
+
import { basename, join } from 'node:path';
|
|
5
|
+
import { setTimeout as delay } from 'node:timers/promises';
|
|
6
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
7
|
+
import { MarAgentError } from '../error.js';
|
|
8
|
+
import { todoItemsFromSnapshot } from '../tools/todo.js';
|
|
9
|
+
import { contextGcBaseFromRecords, contextGcBaseSequence, contextGcMinimumUsageGrowth, contextGcSourceProjectionHash, latestValidContextGcCheckpoint, normalizeContextGcReplacements, parseContextGcCheckpoint, sameContextGcBase, validateContextGcCheckpoint } from './context-gc-checkpoint.js';
|
|
10
|
+
const MAX_SEGMENT_BYTES = 16 * 1024 * 1024;
|
|
11
|
+
const REVERSE_READ_CHUNK_BYTES = 64 * 1024;
|
|
12
|
+
const MAX_INPUT_IMAGES = 5;
|
|
13
|
+
const MAX_INPUT_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
14
|
+
const MAX_INPUT_IMAGES_BYTES = 10 * 1024 * 1024;
|
|
15
|
+
const INPUT_IMAGE_MIME_TYPES = new Set(['image/png', 'image/jpeg', 'image/gif', 'image/webp']);
|
|
16
|
+
export class JsonlSessionStore {
|
|
17
|
+
static #instances = new Map();
|
|
18
|
+
static #opening = new Map();
|
|
19
|
+
#shared;
|
|
20
|
+
#leaseClosed = false;
|
|
21
|
+
constructor(shared) {
|
|
22
|
+
this.#shared = shared;
|
|
23
|
+
}
|
|
24
|
+
static async open(home) {
|
|
25
|
+
const root = join(home, '.mar', 'agent');
|
|
26
|
+
const existing = JsonlSessionStore.#instances.get(root);
|
|
27
|
+
if (existing) {
|
|
28
|
+
existing.references++;
|
|
29
|
+
return new JsonlSessionStore(existing);
|
|
30
|
+
}
|
|
31
|
+
const pending = JsonlSessionStore.#opening.get(root);
|
|
32
|
+
if (pending) {
|
|
33
|
+
const shared = await pending;
|
|
34
|
+
shared.references++;
|
|
35
|
+
return new JsonlSessionStore(shared);
|
|
36
|
+
}
|
|
37
|
+
const opening = JsonlSessionStore.#openExclusive(root);
|
|
38
|
+
JsonlSessionStore.#opening.set(root, opening);
|
|
39
|
+
try {
|
|
40
|
+
const shared = await opening;
|
|
41
|
+
JsonlSessionStore.#instances.set(root, shared);
|
|
42
|
+
return new JsonlSessionStore(shared);
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
JsonlSessionStore.#opening.delete(root);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
static async #openExclusive(root) {
|
|
49
|
+
await mkdir(join(root, 'sessions'), { recursive: true });
|
|
50
|
+
let index = { version: 1, revision: 0, sessions: [] };
|
|
51
|
+
try {
|
|
52
|
+
index = JSON.parse(await readFile(join(root, 'sessions', 'index.json'), 'utf8'));
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
// A missing index starts empty; JSONL remains authoritative for explicit session reads.
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
root,
|
|
59
|
+
index,
|
|
60
|
+
pendingSessions: new Map(),
|
|
61
|
+
references: 1,
|
|
62
|
+
closed: false,
|
|
63
|
+
indexDirty: false,
|
|
64
|
+
segments: new Map()
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
async #saveIndex(deletedIds) {
|
|
68
|
+
const release = await acquireFileLock(join(this.#shared.root, 'sessions', 'index.lock'));
|
|
69
|
+
const path = join(this.#shared.root, 'sessions', 'index.json');
|
|
70
|
+
const temporary = `${path}.${randomUUID()}.tmp`;
|
|
71
|
+
try {
|
|
72
|
+
let disk = { version: 1, revision: 0, sessions: [] };
|
|
73
|
+
try {
|
|
74
|
+
disk = JSON.parse(await readFile(path, 'utf8'));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
// The first index transaction starts from an empty disk snapshot.
|
|
78
|
+
}
|
|
79
|
+
const sessions = new Map(disk.sessions.map((session) => [session.id, session]));
|
|
80
|
+
for (const session of this.#shared.index.sessions) {
|
|
81
|
+
const current = sessions.get(session.id);
|
|
82
|
+
if (!current || current.lastActivityAt <= session.lastActivityAt)
|
|
83
|
+
sessions.set(session.id, session);
|
|
84
|
+
}
|
|
85
|
+
for (const deletedId of typeof deletedIds === 'string' ? [deletedIds] : (deletedIds ?? []))
|
|
86
|
+
sessions.delete(deletedId);
|
|
87
|
+
this.#shared.index = {
|
|
88
|
+
version: 1,
|
|
89
|
+
revision: Math.max(disk.revision, this.#shared.index.revision) + 1,
|
|
90
|
+
sessions: [...sessions.values()]
|
|
91
|
+
};
|
|
92
|
+
await writeFile(temporary, JSON.stringify(this.#shared.index), { mode: 0o600 });
|
|
93
|
+
await rename(temporary, path);
|
|
94
|
+
this.#shared.indexDirty = false;
|
|
95
|
+
}
|
|
96
|
+
finally {
|
|
97
|
+
await rm(temporary, { force: true });
|
|
98
|
+
await release();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
async #refreshIndex() {
|
|
102
|
+
try {
|
|
103
|
+
const disk = JSON.parse(await readFile(join(this.#shared.root, 'sessions', 'index.json'), 'utf8'));
|
|
104
|
+
if (disk.revision <= this.#shared.index.revision)
|
|
105
|
+
return;
|
|
106
|
+
const local = new Map(this.#shared.index.sessions.map((session) => [session.id, session]));
|
|
107
|
+
for (const session of disk.sessions) {
|
|
108
|
+
const current = local.get(session.id);
|
|
109
|
+
if (!current || current.lastActivityAt < session.lastActivityAt)
|
|
110
|
+
local.set(session.id, session);
|
|
111
|
+
}
|
|
112
|
+
this.#shared.index = { ...disk, sessions: [...local.values()] };
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// A concurrent atomic replace can only leave the previous valid in-memory snapshot visible.
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
async createSession(input) {
|
|
119
|
+
this.#assertOpen();
|
|
120
|
+
const id = randomUUID();
|
|
121
|
+
const now = new Date().toISOString();
|
|
122
|
+
const meta = {
|
|
123
|
+
id,
|
|
124
|
+
title: input.title ?? 'New session',
|
|
125
|
+
workspace: input.workspace,
|
|
126
|
+
createdAt: now,
|
|
127
|
+
lastActivityAt: now,
|
|
128
|
+
source: normalizeSessionSource(input.source),
|
|
129
|
+
nextSequence: 1,
|
|
130
|
+
automaticTitlePending: input.title === undefined,
|
|
131
|
+
resume: { version: 1, todoRevision: 0 },
|
|
132
|
+
segments: []
|
|
133
|
+
};
|
|
134
|
+
await mkdir(join(this.#shared.root, 'sessions', id), { recursive: true });
|
|
135
|
+
this.#shared.segments.set(id, 1);
|
|
136
|
+
this.#shared.index = {
|
|
137
|
+
version: 1,
|
|
138
|
+
revision: this.#shared.index.revision + 1,
|
|
139
|
+
sessions: [meta, ...this.#shared.index.sessions]
|
|
140
|
+
};
|
|
141
|
+
await this.#saveIndex();
|
|
142
|
+
await this.append(id, {
|
|
143
|
+
type: 'session.created',
|
|
144
|
+
payload: {
|
|
145
|
+
title: meta.title,
|
|
146
|
+
workspace: meta.workspace,
|
|
147
|
+
automaticTitle: input.title === undefined,
|
|
148
|
+
source: meta.source
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
return meta;
|
|
152
|
+
}
|
|
153
|
+
sessionDirectory(sessionId) {
|
|
154
|
+
this.#assertOpen();
|
|
155
|
+
if (!this.#shared.index.sessions.some((session) => session.id === sessionId) &&
|
|
156
|
+
!this.#shared.pendingSessions.has(sessionId))
|
|
157
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
158
|
+
return join(this.#shared.root, 'sessions', sessionId);
|
|
159
|
+
}
|
|
160
|
+
async persistInputImages(sessionId, images) {
|
|
161
|
+
this.#assertOpen();
|
|
162
|
+
if (images.length === 0)
|
|
163
|
+
return [];
|
|
164
|
+
if (images.length > MAX_INPUT_IMAGES)
|
|
165
|
+
throw new MarAgentError('MAR_AGENT_HOST_LIMIT_EXCEEDED', 'Too many image inputs were provided.');
|
|
166
|
+
const directory = join(this.sessionDirectory(sessionId), 'input_images');
|
|
167
|
+
await mkdir(directory, { recursive: true, mode: 0o700 });
|
|
168
|
+
const written = [];
|
|
169
|
+
let temporary;
|
|
170
|
+
let totalBytes = 0;
|
|
171
|
+
try {
|
|
172
|
+
const metadata = [];
|
|
173
|
+
for (const image of images) {
|
|
174
|
+
if (!INPUT_IMAGE_MIME_TYPES.has(image.mimeType))
|
|
175
|
+
throw new MarAgentError('MAR_AGENT_INPUT_CAPABILITY_UNSUPPORTED', 'Image input MIME type is unsupported.');
|
|
176
|
+
const data = Buffer.from(image.dataBase64, 'base64');
|
|
177
|
+
totalBytes += data.byteLength;
|
|
178
|
+
if (data.byteLength === 0 ||
|
|
179
|
+
data.byteLength > MAX_INPUT_IMAGE_BYTES ||
|
|
180
|
+
totalBytes > MAX_INPUT_IMAGES_BYTES)
|
|
181
|
+
throw new MarAgentError('MAR_AGENT_HOST_LIMIT_EXCEEDED', 'Image input exceeds the supported size limit.');
|
|
182
|
+
const fileName = `${randomUUID()}.bin`;
|
|
183
|
+
temporary = join(directory, `.${fileName}.${randomUUID()}.tmp`);
|
|
184
|
+
const handle = await open(temporary, 'wx', 0o600);
|
|
185
|
+
try {
|
|
186
|
+
await handle.writeFile(data);
|
|
187
|
+
await handle.sync();
|
|
188
|
+
}
|
|
189
|
+
finally {
|
|
190
|
+
await handle.close();
|
|
191
|
+
}
|
|
192
|
+
await rename(temporary, join(directory, fileName));
|
|
193
|
+
temporary = undefined;
|
|
194
|
+
written.push(fileName);
|
|
195
|
+
metadata.push({
|
|
196
|
+
name: image.name,
|
|
197
|
+
mimeType: image.mimeType,
|
|
198
|
+
byteSize: data.byteLength,
|
|
199
|
+
fileName,
|
|
200
|
+
sha256: createHash('sha256').update(data).digest('hex')
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
return metadata;
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
if (temporary !== undefined)
|
|
207
|
+
await rm(temporary, { force: true }).catch(() => undefined);
|
|
208
|
+
await Promise.all(written.map((fileName) => rm(join(directory, fileName), { force: true }).catch(() => undefined)));
|
|
209
|
+
throw error;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async readInputImages(sessionId, value) {
|
|
213
|
+
this.#assertOpen();
|
|
214
|
+
const references = inputImageReferences(value);
|
|
215
|
+
if (references.length === 0)
|
|
216
|
+
return [];
|
|
217
|
+
const directory = join(this.sessionDirectory(sessionId), 'input_images');
|
|
218
|
+
const images = [];
|
|
219
|
+
for (const reference of references) {
|
|
220
|
+
const data = await readInputImageBytes(directory, reference);
|
|
221
|
+
images.push({ mimeType: reference.mimeType, dataBase64: data.toString('base64') });
|
|
222
|
+
}
|
|
223
|
+
return images;
|
|
224
|
+
}
|
|
225
|
+
async readInputImage(sessionId, input) {
|
|
226
|
+
this.#assertOpen();
|
|
227
|
+
if (!Number.isSafeInteger(input.sequence) ||
|
|
228
|
+
input.sequence < 1 ||
|
|
229
|
+
input.sequence >= Number.MAX_SAFE_INTEGER ||
|
|
230
|
+
!Number.isSafeInteger(input.imageIndex) ||
|
|
231
|
+
input.imageIndex < 0)
|
|
232
|
+
return undefined;
|
|
233
|
+
const page = await this.readPage(sessionId, {
|
|
234
|
+
limit: 1,
|
|
235
|
+
beforeSequence: input.sequence + 1
|
|
236
|
+
});
|
|
237
|
+
const record = page.records[0];
|
|
238
|
+
if (record?.sequence !== input.sequence ||
|
|
239
|
+
record.type !== 'turn.user' ||
|
|
240
|
+
!isObject(record.payload))
|
|
241
|
+
return undefined;
|
|
242
|
+
if (!Array.isArray(record.payload.images) || input.imageIndex >= record.payload.images.length)
|
|
243
|
+
return undefined;
|
|
244
|
+
const reference = inputImageReference(record.payload.images[input.imageIndex]);
|
|
245
|
+
if (reference === undefined)
|
|
246
|
+
return undefined;
|
|
247
|
+
const data = await readInputImageBytes(join(this.sessionDirectory(sessionId), 'input_images'), reference);
|
|
248
|
+
return {
|
|
249
|
+
name: reference.name,
|
|
250
|
+
mimeType: reference.mimeType,
|
|
251
|
+
byteSize: reference.byteSize,
|
|
252
|
+
fileName: reference.fileName,
|
|
253
|
+
sha256: reference.sha256,
|
|
254
|
+
dataBase64: data.toString('base64')
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
async removeInputImages(sessionId, images) {
|
|
258
|
+
this.#assertOpen();
|
|
259
|
+
const directory = join(this.sessionDirectory(sessionId), 'input_images');
|
|
260
|
+
await Promise.all(images.flatMap((image) => validInputImageFileName(image.fileName)
|
|
261
|
+
? [rm(join(directory, image.fileName), { force: true })]
|
|
262
|
+
: []));
|
|
263
|
+
}
|
|
264
|
+
async forkSession(sourceSessionId, input) {
|
|
265
|
+
this.#assertOpen();
|
|
266
|
+
const release = await this.acquireSessionLease(sourceSessionId);
|
|
267
|
+
try {
|
|
268
|
+
const source = this.#shared.index.sessions.find((item) => item.id === sourceSessionId);
|
|
269
|
+
if (!source)
|
|
270
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
271
|
+
const records = await this.read(sourceSessionId);
|
|
272
|
+
const boundaryIndex = input.boundaryTurnId === null
|
|
273
|
+
? -1
|
|
274
|
+
: records.findLastIndex((record) => record.turnId === input.boundaryTurnId);
|
|
275
|
+
if (input.boundaryTurnId !== null && boundaryIndex < 0)
|
|
276
|
+
throw new MarAgentError('MAR_AGENT_REWIND_TARGET_INVALID', 'Session rewind target was not found.');
|
|
277
|
+
const createdAt = new Date().toISOString();
|
|
278
|
+
const target = {
|
|
279
|
+
id: randomUUID(),
|
|
280
|
+
title: input.title,
|
|
281
|
+
workspace: source.workspace,
|
|
282
|
+
createdAt,
|
|
283
|
+
lastActivityAt: createdAt,
|
|
284
|
+
source: { type: 'user' },
|
|
285
|
+
nextSequence: 1,
|
|
286
|
+
automaticTitlePending: false,
|
|
287
|
+
resume: { version: 1, todoRevision: 0 },
|
|
288
|
+
segments: []
|
|
289
|
+
};
|
|
290
|
+
await mkdir(join(this.#shared.root, 'sessions', target.id), { recursive: true });
|
|
291
|
+
this.#shared.segments.set(target.id, 1);
|
|
292
|
+
this.#shared.pendingSessions.set(target.id, target);
|
|
293
|
+
try {
|
|
294
|
+
await this.append(target.id, {
|
|
295
|
+
type: 'session.created',
|
|
296
|
+
payload: {
|
|
297
|
+
title: target.title,
|
|
298
|
+
workspace: target.workspace,
|
|
299
|
+
automaticTitle: false,
|
|
300
|
+
source: target.source
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
const retained = input.boundaryTurnId === null ? [] : records.slice(1, boundaryIndex + 1);
|
|
304
|
+
for (const record of retained) {
|
|
305
|
+
if (record.type === 'context.gc.completed')
|
|
306
|
+
continue;
|
|
307
|
+
await this.append(target.id, {
|
|
308
|
+
type: record.type,
|
|
309
|
+
payload: forkedPayload(record.type, record.payload, sourceSessionId, target.id, input.title),
|
|
310
|
+
...(record.executionId === undefined ? {} : { executionId: record.executionId }),
|
|
311
|
+
...(record.turnId === undefined ? {} : { turnId: record.turnId }),
|
|
312
|
+
timestamp: record.timestamp
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
await copyGeneratedImages(this.sessionDirectory(sourceSessionId), this.sessionDirectory(target.id), generatedImageFileNames(retained));
|
|
316
|
+
await copyInputImages(this.sessionDirectory(sourceSessionId), this.sessionDirectory(target.id), inputImageReferencesFromRecords(retained));
|
|
317
|
+
target.lastActivityAt = target.createdAt;
|
|
318
|
+
this.#shared.pendingSessions.delete(target.id);
|
|
319
|
+
this.#shared.index = {
|
|
320
|
+
version: 1,
|
|
321
|
+
revision: this.#shared.index.revision + 1,
|
|
322
|
+
sessions: [target, ...this.#shared.index.sessions]
|
|
323
|
+
};
|
|
324
|
+
this.#shared.indexDirty = true;
|
|
325
|
+
await this.#saveIndex();
|
|
326
|
+
return {
|
|
327
|
+
id: target.id,
|
|
328
|
+
title: target.title,
|
|
329
|
+
workspace: target.workspace,
|
|
330
|
+
createdAt: target.createdAt,
|
|
331
|
+
lastActivityAt: target.createdAt,
|
|
332
|
+
source: target.source
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
catch (error) {
|
|
336
|
+
this.#shared.pendingSessions.delete(target.id);
|
|
337
|
+
const publishedIndex = this.#shared.index.sessions.findIndex((item) => item.id === target.id);
|
|
338
|
+
if (publishedIndex >= 0) {
|
|
339
|
+
this.#shared.index.sessions.splice(publishedIndex, 1);
|
|
340
|
+
this.#shared.index.revision++;
|
|
341
|
+
this.#shared.indexDirty = true;
|
|
342
|
+
await this.#saveIndex([target.id]).catch(() => undefined);
|
|
343
|
+
}
|
|
344
|
+
this.#shared.segments.delete(target.id);
|
|
345
|
+
await rm(join(this.#shared.root, 'sessions', target.id), {
|
|
346
|
+
recursive: true,
|
|
347
|
+
force: true
|
|
348
|
+
}).catch(() => undefined);
|
|
349
|
+
throw error;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
finally {
|
|
353
|
+
await release();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
async rollbackSession(sessionId, input) {
|
|
357
|
+
this.#assertOpen();
|
|
358
|
+
const release = await this.acquireSessionLease(sessionId);
|
|
359
|
+
try {
|
|
360
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
361
|
+
if (!meta)
|
|
362
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
363
|
+
const records = await this.read(sessionId);
|
|
364
|
+
if (records[0]?.type !== 'session.created')
|
|
365
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
|
|
366
|
+
const boundaryIndex = input.boundaryTurnId === null
|
|
367
|
+
? 0
|
|
368
|
+
: records.findLastIndex((record) => record.turnId === input.boundaryTurnId);
|
|
369
|
+
if (input.boundaryTurnId !== null && boundaryIndex < 0)
|
|
370
|
+
throw new MarAgentError('MAR_AGENT_ROLLBACK_TARGET_INVALID', 'Session rollback target was not found.');
|
|
371
|
+
const retained = records.slice(0, boundaryIndex + 1);
|
|
372
|
+
const staged = await stageRollbackSegments(this.sessionDirectory(sessionId), retained);
|
|
373
|
+
const transactionId = randomUUID();
|
|
374
|
+
let generatedTrash = [];
|
|
375
|
+
let inputTrash = [];
|
|
376
|
+
const originalMeta = structuredClone(meta);
|
|
377
|
+
const originalIndexRevision = this.#shared.index.revision;
|
|
378
|
+
const originalSegment = this.#shared.segments.get(sessionId);
|
|
379
|
+
const originalPaths = await this.#segmentPaths(sessionId);
|
|
380
|
+
const backups = originalPaths.map((path) => ({
|
|
381
|
+
path,
|
|
382
|
+
backup: `${path}.${transactionId}.rollback-backup`
|
|
383
|
+
}));
|
|
384
|
+
const installedPaths = [];
|
|
385
|
+
let committed = false;
|
|
386
|
+
try {
|
|
387
|
+
generatedTrash = await stageUnreferencedImages(this.sessionDirectory(sessionId), 'generated_images', new Set(generatedImageFileNames(retained)), transactionId);
|
|
388
|
+
inputTrash = await stageUnreferencedImages(this.sessionDirectory(sessionId), 'input_images', new Set(inputImageReferencesFromRecords(retained).map((image) => image.fileName)), transactionId);
|
|
389
|
+
for (const item of backups)
|
|
390
|
+
await rename(item.path, item.backup);
|
|
391
|
+
for (const item of staged.files) {
|
|
392
|
+
await rename(item.temporaryPath, item.path);
|
|
393
|
+
installedPaths.push(item.path);
|
|
394
|
+
}
|
|
395
|
+
const state = deriveExecutionState(retained);
|
|
396
|
+
const completedAt = new Date().toISOString();
|
|
397
|
+
meta.title = retainedSessionTitle(retained, meta.title);
|
|
398
|
+
meta.lastActivityAt = completedAt;
|
|
399
|
+
meta.nextSequence = (retained.at(-1)?.sequence ?? 0) + 1;
|
|
400
|
+
meta.automaticTitlePending = state.automaticTitlePending;
|
|
401
|
+
meta.resume = state.resume;
|
|
402
|
+
meta.segments = staged.segments;
|
|
403
|
+
this.#shared.segments.set(sessionId, staged.segments.at(-1)?.number ?? 1);
|
|
404
|
+
this.#shared.index.revision++;
|
|
405
|
+
this.#shared.indexDirty = true;
|
|
406
|
+
await this.#saveIndex();
|
|
407
|
+
committed = true;
|
|
408
|
+
await Promise.all([
|
|
409
|
+
...backups.map((item) => rm(item.backup, { force: true }).catch(() => undefined)),
|
|
410
|
+
...generatedTrash.map((item) => rm(item.trash, { force: true }).catch(() => undefined)),
|
|
411
|
+
...inputTrash.map((item) => rm(item.trash, { force: true }).catch(() => undefined))
|
|
412
|
+
]).catch(() => undefined);
|
|
413
|
+
return {
|
|
414
|
+
id: meta.id,
|
|
415
|
+
title: meta.title,
|
|
416
|
+
workspace: meta.workspace,
|
|
417
|
+
createdAt: meta.createdAt,
|
|
418
|
+
lastActivityAt: meta.lastActivityAt,
|
|
419
|
+
source: normalizeSessionSource(meta.source)
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
catch (error) {
|
|
423
|
+
if (!committed) {
|
|
424
|
+
await Promise.all(installedPaths.map((path) => rm(path, { force: true }))).catch(() => undefined);
|
|
425
|
+
await restoreRenamedFiles(backups.map((item) => ({ from: item.backup, to: item.path })));
|
|
426
|
+
await restoreRenamedFiles([...generatedTrash, ...inputTrash]);
|
|
427
|
+
restoreSessionMeta(meta, originalMeta);
|
|
428
|
+
this.#shared.index.revision = originalIndexRevision;
|
|
429
|
+
if (originalSegment === undefined)
|
|
430
|
+
this.#shared.segments.delete(sessionId);
|
|
431
|
+
else
|
|
432
|
+
this.#shared.segments.set(sessionId, originalSegment);
|
|
433
|
+
this.#shared.indexDirty = true;
|
|
434
|
+
}
|
|
435
|
+
throw error;
|
|
436
|
+
}
|
|
437
|
+
finally {
|
|
438
|
+
await Promise.all(staged.files.map((item) => rm(item.temporaryPath, { force: true }))).catch(() => undefined);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
finally {
|
|
442
|
+
await release();
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
async updateTitle(sessionId, title, input = {}) {
|
|
446
|
+
this.#assertOpen();
|
|
447
|
+
const normalized = title.trim();
|
|
448
|
+
if (!normalized)
|
|
449
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Session title is required.');
|
|
450
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
451
|
+
if (!meta)
|
|
452
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
453
|
+
await this.append(sessionId, {
|
|
454
|
+
type: 'session.title.updated',
|
|
455
|
+
payload: { title: normalized, automatic: true },
|
|
456
|
+
...(input.executionId ? { executionId: input.executionId } : {}),
|
|
457
|
+
...(input.turnId ? { turnId: input.turnId } : {})
|
|
458
|
+
});
|
|
459
|
+
meta.title = normalized;
|
|
460
|
+
}
|
|
461
|
+
async clearSession(sessionId) {
|
|
462
|
+
this.#assertOpen();
|
|
463
|
+
const release = await this.acquireSessionLease(sessionId);
|
|
464
|
+
try {
|
|
465
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
466
|
+
if (!meta)
|
|
467
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
468
|
+
const records = await this.read(sessionId);
|
|
469
|
+
if (records[0]?.type !== 'session.created')
|
|
470
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
|
|
471
|
+
const clearedAt = new Date().toISOString();
|
|
472
|
+
const retained = [
|
|
473
|
+
{
|
|
474
|
+
schemaVersion: 1,
|
|
475
|
+
recordId: randomUUID(),
|
|
476
|
+
sequence: 1,
|
|
477
|
+
timestamp: meta.createdAt,
|
|
478
|
+
sessionId,
|
|
479
|
+
type: 'session.created',
|
|
480
|
+
payload: {
|
|
481
|
+
title: meta.title,
|
|
482
|
+
workspace: meta.workspace,
|
|
483
|
+
automaticTitle: meta.automaticTitlePending === true,
|
|
484
|
+
source: normalizeSessionSource(meta.source)
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
];
|
|
488
|
+
const staged = await stageRollbackSegments(this.sessionDirectory(sessionId), retained);
|
|
489
|
+
const transactionId = randomUUID();
|
|
490
|
+
let generatedTrash = [];
|
|
491
|
+
let inputTrash = [];
|
|
492
|
+
const originalMeta = structuredClone(meta);
|
|
493
|
+
const originalIndexRevision = this.#shared.index.revision;
|
|
494
|
+
const originalSegment = this.#shared.segments.get(sessionId);
|
|
495
|
+
const originalPaths = await this.#segmentPaths(sessionId);
|
|
496
|
+
const backups = originalPaths.map((path) => ({
|
|
497
|
+
path,
|
|
498
|
+
backup: `${path}.${transactionId}.clear-backup`
|
|
499
|
+
}));
|
|
500
|
+
const installedPaths = [];
|
|
501
|
+
let committed = false;
|
|
502
|
+
try {
|
|
503
|
+
generatedTrash = await stageUnreferencedImages(this.sessionDirectory(sessionId), 'generated_images', new Set(), transactionId);
|
|
504
|
+
inputTrash = await stageUnreferencedImages(this.sessionDirectory(sessionId), 'input_images', new Set(), transactionId);
|
|
505
|
+
for (const item of backups)
|
|
506
|
+
await rename(item.path, item.backup);
|
|
507
|
+
for (const item of staged.files) {
|
|
508
|
+
await rename(item.temporaryPath, item.path);
|
|
509
|
+
installedPaths.push(item.path);
|
|
510
|
+
}
|
|
511
|
+
meta.lastActivityAt = clearedAt;
|
|
512
|
+
meta.nextSequence = 2;
|
|
513
|
+
meta.resume = { version: 1, todoRevision: 0 };
|
|
514
|
+
meta.segments = staged.segments;
|
|
515
|
+
this.#shared.segments.set(sessionId, 1);
|
|
516
|
+
this.#shared.index.revision++;
|
|
517
|
+
this.#shared.indexDirty = true;
|
|
518
|
+
await this.#saveIndex();
|
|
519
|
+
committed = true;
|
|
520
|
+
await Promise.all([
|
|
521
|
+
...backups.map((item) => rm(item.backup, { force: true }).catch(() => undefined)),
|
|
522
|
+
...generatedTrash.map((item) => rm(item.trash, { force: true }).catch(() => undefined)),
|
|
523
|
+
...inputTrash.map((item) => rm(item.trash, { force: true }).catch(() => undefined))
|
|
524
|
+
]).catch(() => undefined);
|
|
525
|
+
return {
|
|
526
|
+
id: meta.id,
|
|
527
|
+
title: meta.title,
|
|
528
|
+
workspace: meta.workspace,
|
|
529
|
+
createdAt: meta.createdAt,
|
|
530
|
+
lastActivityAt: meta.lastActivityAt,
|
|
531
|
+
source: normalizeSessionSource(meta.source)
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
catch (error) {
|
|
535
|
+
if (!committed) {
|
|
536
|
+
await Promise.all(installedPaths.map((path) => rm(path, { force: true }))).catch(() => undefined);
|
|
537
|
+
await restoreRenamedFiles(backups.map((item) => ({ from: item.backup, to: item.path })));
|
|
538
|
+
await restoreRenamedFiles([...generatedTrash, ...inputTrash]);
|
|
539
|
+
restoreSessionMeta(meta, originalMeta);
|
|
540
|
+
this.#shared.index.revision = originalIndexRevision;
|
|
541
|
+
if (originalSegment === undefined)
|
|
542
|
+
this.#shared.segments.delete(sessionId);
|
|
543
|
+
else
|
|
544
|
+
this.#shared.segments.set(sessionId, originalSegment);
|
|
545
|
+
this.#shared.indexDirty = true;
|
|
546
|
+
}
|
|
547
|
+
throw error;
|
|
548
|
+
}
|
|
549
|
+
finally {
|
|
550
|
+
await Promise.all(staged.files.map((item) => rm(item.temporaryPath, { force: true }))).catch(() => undefined);
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
finally {
|
|
554
|
+
await release();
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
async getSession(sessionId) {
|
|
558
|
+
this.#assertOpen();
|
|
559
|
+
await this.#refreshIndex();
|
|
560
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
561
|
+
if (!meta)
|
|
562
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
563
|
+
return {
|
|
564
|
+
id: meta.id,
|
|
565
|
+
title: meta.title,
|
|
566
|
+
workspace: meta.workspace,
|
|
567
|
+
createdAt: meta.createdAt,
|
|
568
|
+
lastActivityAt: meta.lastActivityAt,
|
|
569
|
+
source: normalizeSessionSource(meta.source)
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
async append(sessionId, input) {
|
|
573
|
+
this.#assertOpen();
|
|
574
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId) ??
|
|
575
|
+
this.#shared.pendingSessions.get(sessionId);
|
|
576
|
+
if (!meta)
|
|
577
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
578
|
+
const published = !this.#shared.pendingSessions.has(sessionId);
|
|
579
|
+
const record = {
|
|
580
|
+
schemaVersion: 1,
|
|
581
|
+
recordId: randomUUID(),
|
|
582
|
+
sequence: meta.nextSequence++,
|
|
583
|
+
timestamp: input.timestamp ?? new Date().toISOString(),
|
|
584
|
+
sessionId,
|
|
585
|
+
...(input.executionId ? { executionId: input.executionId } : {}),
|
|
586
|
+
...(input.turnId ? { turnId: input.turnId } : {}),
|
|
587
|
+
type: input.type,
|
|
588
|
+
payload: input.payload
|
|
589
|
+
};
|
|
590
|
+
const serialized = `${JSON.stringify(record)}\n`;
|
|
591
|
+
let segment = await this.#currentSegment(sessionId);
|
|
592
|
+
let path = this.#segmentPath(sessionId, segment);
|
|
593
|
+
try {
|
|
594
|
+
const current = await stat(path);
|
|
595
|
+
if (current.size > 0 && current.size + Buffer.byteLength(serialized) > MAX_SEGMENT_BYTES) {
|
|
596
|
+
segment += 1;
|
|
597
|
+
this.#shared.segments.set(sessionId, segment);
|
|
598
|
+
path = this.#segmentPath(sessionId, segment);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
catch {
|
|
602
|
+
// The first append creates the first segment.
|
|
603
|
+
}
|
|
604
|
+
const handle = await open(path, 'a', 0o600);
|
|
605
|
+
try {
|
|
606
|
+
await handle.write(serialized);
|
|
607
|
+
await handle.sync();
|
|
608
|
+
}
|
|
609
|
+
finally {
|
|
610
|
+
await handle.close();
|
|
611
|
+
}
|
|
612
|
+
const segmentMetadata = meta.segments ?? (meta.segments = []);
|
|
613
|
+
const known = segmentMetadata.find((item) => item.number === segment);
|
|
614
|
+
if (known) {
|
|
615
|
+
known.lastSequence = record.sequence;
|
|
616
|
+
known.bytes += Buffer.byteLength(serialized);
|
|
617
|
+
}
|
|
618
|
+
else
|
|
619
|
+
segmentMetadata.push({
|
|
620
|
+
number: segment,
|
|
621
|
+
firstSequence: record.sequence,
|
|
622
|
+
lastSequence: record.sequence,
|
|
623
|
+
bytes: Buffer.byteLength(serialized)
|
|
624
|
+
});
|
|
625
|
+
meta.lastActivityAt = record.timestamp;
|
|
626
|
+
this.#applyRecordToResumeIndex(meta, record);
|
|
627
|
+
if (published) {
|
|
628
|
+
this.#shared.index.revision++;
|
|
629
|
+
this.#shared.indexDirty = true;
|
|
630
|
+
}
|
|
631
|
+
return record;
|
|
632
|
+
}
|
|
633
|
+
async read(sessionId) {
|
|
634
|
+
this.#assertOpen();
|
|
635
|
+
try {
|
|
636
|
+
const records = [];
|
|
637
|
+
for (const path of await this.#segmentPaths(sessionId))
|
|
638
|
+
records.push(...(await readRecords(path)));
|
|
639
|
+
return records;
|
|
640
|
+
}
|
|
641
|
+
catch (cause) {
|
|
642
|
+
if (cause instanceof MarAgentError)
|
|
643
|
+
throw cause;
|
|
644
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.', { cause });
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
async readExecutionState(sessionId) {
|
|
648
|
+
this.#assertOpen();
|
|
649
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
650
|
+
if (!meta)
|
|
651
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
652
|
+
if (meta.resume?.version !== 1 ||
|
|
653
|
+
typeof meta.automaticTitlePending !== 'boolean' ||
|
|
654
|
+
meta.resume.compactSequence === undefined)
|
|
655
|
+
return this.#rebuildExecutionState(meta);
|
|
656
|
+
try {
|
|
657
|
+
const contextRecords = await this.#readFromSequence(meta, meta.resume.compactSequence);
|
|
658
|
+
if (contextRecords[0]?.sequence !== meta.resume.compactSequence ||
|
|
659
|
+
!isCompactCheckpoint(contextRecords[0]) ||
|
|
660
|
+
contextRecords.some((record, index) => index > 0 && isCompactCheckpoint(record)))
|
|
661
|
+
return this.#rebuildExecutionState(meta);
|
|
662
|
+
const todo = await this.#readIndexedTodo(meta, contextRecords);
|
|
663
|
+
if (!todo)
|
|
664
|
+
return this.#rebuildExecutionState(meta);
|
|
665
|
+
return {
|
|
666
|
+
automaticTitlePending: meta.automaticTitlePending,
|
|
667
|
+
todo,
|
|
668
|
+
contextRecords
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
catch {
|
|
672
|
+
return this.#rebuildExecutionState(meta);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
async readContext(sessionId) {
|
|
676
|
+
return (await this.readExecutionState(sessionId)).contextRecords;
|
|
677
|
+
}
|
|
678
|
+
async contextGcProjectionHash(sessionId, boundarySequence) {
|
|
679
|
+
this.#assertOpen();
|
|
680
|
+
const hash = contextGcSourceProjectionHash((await this.readExecutionState(sessionId)).contextRecords, boundarySequence);
|
|
681
|
+
if (!hash)
|
|
682
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC projection boundary is invalid.');
|
|
683
|
+
return hash;
|
|
684
|
+
}
|
|
685
|
+
async commitContextGc(sessionId, draft) {
|
|
686
|
+
this.#assertOpen();
|
|
687
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
688
|
+
if (!meta)
|
|
689
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
690
|
+
const records = (await this.readExecutionState(sessionId)).contextRecords;
|
|
691
|
+
const boundarySequence = records.at(-1)?.sequence;
|
|
692
|
+
if (boundarySequence === undefined || boundarySequence !== draft.boundarySequence)
|
|
693
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC projection changed before checkpoint commit.');
|
|
694
|
+
const base = contextGcBaseFromRecords(records, boundarySequence);
|
|
695
|
+
const sourceProjectionHash = contextGcSourceProjectionHash(records, boundarySequence, draft.base);
|
|
696
|
+
if (!sameContextGcBase(base, draft.base) ||
|
|
697
|
+
sourceProjectionHash === undefined ||
|
|
698
|
+
sourceProjectionHash !== draft.sourceProjectionHash)
|
|
699
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC source projection validation failed.');
|
|
700
|
+
const previous = latestValidContextGcCheckpoint(records, boundarySequence, meta.workspace);
|
|
701
|
+
if (previous && !sameContextGcBase(previous.payload.base, draft.base))
|
|
702
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint base changed before commit.');
|
|
703
|
+
if (previous) {
|
|
704
|
+
const minimumUsageGrowth = contextGcMinimumUsageGrowth(draft.trigger.contextWindowTokens);
|
|
705
|
+
if (draft.trigger.normalRolloutOrdinal - previous.payload.trigger.normalRolloutOrdinal < 2 ||
|
|
706
|
+
draft.trigger.contextInputTokens - previous.payload.trigger.contextInputTokens <
|
|
707
|
+
minimumUsageGrowth)
|
|
708
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint interval validation failed.');
|
|
709
|
+
}
|
|
710
|
+
const plannedReplacements = normalizeContextGcReplacements(draft.replacements);
|
|
711
|
+
if (!plannedReplacements || plannedReplacements.length === 0)
|
|
712
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint must contain a replacement.');
|
|
713
|
+
const replacements = normalizeContextGcReplacements([
|
|
714
|
+
...(previous?.payload.replacements ?? []),
|
|
715
|
+
...plannedReplacements
|
|
716
|
+
]);
|
|
717
|
+
if (!replacements ||
|
|
718
|
+
(previous && isDeepStrictEqual(replacements, previous.payload.replacements)))
|
|
719
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC replacement map is invalid.');
|
|
720
|
+
const payload = {
|
|
721
|
+
...structuredClone(draft),
|
|
722
|
+
checkpointId: randomUUID(),
|
|
723
|
+
generation: (previous?.payload.generation ?? 0) + 1,
|
|
724
|
+
replacements
|
|
725
|
+
};
|
|
726
|
+
const candidate = {
|
|
727
|
+
schemaVersion: 1,
|
|
728
|
+
recordId: randomUUID(),
|
|
729
|
+
sequence: boundarySequence + 1,
|
|
730
|
+
timestamp: new Date().toISOString(),
|
|
731
|
+
sessionId,
|
|
732
|
+
type: 'context.gc.completed',
|
|
733
|
+
payload
|
|
734
|
+
};
|
|
735
|
+
if (Buffer.byteLength(JSON.stringify(payload)) >= MAX_SEGMENT_BYTES ||
|
|
736
|
+
validateContextGcCheckpoint([...records, candidate], candidate, meta.workspace) === undefined)
|
|
737
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Context GC checkpoint validation failed.');
|
|
738
|
+
return this.append(sessionId, {
|
|
739
|
+
type: 'context.gc.completed',
|
|
740
|
+
payload
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
async readPage(sessionId, input = {}) {
|
|
744
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
745
|
+
if (!meta)
|
|
746
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
747
|
+
const before = input.beforeSequence ?? Number.POSITIVE_INFINITY;
|
|
748
|
+
const limit = Math.min(1000, Math.max(1, input.limit ?? 100));
|
|
749
|
+
const page = [];
|
|
750
|
+
let hasEarlier = false;
|
|
751
|
+
const paths = (await this.#segmentPaths(sessionId)).reverse();
|
|
752
|
+
for (const [pathIndex, path] of paths.entries()) {
|
|
753
|
+
const segmentNumber = segmentNumberFromPath(path);
|
|
754
|
+
const segment = meta.segments?.find((item) => item.number === segmentNumber);
|
|
755
|
+
if (segment !== undefined && segment.firstSequence >= before)
|
|
756
|
+
continue;
|
|
757
|
+
const needed = limit - page.length;
|
|
758
|
+
const window = await readRecordPageFromTail(path, before, needed);
|
|
759
|
+
page.unshift(...window.records);
|
|
760
|
+
if (window.hasEarlier) {
|
|
761
|
+
hasEarlier = true;
|
|
762
|
+
break;
|
|
763
|
+
}
|
|
764
|
+
if (page.length >= limit) {
|
|
765
|
+
hasEarlier = pathIndex < paths.length - 1;
|
|
766
|
+
break;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
const previousBeforeSequence = hasEarlier ? page[0]?.sequence : undefined;
|
|
770
|
+
return { records: page, ...(previousBeforeSequence ? { previousBeforeSequence } : {}) };
|
|
771
|
+
}
|
|
772
|
+
async compact(sessionId, input) {
|
|
773
|
+
if (!input.summary.trim())
|
|
774
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Compact summary is required.');
|
|
775
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
776
|
+
if (!meta)
|
|
777
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
778
|
+
return this.append(sessionId, {
|
|
779
|
+
type: 'compact.completed',
|
|
780
|
+
payload: {
|
|
781
|
+
summary: input.summary,
|
|
782
|
+
...(input.replacementHistory === undefined
|
|
783
|
+
? {}
|
|
784
|
+
: { replacementHistory: input.replacementHistory }),
|
|
785
|
+
...(input.environment === undefined ? {} : { environment: input.environment }),
|
|
786
|
+
boundarySequence: meta.nextSequence - 1,
|
|
787
|
+
automatic: input.automatic === true,
|
|
788
|
+
...(input.modelId === undefined ? {} : { modelId: input.modelId }),
|
|
789
|
+
...(input.contextWindowTokens === undefined
|
|
790
|
+
? {}
|
|
791
|
+
: { contextWindowTokens: input.contextWindowTokens }),
|
|
792
|
+
...(input.usage === undefined ? {} : { usage: input.usage })
|
|
793
|
+
},
|
|
794
|
+
...(input.executionId ? { executionId: input.executionId } : {}),
|
|
795
|
+
...(input.turnId ? { turnId: input.turnId } : {})
|
|
796
|
+
});
|
|
797
|
+
}
|
|
798
|
+
async acquireSessionLease(sessionId) {
|
|
799
|
+
this.#assertOpen();
|
|
800
|
+
await this.#refreshIndex();
|
|
801
|
+
if (!this.#shared.index.sessions.some((item) => item.id === sessionId))
|
|
802
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
803
|
+
const path = join(this.#shared.root, 'sessions', sessionId, 'lock');
|
|
804
|
+
const release = await acquireFileLock(path, 'Session already has a writer.', 0);
|
|
805
|
+
try {
|
|
806
|
+
await this.#reconcileTail(sessionId);
|
|
807
|
+
}
|
|
808
|
+
catch (error) {
|
|
809
|
+
await release();
|
|
810
|
+
throw error;
|
|
811
|
+
}
|
|
812
|
+
return async () => {
|
|
813
|
+
try {
|
|
814
|
+
if (this.#shared.indexDirty)
|
|
815
|
+
await this.#saveIndex();
|
|
816
|
+
}
|
|
817
|
+
finally {
|
|
818
|
+
await release();
|
|
819
|
+
}
|
|
820
|
+
};
|
|
821
|
+
}
|
|
822
|
+
async list(input = {}) {
|
|
823
|
+
this.#assertOpen();
|
|
824
|
+
await this.#refreshIndex();
|
|
825
|
+
const filter = sessionListFilter(input);
|
|
826
|
+
const start = decodeSessionListCursor(input.cursor, this.#shared.index.revision, filter);
|
|
827
|
+
const limit = Math.min(200, Math.max(1, input.limit ?? 50));
|
|
828
|
+
const ordered = this.#shared.index.sessions
|
|
829
|
+
.filter((session) => sessionMatchesFilter(session, filter))
|
|
830
|
+
.sort((a, b) => b.lastActivityAt.localeCompare(a.lastActivityAt));
|
|
831
|
+
const sessions = ordered.slice(start, start + limit).map((session) => ({
|
|
832
|
+
id: session.id,
|
|
833
|
+
title: session.title,
|
|
834
|
+
workspace: session.workspace,
|
|
835
|
+
createdAt: session.createdAt,
|
|
836
|
+
lastActivityAt: session.lastActivityAt,
|
|
837
|
+
source: normalizeSessionSource(session.source)
|
|
838
|
+
}));
|
|
839
|
+
const next = start + limit < ordered.length
|
|
840
|
+
? encodeSessionListCursor(this.#shared.index.revision, start + limit, filter)
|
|
841
|
+
: undefined;
|
|
842
|
+
return { sessions, ...(next ? { nextCursor: next } : {}) };
|
|
843
|
+
}
|
|
844
|
+
async sessionTree(sessionId) {
|
|
845
|
+
this.#assertOpen();
|
|
846
|
+
await this.#refreshIndex();
|
|
847
|
+
if (!this.#shared.index.sessions.some((session) => session.id === sessionId))
|
|
848
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
849
|
+
return sessionTreeIds(this.#shared.index.sessions, sessionId);
|
|
850
|
+
}
|
|
851
|
+
#applyRecordToResumeIndex(meta, record) {
|
|
852
|
+
if (record.type === 'turn.user')
|
|
853
|
+
meta.automaticTitlePending = false;
|
|
854
|
+
const resume = meta.resume;
|
|
855
|
+
if (resume?.version !== 1 || !Number.isSafeInteger(resume.todoRevision))
|
|
856
|
+
return;
|
|
857
|
+
if (isCompactCheckpoint(record)) {
|
|
858
|
+
resume.compactSequence = record.sequence;
|
|
859
|
+
delete resume.gcSequence;
|
|
860
|
+
delete resume.gcGeneration;
|
|
861
|
+
delete resume.gcBaseSequence;
|
|
862
|
+
}
|
|
863
|
+
else {
|
|
864
|
+
const checkpoint = parseContextGcCheckpoint(record);
|
|
865
|
+
if (checkpoint) {
|
|
866
|
+
resume.gcSequence = record.sequence;
|
|
867
|
+
resume.gcGeneration = checkpoint.generation;
|
|
868
|
+
resume.gcBaseSequence = contextGcBaseSequence(checkpoint.base);
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
if (record.type !== 'todo.updated' || !todoItemsFromSnapshot(record.payload))
|
|
872
|
+
return;
|
|
873
|
+
resume.todoSequence = record.sequence;
|
|
874
|
+
resume.todoRevision++;
|
|
875
|
+
}
|
|
876
|
+
async #readIndexedTodo(meta, contextRecords) {
|
|
877
|
+
const resume = meta.resume;
|
|
878
|
+
if (resume?.version !== 1 ||
|
|
879
|
+
!Number.isSafeInteger(resume.todoRevision) ||
|
|
880
|
+
resume.todoRevision < 0)
|
|
881
|
+
return undefined;
|
|
882
|
+
const latestContextTodo = contextRecords.findLast((record) => record.type === 'todo.updated' && todoItemsFromSnapshot(record.payload) !== undefined);
|
|
883
|
+
if (latestContextTodo &&
|
|
884
|
+
(resume.todoSequence === undefined || latestContextTodo.sequence !== resume.todoSequence))
|
|
885
|
+
return undefined;
|
|
886
|
+
if (resume.todoSequence === undefined)
|
|
887
|
+
return resume.todoRevision === 0 ? { revision: 0, items: [] } : undefined;
|
|
888
|
+
if (resume.todoRevision === 0)
|
|
889
|
+
return undefined;
|
|
890
|
+
const record = contextRecords.find((item) => item.sequence === resume.todoSequence) ??
|
|
891
|
+
(await this.#readRecordAtSequence(meta, resume.todoSequence));
|
|
892
|
+
if (record?.type !== 'todo.updated')
|
|
893
|
+
return undefined;
|
|
894
|
+
const items = todoItemsFromSnapshot(record.payload);
|
|
895
|
+
return items ? { revision: resume.todoRevision, items } : undefined;
|
|
896
|
+
}
|
|
897
|
+
async #readRecordAtSequence(meta, sequence) {
|
|
898
|
+
const segment = meta.segments?.find((item) => item.firstSequence <= sequence && item.lastSequence >= sequence);
|
|
899
|
+
if (!segment)
|
|
900
|
+
return undefined;
|
|
901
|
+
return (await readRecords(this.#segmentPath(meta.id, segment.number))).find((record) => record.sequence === sequence);
|
|
902
|
+
}
|
|
903
|
+
async #readFromSequence(meta, sequence) {
|
|
904
|
+
const segments = (meta.segments ?? [])
|
|
905
|
+
.filter((item) => item.lastSequence >= sequence)
|
|
906
|
+
.sort((left, right) => left.number - right.number);
|
|
907
|
+
if (segments.length === 0)
|
|
908
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session resume index is invalid.');
|
|
909
|
+
const records = [];
|
|
910
|
+
for (const segment of segments)
|
|
911
|
+
records.push(...(await readRecords(this.#segmentPath(meta.id, segment.number))).filter((record) => record.sequence >= sequence));
|
|
912
|
+
return records;
|
|
913
|
+
}
|
|
914
|
+
async #rebuildExecutionState(meta) {
|
|
915
|
+
const state = deriveExecutionState(await this.read(meta.id));
|
|
916
|
+
if (meta.automaticTitlePending !== state.automaticTitlePending ||
|
|
917
|
+
!sameResumeIndex(meta.resume, state.resume)) {
|
|
918
|
+
meta.automaticTitlePending = state.automaticTitlePending;
|
|
919
|
+
meta.resume = state.resume;
|
|
920
|
+
this.#shared.index.revision++;
|
|
921
|
+
this.#shared.indexDirty = true;
|
|
922
|
+
}
|
|
923
|
+
return {
|
|
924
|
+
automaticTitlePending: state.automaticTitlePending,
|
|
925
|
+
todo: state.todo,
|
|
926
|
+
contextRecords: state.contextRecords
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
async delete(sessionId) {
|
|
930
|
+
this.#assertOpen();
|
|
931
|
+
await this.#refreshIndex();
|
|
932
|
+
const tree = sessionTreeIds(this.#shared.index.sessions, sessionId);
|
|
933
|
+
if (tree.length === 0)
|
|
934
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
935
|
+
const releases = [];
|
|
936
|
+
try {
|
|
937
|
+
for (const id of tree.toReversed())
|
|
938
|
+
if (await sessionDirectoryExists(join(this.#shared.root, 'sessions', id)))
|
|
939
|
+
releases.push(await this.acquireSessionLease(id));
|
|
940
|
+
}
|
|
941
|
+
catch (error) {
|
|
942
|
+
await Promise.allSettled(releases.toReversed().map((release) => release()));
|
|
943
|
+
throw error;
|
|
944
|
+
}
|
|
945
|
+
try {
|
|
946
|
+
const deleted = await sessionDirectoryExists(join(this.#shared.root, 'sessions', sessionId));
|
|
947
|
+
for (const id of tree.toReversed()) {
|
|
948
|
+
await rm(join(this.#shared.root, 'sessions', id), { recursive: true, force: true });
|
|
949
|
+
this.#shared.segments.delete(id);
|
|
950
|
+
}
|
|
951
|
+
const deletedSet = new Set(tree);
|
|
952
|
+
this.#shared.index.sessions = this.#shared.index.sessions.filter((session) => !deletedSet.has(session.id));
|
|
953
|
+
this.#shared.index.revision++;
|
|
954
|
+
await this.#saveIndex(tree);
|
|
955
|
+
return { deleted };
|
|
956
|
+
}
|
|
957
|
+
finally {
|
|
958
|
+
await Promise.allSettled(releases.toReversed().map((release) => release()));
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
#assertOpen() {
|
|
962
|
+
if (this.#leaseClosed || this.#shared.closed)
|
|
963
|
+
throw new MarAgentError('MAR_AGENT_DISPOSED', 'Session store is closed.');
|
|
964
|
+
}
|
|
965
|
+
#segmentPath(sessionId, segment) {
|
|
966
|
+
return join(this.#shared.root, 'sessions', sessionId, `events-${String(segment).padStart(6, '0')}.jsonl`);
|
|
967
|
+
}
|
|
968
|
+
async #segmentPaths(sessionId) {
|
|
969
|
+
const directory = join(this.#shared.root, 'sessions', sessionId);
|
|
970
|
+
const names = (await readdir(directory))
|
|
971
|
+
.filter((name) => /^events-\d{6}\.jsonl$/.test(name))
|
|
972
|
+
.sort();
|
|
973
|
+
if (names.length === 0)
|
|
974
|
+
throw new MarAgentError('MAR_AGENT_SESSION_NOT_FOUND', 'Session was not found.');
|
|
975
|
+
return names.map((name) => join(directory, name));
|
|
976
|
+
}
|
|
977
|
+
async #currentSegment(sessionId) {
|
|
978
|
+
const cached = this.#shared.segments.get(sessionId);
|
|
979
|
+
if (cached !== undefined)
|
|
980
|
+
return cached;
|
|
981
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
982
|
+
const indexed = meta?.segments?.at(-1)?.number;
|
|
983
|
+
if (indexed !== undefined) {
|
|
984
|
+
this.#shared.segments.set(sessionId, indexed);
|
|
985
|
+
return indexed;
|
|
986
|
+
}
|
|
987
|
+
const paths = await this.#segmentPaths(sessionId);
|
|
988
|
+
const match = /events-(\d{6})\.jsonl$/.exec(paths.at(-1));
|
|
989
|
+
const segment = Number(match?.[1] ?? 1);
|
|
990
|
+
this.#shared.segments.set(sessionId, segment);
|
|
991
|
+
return segment;
|
|
992
|
+
}
|
|
993
|
+
async #reconcileTail(sessionId) {
|
|
994
|
+
const meta = this.#shared.index.sessions.find((item) => item.id === sessionId);
|
|
995
|
+
const paths = await this.#segmentPaths(sessionId);
|
|
996
|
+
const latestPath = paths.at(-1);
|
|
997
|
+
const records = await readRecords(latestPath);
|
|
998
|
+
const last = records.at(-1);
|
|
999
|
+
const match = /events-(\d{6})\.jsonl$/.exec(latestPath);
|
|
1000
|
+
const segment = Number(match?.[1] ?? 1);
|
|
1001
|
+
this.#shared.segments.set(sessionId, segment);
|
|
1002
|
+
if (last === undefined)
|
|
1003
|
+
return;
|
|
1004
|
+
const bytes = (await stat(latestPath)).size;
|
|
1005
|
+
const firstSequence = records[0].sequence;
|
|
1006
|
+
const known = meta.segments?.find((item) => item.number === segment);
|
|
1007
|
+
const titleRecord = records.findLast((record) => record.type === 'session.title.updated' &&
|
|
1008
|
+
typeof record.payload.title === 'string');
|
|
1009
|
+
const recoveredTitle = titleRecord?.payload?.title;
|
|
1010
|
+
const changed = meta.nextSequence <= last.sequence ||
|
|
1011
|
+
known?.bytes !== bytes ||
|
|
1012
|
+
(recoveredTitle !== undefined && meta.title !== recoveredTitle);
|
|
1013
|
+
meta.nextSequence = Math.max(meta.nextSequence, last.sequence + 1);
|
|
1014
|
+
if (recoveredTitle !== undefined)
|
|
1015
|
+
meta.title = recoveredTitle;
|
|
1016
|
+
meta.lastActivityAt =
|
|
1017
|
+
meta.lastActivityAt < last.timestamp ? last.timestamp : meta.lastActivityAt;
|
|
1018
|
+
if (!meta.segments)
|
|
1019
|
+
meta.segments = [];
|
|
1020
|
+
if (known) {
|
|
1021
|
+
known.firstSequence = firstSequence;
|
|
1022
|
+
known.lastSequence = last.sequence;
|
|
1023
|
+
known.bytes = bytes;
|
|
1024
|
+
}
|
|
1025
|
+
else
|
|
1026
|
+
meta.segments.push({ number: segment, firstSequence, lastSequence: last.sequence, bytes });
|
|
1027
|
+
if (changed) {
|
|
1028
|
+
delete meta.automaticTitlePending;
|
|
1029
|
+
delete meta.resume;
|
|
1030
|
+
this.#shared.index.revision++;
|
|
1031
|
+
this.#shared.indexDirty = true;
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
async close() {
|
|
1035
|
+
if (this.#leaseClosed)
|
|
1036
|
+
return;
|
|
1037
|
+
this.#leaseClosed = true;
|
|
1038
|
+
this.#shared.references--;
|
|
1039
|
+
if (this.#shared.references > 0)
|
|
1040
|
+
return;
|
|
1041
|
+
if (this.#shared.indexDirty)
|
|
1042
|
+
await this.#saveIndex();
|
|
1043
|
+
this.#shared.closed = true;
|
|
1044
|
+
JsonlSessionStore.#instances.delete(this.#shared.root);
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
async function sessionDirectoryExists(path) {
|
|
1048
|
+
try {
|
|
1049
|
+
await lstat(path);
|
|
1050
|
+
return true;
|
|
1051
|
+
}
|
|
1052
|
+
catch (error) {
|
|
1053
|
+
if (error.code === 'ENOENT')
|
|
1054
|
+
return false;
|
|
1055
|
+
throw error;
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
function generatedImageFileNames(records) {
|
|
1059
|
+
const names = new Set();
|
|
1060
|
+
for (const record of records) {
|
|
1061
|
+
if (record.type !== 'tool.completed' || !isObject(record.payload))
|
|
1062
|
+
continue;
|
|
1063
|
+
const artifacts = record.payload.artifacts;
|
|
1064
|
+
if (!Array.isArray(artifacts))
|
|
1065
|
+
continue;
|
|
1066
|
+
for (const artifact of artifacts) {
|
|
1067
|
+
if (!isObject(artifact) ||
|
|
1068
|
+
artifact.kind !== 'image' ||
|
|
1069
|
+
typeof artifact.fileName !== 'string' ||
|
|
1070
|
+
basename(artifact.fileName) !== artifact.fileName ||
|
|
1071
|
+
!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}\.png$/u.test(artifact.fileName))
|
|
1072
|
+
continue;
|
|
1073
|
+
names.add(artifact.fileName);
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
return [...names];
|
|
1077
|
+
}
|
|
1078
|
+
async function stageRollbackSegments(sessionDirectory, records) {
|
|
1079
|
+
const groups = [];
|
|
1080
|
+
for (const record of records) {
|
|
1081
|
+
const line = `${JSON.stringify(record)}\n`;
|
|
1082
|
+
const bytes = Buffer.byteLength(line);
|
|
1083
|
+
let group = groups.at(-1);
|
|
1084
|
+
if (group !== undefined && group.bytes > 0 && group.bytes + bytes > MAX_SEGMENT_BYTES)
|
|
1085
|
+
group = undefined;
|
|
1086
|
+
if (group === undefined) {
|
|
1087
|
+
group = {
|
|
1088
|
+
lines: [],
|
|
1089
|
+
bytes: 0,
|
|
1090
|
+
firstSequence: record.sequence,
|
|
1091
|
+
lastSequence: record.sequence
|
|
1092
|
+
};
|
|
1093
|
+
groups.push(group);
|
|
1094
|
+
}
|
|
1095
|
+
group.lines.push(line);
|
|
1096
|
+
group.bytes += bytes;
|
|
1097
|
+
group.lastSequence = record.sequence;
|
|
1098
|
+
}
|
|
1099
|
+
if (groups.length === 0)
|
|
1100
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.');
|
|
1101
|
+
const transactionId = randomUUID();
|
|
1102
|
+
const files = [];
|
|
1103
|
+
try {
|
|
1104
|
+
for (const [index, group] of groups.entries()) {
|
|
1105
|
+
const number = index + 1;
|
|
1106
|
+
const path = join(sessionDirectory, `events-${String(number).padStart(6, '0')}.jsonl`);
|
|
1107
|
+
const temporaryPath = `${path}.${transactionId}.rollback-tmp`;
|
|
1108
|
+
const handle = await open(temporaryPath, 'wx', 0o600);
|
|
1109
|
+
try {
|
|
1110
|
+
await handle.writeFile(group.lines.join(''));
|
|
1111
|
+
await handle.sync();
|
|
1112
|
+
}
|
|
1113
|
+
finally {
|
|
1114
|
+
await handle.close();
|
|
1115
|
+
}
|
|
1116
|
+
files.push({ path, temporaryPath });
|
|
1117
|
+
}
|
|
1118
|
+
return {
|
|
1119
|
+
files,
|
|
1120
|
+
segments: groups.map((group, index) => ({
|
|
1121
|
+
number: index + 1,
|
|
1122
|
+
firstSequence: group.firstSequence,
|
|
1123
|
+
lastSequence: group.lastSequence,
|
|
1124
|
+
bytes: group.bytes
|
|
1125
|
+
}))
|
|
1126
|
+
};
|
|
1127
|
+
}
|
|
1128
|
+
catch (error) {
|
|
1129
|
+
await Promise.all(files.map((item) => rm(item.temporaryPath, { force: true }))).catch(() => undefined);
|
|
1130
|
+
throw error;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
async function stageUnreferencedImages(sessionDirectory, directoryName, retained, transactionId) {
|
|
1134
|
+
const directory = join(sessionDirectory, directoryName);
|
|
1135
|
+
let names;
|
|
1136
|
+
try {
|
|
1137
|
+
names = await readdir(directory);
|
|
1138
|
+
}
|
|
1139
|
+
catch (error) {
|
|
1140
|
+
if (error.code === 'ENOENT')
|
|
1141
|
+
return [];
|
|
1142
|
+
throw error;
|
|
1143
|
+
}
|
|
1144
|
+
const moved = [];
|
|
1145
|
+
try {
|
|
1146
|
+
for (const name of names) {
|
|
1147
|
+
if (retained.has(name))
|
|
1148
|
+
continue;
|
|
1149
|
+
const from = join(directory, name);
|
|
1150
|
+
const trash = join(directory, `.${name}.${transactionId}.rollback-trash`);
|
|
1151
|
+
await rename(from, trash);
|
|
1152
|
+
moved.push({ from: trash, to: from, trash });
|
|
1153
|
+
}
|
|
1154
|
+
return moved;
|
|
1155
|
+
}
|
|
1156
|
+
catch (error) {
|
|
1157
|
+
await restoreRenamedFiles(moved);
|
|
1158
|
+
throw error;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
async function restoreRenamedFiles(files) {
|
|
1162
|
+
for (const file of files.toReversed())
|
|
1163
|
+
await rename(file.from, file.to).catch(() => undefined);
|
|
1164
|
+
}
|
|
1165
|
+
function retainedSessionTitle(records, fallback) {
|
|
1166
|
+
let title = fallback;
|
|
1167
|
+
for (const record of records) {
|
|
1168
|
+
if ((record.type === 'session.created' || record.type === 'session.title.updated') &&
|
|
1169
|
+
isObject(record.payload) &&
|
|
1170
|
+
typeof record.payload.title === 'string' &&
|
|
1171
|
+
record.payload.title.trim().length > 0)
|
|
1172
|
+
title = record.payload.title;
|
|
1173
|
+
}
|
|
1174
|
+
return title;
|
|
1175
|
+
}
|
|
1176
|
+
function restoreSessionMeta(meta, original) {
|
|
1177
|
+
meta.id = original.id;
|
|
1178
|
+
meta.title = original.title;
|
|
1179
|
+
meta.workspace = original.workspace;
|
|
1180
|
+
meta.createdAt = original.createdAt;
|
|
1181
|
+
meta.lastActivityAt = original.lastActivityAt;
|
|
1182
|
+
if (original.source === undefined)
|
|
1183
|
+
delete meta.source;
|
|
1184
|
+
else
|
|
1185
|
+
meta.source = structuredClone(original.source);
|
|
1186
|
+
meta.nextSequence = original.nextSequence;
|
|
1187
|
+
if (original.automaticTitlePending === undefined)
|
|
1188
|
+
delete meta.automaticTitlePending;
|
|
1189
|
+
else
|
|
1190
|
+
meta.automaticTitlePending = original.automaticTitlePending;
|
|
1191
|
+
if (original.resume === undefined)
|
|
1192
|
+
delete meta.resume;
|
|
1193
|
+
else
|
|
1194
|
+
meta.resume = structuredClone(original.resume);
|
|
1195
|
+
if (original.segments === undefined)
|
|
1196
|
+
delete meta.segments;
|
|
1197
|
+
else
|
|
1198
|
+
meta.segments = structuredClone(original.segments);
|
|
1199
|
+
}
|
|
1200
|
+
async function copyGeneratedImages(sourceSessionDirectory, targetSessionDirectory, fileNames) {
|
|
1201
|
+
if (fileNames.length === 0)
|
|
1202
|
+
return;
|
|
1203
|
+
const source = join(sourceSessionDirectory, 'generated_images');
|
|
1204
|
+
const target = join(targetSessionDirectory, 'generated_images');
|
|
1205
|
+
await mkdir(target, { recursive: true });
|
|
1206
|
+
for (const fileName of fileNames)
|
|
1207
|
+
await copyFile(join(source, fileName), join(target, fileName));
|
|
1208
|
+
}
|
|
1209
|
+
function inputImageReferencesFromRecords(records) {
|
|
1210
|
+
const references = new Map();
|
|
1211
|
+
for (const record of records) {
|
|
1212
|
+
if (record.type !== 'turn.user' || !isObject(record.payload))
|
|
1213
|
+
continue;
|
|
1214
|
+
for (const reference of inputImageReferences(record.payload.images)) {
|
|
1215
|
+
const existing = references.get(reference.fileName);
|
|
1216
|
+
if (existing !== undefined &&
|
|
1217
|
+
(existing.mimeType !== reference.mimeType ||
|
|
1218
|
+
existing.byteSize !== reference.byteSize ||
|
|
1219
|
+
existing.sha256 !== reference.sha256))
|
|
1220
|
+
throw corruptInputImageReference();
|
|
1221
|
+
references.set(reference.fileName, reference);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
return [...references.values()];
|
|
1225
|
+
}
|
|
1226
|
+
function inputImageReferences(value) {
|
|
1227
|
+
if (!Array.isArray(value))
|
|
1228
|
+
return [];
|
|
1229
|
+
const references = [];
|
|
1230
|
+
let totalBytes = 0;
|
|
1231
|
+
for (const image of value) {
|
|
1232
|
+
const reference = inputImageReference(image);
|
|
1233
|
+
if (reference === undefined)
|
|
1234
|
+
continue;
|
|
1235
|
+
totalBytes += reference.byteSize;
|
|
1236
|
+
if (references.length >= MAX_INPUT_IMAGES || totalBytes > MAX_INPUT_IMAGES_BYTES)
|
|
1237
|
+
throw corruptInputImageReference();
|
|
1238
|
+
references.push(reference);
|
|
1239
|
+
}
|
|
1240
|
+
return references;
|
|
1241
|
+
}
|
|
1242
|
+
function inputImageReference(value) {
|
|
1243
|
+
if (!isObject(value) || !Object.hasOwn(value, 'fileName'))
|
|
1244
|
+
return undefined;
|
|
1245
|
+
if (typeof value.name !== 'string' ||
|
|
1246
|
+
typeof value.mimeType !== 'string' ||
|
|
1247
|
+
!INPUT_IMAGE_MIME_TYPES.has(value.mimeType) ||
|
|
1248
|
+
typeof value.byteSize !== 'number' ||
|
|
1249
|
+
!Number.isSafeInteger(value.byteSize) ||
|
|
1250
|
+
value.byteSize <= 0 ||
|
|
1251
|
+
value.byteSize > MAX_INPUT_IMAGE_BYTES ||
|
|
1252
|
+
typeof value.fileName !== 'string' ||
|
|
1253
|
+
!validInputImageFileName(value.fileName) ||
|
|
1254
|
+
typeof value.sha256 !== 'string' ||
|
|
1255
|
+
!/^[a-f0-9]{64}$/u.test(value.sha256))
|
|
1256
|
+
throw corruptInputImageReference();
|
|
1257
|
+
return {
|
|
1258
|
+
name: value.name,
|
|
1259
|
+
fileName: value.fileName,
|
|
1260
|
+
mimeType: value.mimeType,
|
|
1261
|
+
byteSize: value.byteSize,
|
|
1262
|
+
sha256: value.sha256
|
|
1263
|
+
};
|
|
1264
|
+
}
|
|
1265
|
+
function validInputImageFileName(fileName) {
|
|
1266
|
+
return (basename(fileName) === fileName && /^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}\.bin$/u.test(fileName));
|
|
1267
|
+
}
|
|
1268
|
+
async function readInputImageBytes(directory, reference) {
|
|
1269
|
+
const path = join(directory, reference.fileName);
|
|
1270
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
1271
|
+
let handle;
|
|
1272
|
+
try {
|
|
1273
|
+
const before = await lstat(path);
|
|
1274
|
+
if (!before.isFile() || before.size !== reference.byteSize)
|
|
1275
|
+
throw corruptInputImageReference();
|
|
1276
|
+
const flags = process.platform === 'win32'
|
|
1277
|
+
? constants.O_RDONLY
|
|
1278
|
+
: constants.O_RDONLY | constants.O_NOFOLLOW;
|
|
1279
|
+
handle = await open(path, flags);
|
|
1280
|
+
const opened = await handle.stat();
|
|
1281
|
+
if (!opened.isFile() ||
|
|
1282
|
+
opened.size !== reference.byteSize ||
|
|
1283
|
+
opened.dev !== before.dev ||
|
|
1284
|
+
opened.ino !== before.ino)
|
|
1285
|
+
continue;
|
|
1286
|
+
const data = await readExactBytes(handle, reference.byteSize);
|
|
1287
|
+
const after = await handle.stat();
|
|
1288
|
+
if (after.size !== opened.size ||
|
|
1289
|
+
after.mtimeMs !== opened.mtimeMs ||
|
|
1290
|
+
after.ctimeMs !== opened.ctimeMs)
|
|
1291
|
+
continue;
|
|
1292
|
+
if (createHash('sha256').update(data).digest('hex') !== reference.sha256)
|
|
1293
|
+
throw corruptInputImageReference();
|
|
1294
|
+
return data;
|
|
1295
|
+
}
|
|
1296
|
+
catch (cause) {
|
|
1297
|
+
if (cause instanceof MarAgentError)
|
|
1298
|
+
throw cause;
|
|
1299
|
+
throw corruptInputImageReference(cause);
|
|
1300
|
+
}
|
|
1301
|
+
finally {
|
|
1302
|
+
await handle?.close();
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
throw corruptInputImageReference();
|
|
1306
|
+
}
|
|
1307
|
+
async function readExactBytes(handle, byteSize) {
|
|
1308
|
+
const data = Buffer.alloc(byteSize);
|
|
1309
|
+
let offset = 0;
|
|
1310
|
+
while (offset < byteSize) {
|
|
1311
|
+
const { bytesRead } = await handle.read(data, offset, byteSize - offset, offset);
|
|
1312
|
+
if (bytesRead === 0)
|
|
1313
|
+
throw corruptInputImageReference();
|
|
1314
|
+
offset += bytesRead;
|
|
1315
|
+
}
|
|
1316
|
+
const extra = Buffer.allocUnsafe(1);
|
|
1317
|
+
if ((await handle.read(extra, 0, 1, byteSize)).bytesRead !== 0)
|
|
1318
|
+
throw corruptInputImageReference();
|
|
1319
|
+
return data;
|
|
1320
|
+
}
|
|
1321
|
+
async function copyInputImages(sourceSessionDirectory, targetSessionDirectory, references) {
|
|
1322
|
+
if (references.length === 0)
|
|
1323
|
+
return;
|
|
1324
|
+
const source = join(sourceSessionDirectory, 'input_images');
|
|
1325
|
+
const target = join(targetSessionDirectory, 'input_images');
|
|
1326
|
+
await mkdir(target, { recursive: true, mode: 0o700 });
|
|
1327
|
+
for (const reference of references) {
|
|
1328
|
+
const data = await readInputImageBytes(source, reference);
|
|
1329
|
+
await writeFile(join(target, reference.fileName), data, { mode: 0o600, flag: 'wx' });
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
function corruptInputImageReference(cause) {
|
|
1333
|
+
return new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session input image is corrupt.', {
|
|
1334
|
+
...(cause === undefined ? {} : { cause })
|
|
1335
|
+
});
|
|
1336
|
+
}
|
|
1337
|
+
function isObject(value) {
|
|
1338
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
1339
|
+
}
|
|
1340
|
+
function normalizeSessionSource(value) {
|
|
1341
|
+
if (value === undefined || value.type === 'user')
|
|
1342
|
+
return { type: 'user' };
|
|
1343
|
+
if (value.type !== 'subagent' ||
|
|
1344
|
+
!value.parentSessionId ||
|
|
1345
|
+
!value.rootSessionId ||
|
|
1346
|
+
!value.parentExecutionId ||
|
|
1347
|
+
!value.description.trim() ||
|
|
1348
|
+
(value.role !== 'general-purpose' && value.role !== 'explore'))
|
|
1349
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Session source is invalid.');
|
|
1350
|
+
return {
|
|
1351
|
+
type: 'subagent',
|
|
1352
|
+
parentSessionId: value.parentSessionId,
|
|
1353
|
+
rootSessionId: value.rootSessionId,
|
|
1354
|
+
parentExecutionId: value.parentExecutionId,
|
|
1355
|
+
role: value.role,
|
|
1356
|
+
description: value.description.trim()
|
|
1357
|
+
};
|
|
1358
|
+
}
|
|
1359
|
+
function sessionListFilter(input) {
|
|
1360
|
+
const source = input.source ??
|
|
1361
|
+
(input.parentSessionId !== undefined || input.rootSessionId !== undefined
|
|
1362
|
+
? 'subagent'
|
|
1363
|
+
: 'user');
|
|
1364
|
+
if ((source !== 'user' && source !== 'subagent') ||
|
|
1365
|
+
(input.parentSessionId !== undefined &&
|
|
1366
|
+
(source !== 'subagent' || input.parentSessionId.length === 0)) ||
|
|
1367
|
+
(input.rootSessionId !== undefined &&
|
|
1368
|
+
(source !== 'subagent' || input.rootSessionId.length === 0)))
|
|
1369
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Session list filter is invalid.');
|
|
1370
|
+
return {
|
|
1371
|
+
source,
|
|
1372
|
+
...(input.parentSessionId === undefined ? {} : { parentSessionId: input.parentSessionId }),
|
|
1373
|
+
...(input.rootSessionId === undefined ? {} : { rootSessionId: input.rootSessionId })
|
|
1374
|
+
};
|
|
1375
|
+
}
|
|
1376
|
+
function sessionMatchesFilter(meta, filter) {
|
|
1377
|
+
const source = normalizeSessionSource(meta.source);
|
|
1378
|
+
return (source.type === filter.source &&
|
|
1379
|
+
(filter.parentSessionId === undefined ||
|
|
1380
|
+
(source.type === 'subagent' && source.parentSessionId === filter.parentSessionId)) &&
|
|
1381
|
+
(filter.rootSessionId === undefined ||
|
|
1382
|
+
(source.type === 'subagent' && source.rootSessionId === filter.rootSessionId)));
|
|
1383
|
+
}
|
|
1384
|
+
function encodeSessionListCursor(revision, offset, filter) {
|
|
1385
|
+
return Buffer.from(JSON.stringify({ version: 1, revision, offset, filter })).toString('base64url');
|
|
1386
|
+
}
|
|
1387
|
+
function decodeSessionListCursor(cursor, revision, filter) {
|
|
1388
|
+
if (cursor === undefined)
|
|
1389
|
+
return 0;
|
|
1390
|
+
try {
|
|
1391
|
+
const value = JSON.parse(Buffer.from(cursor, 'base64url').toString('utf8'));
|
|
1392
|
+
if (value.version !== 1 ||
|
|
1393
|
+
value.revision !== revision ||
|
|
1394
|
+
!Number.isSafeInteger(value.offset) ||
|
|
1395
|
+
value.offset < 0 ||
|
|
1396
|
+
!isDeepStrictEqual(value.filter, filter))
|
|
1397
|
+
throw new Error('invalid cursor');
|
|
1398
|
+
return value.offset;
|
|
1399
|
+
}
|
|
1400
|
+
catch {
|
|
1401
|
+
throw new MarAgentError('MAR_AGENT_TOOL_INPUT_INVALID', 'Session list cursor is invalid.');
|
|
1402
|
+
}
|
|
1403
|
+
}
|
|
1404
|
+
function sessionTreeIds(sessions, sessionId) {
|
|
1405
|
+
if (!sessions.some((session) => session.id === sessionId))
|
|
1406
|
+
return [];
|
|
1407
|
+
const ids = [sessionId];
|
|
1408
|
+
for (let index = 0; index < ids.length; index++) {
|
|
1409
|
+
const parentId = ids[index];
|
|
1410
|
+
for (const session of sessions) {
|
|
1411
|
+
const source = normalizeSessionSource(session.source);
|
|
1412
|
+
if (source.type === 'subagent' &&
|
|
1413
|
+
source.parentSessionId === parentId &&
|
|
1414
|
+
!ids.includes(session.id))
|
|
1415
|
+
ids.push(session.id);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return ids;
|
|
1419
|
+
}
|
|
1420
|
+
function forkedPayload(type, value, sourceSessionId, targetSessionId, title) {
|
|
1421
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value))
|
|
1422
|
+
return value;
|
|
1423
|
+
const payload = { ...value };
|
|
1424
|
+
if (payload.sessionId === sourceSessionId)
|
|
1425
|
+
payload.sessionId = targetSessionId;
|
|
1426
|
+
if (type === 'session.title.updated') {
|
|
1427
|
+
payload.title = title;
|
|
1428
|
+
payload.automatic = false;
|
|
1429
|
+
}
|
|
1430
|
+
return payload;
|
|
1431
|
+
}
|
|
1432
|
+
function deriveExecutionState(records) {
|
|
1433
|
+
let automaticTitle = false;
|
|
1434
|
+
let sawUserTurn = false;
|
|
1435
|
+
let compactSequence;
|
|
1436
|
+
let todoSequence;
|
|
1437
|
+
let todoRevision = 0;
|
|
1438
|
+
let todoItems = [];
|
|
1439
|
+
for (const record of records) {
|
|
1440
|
+
if (record.type === 'session.created')
|
|
1441
|
+
automaticTitle =
|
|
1442
|
+
record.payload?.automaticTitle === true;
|
|
1443
|
+
else if (record.type === 'turn.user')
|
|
1444
|
+
sawUserTurn = true;
|
|
1445
|
+
else if (isCompactCheckpoint(record))
|
|
1446
|
+
compactSequence = record.sequence;
|
|
1447
|
+
else if (record.type === 'todo.updated') {
|
|
1448
|
+
const items = todoItemsFromSnapshot(record.payload);
|
|
1449
|
+
if (!items)
|
|
1450
|
+
continue;
|
|
1451
|
+
todoSequence = record.sequence;
|
|
1452
|
+
todoRevision++;
|
|
1453
|
+
todoItems = items;
|
|
1454
|
+
}
|
|
1455
|
+
}
|
|
1456
|
+
const boundary = records.findLastIndex(isCompactCheckpoint);
|
|
1457
|
+
const checkpoint = latestValidContextGcCheckpoint(records);
|
|
1458
|
+
return {
|
|
1459
|
+
automaticTitlePending: automaticTitle && !sawUserTurn,
|
|
1460
|
+
todo: { revision: todoRevision, items: todoItems },
|
|
1461
|
+
contextRecords: boundary < 0 ? [...records] : records.slice(boundary),
|
|
1462
|
+
resume: {
|
|
1463
|
+
version: 1,
|
|
1464
|
+
...(compactSequence === undefined ? {} : { compactSequence }),
|
|
1465
|
+
...(checkpoint === undefined
|
|
1466
|
+
? {}
|
|
1467
|
+
: {
|
|
1468
|
+
gcSequence: checkpoint.record.sequence,
|
|
1469
|
+
gcGeneration: checkpoint.payload.generation,
|
|
1470
|
+
gcBaseSequence: contextGcBaseSequence(checkpoint.payload.base)
|
|
1471
|
+
}),
|
|
1472
|
+
...(todoSequence === undefined ? {} : { todoSequence }),
|
|
1473
|
+
todoRevision
|
|
1474
|
+
}
|
|
1475
|
+
};
|
|
1476
|
+
}
|
|
1477
|
+
export function compactSummaryFromCheckpoint(record) {
|
|
1478
|
+
if (record?.type !== 'compact.completed')
|
|
1479
|
+
return undefined;
|
|
1480
|
+
const payload = record.payload;
|
|
1481
|
+
if (payload === null || typeof payload !== 'object' || Array.isArray(payload))
|
|
1482
|
+
return undefined;
|
|
1483
|
+
const summary = payload.summary;
|
|
1484
|
+
return typeof summary === 'string' && summary.trim().length > 0 ? summary : undefined;
|
|
1485
|
+
}
|
|
1486
|
+
export function replacementHistoryFromCheckpoint(record) {
|
|
1487
|
+
if (compactSummaryFromCheckpoint(record) === undefined)
|
|
1488
|
+
return undefined;
|
|
1489
|
+
const history = record.payload.replacementHistory;
|
|
1490
|
+
if (!Array.isArray(history) ||
|
|
1491
|
+
!history.every((message) => message !== null &&
|
|
1492
|
+
typeof message === 'object' &&
|
|
1493
|
+
message.role === 'user' &&
|
|
1494
|
+
typeof message.content === 'string' &&
|
|
1495
|
+
(message.kind === 'user_input' ||
|
|
1496
|
+
(message.kind === 'summary' && message.content.trim().length > 0))) ||
|
|
1497
|
+
history.filter((message) => message.kind === 'summary').length !== 1)
|
|
1498
|
+
return undefined;
|
|
1499
|
+
return history.map(({ role, content, kind }) => ({ role, content, kind }));
|
|
1500
|
+
}
|
|
1501
|
+
function isCompactCheckpoint(record) {
|
|
1502
|
+
return compactSummaryFromCheckpoint(record) !== undefined;
|
|
1503
|
+
}
|
|
1504
|
+
function sameResumeIndex(left, right) {
|
|
1505
|
+
return (left?.version === right.version &&
|
|
1506
|
+
left.compactSequence === right.compactSequence &&
|
|
1507
|
+
left.gcSequence === right.gcSequence &&
|
|
1508
|
+
left.gcGeneration === right.gcGeneration &&
|
|
1509
|
+
left.gcBaseSequence === right.gcBaseSequence &&
|
|
1510
|
+
left.todoSequence === right.todoSequence &&
|
|
1511
|
+
left.todoRevision === right.todoRevision);
|
|
1512
|
+
}
|
|
1513
|
+
async function readRecords(path) {
|
|
1514
|
+
const value = await readFile(path, 'utf8');
|
|
1515
|
+
const lines = value.split('\n');
|
|
1516
|
+
if (lines.at(-1) === '')
|
|
1517
|
+
lines.pop();
|
|
1518
|
+
const records = [];
|
|
1519
|
+
for (const [index, line] of lines.entries()) {
|
|
1520
|
+
if (!line)
|
|
1521
|
+
continue;
|
|
1522
|
+
try {
|
|
1523
|
+
records.push(JSON.parse(line));
|
|
1524
|
+
}
|
|
1525
|
+
catch (cause) {
|
|
1526
|
+
if (index === lines.length - 1 && !value.endsWith('\n'))
|
|
1527
|
+
break;
|
|
1528
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.', {
|
|
1529
|
+
cause
|
|
1530
|
+
});
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
return records;
|
|
1534
|
+
}
|
|
1535
|
+
async function readRecordPageFromTail(path, beforeSequence, limit) {
|
|
1536
|
+
const handle = await open(path, 'r');
|
|
1537
|
+
try {
|
|
1538
|
+
const size = (await handle.stat()).size;
|
|
1539
|
+
let position = size;
|
|
1540
|
+
let pendingLineParts = [];
|
|
1541
|
+
let invalidFinalLineMayBeIgnored = false;
|
|
1542
|
+
let inspectedFileEnd = false;
|
|
1543
|
+
let pageComplete = false;
|
|
1544
|
+
const newestFirst = [];
|
|
1545
|
+
const accept = (line, allowInvalidFinalLine) => {
|
|
1546
|
+
if (line.length === 0)
|
|
1547
|
+
return;
|
|
1548
|
+
let record;
|
|
1549
|
+
try {
|
|
1550
|
+
record = JSON.parse(line.toString('utf8'));
|
|
1551
|
+
}
|
|
1552
|
+
catch (cause) {
|
|
1553
|
+
if (allowInvalidFinalLine)
|
|
1554
|
+
return;
|
|
1555
|
+
throw new MarAgentError('MAR_AGENT_SESSION_CORRUPT', 'Session history is corrupt.', {
|
|
1556
|
+
cause
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
if (record.sequence < beforeSequence)
|
|
1560
|
+
newestFirst.push(record);
|
|
1561
|
+
};
|
|
1562
|
+
while (position > 0 && newestFirst.length <= limit) {
|
|
1563
|
+
const start = Math.max(0, position - REVERSE_READ_CHUNK_BYTES);
|
|
1564
|
+
const chunk = Buffer.allocUnsafe(position - start);
|
|
1565
|
+
let bytesRead = 0;
|
|
1566
|
+
while (bytesRead < chunk.length) {
|
|
1567
|
+
const result = await handle.read(chunk, bytesRead, chunk.length - bytesRead, start + bytesRead);
|
|
1568
|
+
if (result.bytesRead === 0)
|
|
1569
|
+
break;
|
|
1570
|
+
bytesRead += result.bytesRead;
|
|
1571
|
+
}
|
|
1572
|
+
const value = chunk.subarray(0, bytesRead);
|
|
1573
|
+
if (!inspectedFileEnd) {
|
|
1574
|
+
inspectedFileEnd = true;
|
|
1575
|
+
invalidFinalLineMayBeIgnored = value.at(-1) !== 0x0a;
|
|
1576
|
+
}
|
|
1577
|
+
let lineEnd = value.length;
|
|
1578
|
+
for (let index = value.length - 1; index >= 0; index--) {
|
|
1579
|
+
if (value[index] !== 0x0a)
|
|
1580
|
+
continue;
|
|
1581
|
+
const currentPart = value.subarray(index + 1, lineEnd);
|
|
1582
|
+
const line = pendingLineParts.length === 0
|
|
1583
|
+
? currentPart
|
|
1584
|
+
: Buffer.concat([currentPart, ...pendingLineParts]);
|
|
1585
|
+
accept(line, invalidFinalLineMayBeIgnored);
|
|
1586
|
+
invalidFinalLineMayBeIgnored = false;
|
|
1587
|
+
pendingLineParts = [];
|
|
1588
|
+
lineEnd = index;
|
|
1589
|
+
if (newestFirst.length > limit) {
|
|
1590
|
+
pageComplete = true;
|
|
1591
|
+
break;
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
if (!pageComplete && lineEnd > 0)
|
|
1595
|
+
pendingLineParts.unshift(Buffer.from(value.subarray(0, lineEnd)));
|
|
1596
|
+
position = start;
|
|
1597
|
+
}
|
|
1598
|
+
if (position === 0 && newestFirst.length <= limit && pendingLineParts.length > 0)
|
|
1599
|
+
accept(Buffer.concat(pendingLineParts), invalidFinalLineMayBeIgnored);
|
|
1600
|
+
const hasEarlier = newestFirst.length > limit;
|
|
1601
|
+
return {
|
|
1602
|
+
records: newestFirst.slice(0, limit).reverse(),
|
|
1603
|
+
hasEarlier
|
|
1604
|
+
};
|
|
1605
|
+
}
|
|
1606
|
+
finally {
|
|
1607
|
+
await handle.close();
|
|
1608
|
+
}
|
|
1609
|
+
}
|
|
1610
|
+
function segmentNumberFromPath(path) {
|
|
1611
|
+
const match = /events-(\d{6})\.jsonl$/.exec(path);
|
|
1612
|
+
return match === null ? undefined : Number(match[1]);
|
|
1613
|
+
}
|
|
1614
|
+
async function acquireFileLock(path, message = 'Session index is busy.', waitMs = 5000) {
|
|
1615
|
+
const deadline = Date.now() + waitMs;
|
|
1616
|
+
for (;;) {
|
|
1617
|
+
try {
|
|
1618
|
+
const handle = await open(path, 'wx', 0o600);
|
|
1619
|
+
await handle.writeFile(JSON.stringify({ pid: process.pid, createdAt: new Date().toISOString() }));
|
|
1620
|
+
let released = false;
|
|
1621
|
+
return async () => {
|
|
1622
|
+
if (released)
|
|
1623
|
+
return;
|
|
1624
|
+
released = true;
|
|
1625
|
+
await handle.close();
|
|
1626
|
+
await rm(path, { force: true });
|
|
1627
|
+
};
|
|
1628
|
+
}
|
|
1629
|
+
catch (cause) {
|
|
1630
|
+
if (await removeDeadOwner(path))
|
|
1631
|
+
continue;
|
|
1632
|
+
if (Date.now() >= deadline)
|
|
1633
|
+
throw new MarAgentError('MAR_AGENT_SESSION_LOCKED', message, { cause });
|
|
1634
|
+
await delay(25 + Math.floor(Math.random() * 25));
|
|
1635
|
+
}
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
async function removeDeadOwner(path) {
|
|
1639
|
+
try {
|
|
1640
|
+
const owner = JSON.parse(await readFile(path, 'utf8'));
|
|
1641
|
+
if (typeof owner.pid !== 'number' || !Number.isSafeInteger(owner.pid))
|
|
1642
|
+
return false;
|
|
1643
|
+
try {
|
|
1644
|
+
process.kill(owner.pid, 0);
|
|
1645
|
+
return false;
|
|
1646
|
+
}
|
|
1647
|
+
catch (error) {
|
|
1648
|
+
if (error.code !== 'ESRCH')
|
|
1649
|
+
return false;
|
|
1650
|
+
await rm(path, { force: true });
|
|
1651
|
+
return true;
|
|
1652
|
+
}
|
|
1653
|
+
}
|
|
1654
|
+
catch {
|
|
1655
|
+
return false;
|
|
1656
|
+
}
|
|
1657
|
+
}
|