aws-runtime-bridge 1.9.118 → 1.9.120

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.
@@ -1,4 +1,4 @@
1
- const T=["recently_memory","agent_memory","project_memory","session_context"],h=["recently_memory","agent_memory"],x=64,D=32,O=128,R=64,C=1024;function I(y){const e=String(y||"").trim().replace(/\\/g,"/");if(!e)return e;const t=e.startsWith("@/")?e.substring(1):e;return t.startsWith("./")?t:`./${t.replace(/^\/+/,"")}`}class E extends Error{details;constructor(e,t){super(e),this.name="MemoryCapacityError",this.details=t}}const A=/^([a-zA-Z_][a-zA-Z0-9_]*):\/\/(.*)$/;function b(y){const e=(y||"").trim();return e?e.split("|").map(t=>t.trim()).filter(Boolean).map(t=>t.split(/\s+/).filter(Boolean)):[]}function S(y,e){return y.length===0?!1:y.some(t=>t.every(i=>e.includes(i)))}class p{storePath;constructor(e){this.storePath=e}nowIso(){return new Date().toISOString()}normalizeUri(e){const t=String(e||"").trim(),i=A.exec(t);if(!i)throw new Error(`Invalid memory uri: ${e}`);const o=i[1],r=i[2];if(!o||!r)throw new Error(`Invalid memory uri: ${e}`);const n=o.toLowerCase(),s=r.replace(/^\/+|\/+$/g,"");if(!s)throw new Error(`Invalid memory uri path: ${e}`);return{uri:`${n}://${s}`,domain:n,path:s}}normalizeMemoryType(e,t=T){const i=String(e||"").trim();if(!t.includes(i))throw new Error(`Invalid memory_type: ${e}`);return i}ensureTypeMatch(e,t){if(t&&e.memory_type!==t)throw new Error(`Memory type mismatch: expected ${t}, actual ${e.memory_type}`)}async ensureStoreDir(){const{mkdir:e}=await import("node:fs/promises");await e(this.storePath,{recursive:!0})}async loadMemoryFile(e){const{readFile:t}=await import("node:fs/promises");try{const i=await t(e,"utf-8"),o=JSON.parse(i),r=o.by_uri&&typeof o.by_uri=="object"?o.by_uri:{},n={};for(const[s,a]of Object.entries(r)){const d=this.normalizeMemoryType(a.memory_type||"project_memory"),u=this.normalizeUri(a.uri||s),l=a;let c=l.memory_status;c||(l.update_status==="updating"?c="updating":l.recall_status==="recalling"?c="recalling":c="normal");const m={...a};delete m.update_status,delete m.recall_status,n[u.uri]={...m,uri:u.uri,domain:u.domain,path:u.path,memory_type:d,memory_status:c}}return{by_uri:n}}catch{return{by_uri:{}}}}async loadData(){const{readdir:e}=await import("node:fs/promises"),t=await import("node:path");try{const i=await e(this.storePath,{withFileTypes:!0}),o={by_uri:{}};for(const r of i){if(!r.isFile()||!r.name.endsWith(".json"))continue;const n=await this.loadMemoryFile(t.join(this.storePath,r.name));Object.assign(o.by_uri,n.by_uri)}return o}catch{return{by_uri:{}}}}async writeJsonAtomically(e,t){const{rename:i,rm:o,writeFile:r}=await import("node:fs/promises"),n=`${e}.${process.pid}.${Date.now()}.tmp`;try{await r(n,JSON.stringify(t,null,2),"utf-8"),await i(n,e)}catch(s){throw await o(n,{force:!0}),s}}async saveData(e){const{readdir:t,rm:i}=await import("node:fs/promises"),o=await import("node:path");await this.ensureStoreDir();const r=new Map;for(const a of Object.values(e.by_uri)){const d=r.get(a.domain)??{by_uri:{}};d.by_uri[a.uri]=a,r.set(a.domain,d)}for(const[a,d]of r.entries())await this.writeJsonAtomically(o.join(this.storePath,`${a}.json`),d);const n=new Set([...r.keys()].map(a=>`${a}.json`)),s=await t(this.storePath,{withFileTypes:!0});for(const a of s)a.isFile()&&a.name.endsWith(".json")&&!n.has(a.name)&&await i(o.join(this.storePath,a.name),{force:!0})}createEmptyStats(){return{total:0,listable:{count:0,limit:64,hardLimit:128,exceeded:!1,hardExceeded:!1},by_type:{recently_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},agent_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},project_memory:{count:0,limit:null,hardLimit:null,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}},session_context:{count:0,limit:null,hardLimit:1024,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}}}}}calculateStats(e){const t=this.createEmptyStats();for(const i of Object.values(e.by_uri)){t.total+=1;const o=t.by_type[i.memory_type];o.count+=1;const r=a=>h.includes(a)?32:null,n=a=>h.includes(a)?64:a==="session_context"?1024:null,s=o.by_domain[i.domain]??{count:0,limit:r(i.memory_type),hardLimit:n(i.memory_type),exceeded:!1,hardExceeded:!1};s.count+=1,o.by_domain[i.domain]=s,h.includes(i.memory_type)&&(t.listable.count+=1)}t.listable.exceeded=t.listable.count>t.listable.limit,t.listable.hardExceeded=t.listable.count>=t.listable.hardLimit;for(const i of T){const o=t.by_type[i];o.domainCount=Object.keys(o.by_domain).length,o.limit!==null&&o.hardLimit!==null&&(o.exceeded=o.domainCount>o.limit,o.hardExceeded=o.domainCount>=o.hardLimit);for(const r of Object.values(o.by_domain))r.limit!==null&&r.hardLimit!==null&&(r.exceeded=r.count>r.limit,r.hardExceeded=r.count>=r.hardLimit)}return t}generateId(e){return`${e.replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")}_${Date.now().toString(36)}`}ensureListableMemoryCapacity(e,t,i){if(!h.includes(t))return;const r=this.calculateStats(e).by_type[t],n=r.by_domain[i.domain];if(!n&&r.domainCount>=64)throw new E(`Cannot create ${t}: hard domain type limit 64 reached. Please delete an existing ${t} domain type before creating a new ${t}.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:t,limit:64,current:r.domainCount,recommended_actions:[`list_memories({ memory_type: '${t}' })`,`delete_memory({ uri, memory_type: '${t}' })`]});if(n&&n.count>=64)throw new E(`Cannot create ${t}: hard memory limit 64 reached under domain ${i.domain}. Please delete or archive existing ${i.domain}://${t} memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:t,domain:i.domain,limit:64,current:n.count,recommended_actions:[`list_memories({ memory_type: '${t}' })`,`delete_memory({ uri, memory_type: '${t}' })`]})}ensureSessionContextCapacity(e,t,i){if(t!=="session_context")return;const o=Object.values(e.by_uri).filter(r=>r.memory_type==="session_context"&&r.domain===i.domain).length;if(o>=1024)throw new E(`Cannot create session_context: hard limit 1024 reached under domain ${i.domain}. Please delete existing session_context memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:t,domain:i.domain,limit:1024,current:o,recommended_actions:["list_memories({ memory_type: 'session_context' })","delete_memory({ uri, memory_type: 'session_context' })"]})}async getStats(){const e=await this.loadData();return this.calculateStats(e)}static calcAgentMemoryExpiresAt(){return new Date(Date.now()+432e5).toISOString()}static isExpirableType(e){return e==="agent_memory"||e==="recently_memory"}async createMemory(e){const t=this.normalizeMemoryType(e.memory_type),i=this.normalizeUri(e.uri),o=await this.loadData();if(o.by_uri[i.uri])throw new Error(`Memory already exists: ${i.uri}`);this.ensureListableMemoryCapacity(o,t,i),this.ensureSessionContextCapacity(o,t,i);const r=this.nowIso(),n={id:this.generateId(i.uri),uri:i.uri,domain:i.domain,path:i.path,title:e.title||void 0,content:String(e.content||""),memory_type:t,createdAt:r,updatedAt:r,version:1,keywords:e.keywords,bound_files:e.bound_files,file_md5_map:e.file_md5_map||void 0,updating_agent_id:void 0,last_check_time:e.last_check_time||void 0,expiresAt:e.expiresAt||(p.isExpirableType(t)?p.calcAgentMemoryExpiresAt():void 0),memory_status:"normal"};return o.by_uri[i.uri]=n,await this.saveData(o),n}async readMemory(e){const t=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,r=(await this.loadData()).by_uri[t.uri]??null;return r?(this.ensureTypeMatch(r,i),r):null}async updateMemory(e){const t=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),r=o.by_uri[t.uri];if(!r)throw new Error(`Memory not found: ${t.uri}`);this.ensureTypeMatch(r,i);let n=r.content;if(typeof e.old_string=="string"&&typeof e.new_string=="string"){const l=e.old_string;if(!l)throw new Error("old_string cannot be empty when replacing");const c=n.split(l).length-1;if(c===0)throw new Error("old_string not found in memory content");if(c>1)throw new Error("old_string appears multiple times; replace is ambiguous");n=n.replace(l,e.new_string)}typeof e.append=="string"&&e.append.length>0&&(n=`${n}${e.append}`);const s=n!==r.content||typeof e.title=="string"&&e.title!==r.title,a=this.nowIso();let d=r.expiresAt;if(p.isExpirableType(r.memory_type))if(r.memory_type==="recently_memory")d=new Date(Date.now()+24*60*60*1e3).toISOString();else{const l=r.expiresAt?new Date(r.expiresAt):null,c=r.updatedAt?new Date(r.updatedAt):null,m=l&&c&&!isNaN(c.getTime())?Math.max(12*60*60*1e3,l.getTime()-c.getTime()):12*60*60*1e3;d=new Date(Date.now()+m*2).toISOString()}e.expiresAt!==void 0&&(d=e.expiresAt);const u={...r,content:n,title:e.title!==void 0?e.title:r.title,updatedAt:a,version:r.version+1,keywords:e.keywords!==void 0?e.keywords:r.keywords,bound_files:e.bound_files!==void 0?e.bound_files:r.bound_files,file_md5_map:e.file_md5_map!==void 0?e.file_md5_map:e.bound_files!==void 0?void 0:r.file_md5_map,memory_status:e.memory_status!==void 0?e.memory_status:r.memory_status==="updating"?"normal":r.memory_status||"normal",updating_agent_id:e.memory_status!==void 0?e.updating_agent_id||void 0:r.memory_status==="updating"?void 0:r.updating_agent_id,last_check_time:e.last_check_time!==void 0?e.last_check_time:r.last_check_time,expiresAt:d};return o.by_uri[t.uri]=u,await this.saveData(o),u}async deleteMemory(e){const t=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),r=o.by_uri[t.uri];return r?(this.ensureTypeMatch(r,i),delete o.by_uri[t.uri],await this.saveData(o),!0):!1}async listExpiredRecentlyMemories(){const e=await this.loadData(),t=new Date,i=[];for(const o of Object.values(e.by_uri))o.memory_type!=="agent_memory"&&o.memory_type!=="recently_memory"||o.expiresAt&&new Date(o.expiresAt)<=t&&i.push(o);return i.sort((o,r)=>o.expiresAt.localeCompare(r.expiresAt))}async searchMemory(e){const t=await this.loadData(),o=String(e.query||"").trim().toLowerCase(),r=e.memory_type?this.normalizeMemoryType(e.memory_type):void 0,n=typeof e.limit=="number"&&e.limit>0?e.limit:10,s=e.keywords?.map(c=>c.toLowerCase()),a=e.keyword_mode==="all"?"all":"any",d=b(o);if(d.length===0&&(!s||s.length===0))return{query:o,results:[]};const u=new Set,l=[];for(const c of Object.values(t.by_uri)){if(r&&c.memory_type!==r||u.has(c.id))continue;let m=0;if(s&&s.length>0&&c.keywords){const f=c.keywords.map(_=>_.toLowerCase());if(a==="all"){if(s.every(w=>f.includes(w)))m+=10*s.length;else if(d.length===0)continue}else for(const _ of s)f.includes(_)&&(m+=10)}if(d.length>0){const f=`${c.uri}
2
- ${c.title||""}
3
- ${c.content}`.toLowerCase();if(!S(d,f)&&m===0)continue;for(const _ of d){const w=_.filter(M=>f.includes(M)).length;if(w>0){const M=c.uri.toLowerCase(),L=_.filter(g=>M.includes(g)).length;m+=w+L}}}m!==0&&(u.add(c.id),l.push({score:m,record:c}))}return l.sort((c,m)=>m.score!==c.score?m.score-c.score:m.record.updatedAt.localeCompare(c.record.updatedAt)),{query:o,results:l.slice(0,n).map(c=>c.record)}}async listByType(e){const t=e==="session_context"||e==="project_memory"?T:h,i=this.normalizeMemoryType(e,t),o=await this.loadData(),r=new Set,n=[];for(const s of Object.values(o.by_uri))s.memory_type===i&&(r.has(s.id)||(r.add(s.id),n.push(s)));return n.sort((s,a)=>a.updatedAt.localeCompare(s.updatedAt)),n}async listByFile(e,t){const i=await this.loadData(),o=typeof t=="object"&&t!==null?t.memory_type:t,r=o?this.normalizeMemoryType(o):void 0,n=I(e),s=new Set,a=[];for(const d of Object.values(i.by_uri))r&&d.memory_type!==r||s.has(d.id)||d.bound_files&&d.bound_files.length>0&&d.bound_files.some(l=>I(l)===n)&&(s.add(d.id),a.push(d));return a.sort((d,u)=>u.updatedAt.localeCompare(d.updatedAt)),a}async markExpiredMemoriesRecalling(e){const t=await this.listExpiredRecentlyMemories();if(t.length===0)return{marked:0,uris:[]};const i=e?t.filter(s=>e.includes(s.uri)):t;if(i.length===0)return{marked:0,uris:[]};const o=await this.loadData(),r=this.nowIso(),n=[];for(const s of i){const a=o.by_uri[s.uri];a&&(a.memory_status="recalling",a.updatedAt=r,a.version=(a.version||1)+1,n.push(s.uri))}return n.length>0&&await this.saveData(o),{marked:n.length,uris:n}}async clearRecallingExpiredMemories(){const e=await this.loadData(),t=new Date,i=[];for(const o of Object.values(e.by_uri))p.isExpirableType(o.memory_type)&&o.memory_status==="recalling"&&o.expiresAt&&(new Date(o.expiresAt)>t||i.push(o.uri));if(i.length===0)return{deleted:0,uris:[]};for(const o of i)delete e.by_uri[o];return await this.saveData(e),{deleted:i.length,uris:i}}async claimMemoryUpdate(e,t,i){throw new Error("claimMemoryUpdate not supported in local MemoryStore")}async renewMemoryLease(e){throw new Error("renewMemoryLease not supported in local MemoryStore")}async releaseMemoryClaim(e){throw new Error("releaseMemoryClaim not supported in local MemoryStore")}async releaseAllMemoryClaims(){throw new Error("releaseAllMemoryClaims not supported in local MemoryStore")}async getMyClaimedUris(){throw new Error("getMyClaimedUris not supported in local MemoryStore")}}export{E as MemoryCapacityError,p as MemoryStore,I as normalizeBoundFilePath};
1
+ const E=["recently_memory","agent_memory","project_memory","session_context"],h=["recently_memory","agent_memory"],C=64,R=32,Y=128,$=64,P=1024;function L(_){const e=String(_||"").trim().replace(/\\/g,"/");if(!e)return e;const r=e.startsWith("@/")?e.substring(1):e;return r.startsWith("./")?r:`./${r.replace(/^\/+/,"")}`}class T extends Error{details;constructor(e,r){super(e),this.name="MemoryCapacityError",this.details=r}}const b=/^([a-zA-Z_][a-zA-Z0-9_]*):\/\/(.*)$/,g="local",S=50,x=10;function D(_){const e=(_||"").trim();return e?e.split("|").map(r=>r.trim()).filter(Boolean).map(r=>r.split(/\s+/).filter(Boolean)):[]}function O(_,e){return _.length===0?!1:_.some(r=>r.every(i=>e.includes(i)))}class p{storePath;constructor(e){this.storePath=e}nowIso(){return new Date().toISOString()}normalizeUri(e){const r=String(e||"").trim(),i=b.exec(r);if(!i)throw new Error(`Invalid memory uri: ${e}`);const o=i[1],t=i[2];if(!o||!t)throw new Error(`Invalid memory uri: ${e}`);const n=o.toLowerCase(),c=t.replace(/^\/+|\/+$/g,"");if(!c)throw new Error(`Invalid memory uri path: ${e}`);return{uri:`${n}://${c}`,domain:n,path:c}}normalizeMemoryType(e,r=E){const i=String(e||"").trim();if(!r.includes(i))throw new Error(`Invalid memory_type: ${e}`);return i}ensureTypeMatch(e,r){if(r&&e.memory_type!==r)throw new Error(`Memory type mismatch: expected ${r}, actual ${e.memory_type}`)}async ensureStoreDir(){const{mkdir:e}=await import("node:fs/promises");await e(this.storePath,{recursive:!0})}async loadMemoryFile(e){const{readFile:r}=await import("node:fs/promises");try{const i=await r(e,"utf-8"),o=JSON.parse(i),t=o.by_uri&&typeof o.by_uri=="object"?o.by_uri:{},n={};for(const[c,a]of Object.entries(t)){const s=this.normalizeMemoryType(a.memory_type||"project_memory"),d=this.normalizeUri(a.uri||c),m=a;let l=m.memory_status;l||(m.update_status==="updating"?l="updating":m.recall_status==="recalling"?l="recalling":l="normal");const u={...a};delete u.update_status,delete u.recall_status,n[d.uri]={...u,uri:d.uri,domain:d.domain,path:d.path,memory_type:s,memory_status:l}}return{by_uri:n}}catch{return{by_uri:{}}}}async loadData(){const{readdir:e}=await import("node:fs/promises"),r=await import("node:path");try{const i=await e(this.storePath,{withFileTypes:!0}),o={by_uri:{}};for(const t of i){if(!t.isFile()||!t.name.endsWith(".json"))continue;const n=await this.loadMemoryFile(r.join(this.storePath,t.name));Object.assign(o.by_uri,n.by_uri)}return o}catch{return{by_uri:{}}}}async writeJsonAtomically(e,r){const{rename:i,rm:o,writeFile:t}=await import("node:fs/promises"),n=`${e}.${process.pid}.${Date.now()}.tmp`;try{await t(n,JSON.stringify(r,null,2),"utf-8"),await i(n,e)}catch(c){throw await o(n,{force:!0}),c}}async saveData(e){const{readdir:r,rm:i}=await import("node:fs/promises"),o=await import("node:path");await this.ensureStoreDir();const t=new Map;for(const a of Object.values(e.by_uri)){const s=t.get(a.domain)??{by_uri:{}};s.by_uri[a.uri]=a,t.set(a.domain,s)}for(const[a,s]of t.entries())await this.writeJsonAtomically(o.join(this.storePath,`${a}.json`),s);const n=new Set([...t.keys()].map(a=>`${a}.json`)),c=await r(this.storePath,{withFileTypes:!0});for(const a of c)a.isFile()&&a.name.endsWith(".json")&&!n.has(a.name)&&await i(o.join(this.storePath,a.name),{force:!0})}createEmptyStats(){return{total:0,listable:{count:0,limit:64,hardLimit:128,exceeded:!1,hardExceeded:!1},by_type:{recently_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},agent_memory:{count:0,limit:32,hardLimit:64,exceeded:!1,hardExceeded:!1,listable:!0,domainCount:0,by_domain:{}},project_memory:{count:0,limit:null,hardLimit:null,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}},session_context:{count:0,limit:null,hardLimit:1024,exceeded:!1,hardExceeded:!1,listable:!1,domainCount:0,by_domain:{}}}}}calculateStats(e){const r=this.createEmptyStats();for(const i of Object.values(e.by_uri)){r.total+=1;const o=r.by_type[i.memory_type];o.count+=1;const t=a=>h.includes(a)?32:null,n=a=>h.includes(a)?64:a==="session_context"?1024:null,c=o.by_domain[i.domain]??{count:0,limit:t(i.memory_type),hardLimit:n(i.memory_type),exceeded:!1,hardExceeded:!1};c.count+=1,o.by_domain[i.domain]=c,h.includes(i.memory_type)&&(r.listable.count+=1)}r.listable.exceeded=r.listable.count>r.listable.limit,r.listable.hardExceeded=r.listable.count>=r.listable.hardLimit;for(const i of E){const o=r.by_type[i];o.domainCount=Object.keys(o.by_domain).length,o.limit!==null&&o.hardLimit!==null&&(o.exceeded=o.domainCount>o.limit,o.hardExceeded=o.domainCount>=o.hardLimit);for(const t of Object.values(o.by_domain))t.limit!==null&&t.hardLimit!==null&&(t.exceeded=t.count>t.limit,t.hardExceeded=t.count>=t.hardLimit)}return r}generateId(e){return`${e.replace(/[^a-zA-Z0-9]+/g,"_").replace(/^_+|_+$/g,"")}_${Date.now().toString(36)}`}ensureListableMemoryCapacity(e,r,i){if(!h.includes(r))return;const t=this.calculateStats(e).by_type[r],n=t.by_domain[i.domain];if(!n&&t.domainCount>=64)throw new T(`Cannot create ${r}: hard domain type limit 64 reached. Please delete an existing ${r} domain type before creating a new ${r}.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:r,limit:64,current:t.domainCount,recommended_actions:[`list_memories({ memory_type: '${r}' })`,`delete_memory({ uri, memory_type: '${r}' })`]});if(n&&n.count>=64)throw new T(`Cannot create ${r}: hard memory limit 64 reached under domain ${i.domain}. Please delete or archive existing ${i.domain}://${r} memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:r,domain:i.domain,limit:64,current:n.count,recommended_actions:[`list_memories({ memory_type: '${r}' })`,`delete_memory({ uri, memory_type: '${r}' })`]})}ensureSessionContextCapacity(e,r,i){if(r!=="session_context")return;const o=Object.values(e.by_uri).filter(t=>t.memory_type==="session_context"&&t.domain===i.domain).length;if(o>=1024)throw new T(`Cannot create session_context: hard limit 1024 reached under domain ${i.domain}. Please delete existing session_context memories before creating a new one.`,{code:"MEMORY_TYPE_LIMIT_REACHED",memory_type:r,domain:i.domain,limit:1024,current:o,recommended_actions:["list_memories({ memory_type: 'session_context' })","delete_memory({ uri, memory_type: 'session_context' })"]})}async getStats(){const e=await this.loadData();return this.calculateStats(e)}static calcAgentMemoryExpiresAt(){return new Date(Date.now()+432e5).toISOString()}static isExpirableType(e){return e==="agent_memory"||e==="recently_memory"}async createMemory(e){const r=this.normalizeMemoryType(e.memory_type),i=this.normalizeUri(e.uri),o=await this.loadData();if(o.by_uri[i.uri])throw new Error(`Memory already exists: ${i.uri}`);this.ensureListableMemoryCapacity(o,r,i),this.ensureSessionContextCapacity(o,r,i);const t=this.nowIso(),n={id:this.generateId(i.uri),uri:i.uri,domain:i.domain,path:i.path,title:e.title||void 0,content:String(e.content||""),memory_type:r,createdAt:t,updatedAt:t,version:1,keywords:e.keywords,bound_files:e.bound_files,file_md5_map:e.file_md5_map||void 0,updating_agent_id:void 0,last_check_time:e.last_check_time||void 0,expiresAt:e.expiresAt||(p.isExpirableType(r)?p.calcAgentMemoryExpiresAt():void 0),memory_status:"normal"};return o.by_uri[i.uri]=n,await this.saveData(o),n}async readMemory(e){const r=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,t=(await this.loadData()).by_uri[r.uri]??null;return t?(this.ensureTypeMatch(t,i),t):null}async updateMemory(e){const r=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),t=o.by_uri[r.uri];if(!t)throw new Error(`Memory not found: ${r.uri}`);this.ensureTypeMatch(t,i);let n=t.content;if(typeof e.old_string=="string"&&typeof e.new_string=="string"){const m=e.old_string;if(!m)throw new Error("old_string cannot be empty when replacing");const l=n.split(m).length-1;if(l===0)throw new Error("old_string not found in memory content");if(l>1)throw new Error("old_string appears multiple times; replace is ambiguous");n=n.replace(m,e.new_string)}typeof e.append=="string"&&e.append.length>0&&(n=`${n}${e.append}`);const c=n!==t.content||typeof e.title=="string"&&e.title!==t.title,a=this.nowIso();let s=t.expiresAt;if(p.isExpirableType(t.memory_type))if(t.memory_type==="recently_memory")s=new Date(Date.now()+24*60*60*1e3).toISOString();else{const m=t.expiresAt?new Date(t.expiresAt):null,l=t.updatedAt?new Date(t.updatedAt):null,u=m&&l&&!isNaN(l.getTime())?Math.max(12*60*60*1e3,m.getTime()-l.getTime()):12*60*60*1e3;s=new Date(Date.now()+u*2).toISOString()}e.expiresAt!==void 0&&(s=e.expiresAt);const d={...t,content:n,title:e.title!==void 0?e.title:t.title,updatedAt:a,version:t.version+1,keywords:e.keywords!==void 0?e.keywords:t.keywords,bound_files:e.bound_files!==void 0?e.bound_files:t.bound_files,file_md5_map:e.file_md5_map!==void 0?e.file_md5_map:e.bound_files!==void 0?void 0:t.file_md5_map,memory_status:e.memory_status!==void 0?e.memory_status:t.memory_status==="updating"?"normal":t.memory_status||"normal",updating_agent_id:e.memory_status!==void 0?e.updating_agent_id||void 0:t.memory_status==="updating"?void 0:t.updating_agent_id,last_check_time:e.last_check_time!==void 0?e.last_check_time:t.last_check_time,expiresAt:s};return o.by_uri[r.uri]=d,await this.saveData(o),d}async deleteMemory(e){const r=this.normalizeUri(e.uri),i=typeof e.memory_type=="string"?this.normalizeMemoryType(e.memory_type):void 0,o=await this.loadData(),t=o.by_uri[r.uri];return t?(this.ensureTypeMatch(t,i),delete o.by_uri[r.uri],await this.saveData(o),!0):!1}async listExpiredRecentlyMemories(){const e=await this.loadData(),r=new Date,i=[];for(const o of Object.values(e.by_uri))o.memory_type!=="agent_memory"&&o.memory_type!=="recently_memory"||o.expiresAt&&(new Date(o.expiresAt)>r||o.memory_status==="recalling"&&o.updating_agent_id!==g||i.push(o));return i.sort((o,t)=>o.expiresAt.localeCompare(t.expiresAt))}async searchMemory(e){const r=await this.loadData(),o=String(e.query||"").trim().toLowerCase(),t=e.memory_type?this.normalizeMemoryType(e.memory_type):void 0,n=typeof e.limit=="number"&&e.limit>0?e.limit:10,c=e.keywords?.map(l=>l.toLowerCase()),a=e.keyword_mode==="all"?"all":"any",s=D(o);if(s.length===0&&(!c||c.length===0))return{query:o,results:[]};const d=new Set,m=[];for(const l of Object.values(r.by_uri)){if(t&&l.memory_type!==t||d.has(l.id))continue;let u=0;if(c&&c.length>0&&l.keywords){const f=l.keywords.map(y=>y.toLowerCase());if(a==="all"){if(c.every(w=>f.includes(w)))u+=10*c.length;else if(s.length===0)continue}else for(const y of c)f.includes(y)&&(u+=10)}if(s.length>0){const f=`${l.uri}
2
+ ${l.title||""}
3
+ ${l.content}`.toLowerCase();if(!O(s,f)&&u===0)continue;for(const y of s){const w=y.filter(M=>f.includes(M)).length;if(w>0){const M=l.uri.toLowerCase(),I=y.filter(A=>M.includes(A)).length;u+=w+I}}}u!==0&&(d.add(l.id),m.push({score:u,record:l}))}return m.sort((l,u)=>u.score!==l.score?u.score-l.score:u.record.updatedAt.localeCompare(l.record.updatedAt)),{query:o,results:m.slice(0,n).map(l=>l.record)}}async listByType(e){const r=e==="session_context"||e==="project_memory"?E:h,i=this.normalizeMemoryType(e,r),o=await this.loadData(),t=new Set,n=[];for(const c of Object.values(o.by_uri))c.memory_type===i&&(t.has(c.id)||(t.add(c.id),n.push(c)));return n.sort((c,a)=>a.updatedAt.localeCompare(c.updatedAt)),n}async listByFile(e,r){const i=await this.loadData(),o=typeof r=="object"&&r!==null?r.memory_type:r,t=o?this.normalizeMemoryType(o):void 0,n=L(e),c=new Set,a=[];for(const s of Object.values(i.by_uri))t&&s.memory_type!==t||c.has(s.id)||s.bound_files&&s.bound_files.length>0&&s.bound_files.some(m=>L(m)===n)&&(c.add(s.id),a.push(s));return a.sort((s,d)=>d.updatedAt.localeCompare(s.updatedAt)),a}async markExpiredMemoriesRecalling(e){const r=await this.listExpiredRecentlyMemories();if(r.length===0)return{marked:0,uris:[]};const i=r.filter(s=>s.memory_status!=="recalling"),o=e?i.filter(s=>e.includes(s.uri)):i.slice(0,S);if(o.length===0){const s=r.filter(d=>d.memory_status==="recalling").map(d=>d.uri);return{marked:s.length,uris:s}}const t=await this.loadData(),n=this.nowIso(),c=new Date(Date.now()+x*60*1e3).toISOString(),a=[];for(const s of o){const d=t.by_uri[s.uri];d&&(d.memory_status="recalling",d.updating_agent_id=g,d.lease_expires_at=c,d.updatedAt=n,d.version=(d.version||1)+1,a.push(s.uri))}return a.length>0&&await this.saveData(t),{marked:a.length,uris:a}}async clearRecallingExpiredMemories(e){const r=await this.loadData(),i=new Date,o=[];for(const t of Object.values(r.by_uri))p.isExpirableType(t.memory_type)&&t.memory_status==="recalling"&&t.updating_agent_id===g&&t.expiresAt&&(new Date(t.expiresAt)>i||o.push(t.uri));if(e){const t=new Set(e),n=o.filter(c=>t.has(c));o.length=0,o.push(...n)}if(o.length===0)return{deleted:0,uris:[]};for(const t of o)delete r.by_uri[t];return await this.saveData(r),{deleted:o.length,uris:o}}async claimMemoryUpdate(e,r,i){throw new Error("claimMemoryUpdate not supported in local MemoryStore")}async renewMemoryLease(e){throw new Error("renewMemoryLease not supported in local MemoryStore")}async releaseMemoryClaim(e){throw new Error("releaseMemoryClaim not supported in local MemoryStore")}async releaseAllMemoryClaims(){throw new Error("releaseAllMemoryClaims not supported in local MemoryStore")}async getMyClaimedUris(){throw new Error("getMyClaimedUris not supported in local MemoryStore")}}export{T as MemoryCapacityError,p as MemoryStore,L as normalizeBoundFilePath};
4
4
 
@@ -370,6 +370,128 @@ describe('MemoryStore', () => {
370
370
  await rm(dir, { recursive: true, force: true });
371
371
  }
372
372
  });
373
+ // ========== v2.x 并发认领语义测试 ==========
374
+ it('claims up to limit expired memories as recalling with owner and lease', async () => {
375
+ const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
376
+ const storePath = path.join(dir, 'memory');
377
+ const store = new MemoryStore(storePath);
378
+ try {
379
+ // 创建 3 条已过期记忆(不同过期时间,验证最早过期优先)
380
+ const times = [Date.now() - 180_000, Date.now() - 120_000, Date.now() - 60_000];
381
+ const uris = [];
382
+ for (let i = 0; i < 3; i++) {
383
+ const uri = `recent://claim/expire${i}`;
384
+ uris.push(uri);
385
+ await store.createMemory({
386
+ memory_type: 'agent_memory',
387
+ uri,
388
+ content: `expired memory ${i}`,
389
+ expiresAt: new Date(times[i]).toISOString(),
390
+ });
391
+ }
392
+ // 认领(不传 uris → 全部认领)
393
+ const claim = await store.markExpiredMemoriesRecalling();
394
+ assert.equal(claim.marked, 3, 'should claim all 3 expired memories');
395
+ assert.deepEqual(new Set(claim.uris), new Set(uris));
396
+ // 认领后的记录:recalling + owner + 租约
397
+ const held = await store.listExpiredRecentlyMemories();
398
+ assert.equal(held.length, 3, 'own claimed memories still visible via list');
399
+ for (const m of held) {
400
+ assert.equal(m.memory_status, 'recalling');
401
+ assert.equal(m.updating_agent_id, 'local');
402
+ assert.ok(m.lease_expires_at, 'lease should be set');
403
+ }
404
+ // 幂等:再次认领不重复计数,仅续期
405
+ const claimAgain = await store.markExpiredMemoriesRecalling();
406
+ assert.equal(claimAgain.marked, 3, 'idempotent: no new claims counted');
407
+ }
408
+ finally {
409
+ await rm(dir, { recursive: true, force: true });
410
+ }
411
+ });
412
+ it('excludes others-recalling memories from list (ownership filter)', async () => {
413
+ const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
414
+ const storePath = path.join(dir, 'memory');
415
+ const store = new MemoryStore(storePath);
416
+ try {
417
+ // 直接构造一条"他人认领"(updating_agent_id != 'local')的过期记忆
418
+ await store.createMemory({
419
+ memory_type: 'agent_memory',
420
+ uri: 'recent://claim/other1',
421
+ content: 'claimed by another instance',
422
+ expiresAt: new Date(Date.now() - 60_000).toISOString(),
423
+ });
424
+ const data = await store.loadData();
425
+ const rec = data.by_uri['recent://claim/other1'];
426
+ rec.memory_status = 'recalling';
427
+ rec.updating_agent_id = 'other-instance';
428
+ await store.saveData(data);
429
+ // 自己的可认领记忆
430
+ await store.createMemory({
431
+ memory_type: 'agent_memory',
432
+ uri: 'recent://claim/mine1',
433
+ content: 'mine to claim',
434
+ expiresAt: new Date(Date.now() - 30_000).toISOString(),
435
+ });
436
+ // 他人的 recalling 不可见,仅自己的 normal 可见
437
+ const expired = await store.listExpiredRecentlyMemories();
438
+ assert.equal(expired.length, 1, 'others-recalling should be filtered out');
439
+ assert.equal(expired[0]?.uri, 'recent://claim/mine1');
440
+ }
441
+ finally {
442
+ await rm(dir, { recursive: true, force: true });
443
+ }
444
+ });
445
+ it('clearRecallingExpiredMemories only deletes own claimed + supports uris filter', async () => {
446
+ const dir = await mkdtemp(path.join(os.tmpdir(), 'aws-memory-store-'));
447
+ const storePath = path.join(dir, 'memory');
448
+ const store = new MemoryStore(storePath);
449
+ try {
450
+ // 两条自己认领的过期记忆 + 一条他人认领的过期记忆
451
+ await store.createMemory({
452
+ memory_type: 'agent_memory',
453
+ uri: 'recent://clear/own1',
454
+ content: 'own 1',
455
+ expiresAt: new Date(Date.now() - 60_000).toISOString(),
456
+ });
457
+ await store.createMemory({
458
+ memory_type: 'agent_memory',
459
+ uri: 'recent://clear/own2',
460
+ content: 'own 2',
461
+ expiresAt: new Date(Date.now() - 60_000).toISOString(),
462
+ });
463
+ await store.createMemory({
464
+ memory_type: 'agent_memory',
465
+ uri: 'recent://clear/other1',
466
+ content: 'other 1',
467
+ expiresAt: new Date(Date.now() - 60_000).toISOString(),
468
+ });
469
+ await store.markExpiredMemoriesRecalling();
470
+ // 标记"他人认领"(模拟另一实例)
471
+ const data = await store.loadData();
472
+ data.by_uri['recent://clear/other1'].memory_status = 'recalling';
473
+ data.by_uri['recent://clear/other1'].updating_agent_id = 'other-instance';
474
+ await store.saveData(data);
475
+ // 分批收尾:只删 own1
476
+ const partial = await store.clearRecallingExpiredMemories(['recent://clear/own1']);
477
+ assert.equal(partial.deleted, 1);
478
+ assert.deepEqual(partial.uris, ['recent://clear/own1']);
479
+ // own2 仍在,他人认领的仍在(归属校验)
480
+ const remaining = await store.listExpiredRecentlyMemories();
481
+ const remainingUris = remaining.map(m => m.uri).sort();
482
+ assert.deepEqual(remainingUris, ['recent://clear/own2']);
483
+ // 最终收尾:不传 uris 删全部本人认领的
484
+ const final = await store.clearRecallingExpiredMemories();
485
+ assert.equal(final.deleted, 1);
486
+ assert.deepEqual(final.uris, ['recent://clear/own2']);
487
+ // 他人认领的始终未被删除(模拟:其 URI 仍在数据中)
488
+ const dataAfter = await store.loadData();
489
+ assert.ok(dataAfter.by_uri['recent://clear/other1'], 'others-recalling must not be deleted');
490
+ }
491
+ finally {
492
+ await rm(dir, { recursive: true, force: true });
493
+ }
494
+ });
373
495
  });
