@fifthrevision/axle 0.4.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/LICENSE +21 -0
- package/README.md +24 -0
- package/dist/cli.js +12 -0
- package/dist/dag-DzqZGULq.js +12 -0
- package/dist/index.d.ts +481 -0
- package/dist/index.js +3 -0
- package/package.json +54 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Chong Han Chua
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Axle: AI eXecution and Logic Engine
|
|
2
|
+
|
|
3
|
+
Axle is a CLI tool and library for building composable LLM workflows. Inspired by [DSPy](https://dspy.ai), it began as a command-line utility and has since evolved into a general-purpose workflow library.
|
|
4
|
+
|
|
5
|
+
The project is evolving quickly and the API is still unstable, so this README will remain minimal for now.
|
|
6
|
+
|
|
7
|
+
To get started, see the [examples](./examples) directory.
|
|
8
|
+
|
|
9
|
+
## Configuration
|
|
10
|
+
For CLI use, you will need to provide a `ax.config.yml` where you're running the tool.
|
|
11
|
+
|
|
12
|
+
Here's what it looks like. Every field is optional depending on the provider you want to use.
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
openai:
|
|
16
|
+
api-key: "<api-key>"
|
|
17
|
+
anthropic:
|
|
18
|
+
api-key: "<api-key>"
|
|
19
|
+
ollama:
|
|
20
|
+
url: "<url>"
|
|
21
|
+
brave:
|
|
22
|
+
api-key: "<api-key>"
|
|
23
|
+
rateLimit: 1
|
|
24
|
+
```
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
var F=Object.defineProperty;var g=(i,t)=>F(i,"name",{value:t,configurable:!0});import{Command as A}from"@commander-js/extra-typings";import{b as I,i as L,T as u,L as p,R as W,g as _,e as J,d as N}from"./dag-DzqZGULq.js";import x from"yaml";import r from"chalk";import R from"node:readline";import{access as T,mkdir as P,writeFile as M,appendFile as U}from"node:fs/promises";import{homedir as z}from"node:os";import"@anthropic-ai/sdk";import"@google/genai";import"openai";import"serialize-error";import"fs/promises";import"glob";import"node:path";var B="0.4.0",G={version:B};function H(i,t){if(typeof i!="object"||i===null)return t&&(t.value="Config: must be a non-null object"),!1;if("openai"in i){const e=i.openai;if(typeof e!="object"||e===null)return t&&(t.value="Config: openai must be an object"),!1;if(typeof e["api-key"]!="string")return t&&(t.value="Config: openai.api-key must be a string"),!1;if("model"in e&&typeof e.model!="string")return t&&(t.value="Config: openai.model must be a string"),!1}if("anthropic"in i){const e=i.anthropic;if(typeof e!="object"||e===null)return t&&(t.value="Config: anthropic must be an object"),!1;if(typeof e["api-key"]!="string")return t&&(t.value="Config: anthropic.api-key must be a string"),!1;if("model"in e&&typeof e.model!="string")return t&&(t.value="Config: anthropic.model must be a string"),!1}if("ollama"in i){const e=i.ollama;if(typeof e!="object"||e===null)return t&&(t.value="Config: ollama must be an object"),!1;if("url"in e&&typeof e.url!="string")return t&&(t.value="Config: ollama.url must be a string"),!1;if("model"in e&&typeof e.model!="string")return t&&(t.value="Config: ollama.model must be a string"),!1}if("googleai"in i){const e=i.googleai;if(typeof e!="object"||e===null)return t&&(t.value="Config: googleai must be an object"),!1;if(typeof e["api-key"]!="string")return t&&(t.value="Config: googleai.api-key must be a string"),!1;if("model"in e&&typeof e.model!="string")return t&&(t.value="Config: googleai.model must be a string"),!1}if("brave"in i){const e=i.brave;if(typeof e!="object"||e===null)return t&&(t.value="Config: brave must be an object"),!1;if(typeof e["api-key"]!="string")return t&&(t.value="Config: brave.api-key must be a string"),!1;if("rateLimit"in e&&typeof e.rateLimit!="number")return t&&(t.value="Config: brave.rateLimit must be a number"),!1}return!0}g(H,"isServiceConfig");const X="ax.job",K=["yaml","yml","json"];async function V(i,t){const{recorder:e}=t,{content:s,format:o}=await I({path:i,defaults:{name:X,formats:K},loader:"Job File"});let n=null;if(o==="json")n=JSON.parse(s);else if(o==="yaml"||o==="yml")n=x.parse(s);else throw new Error("Invalid job file format");e?.debug?.heading.log("The Job Object"),e?.debug?.log(n);const a={value:""};if(L(n,a))return n;throw new Error(`The job file is not valid: ${a.value}`)}g(V,"getJobConfig");const Y="ax.config",q=["yaml","yml","json"];async function Q(i,t){const{recorder:e}=t,{content:s,format:o}=await I({path:i,defaults:{name:Y,formats:q},loader:"Config File"});let n=null;if(o==="json")n=JSON.parse(s);else if(o==="yaml"||o==="yml")n=x.parse(s);else throw new Error("Invalid config file format");e?.debug?.heading.log("The Config Object"),e?.debug?.log(n);const a={value:""};if(H(n,a))return n;throw new Error(a.value)}g(Q,"getServiceConfig");const Z=["\u280B","\u2819","\u2839","\u2838","\u283C","\u2834","\u2826","\u2827","\u2807","\u280F"],m={success:"\u2713",fail:"\u2717",spinning:Z};class tt{static{g(this,"ConsoleWriter")}tasks=new Map;entries=[];truncate=0;intervalId=null;spinnerInterval=80;lastRender="";isRendering=!1;inline=!0;constructor(t={}){this.truncate=t.truncate??0,this.inline=t.inline??!0}startSpinner(){this.intervalId===null&&(this.intervalId=setInterval(()=>{[...this.tasks.values()].some(e=>e.status===u.Running)&&this.renderTasks()},this.spinnerInterval))}stopSpinner(){this.intervalId!==null&&(clearInterval(this.intervalId),this.intervalId=null)}renderTasks(){if(this.isRendering)return;if(this.isRendering=!0,this.inline&&this.lastRender){const n=this.lastRender.split(`
|
|
3
|
+
`).length;R.moveCursor(process.stdout,0,-n+1),R.clearScreenDown(process.stdout)}const t=[...this.tasks.values()],e=t.filter(n=>n.status===u.Running),s=t.filter(n=>n.status===u.Success||n.status===u.Fail);if(e.length===0&&s.length>0){let n="";for(const a of s){if(a.status===u.Success){const f=r.green(m.success);n+=`${f} ${a.text}
|
|
4
|
+
`}else if(a.status===u.Fail){const f=r.red(m.fail);n+=`${f} ${a.text}
|
|
5
|
+
`}this.tasks.delete(a.id)}console.log(n)}for(const n of this.entries){const{level:a,time:f,kind:c,payload:h}=n;c==="heading"?it(a,h,{truncate:this.truncate}):nt(a,h,{truncate:this.truncate})}this.entries=[];let o="";for(const n of this.tasks.values())if(n.status===u.Running){const a=r.cyan(m.spinning[n.frameIndex]);n.frameIndex=(n.frameIndex+1)%m.spinning.length,o+=`${a} ${n.text}
|
|
6
|
+
`}else if(n.status===u.Success){const a=r.green(m.success);o+=`${a} ${n.text}
|
|
7
|
+
`}else if(n.status===u.Fail){const a=r.red(m.fail);o+=`${a} ${n.text}
|
|
8
|
+
`}this.lastRender=o,process.stdout.write(o),this.isRendering=!1}handleEvent(t){const{level:e,time:s,payload:o}=t;if(o.length>0&&et(o[0])){const a=o[0],{id:f,message:c,status:h}=a;if(h===u.Running)this.tasks.set(f,{id:f,text:c,status:h,frameIndex:0});else if((h===u.Success||h===u.Fail)&&this.tasks.has(f)){const j=this.tasks.get(f);j.status=h,j.text=c}}else this.entries.push(t);this.renderTasks();const n=[...this.tasks.values()].some(a=>a.status===u.Running);n&&this.intervalId===null?this.startSpinner():!n&&this.intervalId!==null&&this.stopSpinner()}destroy(){this.stopSpinner()}}function et(i){if(typeof i!="object"||i===null)return!1;const t=i;if(t.type!=="task"||typeof t.id!="string"||typeof t.message!="string")return!1;switch(t.status){case u.Running:case u.Success:case u.PartialSuccess:case u.Fail:return!0;default:return!1}}g(et,"isTask");function it(i,t,e){let s,o;i===p.Error?(s=r.red,o=r.redBright.bold):i===p.Warn?(s=r.yellow,o=r.yellowBright.bold):i>=p.Info?(s=r.blue,o=r.whiteBright.bold):(s=r.gray,o=r.white);const{message:n,data:a}=D(t);console.log(`${s("==>")} ${o(n)}`),S(i,a,e)}g(it,"heading");function nt(i,t,e){let s;i===p.Error?s=r.red:i===p.Warn?s=r.yellow:i>=p.Info?s=r.white:s=r.gray;const{message:o,data:n}=D(t);o&&console.log(s(o)),S(i,n,e)}g(nt,"body");const $=" ";function S(i,t,e){let s;i===p.Error?(s=r.red,e.truncate=0):i==p.Warn?s=r.yellow:i>=p.Info?s=r.white:s=r.gray,t.forEach(o=>{if(typeof o=="string"){console.log(s(`${$}${o}`));return}for(const[n,a]of Object.entries(o)){let f=JSON.stringify(a,st(e.truncate)," ");const c=`${n}: ${f}`.split(`
|
|
9
|
+
`).map(h=>$+h).join(`
|
|
10
|
+
`);console.log(s(c))}})}g(S,"values");function D(i){const[t,...e]=i;let s="",o=e;if(t){let{message:n,...a}=t;s=n&&typeof n=="string"?n:"",Object.keys(a).length>0&&(o=[a,...o])}return{message:s,data:o}}g(D,"toMsgData");function st(i){return i===0?null:(t,e)=>typeof e=="string"&&e.length>i?e.slice(0,i)+"<...>":e}g(st,"truncator");const y="./logs/",ot="~/.axle/logs/";class at{static{g(this,"LogWriter")}time;initialized=!1;logDir=y;pendingWrites=[];constructor(){this.time=new Date().toISOString()}get filename(){return`${this.logDir}${this.time}.log`}async initialize(){try{await T(y),this.logDir=y}catch{const s=ot.replace("~",z());try{await T(s),this.logDir=s}catch{await P(s,{recursive:!0}),this.logDir=s}}const t=M(this.filename,`AXLE: New run at ${this.time}
|
|
11
|
+
`);this.pendingWrites.push(t);try{await t,this.initialized=!0}finally{const e=this.pendingWrites.indexOf(t);e!==-1&&this.pendingWrites.splice(e,1)}}async writeToLog(t){const{time:e,level:s,payload:o}=t;this.initialized||await this.initialize();const n=o.map(c=>typeof c=="string"?c:JSON.stringify(c)),a=`${p[s]} ${new Date(e).toISOString()} > ${n.join(" >> ")}
|
|
12
|
+
`,f=U(this.filename,a).catch(c=>{console.error(`Failed to write to log file: ${c}`)});this.pendingWrites.push(f);try{await f}finally{const c=this.pendingWrites.indexOf(f);c!==-1&&this.pendingWrites.splice(c,1)}}async handleEvent(t){await this.writeToLog(t)}async flush(){this.pendingWrites.length>0&&await Promise.all(this.pendingWrites)}}const b=new A().name("axle").description("Axle is a CLI tool for running AI workflows").version(G.version).option("--dry-run","Run the application without executing against the AI providers").option("-c, --config <path>","Path to the config file").option("-j, --job <path>","Path to the job file").option("--no-log","Do not write the output to a log file").option("--no-warn-unused","Do not warn about unused variables").option("--no-inline","Do not inline the console output").option("-d, --debug","Print additional debug information").option("--truncate <num>","Truncate printed strings to a certain number of characters, 0 to disable",parseInt,100).option("--args <args...>","Additional arguments in the form key=value");b.parse(process.argv);const d=b.opts(),v={};d.args&&d.args.forEach(i=>{const[t,e]=i.split("=");t&&e&&(v[t.trim()]=e.trim())}),process.on("uncaughtException",async i=>{console.error("Uncaught exception:"),console.error(i),l&&(l.error?.log("Uncaught exception:"),l.error?.log(i.message),l.error?.log(i.stack||""),await l.shutdown()),process.exit(1)});const l=new W;d.debug&&(l.level=p.Debug);const lt=new tt(d);if(l.subscribe(lt),d.log){const i=new at;await i.initialize(),l.subscribe(i)}d.debug&&(l.debug?.heading.log("Options"),l.debug?.log(d),l.debug?.heading.log("Additional Arguments:"),l.debug?.log(v));let w,k;try{w=await Q(d.config??null,{recorder:l}),k=await V(d.job??null,{recorder:l})}catch(i){l.error.log(i.message),l.debug?.log(i.stack),await l.shutdown(),b.outputHelp(),process.exit(1)}let E;try{const{engine:i,...t}=k.using,e={...w[i],...t};E=_(i,e)}catch(i){l.error.log(i.message),l.error.log(i.stack),await l.shutdown(),b.outputHelp(),process.exit(1)}J().setConfig(w),l.info?.heading.log("All systems operational. Running job...");const rt=Date.now();d.dryRun&&l.info?.log("Dry run mode enabled. No API calls will be made.");const C={in:0,out:0},O=await N(k.jobs).execute({provider:E,variables:v,options:d,stats:C,recorder:l});O&&(l.info?.heading.log("Response"),l.info.log(O)),l.info?.heading.log("Usage"),l.info?.log(`Total run time: ${Date.now()-rt}ms`),l.info?.log(`Input tokens: ${C.in} `),l.info?.log(`Output tokens: ${C.out} `),l.info?.heading.log("Complete. Goodbye"),await l.shutdown();
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
var ge=Object.defineProperty;var c=(t,e)=>ge(t,"name",{value:e,configurable:!0});import de from"@anthropic-ai/sdk";import{GoogleGenAI as me,Type as he,FinishReason as w}from"@google/genai";import ye from"openai";import{serializeError as Ee}from"serialize-error";import{readFile as Ie,access as we,constants as Te}from"fs/promises";import{glob as Q}from"glob";import{readFile as F,access as j,stat as Pe,writeFile as Ae,mkdir as ve}from"node:fs/promises";import{resolve as B,extname as Ne,dirname as Re}from"node:path";class E extends Error{static{c(this,"AxleError")}code;id;details;constructor(e,s){super(e,{cause:s?.cause}),this.name=this.constructor.name,this.code=s?.code||"AXLE_ERROR",this.id=s?.id,this.details=s?.details,Object.setPrototypeOf(this,E.prototype)}}const O={CLAUDE_OPUS_4_20250514:"claude-opus-4-20250514",CLAUDE_OPUS_4_LATEST:"claude-opus-4-0",CLAUDE_SONNET_4_20250514:"claude-sonnet-4-20250514",CLAUDE_SONNET_4_LATEST:"claude-sonnet-4-0",CLAUDE_3_7_SONNET_20250219:"claude-3-7-sonnet-20250219",CLAUDE_3_7_SONNET_LATEST:"claude-3-7-sonnet-latest",CLAUDE_3_5_HAIKU_20241022:"claude-3-5-haiku-20241022",CLAUDE_3_5_HAIKU_LATEST:"claude-3-5-haiku-latest"},V=[O.CLAUDE_3_7_SONNET_LATEST,O.CLAUDE_3_7_SONNET_20250219,O.CLAUDE_3_5_HAIKU_LATEST,O.CLAUDE_3_5_HAIKU_20241022,O.CLAUDE_SONNET_4_LATEST,O.CLAUDE_SONNET_4_20250514,O.CLAUDE_OPUS_4_LATEST,O.CLAUDE_OPUS_4_20250514];var m=(t=>(t[t.Stop=0]="Stop",t[t.Length=1]="Length",t[t.FunctionCall=2]="FunctionCall",t[t.Error=3]="Error",t))(m||{});const Oe=O.CLAUDE_SONNET_4_LATEST;class Se{static{c(this,"AnthropicProvider")}name="Anthropic";client;model;constructor(e,s){this.model=s??Oe,this.client=new de({apiKey:e})}createChatRequest(e,s={}){const{recorder:n}=s;return e.hasFiles()&&!V.includes(this.model)&&n?.warn?.log(`Model ${this.model} may not support multimodal content. Use one of: ${V.join(", ")}`),new Me(this,e)}}class Me{static{c(this,"AnthropicChatRequest")}constructor(e,s){this.provider=e,this.chat=s}async execute(e){const{recorder:s}=e,{client:n,model:o}=this.provider,r={model:o,max_tokens:4096,...be(this.chat)};s?.debug?.log(r);let i;try{const a=await n.messages.create(r);i=Ge(a)}catch(a){i={type:"error",error:{type:a.error.error.type??"Undetermined",message:a.error.error.message??"Unexpected error from Anthropic"},usage:{in:0,out:0},raw:a}}return s?.debug?.log(i),i}}function ee(t){switch(t){case"max_tokens":return m.Length;case"end_turn":return m.Stop;case"stop_sequence":return m.Stop;case"tool_use":return m.FunctionCall;default:return m.Error}}c(ee,"getStopReason$2");function be(t){const e=t.messages.map(n=>{switch(n.role){case"assistant":const o=[];return o.push({type:"text",text:n.content}),n.toolCalls&&o.push(...n.toolCalls.map(r=>({type:"tool_use",id:r.id,name:r.name,input:r.arguments}))),{role:"assistant",content:o};case"tool":return{role:"user",content:n.content.map(r=>({type:"tool_result",tool_use_id:r.id,content:r.content}))};default:if(typeof n.content=="string")return{role:"user",content:n.content};{const r=[];for(const i of n.content)if(i.type==="text")r.push({type:"text",text:i.text});else if(i.type==="file"){const a=i.file;a.type==="image"?r.push({type:"image",source:{type:"base64",media_type:a.mimeType,data:a.base64}}):a.type==="document"&&a.mimeType==="application/pdf"&&r.push({type:"document",source:{type:"base64",media_type:"application/pdf",data:a.base64}})}return{role:"user",content:r}}}}),s=t.tools.map(n=>({name:n.name,description:n.description,input_schema:n.parameters}));return{system:t.system,messages:e,tools:s}}c(be,"prepareRequest$2");function Ge(t){const e=ee(t.stop_reason);if(e===m.Error)return{type:"error",error:{type:"Uncaught error",message:"Stop reason is not recognized."},usage:{in:t.usage.input_tokens,out:t.usage.output_tokens},raw:t};if(e===m.FunctionCall){const s=t.content[0],n=s.type==="text"?s.text:"",o=t.content.slice(1).map(r=>{if(r.type==="tool_use")return{id:r.id,name:r.name,arguments:r.input}}).filter(r=>r!==null);return{type:"success",id:t.id,model:t.model,reason:m.FunctionCall,message:{role:t.role,content:n,toolCalls:o},usage:{in:t.usage.input_tokens,out:t.usage.output_tokens},raw:t}}if(t.type=="message"){const s=t.content[0];if(s.type=="text")return{type:"success",id:t.id,model:t.model,reason:ee(t.stop_reason),message:{role:t.role,content:s.text},usage:{in:t.usage.input_tokens,out:t.usage.output_tokens},raw:t}}}c(Ge,"translate");const p={GEMINI_1_0_PRO_VISION_LATEST:"gemini-1.0-pro-vision-latest",GEMINI_PRO_VISION:"gemini-pro-vision",GEMINI_1_5_PRO_LATEST:"gemini-1.5-pro-latest",GEMINI_1_5_PRO_001:"gemini-1.5-pro-001",GEMINI_1_5_PRO_002:"gemini-1.5-pro-002",GEMINI_1_5_PRO:"gemini-1.5-pro",GEMINI_1_5_FLASH_LATEST:"gemini-1.5-flash-latest",GEMINI_1_5_FLASH_001:"gemini-1.5-flash-001",GEMINI_1_5_FLASH_001_TUNING:"gemini-1.5-flash-001-tuning",GEMINI_1_5_FLASH:"gemini-1.5-flash",GEMINI_1_5_FLASH_002:"gemini-1.5-flash-002",GEMINI_1_5_FLASH_8B:"gemini-1.5-flash-8b",GEMINI_1_5_FLASH_8B_001:"gemini-1.5-flash-8b-001",GEMINI_1_5_FLASH_8B_LATEST:"gemini-1.5-flash-8b-latest",GEMINI_1_5_FLASH_8B_EXP_0827:"gemini-1.5-flash-8b-exp-0827",GEMINI_1_5_FLASH_8B_EXP_0924:"gemini-1.5-flash-8b-exp-0924",GEMINI_2_5_PRO_EXP_03_25:"gemini-2.5-pro-exp-03-25",GEMINI_2_5_PRO_PREVIEW_03_25:"gemini-2.5-pro-preview-03-25",GEMINI_2_5_FLASH_PREVIEW_04_17:"gemini-2.5-flash-preview-04-17",GEMINI_2_5_FLASH_PREVIEW_05_20:"gemini-2.5-flash-preview-05-20",GEMINI_2_5_FLASH_PREVIEW_04_17_THINKING:"gemini-2.5-flash-preview-04-17-thinking",GEMINI_2_5_PRO_PREVIEW_05_06:"gemini-2.5-pro-preview-05-06",GEMINI_2_5_PRO_PREVIEW_06_05:"gemini-2.5-pro-preview-06-05",GEMINI_2_0_FLASH_EXP:"gemini-2.0-flash-exp",GEMINI_2_0_FLASH:"gemini-2.0-flash",GEMINI_2_0_FLASH_001:"gemini-2.0-flash-001",GEMINI_2_0_FLASH_EXP_IMAGE_GENERATION:"gemini-2.0-flash-exp-image-generation",GEMINI_2_0_FLASH_LITE_001:"gemini-2.0-flash-lite-001",GEMINI_2_0_FLASH_LITE:"gemini-2.0-flash-lite",GEMINI_2_0_FLASH_PREVIEW_IMAGE_GENERATION:"gemini-2.0-flash-preview-image-generation",GEMINI_2_0_FLASH_LITE_PREVIEW_02_05:"gemini-2.0-flash-lite-preview-02-05",GEMINI_2_0_FLASH_LITE_PREVIEW:"gemini-2.0-flash-lite-preview",GEMINI_2_0_PRO_EXP:"gemini-2.0-pro-exp",GEMINI_2_0_PRO_EXP_02_05:"gemini-2.0-pro-exp-02-05",GEMINI_EXP_1206:"gemini-exp-1206",GEMINI_2_0_FLASH_THINKING_EXP_01_21:"gemini-2.0-flash-thinking-exp-01-21",GEMINI_2_0_FLASH_THINKING_EXP:"gemini-2.0-flash-thinking-exp",GEMINI_2_0_FLASH_THINKING_EXP_1219:"gemini-2.0-flash-thinking-exp-1219",GEMINI_2_5_FLASH_PREVIEW_TTS:"gemini-2.5-flash-preview-tts",GEMINI_2_5_PRO_PREVIEW_TTS:"gemini-2.5-pro-preview-tts",LEARNLM_2_0_FLASH_EXPERIMENTAL:"learnlm-2.0-flash-experimental",GEMMA_3_1B_IT:"gemma-3-1b-it",GEMMA_3_4B_IT:"gemma-3-4b-it",GEMMA_3_12B_IT:"gemma-3-12b-it",GEMMA_3_27B_IT:"gemma-3-27b-it",GEMMA_3N_E4B_IT:"gemma-3n-e4b-it"},te=[p.GEMINI_1_0_PRO_VISION_LATEST,p.GEMINI_PRO_VISION,p.GEMINI_1_5_PRO_LATEST,p.GEMINI_1_5_PRO_001,p.GEMINI_1_5_PRO_002,p.GEMINI_1_5_PRO,p.GEMINI_1_5_FLASH_LATEST,p.GEMINI_1_5_FLASH_001,p.GEMINI_1_5_FLASH_001_TUNING,p.GEMINI_1_5_FLASH,p.GEMINI_1_5_FLASH_002,p.GEMINI_1_5_FLASH_8B,p.GEMINI_1_5_FLASH_8B_001,p.GEMINI_1_5_FLASH_8B_LATEST,p.GEMINI_1_5_FLASH_8B_EXP_0827,p.GEMINI_1_5_FLASH_8B_EXP_0924,p.GEMINI_2_5_PRO_EXP_03_25,p.GEMINI_2_5_PRO_PREVIEW_03_25,p.GEMINI_2_5_FLASH_PREVIEW_04_17,p.GEMINI_2_5_FLASH_PREVIEW_05_20,p.GEMINI_2_5_FLASH_PREVIEW_04_17_THINKING,p.GEMINI_2_5_PRO_PREVIEW_05_06,p.GEMINI_2_5_PRO_PREVIEW_06_05,p.GEMINI_2_0_FLASH_EXP,p.GEMINI_2_0_FLASH,p.GEMINI_2_0_FLASH_001,p.GEMINI_2_0_FLASH_EXP_IMAGE_GENERATION,p.GEMINI_2_0_FLASH_LITE_001,p.GEMINI_2_0_FLASH_LITE,p.GEMINI_2_0_FLASH_PREVIEW_IMAGE_GENERATION,p.GEMINI_2_0_FLASH_LITE_PREVIEW_02_05,p.GEMINI_2_0_FLASH_LITE_PREVIEW,p.GEMINI_2_0_PRO_EXP,p.GEMINI_2_0_PRO_EXP_02_05,p.GEMINI_EXP_1206,p.GEMINI_2_0_FLASH_THINKING_EXP_01_21,p.GEMINI_2_0_FLASH_THINKING_EXP,p.GEMINI_2_0_FLASH_THINKING_EXP_1219,p.GEMINI_2_5_FLASH_PREVIEW_TTS,p.GEMINI_2_5_PRO_PREVIEW_TTS,p.LEARNLM_2_0_FLASH_EXPERIMENTAL,p.GEMMA_3_1B_IT,p.GEMMA_3_4B_IT,p.GEMMA_3_12B_IT,p.GEMMA_3_27B_IT,p.GEMMA_3N_E4B_IT],ke=p.GEMINI_2_5_FLASH_PREVIEW_05_20;class xe{static{c(this,"GoogleAIProvider")}name="GoogleAI";client;model;constructor(e,s){this.model=s??ke,this.client=new me({apiKey:e})}createChatRequest(e,s={}){const{recorder:n}=s;return e.hasFiles()&&!te.includes(this.model)&&n?.warn.log(`Model ${this.model} does not support multimodal content. Use one of: ${te.join(", ")}`),new $e(this,e)}}class $e{static{c(this,"GoogleAIChatRequest")}constructor(e,s){this.provider=e,this.chat=s}async execute(e){const{recorder:s}=e,{client:n,model:o}=this.provider,r=this.prepareRequest(this.chat);s?.debug?.log(r);let i;try{const a=await n.models.generateContent({model:o,...r});i=Le(a,e)}catch(a){s?.error?.log(a),i={type:"error",error:{type:a.name??"Undetermined",message:a.message??"Unexpected error from Google AI"},usage:{in:0,out:0},raw:a}}return s?.debug?.log(i),i}prepareRequest(e){let s;e.messages.length===1&&e.messages[0].role=="user"&&typeof e.messages[0].content=="string"?s=e.messages[0].content:s=e.messages.map(o=>{if(o.role==="user"){if(typeof o.content=="string")return{role:"user",parts:[{text:o.content}]};{const r=[];for(const i of o.content)if(i.type==="text")r.push({text:i.text});else if(i.type==="file"){const a=i.file;(a.type==="image"||a.type==="document")&&r.push({inlineData:{mimeType:a.mimeType,data:a.base64}})}return{role:"user",parts:r}}}else if(o.role==="assistant"){const r={role:"assistant",parts:[]};return o.content&&r.parts.push({text:o.content}),o.toolCalls&&(r.parts=r.parts.concat(o.toolCalls.map(i=>{let a;return typeof i.arguments=="string"?a=JSON.parse(i.arguments):a=i.arguments,{functionCall:{id:i.id??void 0,name:i.name,args:a}}}))),r}else if(o.role==="tool")return{role:"user",parts:o.content.map(r=>({functionResponse:{id:r.id??void 0,name:r.name,response:{output:r.content}}}))}});const n={};return e.system&&(n.systemInstruction=e.system),e.tools.length>0&&(n.tools=e.tools.map(o=>({functionDeclarations:[{name:o.name,description:o.description,parameters:{...o.parameters,type:he.OBJECT}}]}))),{contents:s,config:n}}}function Le(t,e){const{recorder:s}=e,n=t.usageMetadata.promptTokenCount,o=t.usageMetadata.totalTokenCount-n,r={in:n,out:o};if(!t)return{type:"error",error:{type:"InvalidResponse",message:"Invalid or empty response from Google AI"},usage:{in:0,out:0},raw:t};if(t.promptFeedback&&t.promptFeedback.blockReason)return{type:"error",error:{type:"Blocked",message:`Response blocked by Google AI: ${t.promptFeedback.blockReason}, ${t.promptFeedback.blockReasonMessage}`},usage:r,raw:t};if(!t.candidates||t.candidates.length===0)return{type:"error",error:{type:"InvalidResponse",message:"Invalid or empty response from Google AI"},usage:{in:0,out:0},raw:t};t.candidates.length>1&&s?.warn?.log(`We received ${t.candidates.length} response candidates`);const i=t.candidates[0],l=(i.content?.parts||[]).map(f=>f.text).filter(f=>f!==void 0).join(""),[u,_]=Fe(i.finishReason);if(u){let f;return t.functionCalls&&(f=t.functionCalls.map(d=>({id:d.id,name:d.name,arguments:JSON.stringify(d.args)}))),{type:"success",id:t.responseId,model:t.modelVersion,reason:t.functionCalls?m.FunctionCall:_,message:{role:"assistant",...l?{content:l}:{},...f?{toolCalls:f}:{}},usage:r,raw:t}}else return{type:"error",error:{type:"Undetermined",message:`Unexpected stop reason: ${_}`},usage:r,raw:t}}c(Le,"translateResponse$2");function Fe(t){switch(t){case w.STOP:return[!0,m.Stop];case w.MAX_TOKENS:return[!0,m.Length];case w.FINISH_REASON_UNSPECIFIED:case w.SAFETY:case w.RECITATION:case w.LANGUAGE:case w.OTHER:case w.BLOCKLIST:case w.PROHIBITED_CONTENT:case w.SPII:case w.MALFORMED_FUNCTION_CALL:case w.IMAGE_SAFETY:return[!1,m.Error]}}c(Fe,"getStopReason$1");const Ce="http://localhost:11434";class Ue{static{c(this,"OllamaProvider")}name="Ollama";url;model;recorder;constructor(e,s){this.url=s||Ce,this.model=e}createChatRequest(e,s={}){const{recorder:n}=s;return e.hasFiles()&&n?.warn?.log(`Ollama model ${this.model} multimodal support depends on the specific model. Ensure you're using a vision-capable model like llava.`),new De(this.url,this.model,e)}}class De{static{c(this,"OllamaChatCompletionRequest")}chat;url;model;constructor(e,s,n){this.url=e,this.model=s,this.chat=n}async execute(e){const{recorder:s}=e,n={model:this.model,stream:!1,options:{temperature:.7},...He(this.chat)};s?.debug?.log(n);let o;try{const r=await fetch(`${this.url}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)});if(!r.ok)throw console.log(r),new Error(`HTTP error! status: ${r.status}`);const i=await r.json();o=We(i)}catch(r){s?.error?.log("Error fetching Ollama response:",r),o={type:"error",error:{type:"OllamaError",message:r.message||"Unexpected error from Ollama"},usage:{in:0,out:0},raw:JSON.stringify(r)}}return s?.debug?.log(o),o}}function He(t){const e=[];t.system&&e.push({role:"system",content:t.system});const s=t.tools.length>0?t.tools.map(o=>({type:"function",function:o})):void 0,n=t.messages.map(o=>{switch(o.role){case"tool":return o.content.map(r=>({role:"tool",tool_call_id:r.id,content:r.content}));case"assistant":return{role:o.role,content:o.content,tool_calls:o.toolCalls.map(r=>{const i=r.id;return{type:"function",function:{name:r.name,arguments:r.arguments},...i&&{id:i}}})};default:if(typeof o.content=="string")return{role:o.role,content:o.content};{let r="";const i=[];for(const a of o.content)if(a.type==="text")r+=a.text;else if(a.type==="file"){const l=a.file;l.type==="image"&&i.push(l.base64)}return{role:o.role,content:r,...i.length>0&&{images:i}}}}}).flat(1/0);return{messages:[...e,...n],...s&&{tools:s}}}c(He,"prepareRequest$1");function We(t){if(t.done_reason==="stop"&&t.message){const e=t.message.content,s=[];if(t.message.tool_calls)for(const o of t.message.tool_calls)s.push({id:o.id,name:o.function.name,arguments:o.function.arguments});const n=s.length>0;return{type:"success",id:`ollama-${Date.now()}`,model:t.model,reason:n?m.FunctionCall:m.Stop,message:{role:"assistant",content:e,...n&&{toolCalls:s}},usage:{in:t.prompt_eval_count||0,out:t.eval_count||0},raw:t}}return{type:"error",error:{type:"OllamaError",message:"Unexpected error from Ollama"},usage:{in:0,out:0},raw:t}}c(We,"translateResponse$1");const g={GPT_4_1:"gpt-4.1",GPT_4_1_2025_04_14:"gpt-4.1-2025-04-14",GPT_4_1_MINI:"gpt-4.1-mini",GPT_4_1_MINI_2025_04_14:"gpt-4.1-mini-2025-04-14",GPT_4_1_NANO:"gpt-4.1-nano",GPT_4_1_NANO_2025_04_14:"gpt-4.1-nano-2025-04-14",GPT_4O:"gpt-4o",GPT_4O_2024_05_13:"gpt-4o-2024-05-13",GPT_4O_2024_08_06:"gpt-4o-2024-08-06",GPT_4O_2024_11_20:"gpt-4o-2024-11-20",GPT_4O_AUDIO_PREVIEW:"gpt-4o-audio-preview",GPT_4O_AUDIO_PREVIEW_2024_10_01:"gpt-4o-audio-preview-2024-10-01",GPT_4O_AUDIO_PREVIEW_2024_12_17:"gpt-4o-audio-preview-2024-12-17",GPT_4O_AUDIO_PREVIEW_2025_06_03:"gpt-4o-audio-preview-2025-06-03",GPT_4O_MINI:"gpt-4o-mini",GPT_4O_MINI_2024_07_18:"gpt-4o-mini-2024-07-18",GPT_4O_MINI_AUDIO_PREVIEW:"gpt-4o-mini-audio-preview",GPT_4O_MINI_AUDIO_PREVIEW_2024_12_17:"gpt-4o-mini-audio-preview-2024-12-17",GPT_4O_MINI_REALTIME_PREVIEW:"gpt-4o-mini-realtime-preview",GPT_4O_MINI_REALTIME_PREVIEW_2024_12_17:"gpt-4o-mini-realtime-preview-2024-12-17",GPT_4O_MINI_SEARCH_PREVIEW:"gpt-4o-mini-search-preview",GPT_4O_MINI_SEARCH_PREVIEW_2025_03_11:"gpt-4o-mini-search-preview-2025-03-11",GPT_4O_MINI_TRANSCRIBE:"gpt-4o-mini-transcribe",GPT_4O_MINI_TTS:"gpt-4o-mini-tts",GPT_4O_REALTIME_PREVIEW:"gpt-4o-realtime-preview",GPT_4O_REALTIME_PREVIEW_2024_10_01:"gpt-4o-realtime-preview-2024-10-01",GPT_4O_REALTIME_PREVIEW_2024_12_17:"gpt-4o-realtime-preview-2024-12-17",GPT_4O_REALTIME_PREVIEW_2025_06_03:"gpt-4o-realtime-preview-2025-06-03",GPT_4O_SEARCH_PREVIEW:"gpt-4o-search-preview",GPT_4O_SEARCH_PREVIEW_2025_03_11:"gpt-4o-search-preview-2025-03-11",GPT_4O_TRANSCRIBE:"gpt-4o-transcribe",O3_MINI:"o3-mini",O3_MINI_2025_01_31:"o3-mini-2025-01-31",O4_MINI:"o4-mini",O4_MINI_2025_04_16:"o4-mini-2025-04-16"},Be=[g.GPT_4_1,g.GPT_4_1_2025_04_14,g.GPT_4_1_MINI,g.GPT_4_1_MINI_2025_04_14,g.GPT_4_1_NANO,g.GPT_4_1_NANO_2025_04_14,g.GPT_4O,g.GPT_4O_2024_05_13,g.GPT_4O_2024_08_06,g.GPT_4O_2024_11_20,g.GPT_4O_AUDIO_PREVIEW,g.GPT_4O_AUDIO_PREVIEW_2024_10_01,g.GPT_4O_AUDIO_PREVIEW_2024_12_17,g.GPT_4O_AUDIO_PREVIEW_2025_06_03,g.GPT_4O_MINI,g.GPT_4O_MINI_2024_07_18,g.GPT_4O_MINI_AUDIO_PREVIEW,g.GPT_4O_MINI_AUDIO_PREVIEW_2024_12_17,g.GPT_4O_MINI_REALTIME_PREVIEW,g.GPT_4O_MINI_REALTIME_PREVIEW_2024_12_17,g.GPT_4O_MINI_SEARCH_PREVIEW,g.GPT_4O_MINI_SEARCH_PREVIEW_2025_03_11,g.GPT_4O_MINI_TRANSCRIBE,g.GPT_4O_MINI_TTS,g.GPT_4O_REALTIME_PREVIEW,g.GPT_4O_REALTIME_PREVIEW_2024_10_01,g.GPT_4O_REALTIME_PREVIEW_2024_12_17,g.GPT_4O_REALTIME_PREVIEW_2025_06_03,g.GPT_4O_SEARCH_PREVIEW,g.GPT_4O_SEARCH_PREVIEW_2025_03_11,g.GPT_4O_TRANSCRIBE,g.O3_MINI,g.O3_MINI_2025_01_31,g.O4_MINI,g.O4_MINI_2025_04_16];class qe{static{c(this,"OpenAIChatCompletionRequest")}constructor(e,s){this.provider=e,this.chat=s}async execute(e){const{recorder:s}=e,{client:n,model:o}=this.provider,r={model:o,...Ke(this.chat)};s?.debug?.log(r);let i;try{const a=await n.chat.completions.create(r);i=Je(a)}catch(a){s?.error?.log(a),i={type:"error",error:{type:a.type??"Undetermined",message:a.message??"Unexpected error from OpenAI"},usage:{in:0,out:0},raw:a}}return s?.debug?.log(i),i}}function Xe(t){switch(t){case"length":return m.Length;case"stop":return m.Stop;case"tool_calls":return m.FunctionCall;default:return m.Error}}c(Xe,"getStopReason");function Ke(t){const e=[];t.system&&e.push({role:"system",content:t.system});const s=t.tools.length>0?t.tools.map(o=>({type:"function",function:o})):void 0,n=t.messages.map(o=>{switch(o.role){case"tool":return o.content.map(i=>({role:"tool",tool_call_id:i.id,content:i.content}));case"assistant":const r=o.toolCalls?.map(i=>{const a=i.id;return{type:"function",function:{name:i.name,arguments:typeof i.arguments=="string"?i.arguments:JSON.stringify(i.arguments)},...a&&{id:a}}});return{role:o.role,content:o.content,...r&&{toolCalls:r}};default:if(typeof o.content=="string")return{role:o.role,content:o.content};{const i=[];for(const a of o.content)if(a.type==="text")i.push({type:"text",text:a.text});else if(a.type==="file"){const l=a.file;l.type==="image"&&i.push({type:"image_url",image_url:{url:`data:${l.mimeType};base64,${l.base64}`}})}return{role:o.role,content:i}}}}).flat(1/0);return{messages:[...e,...n],...s&&{tools:s}}}c(Ke,"prepareRequest");function Je(t){if(t.choices.length>0){const e=t.choices[0],s=e.message.tool_calls?.map(n=>({id:n.id,name:n.function.name,arguments:n.function.arguments}));return{type:"success",id:t.id,model:t.model,reason:Xe(e.finish_reason),message:{content:e.message.content??"",role:e.message.role,toolCalls:s},usage:{in:t.usage?.prompt_tokens??0,out:t.usage?.completion_tokens??0},raw:t}}return{type:"error",error:{type:"undetermined",message:"Unexpected response from OpenAI"},usage:{in:t.usage?.prompt_tokens??0,out:t.usage?.completion_tokens??0},raw:t}}c(Je,"translateResponse");class ze{static{c(this,"OpenAIResponsesAPI")}constructor(e,s){this.provider=e,this.chat=s}async execute(e){const{recorder:s}=e,{client:n,model:o}=this.provider,r=Ye(this.chat,o);s?.debug?.heading.log("[Open AI Provider] Using the Responses API"),s?.debug?.log(r);let i;try{const a=await n.responses.create(r);i=Ze(a)}catch(a){s?.error?.log(a),i={type:"error",error:{type:a.type??"Undetermined",message:a.message??"Unexpected error from OpenAI"},usage:{in:0,out:0},raw:a}}return s?.debug?.log(i),i}}function Ye(t,e){const s=t.messages.map(o=>{if(o.role==="tool")return o.content.map(r=>({type:"function_call_output",call_id:r.id,output:r.content}));if(o.role==="assistant"){const r=o.toolCalls?.map(i=>{const a=i.id;return{type:"function",function:{name:i.name,arguments:typeof i.arguments=="string"?i.arguments:JSON.stringify(i.arguments)},...a&&{id:a}}});return{role:o.role,content:o.content,...r&&{toolCalls:r}}}if(typeof o.content=="string")return{role:o.role,content:o.content};{const r=[];for(const i of o.content)if(i.type==="text")r.push({type:"input_text",text:i.text});else if(i.type==="file"){const a=i.file;a.type==="image"?r.push({type:"input_image",image_url:`data:${a.mimeType};base64,${a.base64}`}):a.type==="document"&&r.push({type:"input_file",filename:a.path,file_data:`data:${a.mimeType};base64,${a.base64}`})}return{role:o.role,content:r}}}).flat(1),n={model:e,input:s};return t.system&&(n.instructions=t.system),t.tools.length>0&&(n.tools=t.tools.map(o=>({type:"function",strict:!0,...o}))),n}c(Ye,"prepareResponseRequest");function Ze(t){if(t.error)return{type:"error",error:{type:t.error.code||"undetermined",message:t.error.message||"Response generation failed"},usage:{in:t.usage?.input_tokens??0,out:t.usage?.output_tokens??0},raw:t};const e=t.output?.filter(s=>s.type==="function_call")?.map(s=>({id:s.id||"",name:s.function?.name||"",arguments:s.function?.arguments||""}));return{type:"success",id:t.id,model:t.model||"",reason:t.incomplete_details?m.Error:m.Stop,message:{content:t.output_text||"",role:"assistant",...e?.length&&{toolCalls:e}},usage:{in:t.usage?.input_tokens??0,out:t.usage?.output_tokens??0},raw:t}}c(Ze,"translateResponseToAIResponse");const Qe=g.GPT_4_1;class je{static{c(this,"OpenAIProvider")}name="OpenAI";client;model;constructor(e,s){this.model=s||Qe,this.client=new ye({apiKey:e})}createChatRequest(e,s={}){const{recorder:n}=s;return Be.includes(this.model)?new ze(this,e):new qe(this,e)}}function Ve(t,e){if(!e||Object.keys(e).length===0)throw new E(`The provider ${t} is not configured. Please check your configuration.`);switch(t){case"openai":return new je(e["api-key"],e.model);case"anthropic":return new Se(e["api-key"],e.model);case"googleai":return new xe(e["api-key"],e.model);case"ollama":{const s=e;return new Ue(s.model,s.url)}default:throw new E("The provider is unsupported")}}c(Ve,"getProvider");class Y extends E{static{c(this,"TaskError")}constructor(e,s){super(e,{code:"TASK_ERROR",id:s?.id,details:{taskType:s?.taskType,taskIndex:s?.taskIndex,...s?.details},cause:s?.cause}),Object.setPrototypeOf(this,Y.prototype)}}const I={Running:"running",Success:"success",PartialSuccess:"partialSuccess",Fail:"fail"};var P=(t=>(t[t.Trace=10]="Trace",t[t.Debug=20]="Debug",t[t.Info=30]="Info",t[t.Warn=40]="Warn",t[t.Error=50]="Error",t[t.Fatal=60]="Fatal",t))(P||{});class et{static{c(this,"Recorder")}instanceId=crypto.randomUUID();currentLevel=P.Info;logs=[];writers=[];_debug;_info;_warn;_error;constructor(){this.buildMethods()}buildMethods(){this._debug=P.Debug>=this.currentLevel?this.createLoggingFunction(P.Debug):null,this._info=P.Info>=this.currentLevel?this.createLoggingFunction(P.Info):null,this._warn=P.Warn>=this.currentLevel?this.createLoggingFunction(P.Warn):null,this._error=this.createLoggingFunction(P.Error)}set level(e){this.currentLevel=e,this.buildMethods()}get level(){return this.currentLevel}get info(){return this._info}get warn(){return this._warn}get error(){return this._error}get debug(){return this._debug}subscribe(e){this.writers.includes(e)||this.writers.push(e)}unsubscribe(e){const s=this.writers.indexOf(e);s!==-1&&this.writers.splice(s,1)}publish(e){this.logs.push(e);for(const s of this.writers)s.handleEvent(e)}logFunction(e,s,...n){let o=n.map(r=>typeof r=="string"?{message:r}:r instanceof Error?Ee(r):r);this.publish({level:e,time:Date.now(),kind:s,payload:o})}createLoggingFunction(e){return{log:this.logFunction.bind(this,e,"body"),heading:{log:this.logFunction.bind(this,e,"heading")}}}getLogs(e=P.Info){return this.logs.filter(s=>s.level>=e)}async shutdown(){for(const e of this.writers)typeof e.flush=="function"&&await e.flush()}}async function tt({path:t,defaults:e,loader:s="File"}){let n=null,o="";if(t)try{o=B(t),n=await F(o,{encoding:"utf-8"})}catch{throw new Error(`${s} not found, see --help for details`)}else{for(const r of e.formats)try{o=B(e.name+"."+r),n=await F(o,{encoding:"utf-8"});break}catch{continue}if(n===null)throw new Error(`${s} not found, see --help for details`)}return{content:n,format:o.split(".").pop()??""}}c(tt,"loadFile");async function st(t,e){let s="";for(const n of t){const o=await Q(n);e?.debug?.log(`many-files parser. For glob "${n}", found ${o.length} files.`);const r=await Promise.all(o.map(async i=>{const a=await F(i,"utf-8");return i+`:
|
|
2
|
+
`+a}));s+=r.join(`
|
|
3
|
+
`)}return s}c(st,"loadManyFiles");function nt(t,e){t=t.replace("**/*","**");const s=/(?<asterisks>\*{1,2})(?<extension>\.[^\\/]+)?/,n=t.match(s);if(n){let o="";return n.groups?.asterisks.length==1?o+=e.stem:o+=e.dir+e.stem,n.groups?.extension?o+=n.groups.extension:o+=e.ext,t.replace(n[0],o)}return t}c(nt,"replaceFilePattern");function rt(t){const e=/(?<name>[^\\/]+)(?<extension>\.[^\\/]+)$/,s=t.match(e);return s&&s.length>0&&s.groups?{abs:t,dir:t.replace(s[0],""),ext:s.groups.extension,stem:s.groups.name,name:s[0]}:null}c(rt,"pathToComponents");async function se(t){const e=Re(t);try{await j(e)}catch{await ve(e),await se(e)}}c(se,"ensureDirectoryExistence");async function ot({filePath:t,content:e}){await se(t),await Ae(t,e)}c(ot,"writeFileWithDirectories");const ne=[".jpg",".jpeg",".png",".gif",".webp",".bmp",".tiff"],re=[".pdf"],oe=20*1024*1024;async function q(t){const e=B(t);try{await j(e)}catch{throw new Error(`File not found: ${t}`)}const s=await Pe(e);if(s.size>oe)throw new Error(`File too large: ${s.size} bytes. Maximum allowed: ${oe} bytes`);const n=Ne(e).toLowerCase();let o,r;if(ne.includes(n))switch(o="image",n){case".jpg":case".jpeg":r="image/jpeg";break;case".png":r="image/png";break;case".gif":r="image/gif";break;case".webp":r="image/webp";break;case".bmp":r="image/bmp";break;case".tiff":r="image/tiff";break;default:r="image/jpeg"}else if(re.includes(n))o="document",r="application/pdf";else throw new Error(`Unsupported file type: ${n}. Supported types: ${[...ne,...re].join(", ")}`);const a=(await F(e)).toString("base64");return{path:e,base64:a,mimeType:r,size:s.size,name:e.split("/").pop()||"",type:o}}c(q,"loadFileAsBase64");function it(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):at(t.using,e)?!t.jobs||typeof t.jobs!="object"?(e&&(e.value="Missing or invalid 'jobs' property"),!1):ie(t.jobs,e)?!0:(e&&(e.value=`Invalid 'jobs' property: ${e?.value}`),!1):(e&&(e.value=`Invalid 'using' property: ${e?.value}`),!1)}c(it,"isJobConfig");function at(t,e){if(!t||typeof t!="object")return e&&(e.value="Not an object"),!1;if(typeof t.engine!="string")return e&&(e.value="Missing or invalid 'engine' property"),!1;if(!["openai","anthropic","ollama","googleai"].includes(t.engine))return e&&(e.value="Invalid provider type. Must be 'openai', 'anthropic', 'googleai', or 'ollama'"),!1;switch(t.engine){case"ollama":if("model"in t&&typeof t.model!="string")return e&&(e.value="Property 'model' must be a string"),!1;if("url"in t&&typeof t.url!="string")return e&&(e.value="Property 'url' must be a string"),!1;break;case"googleai":case"anthropic":case"openai":if("api-key"in t&&typeof t["api-key"]!="string")return e&&(e.value="Property 'api-key' must be a string"),!1;if("model"in t&&typeof t.model!="string")return e&&(e.value="Property 'model' must be a string"),!1;break}return!0}c(at,"isUsing");function ie(t,e){for(const[s,n]of Object.entries(t))if(!ct(n,e))return e&&(e.value=`Invalid job '${s}': ${e?.value}`),!1;return!0}c(ie,"isDAGJob");function ct(t,e){if(!t||typeof t!="object")return e&&(e.value="Not an object"),!1;if(!ut(t,e))return!1;if("dependsOn"in t&&t.dependsOn!==void 0){const s=t.dependsOn;if(typeof s!="string")if(Array.isArray(s)){for(let n=0;n<s.length;n++)if(typeof s[n]!="string")return e&&(e.value=`Dependency at index ${n} must be a string`),!1}else return e&&(e.value="Property 'dependsOn' must be a string or array of strings"),!1}return!0}c(ct,"isDAGJobValue");function ut(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):"batch"in t?_t(t,e):lt(t,e)}c(ut,"isJob");function lt(t,e){if(!t||typeof t!="object")return e&&(e.value="Not an object"),!1;if("batch"in t)return e&&(e.value="Serial job should not have a batch property"),!1;if(t.tools!==void 0){if(!Array.isArray(t.tools))return e&&(e.value="Property 'tools' must be an array"),!1;for(const s of t.tools)if(typeof s!="string")return e&&(e.value="All tools must be strings"),!1}if(!Array.isArray(t.steps))return e&&(e.value="Property 'steps' must be an array"),!1;for(let s=0;s<t.steps.length;s++)if(!ae(t.steps[s],e))return e&&(e.value=`Invalid step at index ${s}: ${e?.value}`),!1;return!0}c(lt,"isSerialJob");function _t(t,e){if(!t||typeof t!="object")return e&&(e.value="Not an object"),!1;if(t.tools!==void 0){if(!Array.isArray(t.tools))return e&&(e.value="Property 'tools' must be an array"),!1;for(const s of t.tools)if(typeof s!="string")return e&&(e.value="All tools must be strings"),!1}if(!Array.isArray(t.batch))return e&&(e.value="Property 'batch' must be an array"),!1;for(let s=0;s<t.batch.length;s++){const n=t.batch[s];if(!n||typeof n!="object")return e&&(e.value=`Batch item at index ${s} must be an object`),!1;if(n.type!=="files")return e&&(e.value=`Batch item at index ${s} must have type 'files'`),!1;if(typeof n.source!="string")return e&&(e.value=`Batch item at index ${s} must have a string 'source' property`),!1;if(typeof n.bind!="string")return e&&(e.value=`Batch item at index ${s} must have a string 'bind' property`),!1;if(n["skip-if"]!==void 0){if(!Array.isArray(n["skip-if"]))return e&&(e.value=`Batch item at index ${s} must have an array 'skip-if' property`),!1;for(let o=0;o<n["skip-if"].length;o++)if(!ft(n["skip-if"][o],e))return e&&(e.value=`Invalid skip condition at index ${o} in batch item ${s}: ${e?.value}`),!1}}if(!Array.isArray(t.steps))return e&&(e.value="Property 'steps' must be an array"),!1;for(let s=0;s<t.steps.length;s++)if(!ae(t.steps[s],e))return e&&(e.value=`Invalid step at index ${s}: ${e?.value}`),!1;return!0}c(_t,"isBatchJob");function ft(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):t.type!=="file-exist"?(e&&(e.value="Property 'type' must be 'file-exist'"),!1):typeof t.pattern!="string"?(e&&(e.value="Property 'pattern' must be a string"),!1):!0}c(ft,"isSkipOptions");function ae(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):!t.uses||typeof t.uses!="string"?(e&&(e.value="Step must have a string 'uses' property"),!1):t.uses==="chat"?pt(t,e):t.uses==="write-to-disk"?gt(t,e):(e&&(e.value=`Unknown uses type: ${t.uses}`),!1)}c(ae,"isStep");function pt(t,e){if(!t||typeof t!="object")return e&&(e.value="Not an object"),!1;if(t.uses!=="chat")return e&&(e.value="Uses must be 'chat'"),!1;if(typeof t.message!="string")return e&&(e.value="Property 'message' must be a string"),!1;if(t.output!==void 0){if(!t.output||typeof t.output!="object"||Array.isArray(t.output))return e&&(e.value="Property 'output' must be an object"),!1;const s=["string","string[]","number","boolean"];for(const[n,o]of Object.entries(t.output))if(typeof n!="string"||typeof o!="string"||!s.includes(o))return e&&(e.value="Property 'output' must be a Record<string, ResTypeStrings> where ResTypeStrings is 'string' | 'string[]' | 'number' | 'boolean'"),!1}if(t.system!==void 0&&typeof t.system!="string")return e&&(e.value="Property 'system' must be a string"),!1;if(t.replace!==void 0){if(!Array.isArray(t.replace))return e&&(e.value="Property 'replace' must be an array"),!1;for(let s=0;s<t.replace.length;s++)if(!dt(t.replace[s],e))return e&&(e.value=`Invalid replace at index ${s}: ${e?.value}`),!1}if(t.tools!==void 0){if(!Array.isArray(t.tools))return e&&(e.value="Property 'tools' must be an array"),!1;for(const s of t.tools)if(typeof s!="string")return e&&(e.value="All tools must be strings"),!1}if(t.images!==void 0){if(!Array.isArray(t.images))return e&&(e.value="Property 'images' must be an array"),!1;for(let s=0;s<t.images.length;s++)if(!mt(t.images[s],e))return e&&(e.value=`Invalid image at index ${s}: ${e?.value}`),!1}if(t.documents!==void 0){if(!Array.isArray(t.documents))return e&&(e.value="Property 'documents' must be an array"),!1;for(let s=0;s<t.documents.length;s++)if(!ht(t.documents[s],e))return e&&(e.value=`Invalid document at index ${s}: ${e?.value}`),!1}return!0}c(pt,"isChatStep");function gt(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):t.uses!=="write-to-disk"?(e&&(e.value="Uses must be 'write-to-disk'"),!1):typeof t.output!="string"?(e&&(e.value="Property 'output' must be a string"),!1):!0}c(gt,"isWriteToDiskStep");function dt(t,e){if(!t||typeof t!="object")return e&&(e.value="Not an object"),!1;if(typeof t.pattern!="string")return e&&(e.value="Property 'pattern' must be a string"),!1;if(t.source!=="file")return e&&(e.value="Property 'source' must be 'file'"),!1;if(typeof t.files!="string"&&!Array.isArray(t.files))return e&&(e.value="Property 'files' must be a string or an array of strings"),!1;if(Array.isArray(t.files)){for(let s=0;s<t.files.length;s++)if(typeof t.files[s]!="string")return e&&(e.value=`Files entry at index ${s} must be a string`),!1}return!0}c(dt,"isReplace");function mt(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):typeof t.file!="string"?(e&&(e.value="Property 'file' must be a string"),!1):!0}c(mt,"isImageReference");function ht(t,e){return!t||typeof t!="object"?(e&&(e.value="Not an object"),!1):typeof t.file!="string"?(e&&(e.value="Property 'file' must be a string"),!1):!0}c(ht,"isDocumentReference");class yt{static{c(this,"FileRunPlanner")}constructor(e,s,n=[]){this.source=e,this.bind=s,this.skipConditions=n}async plan(e){const s=[],n=await Q(this.source,{withFileTypes:!0});for(const o of n){const r=o.fullpath(),i=rt(r);let a=!1;for(const l of this.skipConditions)if(a=await l.eval({components:i}),a)break;if(!a){const l=await Ie(r,"utf-8"),u={variables:{[this.bind]:l,...i},tasks:e};s.push(u)}}return s}}class Et{static{c(this,"MultiPlanner")}planners;constructor(e){this.planners=e}async plan(e){const s=this.planners.map(async o=>await o.plan(e));return(await Promise.all(s)).flat()}}function X(t,e,s="{{}}"){const n=s==="{{}}"?/\{\{(.*?)\}\}/g:/\{(.*?)\}/g;return t=t.replace(n,(o,r)=>e[r]?e[r]:o),t}c(X,"replaceVariables");class It{static{c(this,"FileExistSkipCondition")}constructor(e){this.pattern=e}type="file-exist";async eval(e){const s=X(this.pattern,e.components,"{}");try{return await we(s,Te.F_OK),!0}catch{return!1}}}var N=(t=>(t.String="string",t.List="string[]",t.Number="number",t.Boolean="boolean",t))(N||{});const ce={response:N.String};class ue{static{c(this,"AbstractInstruct")}type="instruct";_result=void 0;prompt;system=null;inputs={};tools={};files=[];resFormat;rawResponse;finalPrompt;constructor(e,s){this.prompt=e,this.resFormat=s}setInputs(e){this.inputs=e}addInput(e,s){this.inputs[e]=s}addTools(e){for(const s of e)this.tools[s.name]=s}addTool(e){this.tools[e.name]=e}addImage(e){if(e.type!=="image")throw new Error(`Expected image file, got ${e.type}`);this.files.push(e)}addFile(e){this.files.push(e)}hasTools(){return Object.keys(this.tools).length>0}hasFiles(){return this.files.length>0}get result(){return this._result}compile(e,s={}){const n=this.getFinalUserPrompt(e,s),o=this.getFormatInstructions();return n+`
|
|
4
|
+
`+o}getFinalUserPrompt(e,s={}){const{recorder:n,options:o}=s,r={...e,...this.inputs};let i=X(this.prompt,r);if(o?.warnUnused){const a=i.match(/\{\{(.*?)\}\}/g);if(a)throw n?.error.log(`Warning unused variables ${a.join(", ")}`),new Error(`Unused variables: ${a.join(", ")}`)}return i}getFormatInstructions(){let e="";for(const[s,n]of Object.entries(this.resFormat))switch(this.resFormat[s]){case N.String:e+=`
|
|
5
|
+
Use <${s}></${s}> to indicate the answer for ${s}. The answer must be a string.`;break;case N.Number:e+=`
|
|
6
|
+
Use <${s}></${s}> to indicate the answer for ${s}. the answer must be a number.`;break;case N.Boolean:e+=`
|
|
7
|
+
Use <${s}></${s}> to indicate the answer for ${s}. The answer must be a true/false.`;break;case N.List:e+=`
|
|
8
|
+
Use <${s}></${s}> to indicate the answer for ${s}. The answer must be a list of strings. Each string should be in a new line.`;break}return e}finalize(e,s){this.rawResponse=e;const n={},o=Object.keys(this.resFormat);if(o.length===0){if(e.trim()==="{}"||e.trim()==="")return{};throw new Error("Output format is empty, but rawValue is not an empty object representation or empty string.")}s=s||this.parseTaggedSections(e);for(const r of o){const i=r;let a;const l=s.tags[i];if(l)a=l;else throw new Error(`Expected results with tag ${i} but it does not exist`);const u=this.resFormat[r];try{const _=this.typeResponses(u,a);n[r]=_}catch(_){throw new Error(`Cannot convert value of key ${i} to ${u}: ${_.message}`)}}return this._result=n,n}parseTaggedSections(e){const s=/<(\w+)>(.*?)<\/\1>/gs,n={};let o=e;return o=o.replace(s,(r,i,a)=>(n[i]=a,"")),{tags:n,remaining:o.trim()}}typeResponses(e,s){let n;switch(e){case N.String:n=s;break;case N.Number:if(n=parseFloat(s),isNaN(n))throw new Error(`Cannot parse '${s}' as number. Expected a numeric string.`);break;case N.Boolean:const o=s.toLowerCase();if(o==="true")n=!0;else if(o==="false")n=!1;else throw new Error(`Cannot parse '${s}' as boolean. Expected 'true' or 'false'.`);break;case N.List:s===""?n=[]:n=s.split(`
|
|
9
|
+
`).map(r=>r.trim()).filter(r=>r.length>0);break}return n}}class k extends ue{static{c(this,"Instruct")}constructor(e,s){super(e,s)}static with(e,s){return s?new k(e,s):new k(e,ce)}}function $(t){return Array.isArray(t)?t:[t]}c($,"arrayify");function A(t,e){return e?`${e}:${t.slice(0,8)}`:t.slice(0,8)}c(A,"friendly");function wt(t){return new Promise(e=>setTimeout(e,t))}c(wt,"delay");const Tt={name:"brave",description:"Perform a search using the Brave search engine",parameters:{type:"object",properties:{searchTerm:{type:"string",description:"The search term to query"}},required:["searchTerm"]}};class Pt{static{c(this,"BraveSearchTool")}name="brave";schema=Tt;apiKey;throttle;lastExecTime=0;constructor(e){e&&this.setConfig(e)}setConfig(e){const{rateLimit:s}=e;this.apiKey=e["api-key"],this.throttle=s?1100/s:void 0}async execute(e,s={}){const{searchTerm:n}=e,{recorder:o}=s;if(o?.debug?.heading.log(`Brave: searching for ${n}`),this.throttle){for(;Date.now()-this.lastExecTime<this.throttle;)await wt(this.throttle-(Date.now()-this.lastExecTime));this.lastExecTime=Date.now()}try{const r=this.apiKey,i="https://api.search.brave.com/res/v1/web/search",a=new URL(i);a.searchParams.append("q",n),a.searchParams.append("format","json");const l=await fetch(a.toString(),{method:"GET",headers:{Accept:"application/json","X-Subscription-Token":r}});if(!l.ok)throw new Error(`[Brave] HTTP error ${l.status}: ${l.statusText}`);return await l.json()}catch(r){throw o?.error.log("[Brave] Error fetching search results:",r),r}}}const At=new Pt,vt={name:"calculator",description:"Performs basic arithmetic operations",parameters:{type:"object",properties:{operation:{type:"string",description:"The operation to perform (add, subtract, multiply, divide)",enum:["add","subtract","multiply","divide"]},a:{type:"number",description:"First operand"},b:{type:"number",description:"Second operand"}},required:["operation","a","b"]}},Nt={name:"calculator",schema:vt,execute:c(async t=>{const{operation:e,a:s,b:n}=t;switch(e){case"add":return`${s} + ${n} = ${s+n}`;case"subtract":return`${s} - ${n} = ${s-n}`;case"multiply":return`${s} * ${n} = ${s*n}`;case"divide":if(n===0)throw new Error("Cannot divide by zero");return`${s} / ${n} = ${s/n}`;default:throw new Error(`Unknown operation: ${e}`)}},"execute")};class Rt{static{c(this,"ToolRegistry")}executables={};config;setConfig(e){this.config=e}register(e){if(this.executables[e.name])throw new Error(`Tool with name '${e.name}' is already registered`);this.executables[e.name]=e}get(e){const s=this.executables[e];if(!s)throw new Error(`Tool '${e}' is not registered`);return s.setConfig?.(this.config[e]),s}}let L;function le(){return L||(L=new Rt,L.register(Nt),L.register(At)),L}c(le,"getToolRegistry");const Ot={async convert(t,e){const{recorder:s,toolNames:n}=e,{message:o,system:r,replace:i}=t;let a;t.output?a=k.with(o,t.output):a=k.with(o),r&&(a.system=r);const l=[...new Set([...n??[],...t.tools??[]])];for(const u of l){const _=le().get(u);a.addTool(_)}if(i){for(const u of i)if(u.source==="file"){const _=$(u.files),f=await st(_,s);a.addInput(u.pattern,f)}}if(t.images)for(const u of t.images)try{const _=await q(u.file);a.addFile(_)}catch(_){throw new Error(`Failed to load image '${u.file}': ${_.message}`)}if(t.documents)for(const u of t.documents)try{const _=await q(u.file);a.addFile(_)}catch(_){throw new Error(`Failed to load document '${u.file}': ${_.message}`)}return a}};class St{static{c(this,"StepToClassRegistry")}converters=new Map;get(e){const s=this.converters.get(e);if(!s)throw new Error(`No converter registered for step: ${e}`);return s}register(e,s){this.converters.set(e,s)}}class K{static{c(this,"WriteOutputTask")}constructor(e,s=["response"]){this.output=e,this.keys=s}type="write-to-disk"}const Mt={async convert(t){if(t.keys){const e=$(t.keys);return new K(t.output,e)}return new K(t.output)}},J=new St;J.register("write-to-disk",Mt),J.register("chat",Ot);async function C(t,e){const{recorder:s}=e,n=t.tools??void 0,o=t.steps.map(async r=>(r.uses,await J.get(r.uses).convert(r,{recorder:s,toolNames:n})));return Promise.all(o)}c(C,"configToTasks");async function _e(t,e){const{batch:s}=t;return s.length===1?fe(s[0]):new Et(s.map(n=>fe(n)))}c(_e,"configToPlanner");function fe(t){switch(t.type){case"files":let e;return t["skip-if"]&&(e=t["skip-if"].map(n=>bt(n))),new yt(t.source,t.bind,e)}}c(fe,"batchOptionsToPlanner");function bt(t){switch(t.type){case"file-exist":return new It(t.pattern)}}c(bt,"skipOptionsToSkipConditions");function Gt(t){return t.success===!1&&t.error!==void 0}c(Gt,"isErrorResult");function U(t,e){return{response:t,stats:e,success:!0}}c(U,"createResult");function D(t,e,s){return{response:e,stats:s,error:t,success:!1}}c(D,"createErrorResult");class kt{static{c(this,"Chat")}system;messages=[];tools=[];setToolSchemas(e){this.tools=e}addSystem(e){this.system=e}addUser(e){this.messages.push({role:"user",content:e})}addUserWithFiles(e,s=[]){if(s.length===0){this.addUser(e);return}const n=[{type:"text",text:e}];for(const o of s)n.push({type:"file",file:o});this.messages.push({role:"user",content:n})}addAssistant(e,s){this.messages.push({role:"assistant",content:e,toolCalls:s})}addTools(e){this.messages.push({role:"tool",content:e})}hasFiles(){return this.messages.some(e=>Array.isArray(e.content)&&e.content.some(s=>s.type==="file"))}getTextContent(e){return typeof e=="string"?e:e.filter(n=>n.type==="text").map(n=>n.text).join(" ")}getFiles(e){return typeof e=="string"?[]:e.filter(s=>s.type==="file").map(s=>s.file)}toString(){return JSON.stringify({system:this.system,messages:this.messages,tools:this.tools})}}class xt{static{c(this,"WriteToDiskTaskHandler")}taskType="write-to-disk";canHandle(e){return e&&typeof e=="object"&&"type"in e&&e.type==="write-to-disk"}async execute(e){const{task:s,variables:n,options:o={},recorder:r}=e,i=s.output,a=s.keys??[];if(o?.warnUnused){const _=a.filter(f=>!(f in n));_.length>0&&r?.warn?.log(`[Write To Disk] The following keys were not found in the variables: ${_.join(", ")}`)}let l="";if(a.length===1?l=n[a[0]]??"<not found>":l=a.map(_=>`[${_}]:
|
|
10
|
+
${n[_]??"<not found>"}
|
|
11
|
+
`).join(`
|
|
12
|
+
`),o?.dryRun){r?.info?.log("[Dry run] Write to Disk is not executed.");return}let u="";i.includes("*")?u=nt(i,n.file):u=X(i,n,"{}"),await ot({filePath:u,content:l})}}var H=(t=>(t.LastResult="lastResult",t))(H||{});function $t(t,e,s){const{options:n,recorder:o}=s,r=n?.warnUnused??!0;for(const[i,a]of Object.entries(t))r&&e[i]&&o?.warn?.log(`Warning: Variable "${i}" is being overwritten. Previous value: ${e[i]}, new value: ${a}`),e[i]=a}c($t,"setResultsIntoVariables");class Lt{static{c(this,"ChatTaskHandler")}taskType="instruct";canHandle(e){return e&&typeof e=="object"&&"type"in e&&e.type==="instruct"}async execute(e){const{task:s,...n}=e;await Ft({instruct:s,...n})}}async function Ft(t){const{instruct:e,chat:s,provider:n,stats:o,variables:r,options:i,recorder:a}=t;e.system&&s.addSystem(e.system);const l=e.compile(r,{recorder:a,options:i});if(e.hasFiles()?s.addUserWithFiles(l,e.files):s.addUser(l),e.hasTools()){const _=Ut(e.tools);s.setToolSchemas(_)}if(i?.dryRun)return a?.debug?.log(s),{action:"complete"};let u=!0;for(;u;){const f=await n.createChatRequest(s,{recorder:a}).execute({recorder:a});if(o.in+=f.usage.in,o.out+=f.usage.out,f.type==="error")throw new Error(JSON.stringify(f.error));if(f.type==="success")switch(f.reason){case m.Stop:{if(f.message.content){const d=f.message.content;s.addAssistant(d);const h=e.finalize(d);$t(h,r,{options:i,recorder:a}),r[H.LastResult]=h}return u=!1,{action:"continue"}}case m.Length:throw new Error("Incomplete model output due to `max_tokens` parameter or token limit");case m.FunctionCall:{let d=f.message;if(f.message&&s.addAssistant(d.content,d.toolCalls),d.toolCalls&&d.toolCalls.length>0){const h=await Ct(d.toolCalls,e,{recorder:a});a?.debug?.log(h),s.addTools(h),u=!0}else u=!1;break}}if(f.type!=="success")throw a?.debug?.log(f),new Error("Unexpected response type")}return{action:"continue"}}c(Ft,"executeChatAction");async function Ct(t,e,s={}){const{recorder:n}=s,o=[];for(const r of t)o.push(new Promise((i,a)=>{const l=e.tools[r.name];if(!l){a(`Tool not found: ${r.name}`);return}n?.debug?.heading.log(`Executing tool ${l.name}`);let u={};try{u=typeof r.arguments=="string"?JSON.parse(r.arguments):r.arguments}catch{a(`argument for tool ${r.name} is not valid: ${JSON.stringify(r.arguments)}`)}l.execute(u).then(_=>{n?.debug?.log(`Complete tool ${l.name}: ${r.id}`),i({id:r.id,name:r.name,content:JSON.stringify(_)})}).catch(a)}));return Promise.all(o)}c(Ct,"executeToolCalls");function Ut(t){const e=[];for(const[s,n]of Object.entries(t))e.push(n.schema);return e}c(Ut,"getToolSchemas");class Dt{static{c(this,"TaskRegistry")}handlers=new Map;register(e){this.handlers.set(e.taskType,e)}getHandler(e){return this.handlers.get(e.type)}hasHandler(e){return this.handlers.has(e.type)}async executeTask(e){const{task:s}=e,n=s.type,o=this.getHandler(s);if(!o)throw new Error(`No handler registered for action type: ${n}`);if(!o.canHandle(s))throw new Error(`Handler found but action does not match expected format: ${n}`);await o.execute(e)}}function Ht(){const t=new Dt;return t.register(new Lt),t}c(Ht,"createBaseRegistry");function Wt(){const t=Ht();return t.register(new xt),t}c(Wt,"createNodeRegistry");const z=c((t,...e)=>{const s=c(async o=>{const{recorder:r}=o;let i=[];return"steps"in t?i=await C(t,{recorder:r}):i=[t,...e],i},"prepare");return{execute:c(async o=>{const{provider:r,variables:i,options:a,stats:l,recorder:u,name:_}=o,f=crypto.randomUUID(),d=Wt();u?.info?.log({type:"task",id:f,status:I.Running,message:`[${A(f,_)}] Starting job`});try{const h=await s({recorder:u}),y=new kt;for(const[S,T]of h.entries()){u?.info?.log({type:"task",id:f,status:I.Running,message:`[${A(f,_)}] Processing step ${S+1}: ${T.type}`});try{await d.executeTask({task:T,chat:y,provider:r,variables:i,options:a,stats:l,recorder:u})}catch(v){throw v instanceof E?v:new Y(`Error executing task ${T.type}`,{id:f,taskType:T.type,taskIndex:S,cause:v instanceof Error?v:new Error(String(v))})}}return u?.info?.log({type:"task",status:I.Success,id:f,message:`[${A(f,_)}] Completed ${h.length} steps`}),U(i[H.LastResult],l)}catch(h){const y=h instanceof E?h:new E("Serial workflow execution failed",{id:f,cause:h instanceof Error?h:new Error(String(h))});return u?.info?.log({type:"task",status:I.Fail,id:f,message:`[${A(f,_)}] Failed: ${y.message}`}),u?.error.log(y),D(y,i[H.LastResult],l)}},"execute")}},"serialWorkflow"),pe=c((t,...e)=>{const s=c(async o=>{const{recorder:r}=o;let i=[],a=null;if("batch"in t){const l=t;a=await _e(l),i=await C(l,{recorder:r})}else a=t,i=[...e];return[a,i]},"prepare");return{execute:c(async o=>{const{provider:r,variables:i,options:a,stats:l,recorder:u,name:_}=o,f=crypto.randomUUID();try{const[d,h]=await s({recorder:u}),y=await d.plan(h);if(u?.debug?.heading.log("Runs",y),y.length===0)return u?.info?.log("No runs to execute"),U([],l);let S=0;u?.info?.log({type:"task",status:I.Running,id:f,message:`[${A(f,"CRW")}] Working on 0/${y.length}`});const T=c(async(R,W)=>{try{return await z(...R.tasks).execute({provider:r,variables:{...R.variables,...i},options:a,stats:l,recorder:u,name:`${_}-${W}`})}catch(M){const Z=M instanceof E?M:new E("Error executing run",{cause:M instanceof Error?M:new Error(String(M))});return u?.error?.log(Z),D(Z,null,l)}finally{S++,u?.info?.log({type:"task",status:I.Running,id:f,message:`[${A(f,"CRW")}] Working on ${S}/${y.length}`})}},"executeRun"),v=5;let G=[];for(let R=0;R<y.length;R+=v){const W=y.slice(R,R+v),M=await Promise.all(W.map(T));G=G.concat(M)}const b=G.some(Gt);u?.info?.log({type:"task",status:b?I.PartialSuccess:I.Success,id:f,message:`[${A(f,"CRW")}] All jobs (${y.length}) completed${b?" with some errors":""}`});const x=G.map(R=>R.response);return U(x,l)}catch(d){const h=d instanceof E?d:new E("Concurrent workflow execution failed",{id:f,cause:d instanceof Error?d:new Error(String(d))});return u?.error?.log(h),D(h,null,l)}},"execute")}},"concurrentWorkflow");class Bt{static{c(this,"DAGParser")}static parse(e){const s=new Map;for(const[o,r]of Object.entries(e)){const i=this.parseNodeDefinition(o,r);s.set(o,i)}return this.validateDependencies(s),this.checkForCycles(s),{stages:this.createExecutionStages(s),nodes:s}}static parseNodeDefinition(e,s){if(this.isSimpleTask(s))return{id:e,tasks:Array.isArray(s)?s:[s],dependencies:[],executionType:"serial"};if(this.isConcurrentNodeDefinition(s)){const i=s,a=i.dependsOn?$(i.dependsOn):[];return{id:e,tasks:i.tasks,dependencies:a,planner:i.planner,executionType:"concurrent"}}const n=s,o=n.dependsOn?$(n.dependsOn):[],r=$(n.task);return{id:e,tasks:r,dependencies:o,executionType:"serial"}}static isSimpleTask(e){return e.type||Array.isArray(e)}static isConcurrentNodeDefinition(e){return e&&typeof e=="object"&&"planner"in e}static validateDependencies(e){for(const s of e.values())for(const n of s.dependencies)if(!e.has(n))throw new E(`Node "${s.id}" depends on non-existent node "${n}"`)}static checkForCycles(e){const s=new Set,n=new Set,o=c(r=>{if(n.has(r))return!0;if(s.has(r))return!1;s.add(r),n.add(r);const i=e.get(r);for(const a of i.dependencies)if(o(a))return!0;return n.delete(r),!1},"hasCycle");for(const r of e.keys())if(o(r))throw new E(`Circular dependency detected involving node "${r}"`)}static createExecutionStages(e){const s=[],n=new Set,o=new Set(e.keys());for(;o.size>0;){const r=[];for(const i of o)e.get(i).dependencies.every(u=>n.has(u))&&r.push(i);if(r.length===0)throw new E("Unable to resolve DAG dependencies - possible circular reference");s.push(r),r.forEach(i=>{n.add(i),o.delete(i)})}return s}}class qt{static{c(this,"DAGJobToDefinition")}static async convert(e,s){const{recorder:n}=s,o={};for(const[r,i]of Object.entries(e)){const{dependsOn:a,...l}=i;if("batch"in l){const u=l,_=await _e(u),f=await C(u,{recorder:n}),d={planner:_,tasks:f,...a?{dependsOn:a}:{}};o[r]=d}else{const u=await C(l,{recorder:n});if(a){const _={task:u,dependsOn:a};o[r]=_}else o[r]=u}}return o}}async function Xt(t,e,s,n={}){const{variables:o}=s,r=e.nodes.get(t);try{let i;if(r.executionType==="concurrent"&&r.planner?i=await pe(r.planner,...r.tasks).execute({...s,variables:o,name:t}):i=await z(...r.tasks).execute({...s,variables:o,name:t}),!i.success)throw new E(`Node "${t}" failed: ${i.error?.message}`);return i.response}catch(i){if(!n.continueOnError)throw i;return null}}c(Xt,"executeNode");const Kt=c((t,e={})=>{const s=c(async(o,r)=>{const{recorder:i}=r,a={value:""};return ie(o,a)?await qt.convert(o,r):(i?.warn?.log(a),o)},"prepare");return{execute:c(async o=>{const{stats:r,recorder:i}=o,{maxConcurrency:a=3}=e,l=crypto.randomUUID();try{const u=await s(t,{recorder:i});i?.debug?.log(u);const _=Bt.parse(u),f=new Map;i?.info?.log({type:"task",id:l,status:I.Running,message:`[${A(l)}] Starting workflow execution with ${_.stages.length} stages`});for(const[h,y]of _.stages.entries()){i?.info?.log({type:"task",id:l,status:I.Running,message:`[${A(l)}] Stage ${h+1}/${_.stages.length}, executing ${y.length} nodes: ${y.join(", ")}`});const S=Math.min(y.length,a);for(let T=0;T<y.length;T+=S){const v=y.slice(T,T+S);(await Promise.all(v.map(async b=>{const x=await Xt(b,_,o,e);return{nodeId:b,result:x}}))).forEach(({nodeId:b,result:x})=>{f.set(b,x)})}}i?.info?.log({type:"task",status:I.Success,id:l,message:`[${A(l)}] Workflow execution completed successfully`});const d=Object.fromEntries(f);return U(d,r)}catch(u){const _=u instanceof E?u:new E("DAG workflow execution failed",{id:l,cause:u instanceof Error?u:new Error(String(u))});return i?.info?.log({type:"task",status:I.Fail,id:l,message:`[${A(l)}] Workflow execution failed: ${_.message}`}),i?.error?.log(_),D(_,null,r)}},"execute")}},"dagWorkflow");export{E as A,ce as D,k as I,P as L,et as R,I as T,K as W,ue as a,tt as b,pe as c,Kt as d,le as e,Ve as g,it as i,q as l,z as s};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,481 @@
|
|
|
1
|
+
type PlainObject = Record<string, unknown>;
|
|
2
|
+
type ProgramOptions = {
|
|
3
|
+
dryRun?: boolean;
|
|
4
|
+
config?: string;
|
|
5
|
+
warnUnused?: boolean;
|
|
6
|
+
job?: string;
|
|
7
|
+
log?: boolean;
|
|
8
|
+
debug?: boolean;
|
|
9
|
+
args?: string[];
|
|
10
|
+
};
|
|
11
|
+
interface Stats {
|
|
12
|
+
in: number;
|
|
13
|
+
out: number;
|
|
14
|
+
}
|
|
15
|
+
interface Task {
|
|
16
|
+
readonly type: string;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
interface RecorderLevelFunctions {
|
|
20
|
+
log: (...message: (string | unknown | Error)[]) => void;
|
|
21
|
+
heading: {
|
|
22
|
+
log: (...message: (string | unknown | Error)[]) => void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
type RecorderEntry = {
|
|
26
|
+
level: LogLevel;
|
|
27
|
+
time: number;
|
|
28
|
+
kind: VisualLevel;
|
|
29
|
+
payload: PlainObject[];
|
|
30
|
+
};
|
|
31
|
+
type VisualLevel = "heading" | "body";
|
|
32
|
+
declare enum LogLevel {
|
|
33
|
+
Trace = 10,
|
|
34
|
+
Debug = 20,
|
|
35
|
+
Info = 30,
|
|
36
|
+
Warn = 40,
|
|
37
|
+
Error = 50,
|
|
38
|
+
Fatal = 60
|
|
39
|
+
}
|
|
40
|
+
interface RecorderWriter {
|
|
41
|
+
handleEvent(event: RecorderEntry): void | Promise<void>;
|
|
42
|
+
flush?(): Promise<void>;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
declare class Recorder {
|
|
46
|
+
instanceId: `${string}-${string}-${string}-${string}-${string}`;
|
|
47
|
+
private currentLevel;
|
|
48
|
+
private logs;
|
|
49
|
+
private writers;
|
|
50
|
+
private _debug;
|
|
51
|
+
private _info;
|
|
52
|
+
private _warn;
|
|
53
|
+
private _error;
|
|
54
|
+
constructor();
|
|
55
|
+
buildMethods(): void;
|
|
56
|
+
set level(level: LogLevel);
|
|
57
|
+
get level(): LogLevel;
|
|
58
|
+
get info(): RecorderLevelFunctions;
|
|
59
|
+
get warn(): RecorderLevelFunctions;
|
|
60
|
+
get error(): RecorderLevelFunctions;
|
|
61
|
+
get debug(): RecorderLevelFunctions;
|
|
62
|
+
subscribe(writer: RecorderWriter): void;
|
|
63
|
+
unsubscribe(writer: RecorderWriter): void;
|
|
64
|
+
private publish;
|
|
65
|
+
private logFunction;
|
|
66
|
+
private createLoggingFunction;
|
|
67
|
+
getLogs(level?: LogLevel): RecorderEntry[];
|
|
68
|
+
/**
|
|
69
|
+
* Ensures all writers have completed their pending operations
|
|
70
|
+
* Call this before exiting the process to ensure logs are written
|
|
71
|
+
*/
|
|
72
|
+
shutdown(): Promise<void>;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface FileInfo {
|
|
76
|
+
path: string;
|
|
77
|
+
base64: string;
|
|
78
|
+
mimeType: string;
|
|
79
|
+
size: number;
|
|
80
|
+
name: string;
|
|
81
|
+
type: "image" | "document";
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Load a file and encode it to base64 with validation
|
|
85
|
+
* @param filePath - Path to the file
|
|
86
|
+
* @returns FileInfo object with base64 data and metadata
|
|
87
|
+
*/
|
|
88
|
+
declare function loadFileAsBase64(filePath: string): Promise<FileInfo>;
|
|
89
|
+
|
|
90
|
+
interface ToolSchema {
|
|
91
|
+
name: string;
|
|
92
|
+
description: string;
|
|
93
|
+
parameters: {
|
|
94
|
+
type: "object";
|
|
95
|
+
properties: Record<string, object>;
|
|
96
|
+
required: string[];
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
interface ToolExecutable {
|
|
100
|
+
name: string;
|
|
101
|
+
schema: ToolSchema;
|
|
102
|
+
setConfig?: (config: {
|
|
103
|
+
[key: string]: any;
|
|
104
|
+
}) => void;
|
|
105
|
+
execute: (params: {
|
|
106
|
+
[key: string]: any;
|
|
107
|
+
}) => Promise<string>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
declare class Chat {
|
|
111
|
+
system: string;
|
|
112
|
+
messages: ChatItem[];
|
|
113
|
+
tools: ToolSchema[];
|
|
114
|
+
setToolSchemas(schemas: ToolSchema[]): void;
|
|
115
|
+
addSystem(message: string): void;
|
|
116
|
+
addUser(message: string): void;
|
|
117
|
+
addUserWithFiles(message: string, files?: FileInfo[]): void;
|
|
118
|
+
addAssistant(message: string, toolCalls?: ToolCall[]): void;
|
|
119
|
+
addTools(input: Array<ChatItemToolCallResult>): void;
|
|
120
|
+
hasFiles(): boolean;
|
|
121
|
+
getTextContent(content: string | ChatContent[]): string;
|
|
122
|
+
getFiles(content: string | ChatContent[]): FileInfo[];
|
|
123
|
+
toString(): string;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
type OllamaProviderConfig = {
|
|
127
|
+
url?: string;
|
|
128
|
+
model: string;
|
|
129
|
+
};
|
|
130
|
+
type AnthropicProviderConfig = {
|
|
131
|
+
"api-key": string;
|
|
132
|
+
model?: string;
|
|
133
|
+
};
|
|
134
|
+
type OpenAIProviderConfig = {
|
|
135
|
+
"api-key": string;
|
|
136
|
+
model?: string;
|
|
137
|
+
};
|
|
138
|
+
type GoogleAIProviderConfig = {
|
|
139
|
+
"api-key": string;
|
|
140
|
+
model?: string;
|
|
141
|
+
};
|
|
142
|
+
interface AIProviderConfig {
|
|
143
|
+
ollama: OllamaProviderConfig;
|
|
144
|
+
anthropic: AnthropicProviderConfig;
|
|
145
|
+
openai: OpenAIProviderConfig;
|
|
146
|
+
googleai: GoogleAIProviderConfig;
|
|
147
|
+
}
|
|
148
|
+
interface AIProvider {
|
|
149
|
+
createChatRequest(chat: Chat, context: {
|
|
150
|
+
recorder?: Recorder;
|
|
151
|
+
}): AIRequest;
|
|
152
|
+
}
|
|
153
|
+
interface AIRequest {
|
|
154
|
+
execute(runtime: {
|
|
155
|
+
recorder?: Recorder;
|
|
156
|
+
}): Promise<AIResponse>;
|
|
157
|
+
}
|
|
158
|
+
interface ToolCall {
|
|
159
|
+
id: string;
|
|
160
|
+
name: string;
|
|
161
|
+
arguments: string | Record<string, unknown>;
|
|
162
|
+
}
|
|
163
|
+
type AIResponse = AISuccessResponse | AIErrorResponse;
|
|
164
|
+
interface AISuccessResponse {
|
|
165
|
+
type: "success";
|
|
166
|
+
id: string;
|
|
167
|
+
reason: StopReason;
|
|
168
|
+
message: ChatItemAssistant;
|
|
169
|
+
model: string;
|
|
170
|
+
toolCalls?: ToolCall[];
|
|
171
|
+
usage: Stats;
|
|
172
|
+
raw: any;
|
|
173
|
+
}
|
|
174
|
+
interface AIErrorResponse {
|
|
175
|
+
type: "error";
|
|
176
|
+
error: {
|
|
177
|
+
type: string;
|
|
178
|
+
message: string;
|
|
179
|
+
};
|
|
180
|
+
usage: Stats;
|
|
181
|
+
raw: any;
|
|
182
|
+
}
|
|
183
|
+
declare enum StopReason {
|
|
184
|
+
Stop = 0,
|
|
185
|
+
Length = 1,
|
|
186
|
+
FunctionCall = 2,
|
|
187
|
+
Error = 3
|
|
188
|
+
}
|
|
189
|
+
type ChatItem = ChatItemUser | ChatItemAssistant | ChatItemToolCall;
|
|
190
|
+
interface ChatItemUser {
|
|
191
|
+
role: "user";
|
|
192
|
+
name?: string;
|
|
193
|
+
content: string | ChatContent[];
|
|
194
|
+
}
|
|
195
|
+
interface ChatItemAssistant {
|
|
196
|
+
role: "assistant";
|
|
197
|
+
content?: string;
|
|
198
|
+
toolCalls?: ToolCall[];
|
|
199
|
+
}
|
|
200
|
+
interface ChatItemToolCallResult {
|
|
201
|
+
id: string;
|
|
202
|
+
name: string;
|
|
203
|
+
content: string;
|
|
204
|
+
}
|
|
205
|
+
interface ChatItemToolCall {
|
|
206
|
+
role: "tool";
|
|
207
|
+
content: Array<ChatItemToolCallResult>;
|
|
208
|
+
}
|
|
209
|
+
type ChatContent = ChatContentText | ChatContentFile;
|
|
210
|
+
interface ChatContentText {
|
|
211
|
+
type: "text";
|
|
212
|
+
text: string;
|
|
213
|
+
}
|
|
214
|
+
interface ChatContentFile {
|
|
215
|
+
type: "file";
|
|
216
|
+
file: FileInfo;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
declare class AxleError extends Error {
|
|
220
|
+
readonly code: string;
|
|
221
|
+
readonly id?: string;
|
|
222
|
+
readonly details?: Record<string, any>;
|
|
223
|
+
constructor(message: string, options?: {
|
|
224
|
+
code?: string;
|
|
225
|
+
id?: string;
|
|
226
|
+
details?: Record<string, any>;
|
|
227
|
+
cause?: Error;
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
interface Planner {
|
|
232
|
+
plan(tasks: Task[]): Promise<Run[]>;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface Run {
|
|
236
|
+
tasks: Task[];
|
|
237
|
+
variables: Record<string, any>;
|
|
238
|
+
}
|
|
239
|
+
interface SerializedExecutionResponse {
|
|
240
|
+
response: string;
|
|
241
|
+
stats: Stats;
|
|
242
|
+
}
|
|
243
|
+
interface WorkflowResult<T = any> {
|
|
244
|
+
response: T;
|
|
245
|
+
stats?: Stats;
|
|
246
|
+
error?: AxleError;
|
|
247
|
+
success: boolean;
|
|
248
|
+
}
|
|
249
|
+
interface WorkflowExecutable {
|
|
250
|
+
execute: (context: {
|
|
251
|
+
provider: AIProvider;
|
|
252
|
+
variables: Record<string, any>;
|
|
253
|
+
options?: ProgramOptions;
|
|
254
|
+
stats?: Stats;
|
|
255
|
+
recorder?: Recorder;
|
|
256
|
+
name?: string;
|
|
257
|
+
}) => Promise<WorkflowResult>;
|
|
258
|
+
}
|
|
259
|
+
interface DAGNodeDefinition {
|
|
260
|
+
task: Task | Task[];
|
|
261
|
+
dependsOn?: string | string[];
|
|
262
|
+
}
|
|
263
|
+
interface DAGConcurrentNodeDefinition {
|
|
264
|
+
planner: Planner;
|
|
265
|
+
tasks: Task[];
|
|
266
|
+
dependsOn?: string | string[];
|
|
267
|
+
}
|
|
268
|
+
interface DAGDefinition {
|
|
269
|
+
[nodeName: string]: Task | Task[] | DAGNodeDefinition | DAGConcurrentNodeDefinition;
|
|
270
|
+
}
|
|
271
|
+
interface DAGWorkflowOptions {
|
|
272
|
+
continueOnError?: boolean;
|
|
273
|
+
maxConcurrency?: number;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
declare class Axle {
|
|
277
|
+
private provider;
|
|
278
|
+
private stats;
|
|
279
|
+
private variables;
|
|
280
|
+
private recorder;
|
|
281
|
+
constructor(config: Partial<AIProviderConfig>);
|
|
282
|
+
addWriter(writer: RecorderWriter): void;
|
|
283
|
+
/**
|
|
284
|
+
* The execute function takes in a list of Tasks
|
|
285
|
+
* @param tasks
|
|
286
|
+
* @returns
|
|
287
|
+
*/
|
|
288
|
+
execute(...tasks: Task[]): Promise<WorkflowResult>;
|
|
289
|
+
/**
|
|
290
|
+
* Execute a DAG workflow
|
|
291
|
+
* @param dagDefinition - The DAG definition object
|
|
292
|
+
* @param variables - Additional variables to pass to the workflow
|
|
293
|
+
* @param options - DAG execution options
|
|
294
|
+
* @returns Promise<WorkflowResult>
|
|
295
|
+
*/
|
|
296
|
+
executeDAG(dagDefinition: DAGDefinition, variables?: Record<string, any>, options?: DAGWorkflowOptions): Promise<WorkflowResult>;
|
|
297
|
+
get logs(): RecorderEntry[];
|
|
298
|
+
/**
|
|
299
|
+
* Load a file and encode it to base64 for use with multimodal models
|
|
300
|
+
* @param filePath - Path to the image or PDF file
|
|
301
|
+
* @returns FileInfo object with base64 data and metadata
|
|
302
|
+
*/
|
|
303
|
+
static loadFile(filePath: string): Promise<FileInfo>;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
declare enum ResTypes {
|
|
307
|
+
String = "string",
|
|
308
|
+
List = "string[]",
|
|
309
|
+
Number = "number",
|
|
310
|
+
Boolean = "boolean"
|
|
311
|
+
}
|
|
312
|
+
type ResTypeStrings = `${ResTypes}`;
|
|
313
|
+
type StringToType<S extends ResTypeStrings> = S extends ResTypes.String ? string : S extends ResTypes.List ? string[] : S extends ResTypes.Number ? number : S extends ResTypes.Boolean ? boolean : never;
|
|
314
|
+
type StructuredOutput<T extends Record<string, ResTypeStrings>> = {
|
|
315
|
+
[K in keyof T]: StringToType<T[K]>;
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
declare abstract class AbstractInstruct<O extends Record<string, ResTypeStrings>> implements Task {
|
|
319
|
+
readonly type = "instruct";
|
|
320
|
+
protected _result: StructuredOutput<O> | undefined;
|
|
321
|
+
prompt: string;
|
|
322
|
+
system: string | null;
|
|
323
|
+
inputs: Record<string, string>;
|
|
324
|
+
tools: Record<string, ToolExecutable>;
|
|
325
|
+
files: FileInfo[];
|
|
326
|
+
resFormat: O;
|
|
327
|
+
rawResponse: string;
|
|
328
|
+
finalPrompt: string;
|
|
329
|
+
protected constructor(prompt: string, resFormat: O);
|
|
330
|
+
setInputs(inputs: Record<string, string>): void;
|
|
331
|
+
addInput(name: string, value: string): void;
|
|
332
|
+
addTools(tools: ToolExecutable[]): void;
|
|
333
|
+
addTool(tool: ToolExecutable): void;
|
|
334
|
+
addImage(file: FileInfo): void;
|
|
335
|
+
addFile(file: FileInfo): void;
|
|
336
|
+
hasTools(): boolean;
|
|
337
|
+
hasFiles(): boolean;
|
|
338
|
+
get result(): StructuredOutput<O>;
|
|
339
|
+
compile(variables: Record<string, string>, runtime?: {
|
|
340
|
+
recorder?: Recorder;
|
|
341
|
+
options?: {
|
|
342
|
+
warnUnused?: boolean;
|
|
343
|
+
};
|
|
344
|
+
}): string;
|
|
345
|
+
protected getFinalUserPrompt(variables: Record<string, string>, runtime?: {
|
|
346
|
+
recorder?: Recorder;
|
|
347
|
+
options?: {
|
|
348
|
+
warnUnused?: boolean;
|
|
349
|
+
};
|
|
350
|
+
}): string;
|
|
351
|
+
protected getFormatInstructions(): string;
|
|
352
|
+
/**
|
|
353
|
+
*
|
|
354
|
+
* @param rawValue - the raw value from the AI
|
|
355
|
+
* @param taggedSections - optional, for overrides to use
|
|
356
|
+
* @returns - the parsed result
|
|
357
|
+
*/
|
|
358
|
+
finalize(rawValue: string, taggedSections?: {
|
|
359
|
+
tags: Record<string, string>;
|
|
360
|
+
remaining: string;
|
|
361
|
+
}): StructuredOutput<O>;
|
|
362
|
+
protected parseTaggedSections(input: string): {
|
|
363
|
+
tags: Record<string, string>;
|
|
364
|
+
remaining: string;
|
|
365
|
+
};
|
|
366
|
+
protected typeResponses(typeString: ResTypeStrings, rawValue: string): StringToType<ResTypes>;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
type DefaultResFormatType$1 = {
|
|
370
|
+
response: ResTypes.String;
|
|
371
|
+
};
|
|
372
|
+
declare class Instruct<O extends Record<string, ResTypeStrings>> extends AbstractInstruct<O> {
|
|
373
|
+
private constructor();
|
|
374
|
+
static with<NewO extends Record<string, ResTypeStrings>>(prompt: string, resFormat: NewO): Instruct<NewO>;
|
|
375
|
+
static with(prompt: string): Instruct<DefaultResFormatType$1>;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
type DefaultResFormatType = {
|
|
379
|
+
response: ResTypes.String;
|
|
380
|
+
};
|
|
381
|
+
declare class ChainOfThought<O extends Record<string, ResTypeStrings>> extends AbstractInstruct<O> {
|
|
382
|
+
private constructor();
|
|
383
|
+
static with<NewO extends Record<string, ResTypeStrings>>(prompt: string, resFormat: NewO): ChainOfThought<NewO>;
|
|
384
|
+
static with(prompt: string): ChainOfThought<DefaultResFormatType>;
|
|
385
|
+
compile(variables: Record<string, string>, runtime?: {
|
|
386
|
+
recorder?: Recorder;
|
|
387
|
+
options?: {
|
|
388
|
+
warnUnused?: boolean;
|
|
389
|
+
};
|
|
390
|
+
}): string;
|
|
391
|
+
finalize(rawValue: string): StructuredOutput<O> & {
|
|
392
|
+
thinking: any;
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
interface WriteToDiskTask extends Task {
|
|
397
|
+
type: "write-to-disk";
|
|
398
|
+
output: string;
|
|
399
|
+
keys: string[];
|
|
400
|
+
}
|
|
401
|
+
declare class WriteOutputTask implements WriteToDiskTask {
|
|
402
|
+
output: string;
|
|
403
|
+
keys: string[];
|
|
404
|
+
type: "write-to-disk";
|
|
405
|
+
constructor(output: string, keys?: string[]);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
interface DAGJob {
|
|
409
|
+
[name: string]: Job & {
|
|
410
|
+
dependsOn?: string | string[];
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
type Job = SerialJob | BatchJob;
|
|
414
|
+
interface SerialJob {
|
|
415
|
+
tools?: string[];
|
|
416
|
+
steps: Step[];
|
|
417
|
+
}
|
|
418
|
+
interface BatchJob {
|
|
419
|
+
tools?: string[];
|
|
420
|
+
batch: BatchOptions[];
|
|
421
|
+
steps: Step[];
|
|
422
|
+
}
|
|
423
|
+
interface SkipOptions {
|
|
424
|
+
type: "file-exist";
|
|
425
|
+
pattern: string;
|
|
426
|
+
}
|
|
427
|
+
interface BatchOptions {
|
|
428
|
+
type: "files";
|
|
429
|
+
source: string;
|
|
430
|
+
bind: string;
|
|
431
|
+
["skip-if"]?: SkipOptions[];
|
|
432
|
+
}
|
|
433
|
+
type Step = ChatStep | WriteToDiskStep;
|
|
434
|
+
interface StepBase {
|
|
435
|
+
readonly uses: string;
|
|
436
|
+
}
|
|
437
|
+
interface ChatStep extends StepBase {
|
|
438
|
+
uses: "chat";
|
|
439
|
+
system?: string;
|
|
440
|
+
message: string;
|
|
441
|
+
output?: Record<string, ResTypeStrings>;
|
|
442
|
+
replace?: Replace[];
|
|
443
|
+
tools?: string[];
|
|
444
|
+
images?: ImageReference[];
|
|
445
|
+
documents?: DocumentReference[];
|
|
446
|
+
}
|
|
447
|
+
interface WriteToDiskStep extends StepBase {
|
|
448
|
+
uses: "write-to-disk";
|
|
449
|
+
output: string;
|
|
450
|
+
keys: string | string[];
|
|
451
|
+
}
|
|
452
|
+
interface Replace {
|
|
453
|
+
source: "file";
|
|
454
|
+
pattern: string;
|
|
455
|
+
files: string | string[];
|
|
456
|
+
}
|
|
457
|
+
interface ImageReference {
|
|
458
|
+
file: string;
|
|
459
|
+
}
|
|
460
|
+
interface DocumentReference {
|
|
461
|
+
file: string;
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
interface ConcurrentWorkflow {
|
|
465
|
+
(jobConfig: BatchJob): WorkflowExecutable;
|
|
466
|
+
(planner: Planner, ...instructions: Task[]): WorkflowExecutable;
|
|
467
|
+
}
|
|
468
|
+
declare const concurrentWorkflow: ConcurrentWorkflow;
|
|
469
|
+
|
|
470
|
+
interface DAGWorkflow {
|
|
471
|
+
(definition: DAGDefinition | DAGJob, options?: DAGWorkflowOptions): WorkflowExecutable;
|
|
472
|
+
}
|
|
473
|
+
declare const dagWorkflow: DAGWorkflow;
|
|
474
|
+
|
|
475
|
+
interface SerialWorkflow {
|
|
476
|
+
(jobConfig: SerialJob): WorkflowExecutable;
|
|
477
|
+
(...instructions: Task[]): WorkflowExecutable;
|
|
478
|
+
}
|
|
479
|
+
declare const serialWorkflow: SerialWorkflow;
|
|
480
|
+
|
|
481
|
+
export { type AIProvider, Axle, ChainOfThought, type DAGDefinition, type DAGWorkflowOptions, type FileInfo, Instruct, type SerializedExecutionResponse, WriteOutputTask, concurrentWorkflow, dagWorkflow, loadFileAsBase64, serialWorkflow };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var d=Object.defineProperty;var a=(c,e)=>d(c,"name",{value:e,configurable:!0});import{R as p,A as o,g,s as l,d as u,l as h,a as w,D as f}from"./dag-DzqZGULq.js";import{I as U,W,c as D}from"./dag-DzqZGULq.js";import"@anthropic-ai/sdk";import"@google/genai";import"openai";import"serialize-error";import"fs/promises";import"glob";import"node:fs/promises";import"node:path";class x{static{a(this,"Axle")}provider;stats={in:0,out:0};variables={};recorder=new p;constructor(e){if(Object.entries(e).length!==1)throw new o("Must have exactly one config");try{const r=Object.keys(e)[0],t=e[r];this.provider=g(r,t)}catch(r){throw r instanceof o?r:new o("Failed to initialize provider",{code:"PROVIDER_INIT_ERROR",cause:r instanceof Error?r:new Error(String(r))})}}addWriter(e){this.recorder.subscribe(e)}async execute(...e){try{let r;return r=await l(...e).execute({provider:this.provider,variables:this.variables,stats:this.stats,recorder:this.recorder}),r}catch(r){const t=r instanceof o?r:new o("Execution failed",{cause:r instanceof Error?r:new Error(String(r))});return this.recorder.error?.log(t),{response:null,error:t,success:!1}}}async executeDAG(e,r={},t){try{return await u(e,t).execute({provider:this.provider,variables:{...this.variables,...r},stats:this.stats,recorder:this.recorder})}catch(s){const i=s instanceof o?s:new o("DAG execution failed",{cause:s instanceof Error?s:new Error(String(s))});return this.recorder.error?.log(i),{response:null,error:i,success:!1}}}get logs(){return this.recorder.getLogs()}static async loadFile(e){return h(e)}}class n extends w{static{a(this,"ChainOfThought")}constructor(e,r){super(e,r)}static with(e,r){return r?new n(e,r):new n(e,f)}compile(e,r={}){const t=this.getFinalUserPrompt(e,r),s=this.getFormatInstructions();return[t,`
|
|
2
|
+
Let's think step by step. Use <thinking></thinking> tags to show your reasoning and thought process.`,s].join(`
|
|
3
|
+
`)}finalize(e){const r=this.parseTaggedSections(e),t=super.finalize(e,r);if("thinking"in r.tags)t.thinking=r.tags.thinking;else throw new Error("Expected results with tag <thinking> but it does not exist");return t}}export{x as Axle,n as ChainOfThought,U as Instruct,W as WriteOutputTask,D as concurrentWorkflow,u as dagWorkflow,h as loadFileAsBase64,l as serialWorkflow};
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fifthrevision/axle",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "axle is a command line tool for running workflows against LLM APIs.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"axle": "./dist/cli.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"start": "tsx ./src/cli.ts",
|
|
22
|
+
"build": "pkgroll --clean-dist --minify",
|
|
23
|
+
"build-dev": "pkgroll --clean-dist",
|
|
24
|
+
"test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
|
|
25
|
+
"get-models": "npx tsx scripts/getModels.ts",
|
|
26
|
+
"prompt-scenarios": "npx tsx ./scripts/prompt.scenarios.ts",
|
|
27
|
+
"test-providers": "npx tsx ./scripts/testProviders.ts"
|
|
28
|
+
},
|
|
29
|
+
"author": "",
|
|
30
|
+
"license": "ISC",
|
|
31
|
+
"dependencies": {
|
|
32
|
+
"@anthropic-ai/sdk": "^0",
|
|
33
|
+
"@commander-js/extra-typings": "^14",
|
|
34
|
+
"@google/genai": "^1.0.0",
|
|
35
|
+
"chalk": "^5.3.0",
|
|
36
|
+
"commander": "^14",
|
|
37
|
+
"glob": "^11.0.0",
|
|
38
|
+
"openai": "^5.0.2",
|
|
39
|
+
"serialize-error": "^12.0.0",
|
|
40
|
+
"yaml": "^2.5.0"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"@types/jest": "^29.5.12",
|
|
44
|
+
"dotenv": "^16.5.0",
|
|
45
|
+
"husky": "^9.1.4",
|
|
46
|
+
"jest": "^29.7.0",
|
|
47
|
+
"pkgroll": "^2.4.2",
|
|
48
|
+
"prettier": "^3.3.3",
|
|
49
|
+
"prettier-plugin-organize-imports": "^4.0.0",
|
|
50
|
+
"ts-jest": "^29.2.4",
|
|
51
|
+
"tsx": "^4.17.0",
|
|
52
|
+
"typescript": "^5.5.4"
|
|
53
|
+
}
|
|
54
|
+
}
|