@fifthrevision/axle-cli 0.28.0 → 0.30.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +5 -5
- package/dist/store/index.js +1 -1
- package/dist/tools/index.js +1 -1
- package/dist/{tools-Cp5kiYmz.js → tools-DTZhd_3g.js} +4 -4
- package/package.json +2 -6
- package/dist/memory/index.d.ts +0 -30
- package/dist/memory/index.js +0 -1
- package/dist/memory-BS-U-K_q.js +0 -20
- package/dist/store-BFxiiKeG.js +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{
|
|
3
|
-
`)}const H=`.axle/batch.jsonl`;function
|
|
4
|
-
`)){let n=e.trim();if(n)try{let e=JSON.parse(n);e.file&&e.hash&&t.set(e.file,e)}catch{}}return t}async function
|
|
5
|
-
`,`utf-8`)}async function
|
|
6
|
-
> `);if(r===null||r.trim()===``)break;try{let i=await e.send(r.trim()).final;if(
|
|
2
|
+
import{a as e,i as t,n,r,t as i}from"./tools-DTZhd_3g.js";import{Command as a}from"@commander-js/extra-typings";import{Agent as o,Instruct as s,MCP as c,SimpleWriter as l,Tracer as u,addStats as d,anthropic as f,chatCompletions as p,createAgentConfig as m,createStats as h,gemini as g,loadFileContent as _,openai as v}from"@fifthrevision/axle";import{Models as y}from"@fifthrevision/axle/models";import{z as b}from"zod";import{appendFile as ee,mkdir as x,readFile as S}from"node:fs/promises";import{basename as te,dirname as ne,extname as C}from"node:path";import{config as w}from"dotenv";import T from"yaml";import{glob as re}from"glob";import{createInterface as ie}from"node:readline";import{createHash as ae}from"node:crypto";var oe=`0.30.0`;async function se(e,t){let n=[];for(let r of e){let e=new c(r);await e.connect({span:t}),n.push(e)}return n}async function ce(e,t){for(let n of e)try{await n.close({span:t})}catch{}}function le(a,o){switch(a){case`calculator`:return e;case`exec`:{let e=o?.exec;return e&&t.configure(e),t}case`patch-file`:return r;case`read-file`:return n;case`write-file`:return i;default:throw Error(`Unknown tool: ${a}`)}}function ue(e,t){return e.map(e=>le(e,t))}const E={anthropic:y.Anthropic.CLAUDE_HAIKU_4_5,gemini:y.Google.GEMINI_3_5_FLASH,openai:y.OpenAI.GPT_5_4_MINI};function de(e,t){let n=e.config??{};switch(e.type){case`openai`:{let e={...t.openai,...n},r=D(e);if(!r)throw Error(`The provider openai is not configured. Please check your configuration.`);return{provider:v(r,{maxRetries:e.maxRetries,timeoutMs:e.timeoutMs}),model:O(e,E.openai)}}case`anthropic`:{let e={...t.anthropic,...n},r=D(e);if(!r)throw Error(`The provider anthropic is not configured. Please check your configuration.`);return{provider:f(r,{maxRetries:e.maxRetries,timeoutMs:e.timeoutMs}),model:O(e,E.anthropic)}}case`gemini`:{let e={...t.gemini,...n},r=D(e);if(!r)throw Error(`The provider gemini is not configured. Please check your configuration.`);return{provider:g(r,{maxRetries:e.maxRetries,timeoutMs:e.timeoutMs}),model:O(e,E.gemini)}}case`chatcompletions`:{let e={...t.chatcompletions,...n},r=e[`base-url`],i=e.model;if(!r||!i)throw Error(`The provider chatcompletions is not configured. Please check your configuration.`);return{provider:p(r,{apiKey:D(e),maxRetries:e.maxRetries,timeoutMs:e.timeoutMs,vendor:e.vendor}),model:i}}default:throw Error(`Unknown provider type: ${e.type}`)}}function D(e){let t=e.apiKeyEnv??e[`api-key-env`];return typeof t==`string`&&t.length>0?process.env[t]:e[`api-key`]}function O(e,t){return typeof e.model==`string`&&e.model.length>0?e.model:t}function fe(e){let{type:t,...n}=e.provider,r=Object.keys(n).length>0?{type:t,config:n}:{type:t};return{version:1,name:e.name,provider:r,tools:e.tools?.map(e=>({name:e})),providerTools:e.provider_tools?.map(e=>({name:e})),mcps:e.mcps}}async function pe(e,t,n){let r=fe(e),i=r.mcps?.length?await se(r.mcps,n):[];return{agentConfig:await m(r,e=>{let n=de(e.provider,t);return{provider:n.provider,model:n.model,tools:e.tools?.length?ue(e.tools.map(e=>e.name)):void 0,mcps:i.length>0?i:void 0}}),mcps:i}}b.object({value:b.string()}),b.object({timeout:b.number().optional(),maxBuffer:b.number().optional(),cwd:b.string().optional()});const k={"api-key":b.string().optional(),apiKeyEnv:b.string().optional(),"api-key-env":b.string().optional()},A={maxRetries:b.number().int().nonnegative().optional(),timeoutMs:b.number().int().positive().optional()},j=b.strictObject({type:b.literal(`chatcompletions`),"base-url":b.string().optional(),model:b.string().optional(),vendor:b.enum([`openrouter`,`together`]).optional(),...k,...A}),M=b.strictObject({type:b.literal(`anthropic`),model:b.string().optional(),...k,...A}),N=b.strictObject({type:b.literal(`openai`),model:b.string().optional(),...k,...A}),P=b.strictObject({type:b.literal(`gemini`),model:b.string().optional(),...k,...A}),F=b.discriminatedUnion(`type`,[j,M,N,P]),I=b.object({transport:b.literal(`stdio`),name:b.string().optional(),command:b.string(),args:b.array(b.string()).optional(),env:b.record(b.string(),b.string()).optional()}),L=b.object({transport:b.literal(`http`),name:b.string().optional(),url:b.string(),headers:b.record(b.string(),b.string()).optional()}),R=b.discriminatedUnion(`transport`,[I,L]),z=b.object({files:b.string(),resume:b.boolean().default(!1),concurrency:b.number().int().positive().default(3)}),B=b.object({name:b.string().optional(),provider:F,task:b.string(),tools:b.array(b.string()).optional(),provider_tools:b.array(b.string()).optional(),files:b.array(b.string()).optional(),mcps:b.array(R).optional(),batch:z.optional()});async function me(e,t){let{span:n}=t,r=C(e).slice(1);if(r!==`yaml`&&r!==`yml`)throw Error(`Invalid job file format. Expected .yaml or .yml`);let i;try{i=await S(e,{encoding:`utf-8`})}catch{throw Error(`Job File not found, see --help for details`)}let a=T.parse(i);n?.debug(`Job config: `+JSON.stringify(a,null,2));let o=B.safeParse(a);if(!o.success)throw Error(`The job file is not valid:\n${ye(o.error)}`);return o.data.name||(o.data.name=te(e,C(e))),o.data}async function he(e){let{span:t}=e;w({quiet:!0});let n=ge();return t?.debug(`Service config: `+JSON.stringify(V(n),null,2)),n}function ge(){return _e({openai:process.env.OPENAI_API_KEY?{"api-key":process.env.OPENAI_API_KEY,model:process.env.OPENAI_MODEL}:void 0,anthropic:process.env.ANTHROPIC_API_KEY?{"api-key":process.env.ANTHROPIC_API_KEY,model:process.env.ANTHROPIC_MODEL}:void 0,gemini:process.env.GEMINI_API_KEY?{"api-key":process.env.GEMINI_API_KEY,model:process.env.GEMINI_MODEL}:void 0,chatcompletions:process.env.CHATCOMPLETIONS_BASE_URL&&process.env.CHATCOMPLETIONS_MODEL?{"base-url":process.env.CHATCOMPLETIONS_BASE_URL,model:process.env.CHATCOMPLETIONS_MODEL,"api-key":process.env.CHATCOMPLETIONS_API_KEY}:void 0})}function _e(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>e&&Object.keys(e).length>0))}function V(e){return Array.isArray(e)?e.map(e=>V(e)):!e||typeof e!=`object`?e:Object.fromEntries(Object.entries(e).map(([e,t])=>[e,ve(e)&&t?`[redacted]`:V(t)]))}function ve(e){return e===`api-key`||e.toLowerCase().includes(`secret`)}function ye(e){return e.issues.map(e=>` - ${e.path.join(`.`)||`root`}: ${e.message}`).join(`
|
|
3
|
+
`)}const H=`.axle/batch.jsonl`;function be(e,t){let n=ae(`sha256`);return n.update(e),n.update(`\0`),n.update(t),n.digest(`hex`)}async function xe(e=H){let t=new Map,n;try{n=await S(e,`utf-8`)}catch{return t}for(let e of n.split(`
|
|
4
|
+
`)){let n=e.trim();if(n)try{let e=JSON.parse(n);e.file&&e.hash&&t.set(e.file,e)}catch{}}return t}async function Se(e,t=H){await x(ne(t),{recursive:!0}),await ee(t,JSON.stringify(e)+`
|
|
5
|
+
`,`utf-8`)}async function Ce(e,t,n,r,i,a){let c=new s({prompt:e.task});if(e.files)for(let t of e.files)c.addFile(await _(t));let l=a.startSpan(`job`,{type:`workflow`}),u=new o({...t,observability:{trace:l}});try{let e=await u.send(c.withInputs(n)).final;if(d(i,e.usage),e.response){let t=e.response;a.info(t,{markdown:!0})}r.interactive&&await we(u,i,a),l.end()}catch(e){let t=e instanceof Error?e.message:String(e);throw l.error(t),l.end(`error`),e}}async function we(e,t,n){let r=ie({input:process.stdin,output:process.stdout});r.on(`SIGINT`,()=>{r.close()});let i=e=>new Promise(t=>{r.question(e,t),r.once(`close`,()=>t(null))});try{for(;;){let r=await i(`
|
|
6
|
+
> `);if(r===null||r.trim()===``)break;try{let i=await e.send(r.trim()).final;if(d(t,i.usage),i.response){let e=i.response;n.info(e,{markdown:!0})}}catch(e){let t=e instanceof Error?e.message:String(e);n.error(t)}}}finally{r.close()}}async function Te(e,t,n,r,i,a,c){let l=await re(t.files);if(l.length===0){c.warn(`No files matched pattern: ${t.files}`);return}c.info(`Batch: ${l.length} file(s) matched "${t.files}"`);let u=t.resume?await xe():new Map,f=e.files?await Promise.all(e.files.map(e=>_(e))):[],p=0,m=0,h=0;await Ee(t.concurrency??3,l,async i=>{let l=c.startSpan(`batch:${i}`,{type:`workflow`});try{let c=await S(i),h=be(e.task,c),g=u.get(i);if(t.resume&&g&&g.hash===h){l.info(`Skipped (already completed)`),l.end(),m++;return}let v=new s({prompt:e.task});for(let e of f)v.addFile(e);v.addFile(await _(i));let y={...r,file:i};d(a,(await new o({...n,observability:{trace:l}}).send(v.withInputs(y)).final).usage),await Se({file:i,hash:h,timestamp:Date.now()}),l.end(),p++}catch(e){let t=e instanceof Error?e.message:String(e);l.error(`Failed: ${t}`),l.end(`error`),h++}}),c.info(`Batch complete: ${p} completed, ${m} skipped, ${h} failed`)}async function Ee(e,t,n){let r=0;async function i(){for(;r<t.length;)await n(t[r++])}let a=Array.from({length:Math.min(e,t.length)},()=>i());await Promise.all(a)}const U=new a().name(`axle`).description(`Axle is a CLI tool for running AI workflows`).version(oe).requiredOption(`-j, --job <path>`,`Path to the YAML job file`).option(`--no-log`,`Do not write the output to a log file`).option(`-d, --debug`,`Print additional debug information`).option(`-i, --interactive`,`Continue the conversation interactively after the initial task`).option(`--args <args...>`,`Additional arguments in the form key=value`);U.parse(process.argv);const W=U.opts(),G={date:new Date().toISOString().split(`T`)[0],datetime:new Date().toISOString(),cwd:process.cwd()};W.args&&W.args.forEach(e=>{let[t,n]=e.split(`=`);t&&n&&(G[t.trim()]=n.trim())});const K=new u;W.debug&&(K.minLevel=`debug`);const De=new l({minLevel:W.debug?`debug`:`info`,showInternal:W.debug,showTimestamp:!0,markdown:!0});if(K.addWriter(De),W.log){let e=new l({minLevel:`debug`,showInternal:!0,showTimestamp:!0,output:e=>{}});K.addWriter(e)}const q=K.startSpan(`cli`,{type:`root`});process.on(`uncaughtException`,async e=>{console.error(`Uncaught exception:`),console.error(e),q.error(`Uncaught exception:`),q.error(e.message),q.error(e.stack||``),q.end(`error`),await K.flush(),process.exit(1)}),W.debug&&(q.debug(`Options: `+JSON.stringify(W,null,2)),q.debug(`Additional Arguments: `+JSON.stringify(G,null,2)));let J,Y;try{J=await he({span:q}),Y=await me(W.job,{span:q})}catch(e){let t=e instanceof Error?e:Error(String(e));q.error(t.message),q.debug(t.stack??``),q.end(`error`),await K.flush(),U.outputHelp(),process.exit(1)}let X=[],Z;try{let e=await pe(Y,J,q);Z=e.agentConfig,X=e.mcps}catch(e){let t=e instanceof Error?e:Error(String(e));q.error(t.message),q.error(t.stack??``),q.end(`error`),await K.flush(),U.outputHelp(),process.exit(1)}if(!Z)throw Error(`Failed to create agent config.`);q.info(`All systems operational. Running job...`);const Q=h(),Oe=performance.now(),$={task:Y.task,files:Y.files};try{Y.batch?await Te($,Y.batch,Z,G,W,Q,q):await Ce($,Z,G,W,Q,q)}catch(e){let t=e instanceof Error?e:Error(String(e));q.error(t.message),q.debug(t.stack??``)}finally{X.length>0&&await ce(X,q)}const ke=performance.now()-Oe;q.info(`Total run time: ${Math.round(ke)}ms`),q.info(`Input tokens: ${Q.in}`),q.info(`Output tokens: ${Q.out}`),Q.cachedIn!==void 0&&q.info(`Cached input tokens: ${Q.cachedIn}`),Q.cacheWriteIn!==void 0&&q.info(`Cache write input tokens: ${Q.cacheWriteIn}`),Q.reasoningOut!==void 0&&q.info(`Reasoning output tokens: ${Q.reasoningOut}`),q.info(`Complete. Goodbye`),q.end(),await K.flush();export{};
|
package/dist/store/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t
|
|
1
|
+
import e from"node:fs/promises";import t from"node:path";var n=class{rootPath;constructor(e){this.rootPath=e}async read(n){let r=t.join(this.rootPath,n);try{return await e.readFile(r,`utf-8`)}catch{return null}}async write(n,r){let i=t.join(this.rootPath,n);await e.mkdir(t.dirname(i),{recursive:!0}),await e.writeFile(i,r,`utf-8`)}};export{n as LocalFileStore};
|
package/dist/tools/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,n,r,t as i}from"../tools-
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"../tools-DTZhd_3g.js";export{e as calculatorTool,t as execTool,r as patchFileTool,n as readFileTool,i as writeFileTool};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import*as e from"zod";import{z as t}from"zod";import{mkdir as
|
|
2
|
-
`);if(
|
|
3
|
-
`),u=l.indexOf(t);if(u===-1)throw Error(`old_string not found within lines ${
|
|
1
|
+
import*as e from"zod";import{z as t}from"zod";import{spawn as n}from"node:child_process";import{mkdir as r,readFile as i,writeFile as a}from"node:fs/promises";import{dirname as o}from"node:path";const s={name:`calculator`,description:`Performs basic arithmetic operations`,schema:t.object({operation:t.enum([`add`,`subtract`,`multiply`,`divide`]).describe(`The operation to perform (add, subtract, multiply, divide)`),a:t.number().describe(`First operand`),b:t.number().describe(`Second operand`)}),execute:async({operation:e,a:t,b:n})=>{switch(e){case`add`:return`${t} + ${n} = ${t+n}`;case`subtract`:return`${t} - ${n} = ${t-n}`;case`multiply`:return`${t} * ${n} = ${t*n}`;case`divide`:if(n===0)throw Error(`Cannot divide by zero`);return`${t} / ${n} = ${t/n}`;default:throw Error(`Unknown operation: ${e}`)}}};async function c(e,t={}){let r=t.timeout??3e4,i=t.maxBuffer??1048576;return new Promise((a,o)=>{let s=n(e,[],{shell:!0,cwd:t.cwd}),c=``,l=``,u=!1,d=!1,f=!1,p=setTimeout(()=>{u=!0,s.kill(`SIGTERM`)},r),m=()=>{d=!0,s.kill(`SIGTERM`)};t.signal?.addEventListener(`abort`,m);let h=()=>{clearTimeout(p),t.signal?.removeEventListener(`abort`,m)};s.stdout?.setEncoding(`utf-8`),s.stderr?.setEncoding(`utf-8`),s.stdout?.on(`data`,e=>{if(c+=e,c.length+l.length>i){f=!0,s.kill(`SIGTERM`);return}t.onChunk?.(e)}),s.stderr?.on(`data`,e=>{if(l+=e,c.length+l.length>i){f=!0,s.kill(`SIGTERM`);return}t.onChunk?.(e)}),s.on(`error`,e=>{h(),o(e)}),s.on(`close`,e=>{if(h(),u){let e=Error(`Command timed out after ${r}ms`);e.stdout=c,e.stderr=l,o(e);return}if(d){let e=Error(`Command aborted`);e.stdout=c,e.stderr=l,o(e);return}if(f){let e=Error(`Command output exceeded maxBuffer (${i} bytes)`);e.stdout=c,e.stderr=l,o(e);return}if(e!==0){let t=Error(`Command failed with exit code ${e}`);t.stdout=c,t.stderr=l,t.code=e??-1,o(t);return}a({stdout:c,stderr:l})})})}function l(e){if(e instanceof Error){let t=e,n=`Error executing command: ${e.message}`;return t.stdout&&(n+=`\n[stdout]: ${t.stdout}`),t.stderr&&(n+=`\n[stderr]: ${t.stderr}`),n}return`Error executing command: ${String(e)}`}function u(e,t){return t&&t.trim()?`${e}\n[stderr]: ${t}`:e}const d=e.object({command:e.string().describe(`The shell command to execute`)}),f=new class{name=`exec`;description=`Execute a shell command and return the output.`;schema=d;timeout=3e4;maxBuffer=1024*1024;cwd;constructor(e){e&&this.configure(e)}configure(e){this.timeout=e.timeout??3e4,this.maxBuffer=e.maxBuffer??1024*1024,this.cwd=e.cwd}summarize(e){return e.command}async execute(e,t){let{command:n}=e;try{let e=await c(n,{timeout:this.timeout,maxBuffer:this.maxBuffer,cwd:this.cwd,signal:t.signal,onChunk:e=>t.emit(e)});return u(e.stdout,e.stderr)}catch(e){return l(e)}}},p={name:`patch-file`,description:`Patch a file by replacing an exact string match within a specified line range`,schema:t.object({path:t.string().describe(`The file path to patch`),old_string:t.string().describe(`The exact text to find and replace`),new_string:t.string().describe(`The replacement text`),start_line:t.number().int().positive().describe(`1-indexed start line of the region to match within`),end_line:t.number().int().positive().describe(`1-indexed end line (inclusive) of the region to match within`)}),summarize:({path:e,start_line:t,end_line:n})=>`${e}:${t}:${n}`,execute:async({path:e,old_string:t,new_string:n,start_line:r,end_line:o})=>{if(o<r)throw Error(`end_line (${o}) must be >= start_line (${r})`);let s;try{s=await i(e,`utf-8`)}catch(t){throw t instanceof Error?Error(`Failed to read file "${e}": ${t.message}`):t}let c=s.split(`
|
|
2
|
+
`);if(r>c.length)throw Error(`start_line (${r}) exceeds file length (${c.length} lines)`);if(o>c.length)throw Error(`end_line (${o}) exceeds file length (${c.length} lines)`);let l=c.slice(r-1,o).join(`
|
|
3
|
+
`),u=l.indexOf(t);if(u===-1)throw Error(`old_string not found within lines ${r}-${o} of "${e}"`);if(l.indexOf(t,u+1)!==-1)throw Error(`old_string matches multiple times within lines ${r}-${o} of "${e}"`);let d=l.replace(t,n),f=[...c.slice(0,r-1),...d.split(`
|
|
4
4
|
`),...c.slice(o)].join(`
|
|
5
|
-
`);try{await
|
|
5
|
+
`);try{await a(e,f,`utf-8`)}catch(t){throw t instanceof Error?Error(`Failed to write file "${e}": ${t.message}`):t}return`Successfully patched "${e}" (lines ${r}-${o})`}},m={name:`read-file`,description:`Read the contents of a file from disk`,schema:t.object({path:t.string().describe(`The file path to read from`)}),summarize:({path:e})=>e,execute:async({path:e})=>{try{return await i(e,`utf-8`)}catch(t){throw t instanceof Error?Error(`Failed to read file "${e}": ${t.message}`):t}}},h={name:`write-file`,description:`Write content to a file on disk, creating directories if needed`,schema:t.object({path:t.string().describe(`The file path to write to`),content:t.string().describe(`The content to write to the file`)}),summarize:({path:e})=>e,execute:async({path:e,content:t})=>{try{return await r(o(e),{recursive:!0}),await a(e,t,`utf-8`),`Successfully wrote ${t.length} characters to "${e}"`}catch(t){throw t instanceof Error?Error(`Failed to write file "${e}": ${t.message}`):t}}};export{s as a,f as i,m as n,p as r,h as t};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fifthrevision/axle-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.30.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/johncch/axle.git"
|
|
@@ -15,10 +15,6 @@
|
|
|
15
15
|
"types": "./dist/tools/index.d.ts",
|
|
16
16
|
"import": "./dist/tools/index.js"
|
|
17
17
|
},
|
|
18
|
-
"./memory": {
|
|
19
|
-
"types": "./dist/memory/index.d.ts",
|
|
20
|
-
"import": "./dist/memory/index.js"
|
|
21
|
-
},
|
|
22
18
|
"./store": {
|
|
23
19
|
"types": "./dist/store/index.d.ts",
|
|
24
20
|
"import": "./dist/store/index.js"
|
|
@@ -36,7 +32,7 @@
|
|
|
36
32
|
"glob": "^13.0.6",
|
|
37
33
|
"yaml": "^2.9.0",
|
|
38
34
|
"zod": "^4.4.3",
|
|
39
|
-
"@fifthrevision/axle": "0.
|
|
35
|
+
"@fifthrevision/axle": "0.30.0"
|
|
40
36
|
},
|
|
41
37
|
"devDependencies": {
|
|
42
38
|
"@arethetypeswrong/core": "^0.18.2",
|
package/dist/memory/index.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { AIProvider, AgentMemory, ExecutableTool, FileStore, MemoryContext, RecallResult } from "@fifthrevision/axle";
|
|
2
|
-
|
|
3
|
-
//#region src/memory/ProceduralMemory.d.ts
|
|
4
|
-
interface ProceduralMemoryConfig {
|
|
5
|
-
provider: AIProvider;
|
|
6
|
-
model: string;
|
|
7
|
-
enableTools?: boolean;
|
|
8
|
-
store: FileStore;
|
|
9
|
-
/** Memory-owned partition metadata, such as user or workspace ids. */
|
|
10
|
-
scope?: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
declare class ProceduralMemory implements AgentMemory {
|
|
13
|
-
private provider;
|
|
14
|
-
private model;
|
|
15
|
-
private enableTools;
|
|
16
|
-
private store;
|
|
17
|
-
private scope?;
|
|
18
|
-
private lastAgentName?;
|
|
19
|
-
constructor(config: ProceduralMemoryConfig);
|
|
20
|
-
recall(context: MemoryContext): Promise<RecallResult>;
|
|
21
|
-
record(context: MemoryContext): Promise<void>;
|
|
22
|
-
tools(): ExecutableTool[];
|
|
23
|
-
private formatMessages;
|
|
24
|
-
private parseInstructions;
|
|
25
|
-
private getStorePath;
|
|
26
|
-
private loadStore;
|
|
27
|
-
private saveStore;
|
|
28
|
-
}
|
|
29
|
-
//#endregion
|
|
30
|
-
export { ProceduralMemory, type ProceduralMemoryConfig };
|
package/dist/memory/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"../memory-BS-U-K_q.js";export{e as ProceduralMemory};
|
package/dist/memory-BS-U-K_q.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import{generate as e}from"@fifthrevision/axle";import t from"node:crypto";import{z as n}from"zod";var r=class{provider;model;enableTools;store;scope;lastAgentName;constructor(e){this.provider=e.provider,this.model=e.model,this.enableTools=e.enableTools??!1,this.store=e.store,this.scope=e.scope}async recall(e){let t=e.span?.startSpan(`memory.recall`,{type:`internal`});this.lastAgentName=e.agentName;let n=await this.loadStore(e.agentName);if(n.instructions.length===0)return t?.info(`no stored instructions`),t?.end(),{};t?.info(`loaded instructions`,{count:n.instructions.length});let r=n.instructions.map((e,t)=>`${t+1}. ${e}`).join(`
|
|
2
|
-
`);return t?.end(),{systemSuffix:`## Learned Instructions\n\n${r}`}}async record(t){if(!t.newMessages||t.newMessages.length===0)return;let n=t.span?.startSpan(`memory.record`,{type:`internal`}),r=this.formatMessages(t.newMessages);if(!r.trim()){n?.info(`no text content to extract from`),n?.end();return}let a=n?.startSpan(`memory.extract`,{type:`llm`}),o=await e({provider:this.provider,model:this.model,messages:[{role:`user`,content:r}],system:`You are a memory extraction system. Your job is to extract learnings from a conversation that should be remembered for future runs.
|
|
3
|
-
|
|
4
|
-
Only extract:
|
|
5
|
-
- Explicit user corrections (e.g., "No, always use bullet points")
|
|
6
|
-
- Stated preferences (e.g., "I prefer concise summaries")
|
|
7
|
-
- Patterns that clearly emerged from user feedback
|
|
8
|
-
|
|
9
|
-
Do NOT extract:
|
|
10
|
-
- General knowledge or facts from the conversation content
|
|
11
|
-
- Inferences or speculation about what the user might want
|
|
12
|
-
- Task-specific details that won't apply to future runs
|
|
13
|
-
|
|
14
|
-
Respond with a JSON array of instruction strings. Each instruction should be a clear, actionable directive.
|
|
15
|
-
If there are no learnings to extract, respond with an empty array: []
|
|
16
|
-
|
|
17
|
-
Example response:
|
|
18
|
-
["Always use bullet points for lists", "Keep summaries under 3 sentences"]`,span:a});if(!o.ok){n?.warn(`extraction failed`,{error:o.error}),n?.end();return}let s=i(o.final.content);if(!s){n?.end();return}let c=this.parseInstructions(s);if(c.length===0){n?.info(`no instructions extracted`),n?.end();return}let l=await this.loadStore(t.agentName);l.instructions.push(...c),await this.saveStore(t.agentName,l),n?.info(`saved instructions`,{count:c.length}),n?.end()}tools(){if(!this.enableTools)return[];let e=this;return[{name:`add_instruction`,description:`Save a learned instruction for future runs. Use this when the user explicitly asks you to remember something.`,schema:n.object({instruction:n.string().describe(`The instruction to remember`)}),async execute(t){if(!e.lastAgentName)return`Error: memory not initialized (no recall has been called yet)`;let n=await e.loadStore(e.lastAgentName);return n.instructions.push(t.instruction),await e.saveStore(e.lastAgentName,n),`Instruction saved: "${t.instruction}"`}}]}formatMessages(e){let t=[];for(let n of e)if(n.role===`user`){let e=typeof n.content==`string`?n.content:i(n.content);e&&t.push(`User: ${e}`)}else if(n.role===`assistant`){let e=i(n.content);e&&t.push(`Assistant: ${e}`)}return t.join(`
|
|
19
|
-
|
|
20
|
-
`)}parseInstructions(e){let t=e.trim(),n=t.match(/^```(?:json)?\s*\n?([\s\S]*?)\n?\s*```$/);n&&(t=n[1].trim());try{let e=JSON.parse(t);if(Array.isArray(e)&&e.every(e=>typeof e==`string`))return e}catch{}return[]}getStorePath(e,n){let r=e??`default`,i=r;if(n&&Object.keys(n).length>0){let e=Object.entries(n).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${e}=${t}`).join(`&`);i=`${r}-${t.createHash(`sha256`).update(e).digest(`hex`).slice(0,8)}`}return`memory/procedural/${i}.json`}async loadStore(e){let t=this.getStorePath(e,this.scope),n=await this.store.read(t);if(n)try{let e=JSON.parse(n);if(e&&Array.isArray(e.instructions))return{instructions:e.instructions}}catch{}return{instructions:[]}}async saveStore(e,t){if(!t)return;let n=this.getStorePath(e,this.scope);await this.store.write(n,JSON.stringify(t,null,2))}};function i(e){return typeof e==`string`?e:e.filter(e=>e.type===`text`||e.type===`thinking`).map(e=>e.text).join(``)}export{r as t};
|
package/dist/store-BFxiiKeG.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import e from"node:fs/promises";import t from"node:path";var n=class{rootPath;constructor(e){this.rootPath=e}async read(n){let r=t.join(this.rootPath,n);try{return await e.readFile(r,`utf-8`)}catch{return null}}async write(n,r){let i=t.join(this.rootPath,n);await e.mkdir(t.dirname(i),{recursive:!0}),await e.writeFile(i,r,`utf-8`)}};export{n as t};
|