374
496
  // ========== listByFile 与 normalizeBoundFilePath 测试 ==========
375
497
  describe('normalizeBoundFilePath', () => {
@@ -21,11 +21,14 @@ const e={type:"string",enum:["recently_memory","agent_memory","project_memory"],
21
21
  - \u641C\u7D22\u7ED3\u679C\u4F7F\u7528 5 \u79D2\u5185\u5B58\u7F13\u5B58\uFF0C\u8FDE\u7EED\u641C\u7D22\u4E0D\u4F1A\u91CD\u590D\u8BFB\u76D8\u3002
22
22
  - \u8BB0\u5FC6\u5199\u5165\u64CD\u4F5C\u4F1A\u81EA\u52A8\u6E05\u9664\u7F13\u5B58\uFF0C\u786E\u4FDD\u6570\u636E\u4E00\u81F4\u6027\u3002`,inputSchema:{type:"object",properties:{query:{type:"string",description:"\u641C\u7D22\u5173\u952E\u5B57\u3002\u652F\u6301 | OR \u5206\u9694\u7B26\u548C\u7A7A\u683C AND \u8BCD\u7EC4\u3002\u4F8B\u5982\u300C\u67B6\u6784|\u6280\u672F \u8BBE\u8BA1\u300D\u8868\u793A\u641C\u7D22\u5305\u542B\u300C\u67B6\u6784\u300D\u6216\u540C\u65F6\u5305\u542B\u300C\u6280\u672F+\u8BBE\u8BA1\u300D\u7684\u8BB0\u5F55\u3002"},limit:{type:"number",description:"\u6700\u591A\u8FD4\u56DE\u6761\u6570\uFF0C\u9ED8\u8BA4 10\u3002"},memory_type:e,keywords:{type:"array",items:{type:"string"},description:"\u6309\u5173\u952E\u8BCD\u8FC7\u6EE4\u3002\u914D\u5408 keyword_mode \u63A7\u5236\u5339\u914D\u903B\u8F91\uFF08any=\u4EFB\u4E00\u5339\u914D\uFF0Call=\u5168\u90E8\u5339\u914D\uFF09\u3002\u5173\u952E\u8BCD\u5339\u914D\u4F18\u5148\u7EA7\u9AD8\u4E8E\u5185\u5BB9\u5339\u914D\u3002"},keyword_mode:{type:"string",enum:["any","all"],description:"\u5173\u952E\u8BCD\u8FC7\u6EE4\u6A21\u5F0F\uFF1Aany\uFF08\u9ED8\u8BA4\uFF0C\u4EFB\u4E00\u5173\u952E\u8BCD\u5339\u914D\u5373\u9009\u4E2D\uFF09\u3001all\uFF08\u6240\u6709\u5173\u952E\u8BCD\u90FD\u9700\u5339\u914D\uFF09\u3002"},scope:{type:"string",enum:["own","children","all"],description:"\u641C\u7D22\u8303\u56F4\uFF1Aown\uFF08\u9ED8\u8BA4\uFF0C\u4EC5\u641C\u7D22\u81EA\u5DF1\u7684\u8BB0\u5FC6\uFF09\u3001children\uFF08\u641C\u7D22\u5B50Agent\u7ED1\u5B9A\u4E86\u6587\u4EF6\u7684\u8BB0\u5FC6\uFF09\u3001all\uFF08\u5408\u5E76\u641C\u7D22\u81EA\u5DF1\u548C\u5B50Agent\u7684\u8BB0\u5FC6\uFF09\u3002"}},required:["query"]}},y={name:"list_memories",description:"\u6309\u7C7B\u578B\u5217\u51FA\u5F53\u524D Agent \u5DE5\u4F5C\u533A\u7684 recently_memory\u3001agent_memory \u6216 project_memory\u3002agent_memory \u4E3B\u8981\u7528 search_memory \u68C0\u7D22\uFF1Bproject_memory \u540C\u6837\u652F\u6301 list\u3002",inputSchema:{type:"object",properties:{memory_type:t},required:["memory_type"]}},_={name:"get_memory_stats",description:"\u83B7\u53D6\u5F53\u524D Agent \u5DE5\u4F5C\u533A\u672C\u5730\u8BB0\u5FC6\u7684\u5BB9\u91CF\u7EDF\u8BA1\u3002\u9ED8\u8BA4\u8FD4\u56DE\u77ED\u671F/\u8FD1\u671F/\u957F\u671F\u603B\u6570\u3001\u77ED\u671F/\u8FD1\u671F\u4E0B\u7684 URI domain \u7C7B\u578B\u5360\u7528\u3001\u4EE5\u53CA\u6BCF\u4E2A domain \u4E0B memory \u6761\u6570\u5360\u7528\uFF1B\u4F20 memory_type \u65F6\u53EA\u8FD4\u56DE\u8BE5\u5C42\u7EA7\u7684\u7C7B\u578B\u5360\u7528\u8BE6\u60C5\u3002",inputSchema:{type:"object",properties:{memory_type:e},required:[]}},s={name:"list_memories_by_file",description:"\u67E5\u8BE2\u7ED1\u5B9A\u4E86\u6307\u5B9A\u6587\u4EF6\u7684\u6240\u6709 Memory\u3002\u9ED8\u8BA4\u5408\u5E76\u641C\u7D22\u81EA\u8EAB\u4E0E\u5B50Agent\uFF08\u5DE5\u4F5C\u533A\u8DEF\u5F84\u4E3A\u5F53\u524D\u8DEF\u5F84\u5B50\u76EE\u5F55\u7684Agent\uFF09\u7ED1\u5B9A\u4E86\u6587\u4EF6\u7684\u8BB0\u5FC6\uFF0C\u5B50Agent\u7684\u8BB0\u5FC6\u4F1A\u505Apath_prefix\u81EA\u52A8\u5339\u914D\uFF0C\u65E0\u9700\u624B\u52A8\u8BA1\u7B97\u8DEF\u5F84\u3002\u4F8B\u5982\u7236Agent\u641C\u7D22 ./a/b/c/src/a.txt\uFF0C\u5B50Agent(\u5DE5\u4F5C\u8DEF\u5F84./a/b/c)\u7ED1\u5B9A./src/a.txt\u7684\u8BB0\u5FC6\u4F1A\u88AB\u81EA\u52A8\u5339\u914D\u3002",inputSchema:{type:"object",properties:{file_path:{type:"string",description:"\u6587\u4EF6\u8DEF\u5F84\uFF0C\u4F8B\u5982 /path/to/file.md"},memory_type:e,scope:{type:"string",enum:["own","children","all"],description:"\u641C\u7D22\u8303\u56F4\uFF1Aown\uFF08\u4EC5\u641C\u7D22\u81EA\u5DF1\u7684\u8BB0\u5FC6\uFF09\u3001children\uFF08\u641C\u7D22\u5B50Agent\u7ED1\u5B9A\u4E86\u6587\u4EF6\u7684\u8BB0\u5FC6\uFF0C\u6309path_prefix\u81EA\u52A8\u5339\u914D\uFF09\u3001all\uFF08\u9ED8\u8BA4\uFF0C\u5408\u5E76\u641C\u7D22\u81EA\u5DF1\u548C\u5B50Agent\u7684\u8BB0\u5FC6\uFF09\u3002"}},required:["file_path"]}},c={name:"abandon_memory_update",description:"\u653E\u5F03\u6307\u5B9A Memory \u7684\u66F4\u65B0\u4E2D\u72B6\u6001\u3002\u5F53\u7CFB\u7EDF\u68C0\u6D4B\u5230\u6587\u4EF6\u53D8\u66F4\u5E76\u81EA\u52A8\u6807\u8BB0\u4E3A\u66F4\u65B0\u4E2D\u540E\uFF0C\u5982\u679C Agent \u51B3\u5B9A\u6682\u4E0D\u66F4\u65B0\uFF0C\u53EF\u4EE5\u8C03\u7528\u6B64\u5DE5\u5177\u6E05\u9664\u66F4\u65B0\u6807\u8BB0\u3002\u6CE8\u610F\uFF1A\u82E5\u5F53\u524D\u5DF2\u7ED1\u5B9A\u7684\u6587\u4EF6\u4E2D\u5B58\u5728\u5DF2\u5220\u9664\u7684\u6587\u4EF6\uFF0C\u653E\u5F03\u66F4\u65B0\u5C06\u5931\u8D25\uFF0C\u9700\u5148\u901A\u8FC7 update_memory \u4FEE\u6B63 bound_files \u5217\u8868\uFF08\u79FB\u9664\u4E0D\u5B58\u5728\u7684\u6587\u4EF6\uFF09\u3002",inputSchema:{type:"object",properties:{uri:r,memory_type:e},required:["uri"]}},a={name:"memory_recurrence",description:`\u83B7\u53D6\u5DF2\u8FC7\u671F\u7684 agent_memory\uFF08agent \u5BF9\u5916\u90E8\u73AF\u5883\u7684\u8BA4\u77E5\u8BB0\u5FC6\uFF09\u3002
23
23
  \u8FC7\u671F\u6761\u4EF6\uFF1Aagent_memory \u7684 expires_at < NOW()\u3002\u521D\u59CB TTL 12h\uFF0C\u6BCF\u6B21 update_memory \u7EED\u671F\u65F6 TTL \xD72\u3002
24
- \u8C03\u7528\u540E\uFF0C\u7CFB\u7EDF\u4F1A\u5C06\u8FD9\u4E9B\u8BB0\u5FC6\u6807\u8BB0\u4E3A[\u56DE\u5FC6\u4E2D](recalling)\u72B6\u6001\u3002
24
+ \u8C03\u7528\u540E\uFF0C\u7CFB\u7EDF\u4F1A\u539F\u5B50\u8BA4\u9886\u6700\u591A 50 \u6761\u5DF2\u8FC7\u671F\u8BB0\u5FC6\u4E3A[\u56DE\u5FC6\u4E2D](recalling)\u72B6\u6001\uFF08\u8BA4\u9886\u8005+\u8BA4\u9886\u79DF\u7EA6\uFF0C\u5E42\u7B49\u53EF\u91CD\u590D\u8C03\u7528\uFF09\u3002
25
+ \u5DF2\u7EED\u671F\u7684\u8BB0\u5FC6\uFF08expiresAt \u5728\u672A\u6765\uFF09\u4E0D\u4F1A\u518D\u6B21\u51FA\u73B0\uFF1B\u51B3\u5B9A\u4E0D\u4FDD\u7559\u7684\u8BB0\u5FC6\u4FDD\u6301[\u56DE\u5FC6\u4E2D]\u72B6\u6001\uFF0C
26
+ \u5728\u672C\u6279\u5BA1\u67E5\u5B8C\u6BD5\u540E\u901A\u8FC7 memory_recurrence_complete(uris=[\u672C\u6279\u786E\u5B9A\u5220\u9664\u7684URI]) \u6E05\u7406\u5220\u9664\u3002
25
27
  Agent \u5E94\u5BA1\u67E5\u8FD9\u4E9B\u8BB0\u5FC6\u5185\u5BB9\uFF0C\u51B3\u5B9A\u662F\uFF1A
26
- 1) \u901A\u8FC7 update_memory \u7EED\u671F\uFF08TTL \xD72\uFF0C\u72B6\u6001\u6062\u590D normal\uFF09
27
- 2) \u4E0D\u5904\u7406\uFF0C\u56DE\u5FC6\u5B8C\u6210\u540E\u8C03\u7528 memory_recurrence_complete \u5220\u9664\u5B83\u4EEC`,inputSchema:{type:"object",properties:{limit:{type:"number",description:"\u6BCF\u6B21\u6279\u91CF\u5904\u7406\u7684\u8BB0\u5FC6\u6570\u91CF\uFF08\u6309\u8FC7\u671F\u65F6\u95F4\u6700\u65E9\u4F18\u5148\uFF0C\u9ED8\u8BA4 10\uFF09\u3002\u4F8B\u5982 totalExpired=40\u3001limit=10 \u65F6\u7B2C\u4E00\u6B21\u8FD4\u56DE 10 \u6761\uFF0Cremaining=30\u3002",default:10}},required:[]}},d={name:"memory_recurrence_complete",description:`\u5B8C\u6210\u5373\u5C06\u9057\u5FD8\u7684\u8BB0\u5FC6\u758F\u7406\u5DE5\u4F5C\u3002
28
- Agent \u5DF2\u5BA1\u67E5\u5B8C memory_recurrence \u8FD4\u56DE\u7684\u6240\u6709\u8FC7\u671F agent_memory\uFF0C
29
- \u5DF2\u5B8C\u6210\u5FC5\u8981\u7684\u7EED\u671F\u64CD\u4F5C\uFF0C\u73B0\u5728\u6E05\u7406\u8FD9\u4E9B\u5DF2\u6807\u8BB0\u4E3A[\u56DE\u5FC6\u4E2D]\u7684\u8FC7\u671F\u8BB0\u5FC6\u3002
30
- \u8C03\u7528\u540E\u7CFB\u7EDF\u5C06\u5220\u9664\u6240\u6709[\u56DE\u5FC6\u4E2D]\u72B6\u6001\u7684\u5DF2\u8FC7\u671F agent_memory\u3002`,inputSchema:{type:"object",properties:{},required:[]}};export{c as ABANDON_MEMORY_UPDATE_TOOL,n as CREATE_MEMORY_TOOL,i as DELETE_MEMORY_TOOL,_ as GET_MEMORY_STATS_TOOL,s as LIST_MEMORIES_BY_FILE_TOOL,y as LIST_MEMORIES_TOOL,d as MEMORY_RECURRENCE_COMPLETE_TOOL,a as MEMORY_RECURRENCE_TOOL,o as READ_MEMORY_TOOL,p as SEARCH_MEMORY_TOOL,m as UPDATE_MEMORY_TOOL};
28
+ 1) \u901A\u8FC7 update_memory \u7EED\u671F\uFF08TTL \xD72\uFF0C\u7EED\u671F\u540E\u4E0D\u518D\u8FC7\u671F\uFF0C\u4E0D\u4F1A\u88AB\u5220\u9664\uFF09
29
+ 2) \u4E0D\u7EED\u671F\uFF0C\u672C\u6279\u5BA1\u67E5\u5B8C\u6BD5\u540E\u8C03\u7528 memory_recurrence_complete(uris=[...]) \u5220\u9664\u5B83\u4EEC`,inputSchema:{type:"object",properties:{limit:{type:"number",description:"\u6BCF\u6B21\u6279\u91CF\u5904\u7406\u7684\u8BB0\u5FC6\u6570\u91CF\uFF08\u6309\u8FC7\u671F\u65F6\u95F4\u6700\u65E9\u4F18\u5148\uFF0C\u9ED8\u8BA4 10\uFF09\u3002\u4F8B\u5982 totalExpired=40\u3001limit=10 \u65F6\u7B2C\u4E00\u6B21\u8FD4\u56DE 10 \u6761\uFF0Cremaining=30\u3002",default:10}},required:[]}},d={name:"memory_recurrence_complete",description:`\u5B8C\u6210\u5373\u5C06\u9057\u5FD8\u7684\u8BB0\u5FC6\u758F\u7406\u5DE5\u4F5C\u3002
30
+ \u5220\u9664\u672C\u4EBA\u8BA4\u9886\u7684[\u56DE\u5FC6\u4E2D](recalling)\u72B6\u6001\u5DF2\u8FC7\u671F agent_memory\u3002
31
+ \u63A8\u8350\u7528\u6CD5\uFF1A\u6BCF\u6279\u5BA1\u67E5\u5B8C\u6BD5\u540E\u8C03\u7528 memory_recurrence_complete(uris=[\u672C\u6279\u786E\u5B9A\u5220\u9664\u7684URI]) \u5206\u6279\u6E05\u7406\uFF1B
32
+ \u5168\u90E8\u6279\u6B21\u5904\u7406\u5B8C\u6BD5\u540E\u8C03\u7528 memory_recurrence_complete()\uFF08\u4E0D\u5E26\u53C2\u6570\uFF09\u5220\u9664\u5269\u4F59\u5168\u90E8\u3002
33
+ \u8BE5\u5DE5\u5177\u4EC5\u5220\u9664\uFF0C\u4E0D\u505A\u5F52\u6863\uFF1B\u9700\u8981\u957F\u671F\u4FDD\u7559\u7684\u5185\u5BB9\u8BF7\u5148\u8C03\u7528 create_memory \u4FDD\u5B58\u540E\u518D\u5220\u9664\u65E7\u6761\u76EE\u3002`,inputSchema:{type:"object",properties:{uris:{type:"array",items:{type:"string"},description:"\u53EF\u9009\u3002\u672C\u6279\u786E\u5B9A\u5220\u9664\u7684 memory URI \u5217\u8868\uFF1B\u4E0D\u4F20\u65F6\u5220\u9664\u672C\u4EBA\u8BA4\u9886\u7684\u5168\u90E8[\u56DE\u5FC6\u4E2D]\u5DF2\u8FC7\u671F\u8BB0\u5FC6\u3002"}},required:[]}};export{c as ABANDON_MEMORY_UPDATE_TOOL,n as CREATE_MEMORY_TOOL,i as DELETE_MEMORY_TOOL,_ as GET_MEMORY_STATS_TOOL,s as LIST_MEMORIES_BY_FILE_TOOL,y as LIST_MEMORIES_TOOL,d as MEMORY_RECURRENCE_COMPLETE_TOOL,a as MEMORY_RECURRENCE_TOOL,o as READ_MEMORY_TOOL,p as SEARCH_MEMORY_TOOL,m as UPDATE_MEMORY_TOOL};
31
34
 
@@ -20,7 +20,7 @@ export declare class ServerMemoryStore implements MemoryStorePort {
20
20
  marked: number;
21
21
  uris: string[];
22
22
  }>;
23
- clearRecallingExpiredMemories(): Promise<{
23
+ clearRecallingExpiredMemories(uris?: string[]): Promise<{
24
24
  deleted: number;
25
25
  uris: string[];
26
26
  }>;
@@ -1,2 +1,2 @@
1
- class a{agentClient;constructor(e){this.agentClient=e}ensureSuccess(e){if(e&&typeof e=="object"&&"error"in e){const t=e.error;throw new Error(typeof t=="string"?t:"Server memory operation failed")}return e}async getStats(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("get_memory_stats",{}))}async createMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("create_memory",e))}async readMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("read_memory",e))}async updateMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("update_memory",e))}async deleteMemory(e){return!!this.ensureSuccess(await this.agentClient.callAgentScopedTool("delete_memory",e)).deleted}async searchMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("search_memory",e))}async listByType(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("list_memories",{memory_type:e}))}async listExpiredRecentlyMemories(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("list_expired_memories",{}))}async markExpiredMemoriesRecalling(e){const t={};return e&&e.length>0&&(t.uris=e),this.ensureSuccess(await this.agentClient.callAgentScopedTool("mark_expired_memories_recalling",t))}async clearRecallingExpiredMemories(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("clear_recalling_expired_memories",{}))}async claimMemoryUpdate(e,t,s){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("claim_memory_update",{uris:e,lease_minutes:t,...s?{memory_type:s}:{}}))}async renewMemoryLease(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("renew_memory_lease",{lease_minutes:e}))}async releaseMemoryClaim(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("release_memory_update",{uri:e}))}async releaseAllMemoryClaims(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("release_all_memory_updates",{}))}async getMyClaimedUris(){const e=await this.agentClient.callAgentScopedTool("get_my_claimed_memory_uris",{});return this.ensureSuccess(e),e.uris??[]}async listByFile(e,t){const s=typeof t=="object"&&t!==null?{memory_type:t.memory_type,scope:t.scope}:{memory_type:t},r=await this.agentClient.callAgentScopedTool("list_memories_by_file",{file_path:e,...s.memory_type?{memory_type:s.memory_type}:{},...s.scope?{scope:s.scope}:{}});return this.ensureSuccess(r),r.results??[]}}export{a as ServerMemoryStore};
1
+ class a{agentClient;constructor(e){this.agentClient=e}ensureSuccess(e){if(e&&typeof e=="object"&&"error"in e){const t=e.error;throw new Error(typeof t=="string"?t:"Server memory operation failed")}return e}async getStats(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("get_memory_stats",{}))}async createMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("create_memory",e))}async readMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("read_memory",e))}async updateMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("update_memory",e))}async deleteMemory(e){return!!this.ensureSuccess(await this.agentClient.callAgentScopedTool("delete_memory",e)).deleted}async searchMemory(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("search_memory",e))}async listByType(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("list_memories",{memory_type:e}))}async listExpiredRecentlyMemories(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("list_expired_memories",{}))}async markExpiredMemoriesRecalling(e){const t={};return e&&e.length>0&&(t.uris=e),this.ensureSuccess(await this.agentClient.callAgentScopedTool("mark_expired_memories_recalling",t))}async clearRecallingExpiredMemories(e){const t={};return e&&e.length>0&&(t.uris=e),this.ensureSuccess(await this.agentClient.callAgentScopedTool("clear_recalling_expired_memories",t))}async claimMemoryUpdate(e,t,s){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("claim_memory_update",{uris:e,lease_minutes:t,...s?{memory_type:s}:{}}))}async renewMemoryLease(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("renew_memory_lease",{lease_minutes:e}))}async releaseMemoryClaim(e){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("release_memory_update",{uri:e}))}async releaseAllMemoryClaims(){return this.ensureSuccess(await this.agentClient.callAgentScopedTool("release_all_memory_updates",{}))}async getMyClaimedUris(){const e=await this.agentClient.callAgentScopedTool("get_my_claimed_memory_uris",{});return this.ensureSuccess(e),e.uris??[]}async listByFile(e,t){const s=typeof t=="object"&&t!==null?{memory_type:t.memory_type,scope:t.scope}:{memory_type:t},r=await this.agentClient.callAgentScopedTool("list_memories_by_file",{file_path:e,...s.memory_type?{memory_type:s.memory_type}:{},...s.scope?{scope:s.scope}:{}});return this.ensureSuccess(r),r.results??[]}}export{a as ServerMemoryStore};
2
2
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aws-runtime-bridge",
3
- "version": "1.9.118",
3
+ "version": "1.9.120",
4
4
  "description": "AgentsWorkStudio runtime bridge service for machine-level agent runtime integration",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -13,6 +13,7 @@
13
13
  "dist",
14
14
  "scripts/ensure-bin-executable.mjs",
15
15
  "scripts/ensure-playwright-browser.mjs",
16
+ "scripts/ensure-build-tools.mjs",
16
17
  "package/aws-client-agent-mcp/dist",
17
18
  "package/aws-client-agent-mcp/package.json",
18
19
  "package/aws-client-agent-mcp/README.md",
@@ -39,6 +40,7 @@
39
40
  "build:sdk": "npm run build --prefix package/cc-switch-sdk",
40
41
  "build:all": "npm run build:sdk && npm run build:acode && npm run build:agent-mcp",
41
42
  "prebuild": "npm run build:all",
43
+ "preinstall": "node scripts/ensure-build-tools.mjs",
42
44
  "build": "tsc -p tsconfig.json && node scripts/minify-dist.mjs",
43
45
  "postinstall": "node scripts/ensure-bin-executable.mjs && node scripts/ensure-playwright-browser.mjs",
44
46
  "pretypecheck": "npm run build:all",
@@ -0,0 +1,141 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * preinstall 钩子:Linux 上确保 node-pty 等原生依赖编译所需的 C/C++ 工具链已就绪。
4
+ *
5
+ * 背景:node-pty(终端 PTY)的 npm 包只为 darwin/win32 提供预编译产物,
6
+ * Linux 上安装时总是走 node-gyp 源码编译(其 scripts/prebuild.js 检测到
7
+ * prebuilds/linux-x64 不存在即回退编译)。若服务器缺少 g++/make/python3,
8
+ * `npm install -g aws-runtime-bridge` 会在编译 node-pty 时报
9
+ * 「make: g++: No such file or directory」直接失败。
10
+ *
11
+ * 本脚本在依赖安装之前(preinstall 阶段)自动补齐工具链:
12
+ * - Linux + root(如 sudo npm install -g):按发行版自动安装
13
+ * (apt-get / dnf / yum / zypper / apk / pacman),一步到位。
14
+ * - Linux 非 root:输出可操作的 sudo 命令提示并以非零退出(缺少工具链时
15
+ * 依赖安装必然失败,提前给出明确报错比 node-gyp 的原始报错更友好)。
16
+ * - 其他平台(Windows/macOS):无需编译,静默跳过。
17
+ * - 幂等:工具链已就绪时直接跳过,重复安装无副作用。
18
+ * - 跳过:设置环境变量 AWS_BRIDGE_SKIP_BUILD_TOOLS=1(自行负责)。
19
+ */
20
+ import { spawnSync } from "node:child_process";
21
+
22
+ const SKIP_ENV = "AWS_BRIDGE_SKIP_BUILD_TOOLS";
23
+
24
+ /** node-pty 源码编译所需的最小工具链。 */
25
+ const REQUIRED_TOOLS = ["g++", "make", "python3"];
26
+
27
+ /** 常见发行版包管理器及其编译工具链安装命令(顺序即探测优先级)。 */
28
+ const PACKAGE_MANAGERS = [
29
+ {
30
+ id: "apt-get",
31
+ update: ["apt-get", "update"],
32
+ install: ["apt-get", "install", "-y", "build-essential", "python3"],
33
+ },
34
+ {
35
+ id: "dnf",
36
+ install: ["dnf", "install", "-y", "gcc-c++", "make", "python3"],
37
+ },
38
+ {
39
+ id: "yum",
40
+ install: ["yum", "install", "-y", "gcc-c++", "make", "python3"],
41
+ },
42
+ {
43
+ id: "zypper",
44
+ install: ["zypper", "install", "-y", "gcc-c++", "make", "python3"],
45
+ },
46
+ {
47
+ id: "apk",
48
+ install: ["apk", "add", "--no-cache", "build-base", "python3"],
49
+ },
50
+ {
51
+ id: "pacman",
52
+ install: ["pacman", "-S", "--noconfirm", "base-devel", "python3"],
53
+ },
54
+ ];
55
+
56
+ /** 探测命令是否可用(ENOENT 或非零退出视为缺失)。 */
57
+ function toolAvailable(bin) {
58
+ const result = spawnSync(bin, ["--version"], { stdio: "ignore" });
59
+ return !result.error && result.status === 0;
60
+ }
61
+
62
+ function run(argv, { fatal = true } = {}) {
63
+ const result = spawnSync(argv[0], argv.slice(1), { stdio: "inherit" });
64
+ if (result.error || result.status !== 0) {
65
+ if (fatal) {
66
+ console.error(`[aws-runtime-bridge] 命令执行失败:${argv.join(" ")}`);
67
+ return false;
68
+ }
69
+ console.warn(`[aws-runtime-bridge] 命令执行失败(已忽略):${argv.join(" ")}`);
70
+ }
71
+ return !result.error && result.status === 0;
72
+ }
73
+
74
+ function main() {
75
+ // 非 Linux 平台无需编译工具链
76
+ if (process.platform !== "linux") return;
77
+
78
+ const missing = REQUIRED_TOOLS.filter((bin) => !toolAvailable(bin));
79
+ if (missing.length === 0) return; // 已就绪,幂等跳过
80
+
81
+ if (process.env[SKIP_ENV] === "1") {
82
+ console.warn(
83
+ `[aws-runtime-bridge] ${SKIP_ENV}=1,跳过编译工具链自动安装;` +
84
+ `但 Linux 上 node-pty 必须源码编译,缺少 ${missing.join("、")} 会导致安装失败`,
85
+ );
86
+ return; // 用户显式要求跳过,放行由后续 node-gyp 自行报错
87
+ }
88
+
89
+ const isRoot = typeof process.getuid === "function" && process.getuid() === 0;
90
+ const manualHint =
91
+ "Ubuntu/Debian:sudo apt-get update && sudo apt-get install -y build-essential python3\n" +
92
+ " Fedora/RHEL:sudo dnf install -y gcc-c++ make python3(旧版 CentOS 用 yum)\n" +
93
+ " openSUSE:sudo zypper install -y gcc-c++ make python3\n" +
94
+ " Alpine:sudo apk add --no-cache build-base python3";
95
+
96
+ if (!isRoot) {
97
+ console.error(
98
+ `[aws-runtime-bridge] Linux 上 node-pty 无预编译产物,需要现场编译,` +
99
+ `但当前缺少:${missing.join("、")}。请先用 root 安装编译工具链后重试:\n` +
100
+ manualHint,
101
+ );
102
+ process.exit(1);
103
+ }
104
+
105
+ const pm = PACKAGE_MANAGERS.find((entry) => toolAvailable(entry.id));
106
+ if (!pm) {
107
+ console.error(
108
+ `[aws-runtime-bridge] 未识别到支持的包管理器,且缺少编译工具链:${missing.join("、")}。` +
109
+ `请手动安装后重试:\n${manualHint}`,
110
+ );
111
+ process.exit(1);
112
+ }
113
+
114
+ console.log(
115
+ `[aws-runtime-bridge] 检测到缺少编译工具链(${missing.join("、")}),` +
116
+ `正在用 ${pm.id} 自动安装(node-pty 在 Linux 上需要源码编译)...`,
117
+ );
118
+
119
+ if (pm.update && !run(pm.update, { fatal: false })) {
120
+ console.warn("[aws-runtime-bridge] 包索引更新失败,继续尝试直接安装...");
121
+ }
122
+
123
+ if (!run(pm.install)) {
124
+ console.error(
125
+ `[aws-runtime-bridge] 编译工具链自动安装失败,请手动执行后重试:\n${manualHint}`,
126
+ );
127
+ process.exit(1);
128
+ }
129
+
130
+ const stillMissing = REQUIRED_TOOLS.filter((bin) => !toolAvailable(bin));
131
+ if (stillMissing.length > 0) {
132
+ console.error(
133
+ `[aws-runtime-bridge] 安装后仍缺少:${stillMissing.join("、")},请手动安装后重试:\n${manualHint}`,
134
+ );
135
+ process.exit(1);
136
+ }
137
+
138
+ console.log("[aws-runtime-bridge] 编译工具链已就绪,继续安装...");
139
+ }
140
+
141
+ main();