@perstack/runtime 0.0.9 → 0.0.11

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/index.js CHANGED
@@ -1,7 +1,1667 @@
1
- import {existsSync}from'fs';import {readFile,writeFile,mkdir,readdir}from'fs/promises';import pe from'path';import {createId}from'@paralleldrive/cuid2';import ko from'smol-toml';import {setup,assign,createActor}from'xstate';import {z as z$1,ZodError}from'zod';import {anthropic}from'@ai-sdk/anthropic';import {google}from'@ai-sdk/google';import {openai}from'@ai-sdk/openai';import {Client}from'@modelcontextprotocol/sdk/client/index.js';import {SSEClientTransport}from'@modelcontextprotocol/sdk/client/sse.js';import {StdioClientTransport}from'@modelcontextprotocol/sdk/client/stdio.js';import {McpError}from'@modelcontextprotocol/sdk/types.js';import {generateText,jsonSchema}from'ai';import {dedent}from'ts-dedent';var ft="claude-4-sonnet-20250514",ge=["claude-4-opus-20250514","claude-4-sonnet-20250514","claude-3-7-sonnet-20250219","claude-3-5-sonnet-latest","claude-3-5-sonnet-20241022","claude-3-5-sonnet-20240620","claude-3-5-haiku-latest","claude-3-5-haiku-20241022"],ue=["gemini-2.5-pro-preview-05-06","gemini-2.5-pro-exp-03-25","gemini-2.5-flash-preview-04-17","gemini-2.0-pro-exp-02-05","gemini-2.0-flash-thinking-exp-01-21","gemini-2.0-flash","gemini-2.0-flash-001","gemini-2.0-flash-live-001","gemini-2.0-flash-lite","gemini-2.0-flash-exp","gemini-1.5-pro","gemini-1.5-pro-latest","gemini-1.5-pro-001","gemini-1.5-pro-002","gemini-1.5-flash","gemini-1.5-flash-latest","gemini-1.5-flash-001","gemini-1.5-flash-002","gemini-1.5-flash-8b","gemini-1.5-flash-8b-latest","gemini-1.5-flash-8b-001"],de=["o4-mini","o4-mini-2025-04-16","o3","o3-2025-04-16","o3-mini","o3-mini-2025-01-31","o1","o1-2024-12-17","o1-mini","o1-mini-2024-09-12","gpt-4.5-preview","gpt-4.5-preview-2025-02-27","gpt-4.1","gpt-4.1-2025-04-14","gpt-4.1-mini","gpt-4.1-mini-2025-04-14","gpt-4.1-nano","gpt-4.1-nano-2025-04-14","gpt-4o","gpt-4o-2024-05-13","gpt-4o-2024-08-06","gpt-4o-2024-11-20","gpt-4o-audio-preview","gpt-4o-audio-preview-2024-10-01","gpt-4o-audio-preview-2024-12-17","gpt-4o-search-preview","gpt-4o-search-preview-2025-03-11","gpt-4o-mini-search-preview","gpt-4o-mini-search-preview-2025-03-11","gpt-4o-mini","gpt-4o-mini-2024-07-18"],ht=Object.fromEntries([...ge,...ue,...de].map(e=>[e,{default:e===ft,model:e}]));function te(){let e=Object.values(ht).find(t=>t.default);if(!e)throw new Error("No default model found");return e.model}function z(e){let t=e??te();if(ge.includes(t))return anthropic(t);if(ue.includes(t))return google(t);if(de.includes(t))return openai(t);throw new Error(`Unsupported model: ${t}`)}var I=z$1.object({id:z$1.string()}),A=I.extend({type:z$1.literal("textPart"),text:z$1.string()}),yt=I.extend({type:z$1.literal("imageUrlPart"),url:z$1.string().url(),mimeType:z$1.string()}),fe=I.extend({type:z$1.literal("imageInlinePart"),encodedData:z$1.string(),mimeType:z$1.string()}),xt=I.extend({type:z$1.literal("imageBinaryPart"),data:z$1.string(),mimeType:z$1.string()}),kt=I.extend({type:z$1.literal("fileUrlPart"),url:z$1.string().url(),mimeType:z$1.string()}),Tt=I.extend({type:z$1.literal("fileInlinePart"),encodedData:z$1.string(),mimeType:z$1.string()}),Rt=I.extend({type:z$1.literal("fileBinaryPart"),data:z$1.string(),mimeType:z$1.string()}),St=I.extend({type:z$1.literal("toolCallPart"),toolCallId:z$1.string(),toolName:z$1.string(),args:z$1.unknown()}),Pt=I.extend({type:z$1.literal("toolResultPart"),toolCallId:z$1.string(),toolName:z$1.string(),contents:z$1.array(z$1.union([A,fe])),isError:z$1.boolean().optional()}),L=z$1.object({id:z$1.string()}),Ct=L.extend({type:z$1.literal("instructionMessage"),contents:z$1.array(A),cache:z$1.boolean().optional()}),vt=L.extend({type:z$1.literal("userMessage"),contents:z$1.array(z$1.union([A,yt,fe,xt,kt,Tt,Rt])),cache:z$1.boolean().optional()}),wt=L.extend({type:z$1.literal("expertMessage"),contents:z$1.array(z$1.union([A,St])),cache:z$1.boolean().optional()}),It=L.extend({type:z$1.literal("toolMessage"),contents:z$1.array(Pt),cache:z$1.boolean().optional()}),he=z$1.union([Ct,vt,wt,It]);var Mt=/^(@[a-z0-9][a-z0-9_-]*\/)?[a-z0-9][a-z0-9_-]*$/,bt=/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?$/,Et=/^[a-z0-9][a-z0-9_-]*$/,D=/^((?:@[a-z0-9][a-z0-9_\.-]*\/)?[a-z0-9][a-z0-9_\.-]*)(?:@((?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?)|@([a-z0-9][a-z0-9_\.-]*))?$/,Uo=/^[a-z0-9][a-z0-9._-]*$/,$t=214;function jo(e){let t=e.match(D);if(!t)throw new Error(`Invalid expert key format: ${e}`);let[o,r,a,i]=t;return {key:o,name:r,version:a,tag:i}}var G=z$1.object({type:z$1.literal("mcpStdioSkill"),name:z$1.string(),description:z$1.string().optional(),rule:z$1.string().optional(),pick:z$1.array(z$1.string()).optional().default([]),omit:z$1.array(z$1.string()).optional().default([]),command:z$1.string(),packageName:z$1.string().optional(),args:z$1.array(z$1.string()).optional().default([]),requiredEnv:z$1.array(z$1.string()).optional().default([])}),K=z$1.object({type:z$1.literal("mcpSseSkill"),name:z$1.string(),description:z$1.string().optional(),rule:z$1.string().optional(),pick:z$1.array(z$1.string()).optional().default([]),omit:z$1.array(z$1.string()).optional().default([]),endpoint:z$1.string()}),ye=z$1.object({name:z$1.string(),description:z$1.string().optional(),inputJsonSchema:z$1.string()}),q=z$1.object({type:z$1.literal("interactiveSkill"),name:z$1.string(),description:z$1.string().optional(),rule:z$1.string().optional(),tools:z$1.record(z$1.string(),ye.omit({name:true})).transform(e=>Object.fromEntries(Object.entries(e).map(([t,o])=>[t,ye.parse({...o,name:t})])))}),J=z$1.object({key:z$1.string().regex(D).min(1),name:z$1.string().regex(Mt).min(1).max($t),version:z$1.string().regex(bt),description:z$1.string().min(1).max(1024*2).optional(),instruction:z$1.string().min(1).max(1024*20),skills:z$1.record(z$1.string(),z$1.discriminatedUnion("type",[G.omit({name:true}),K.omit({name:true}),q.omit({name:true})])).optional().default({"@perstack/base":{type:"mcpStdioSkill",description:"Base skill",command:"npx",args:["-y","@perstack/base"]}}).transform(e=>Object.fromEntries(Object.entries(e).map(([t,o])=>[t,z$1.discriminatedUnion("type",[G,K,q]).parse({...o,name:t})]))),delegates:z$1.array(z$1.string().regex(D).min(1)).optional().default([]),tags:z$1.array(z$1.string().regex(Et).min(1)).optional().default([])}),Nt=z$1.object({promptTokens:z$1.number(),completionTokens:z$1.number(),totalTokens:z$1.number(),cacheCreationInputTokens:z$1.number(),cacheReadInputTokens:z$1.number()}),Ft=z$1.enum(["init","proceeding","completed","stoppedByInteractiveTool","stoppedByDelegate","stoppedByExceededMaxSteps","stoppedByError"]),oe=z$1.object({id:z$1.string(),runId:z$1.string(),status:Ft,stepNumber:z$1.number(),messages:z$1.array(he),expert:z$1.object({key:z$1.string(),name:z$1.string(),version:z$1.string()}),delegateTo:z$1.object({expert:z$1.object({key:z$1.string(),name:z$1.string(),version:z$1.string()}),toolCallId:z$1.string(),toolName:z$1.string(),query:z$1.string()}).optional(),delegatedBy:z$1.object({expert:z$1.object({key:z$1.string(),name:z$1.string(),version:z$1.string()}),toolCallId:z$1.string(),toolName:z$1.string(),checkpointId:z$1.string()}).optional(),usage:Nt}),ke=z$1.object({setting:z$1.object({runId:z$1.string().optional().transform(e=>e??createId()),expertKey:z$1.string().regex(D).min(1),input:z$1.object({text:z$1.string().optional(),interactiveToolCallResult:z$1.object({toolCallId:z$1.string(),toolName:z$1.string(),text:z$1.string()}).optional()}),experts:z$1.record(z$1.string().regex(D).min(1),J.omit({key:true})).optional().default({}).transform(e=>Object.fromEntries(Object.entries(e).map(([t,o])=>[t,J.parse({...o,key:t})]))),model:z$1.string().optional().default(te()),temperature:z$1.number().min(0).max(1).optional().default(.3),maxSteps:z$1.number().min(1).optional(),maxRetries:z$1.number().min(0).optional().default(10),workspace:z$1.string().optional(),startedAt:z$1.number().optional().default(Date.now()),updatedAt:z$1.number().optional().default(Date.now())}),checkpoint:oe.optional()});function k(e){return (t,o,r)=>({type:e,id:createId(),expertKey:o.expert.key,timestamp:Date.now(),runId:t.runId,stepNumber:o.stepNumber,...r})}var ne=k("startRun"),Te=k("startGeneration"),re=k("retry"),Re=k("callTool"),Se=k("callInteractiveTool"),Pe=k("callDelegate"),Ce=k("resolveToolResult"),ve=k("resolveThought"),we=k("resolvePdfFile"),Ie=k("resolveImageFile"),Me=k("attemptCompletion"),$=k("finishToolCall"),be=k("completeRun"),Ee=k("stopRunByInteractiveTool"),$e=k("stopRunByDelegate"),Ne=k("stopRunByExceededMaxSteps"),Fe=k("continueToNextStep");async function De(e,t){let o=O(e),a=(await readdir(o,{withFileTypes:true}).then(s=>s.filter(u=>u.isFile()&&u.name.startsWith("checkpoint-")))).find(s=>s.name.endsWith(`-${t}.json`));if(!a)throw new Error(`checkpoint not found: ${e} ${t}`);let i=`${o}/${a.name}`,c=await readFile(i,"utf8");return oe.parse(JSON.parse(c))}async function Oe(e,t){let{id:o,runId:r,stepNumber:a}=e,i=O(r),c=`${i}/checkpoint-${t}-${a}-${o}.json`;await mkdir(i,{recursive:true}),await writeFile(c,JSON.stringify(e,null,2));}async function Be(e){let{timestamp:t,runId:o,stepNumber:r,type:a}=e,i=O(o),c=`${i}/event-${t}-${r}-${a}.json`;await mkdir(i,{recursive:true}),await writeFile(c,JSON.stringify(e,null,2));}var _e={version:"0.0.9"};var m=console.info,ze=console.debug,g=e=>{let t=new Date().toISOString(),o=e.stepNumber,r=e.expertKey;return `${t} ${o} ${r}`};async function se(e){switch(await Be(e),e.type){case "startRun":{m(`${g(e)} \u{1F99C} Perstack@${_e.version} started`);let{inputMessages:t}=e;for(let o of t)o.type==="userMessage"?Ot(o):o.type==="toolMessage"&&Bt(o);break}case "startGeneration":{m(`${g(e)} \u{1F99C} Generating tool call`);break}case "retry":{B(e),m(`${g(e)} \u{1F99C} Retrying tool call generation`);break}case "callTool":{if(B(e),m(`${g(e)} \u{1F99C} Calling tool`),e.toolCall.skillName==="@perstack/base")switch(e.toolCall.toolName){case "think":{let t=e.toolCall.args.thought;m(`${g(e)} \u{1F4AD} Thought Updated:`),ze(t);break}case "readPdfFile":{let t=e.toolCall.args.path;m(`${g(e)} \u{1F4C4} Reading PDF: ${t}`);break}case "readImageFile":{let t=e.toolCall.args.path;m(`${g(e)} \u{1F5BC}\uFE0F Reading Image: ${t}`);break}default:{m(`${g(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`),m(`${g(e)} \u{1F527} Args: ${e.toolCall.args}`);break}}else m(`${g(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`),m(`${g(e)} \u{1F527} Args: ${e.toolCall.args}`);break}case "callInteractiveTool":{B(e),m(`${g(e)} \u{1F99C} Calling interactive tool`),m(`${g(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`),m(`${g(e)} \u{1F527} Args: ${e.toolCall.args}`);break}case "callDelegate":{B(e),m(`${g(e)} \u{1F99C} Calling delegate`),m(`${g(e)} \u{1F527} Tool: ${e.toolCall.toolName}`),m(`${g(e)} \u{1F527} Args: ${e.toolCall.args}`);break}case "resolveToolResult":{if(m(`${g(e)} \u{1F527} Resolved Tool Result`),e.toolResult.skillName==="@perstack/base")switch(e.toolResult.toolName){case "todo":{let t=e.toolResult.result.find(r=>r.type==="textPart")?.text,{todos:o}=JSON.parse(t??"{}");m(`${g(e)} \u{1F4C4} Todo:`);for(let r of o)ze(`${r.completed?"[x]":"[ ]"} ${r.id}: ${r.title}`);break}default:{m(`${g(e)} \u{1F527} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`),m(`${g(e)} \u{1F527} Result: ${e.toolResult.result}`);break}}else m(`${g(e)} \u{1F527} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`),m(`${g(e)} \u{1F527} Result: ${e.toolResult.result}`);break}case "resolveThought":{m(`${g(e)} \u{1F4AD} Resolved Thought:`,e.toolResult);break}case "resolvePdfFile":{m(`${g(e)} \u{1F4C4} Resolved PDF:`,e.toolResult);break}case "resolveImageFile":{m(`${g(e)} \u{1F5BC}\uFE0F Resolved Image:`,e.toolResult);break}case "attemptCompletion":{m(`${g(e)} \u2705 Attempting completion`);break}case "completeRun":{B(e),m(`${g(e)} \u{1F99C} Completing run`),m(`${g(e)} \u{1F99C} Result:`,e.text);break}case "stopRunByInteractiveTool":{m(`${g(e)} \u{1F99C} Stopping run by interactive tool`);break}case "stopRunByDelegate":{m(`${g(e)} \u{1F99C} Stopping run by delegate`);break}case "stopRunByExceededMaxSteps":{m(`${g(e)} \u{1F99C} Stopping run by exceeded max steps`);break}case "continueToNextStep":{m(`${g(e)} \u{1F99C} Continuing to next step`);break}}}function Ot(e){let t=new Date().toISOString(),o=e.contents;for(let r of o)r.type==="textPart"?m(`${t} \u{1F4AC} User: ${r.text}`):r.type==="imageUrlPart"?m(`${t} \u{1F5BC}\uFE0F User: ${r.url}`):r.type==="imageInlinePart"?m(`${t} \u{1F5BC}\uFE0F User: Inline image`):r.type==="imageBinaryPart"?m(`${t} \u{1F5BC}\uFE0F User: Binary image`):r.type==="fileUrlPart"?m(`${t} \u{1F4C4} User: ${r.url}`):r.type==="fileInlinePart"?m(`${t} \u{1F4C4} User: Inline file`):r.type==="fileBinaryPart"&&m(`${t} \u{1F4C4} User: Binary file`);}function Bt(e){let t=new Date().toISOString(),o=e.contents;for(let r of o)if(r.type==="toolResultPart"){let{contents:a}=r;for(let i of a)i.type==="textPart"?m(`${t} \u{1F4AC} Tool Result: ${i.text}`):i.type==="imageInlinePart"&&m(`${t} \u{1F5BC}\uFE0F Tool Result: Inline image`);}}function B(e){let t=[`In: ${e.usage.promptTokens.toLocaleString()}`,`Out: ${e.usage.completionTokens.toLocaleString()}`,`Total: ${e.usage.totalTokens.toLocaleString()}`,`Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,`Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`].join(", ");m(`${g(e)} \u{1F4CA} Tokens usage: ${t}`);let o=[`In: ${e.usage.promptTokens.toLocaleString()}`,`Out: ${e.usage.completionTokens.toLocaleString()}`,`Total: ${e.usage.totalTokens.toLocaleString()}`,`Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,`Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`].join(", ");m(`${g(e)} \u{1F4CA} Total usage: ${o}`);}var V=class{listeners=[];subscribe(t){this.listeners.push(t);}async emit(t){for(let o of this.listeners)await o({...t,id:createId(),timestamp:Date.now()});}};var zt=z$1.object({name:z$1.string(),version:z$1.string(),minRuntimeVersion:z$1.string(),description:z$1.string(),instruction:z$1.string(),skills:z$1.record(z$1.string(),z$1.discriminatedUnion("type",[G.omit({name:true}),K.omit({name:true}),q.omit({name:true})])),delegates:z$1.array(z$1.string()),tags:z$1.array(z$1.string()),status:z$1.string(),owner:z$1.object({name:z$1.string()}),createdAt:z$1.string().datetime(),updatedAt:z$1.string().datetime()}),Ae=z$1.object({data:z$1.object({expert:zt})});var Y=class{baseUrl;registry;apiKey;constructor(t){this.baseUrl=t?.baseUrl??process.env.PERSTACK_API_BASE_URL??"https://api.perstack.ai",this.apiKey=t?.apiKey??process.env.PERSTACK_API_KEY,this.registry=new ae(this);}},ae=class{client;endpoint;constructor(t){this.client=t,this.endpoint="/api/registry/v1/experts";}async get(t){let o=encodeURIComponent(t),r=new URL(`${this.endpoint}/${o}`,this.client.baseUrl),a={"Content-Type":"application/json",Authorization:`Bearer ${this.client.apiKey}`},i=await fetch(r.toString(),{headers:a});if(!i.ok)throw new Error(`Registry returned non-200 status code: ${i.status}, reason: ${i.statusText}`);let c=await i.json();return Ae.parse(c)}};async function ie(e,t){if(t[e])return t[e];let o=new Y,{data:r}=await o.registry.get(e),a=J.parse({...r.expert,key:e});return t[e]=a,a}var _=class{_toolDefinitions=[];_initialized=false;name;type;skill;interactiveSkill;expert;_mcpClient;_params;constructor(t){switch(this._params=t,this.type=t.type,t.type){case "mcp":this.name=t.skill.name,this.skill=t.skill;break;case "interactive":this.name=t.interactiveSkill.name,this.interactiveSkill=t.interactiveSkill;break;case "delegate":this.name=t.expert.name,this.expert=t.expert;break}}async init(){switch(this._params.type){case "mcp":{await this._initMcpSkill(this._params);break}case "interactive":{await this._initInteractiveSkill(this._params);break}case "delegate":{await this._initDelegate(this._params);break}}}async _initMcpSkill(t){switch(this._mcpClient=new Client({name:`${t.skill.name}-mcp-client`,version:"1.0.0"}),t.skill.type){case "mcpStdioSkill":{if(!t.skill.command)throw new Error(`Skill ${t.skill.name} has no command`);let{command:r,args:a}=this._getCommandArgs(t.skill);console.error(r,a);let i=new StdioClientTransport({command:r,args:a,env:Object.fromEntries(Object.entries(process.env).filter(([c,s])=>s!==void 0&&s!=="").map(([c,s])=>[c,s]))});await this._mcpClient.connect(i);break}case "mcpSseSkill":{if(!t.skill.endpoint)throw new Error(`Skill ${t.skill.name} has no endpoint`);let r=new SSEClientTransport(new URL(t.skill.endpoint));await this._mcpClient.connect(r);break}}let{tools:o}=await this._mcpClient.listTools();this._toolDefinitions=o.map(r=>({skillName:t.skill.name,name:r.name,description:r.description,inputSchema:r.inputSchema,interactive:false})),this._initialized=true;}_getCommandArgs(t){let{name:o,command:r,packageName:a,args:i}=t;if(!a&&(!i||i.length===0))throw new Error(`Skill ${o} has no packageName or args. Please provide one of them.`);if(a&&i&&i.length>0)throw new Error(`Skill ${o} has both packageName and args. Please provide only one of them.`);let c=i&&i.length>0?i:[a];return r==="npx"&&!c.includes("-y")&&(c=["-y",...c]),{command:r,args:c}}async _initInteractiveSkill(t){this._toolDefinitions=Object.values(t.interactiveSkill.tools).map(o=>({skillName:t.interactiveSkill.name,name:o.name,description:o.description,inputSchema:JSON.parse(o.inputJsonSchema),interactive:true})),this._initialized=true;}async _initDelegate(t){this._toolDefinitions=[{skillName:t.expert.name,name:t.expert.name.split("/").pop()??t.expert.name,description:t.expert.description,inputSchema:{type:"object",properties:{query:{type:"string"}},required:["query"]},interactive:false}],this._initialized=true;}async close(){this._mcpClient&&await this._mcpClient.close();}async getToolDefinitions(){if(!this._initialized)throw new Error(`${this.name} is not initialized`);if(this._params.type==="mcp"){let t=this._params.skill.omit??[],o=this._params.skill.pick??[];return this._toolDefinitions.filter(r=>t.length>0?!t.includes(r.name):true).filter(r=>o.length>0?o.includes(r.name):true)}return this._toolDefinitions}async callTool(t,o){switch(this._params.type){case "mcp":{if(!this._mcpClient)throw new Error(`${this.name} is not initialized`);try{let r=await this._mcpClient.callTool({name:t,arguments:o});return this._convertToolResult(r,t,o)}catch(r){return this._handleToolError(r,t)}}case "interactive":return [];case "delegate":return []}}_handleToolError(t,o){if(t instanceof McpError)return [{type:"textPart",text:`Error calling tool ${o}: ${t.message}`,id:createId()}];if(t instanceof ZodError)return [{type:"textPart",text:`Invalid tool call arguments: ${t}`,id:createId()}];throw t}_convertToolResult(t,o,r){return !t.content||t.content.length===0?[{type:"textPart",text:`Tool ${o} returned nothing with arguments: ${JSON.stringify(r)}`,id:createId()}]:t.content.filter(a=>a.type!=="audio"&&a.type!=="resource_link").map(a=>this._convertPart(a))}_convertPart(t){switch(t.type){case "text":return !t.text||t.text===""?{type:"textPart",text:"Error: No content",id:createId()}:{type:"textPart",text:t.text,id:createId()};case "image":if(!t.data||!t.mimeType)throw new Error("Image part must have both data and mimeType");return {type:"imageInlinePart",encodedData:t.data,mimeType:t.mimeType,id:createId()};case "resource":if(!t.resource)throw new Error("Resource part must have resource content");return this._convertResource(t.resource)}}_convertResource(t){if(!t.mimeType)throw new Error(`Resource ${JSON.stringify(t)} has no mimeType`);if(t.text&&typeof t.text=="string")return {type:"textPart",text:t.text,id:createId()};if(t.blob&&typeof t.blob=="string")return {type:"fileInlinePart",encodedData:t.blob,mimeType:t.mimeType,id:createId()};throw new Error(`Unsupported resource type: ${JSON.stringify(t)}`)}};async function Le(e,t){let o={},{skills:r}=e;r["@perstack/base"]||(r["@perstack/base"]={type:"mcpStdioSkill",name:"@perstack/base",description:"The base skill for Perstack",pick:[],omit:[],command:"npx",args:["-y","@perstack/base"],requiredEnv:[]});let a=await Promise.all(Object.values(r).filter(s=>s.type==="mcpStdioSkill"||s.type==="mcpSseSkill").map(async s=>{let u=new _({type:"mcp",skill:s});return await u.init(),u})),i=await Promise.all(Object.values(r).filter(s=>s.type==="interactiveSkill").map(async s=>{let u=new _({type:"interactive",interactiveSkill:s});return await u.init(),u})),c=await Promise.all(e.delegates.map(async s=>{let u=t[s],h=new _({type:"delegate",expert:u});return await h.init(),h}));for(let s of a)o[s.name]=s;for(let s of i)o[s.name]=s;for(let s of c)o[s.name]=s;return o}async function Ge(e){for(let t of Object.values(e))await t.close();}async function N(e,t){for(let o of Object.values(e)){let r=await o.getToolDefinitions();for(let a of r)if(a.name===t)return o}throw new Error(`Tool ${t} not found`)}async function Ke(e){let t={};for(let o of Object.values(e)){let r=await o.getToolDefinitions();for(let a of r)t[a.name]={description:a.description,parameters:jsonSchema(a.inputSchema)};}return t}async function qe({setting:e,checkpoint:t,step:o,skillManagers:r}){if(!o?.toolCall)throw new Error("No tool call found");let{id:a,toolName:i,args:c}=o.toolCall,s=await N(r,i);if(!s||!s.expert)throw new Error(`Delegation error: skill manager "${i}" not found`);if(!c||!c.query||typeof c.query!="string")throw new Error("Delegation error: query is undefined");return $e(e,t,{checkpoint:{...t,status:"stoppedByDelegate",delegateTo:{expert:{key:s.expert.key,name:s.expert.name,version:s.expert.version},toolCallId:a,toolName:i,query:c.query}},step:{...o,finishedAt:new Date().getTime()}})}async function Je({setting:e,checkpoint:t,step:o}){return Ee(e,t,{checkpoint:{...t,status:"stoppedByInteractiveTool"},step:{...o,finishedAt:new Date().getTime()}})}async function Ve({setting:e,checkpoint:t,step:o,skillManagers:r}){if(!o?.toolCall)throw new Error("No tool call found");let{id:a,skillName:i,toolName:c,args:s}=o.toolCall,u=await N(r,c);if(u.type!=="mcp")throw new Error(`Incorrect SkillType, required MCP, got ${u.type}`);let h=await u.callTool(c,s),d={id:a,skillName:i,toolName:c,result:h};if(i==="@perstack/base"){if(c==="think")return ve(e,t,{toolResult:d});if(c==="attemptCompletion")return Me(e,t,{toolResult:d});if(c==="readPdfFile")return we(e,t,{toolResult:d});if(c==="readImageFile")return Ie(e,t,{toolResult:d})}return Ce(e,t,{toolResult:d})}async function Ye({setting:e,checkpoint:t,step:o}){return e.maxSteps!==void 0&&t.stepNumber>e.maxSteps?Ne(e,t,{checkpoint:{...t,status:"stoppedByExceededMaxSteps"},step:{...o,finishedAt:new Date().getTime()}}):Fe(e,t,{checkpoint:{...t},step:{...o,finishedAt:new Date().getTime()},nextCheckpoint:{...t,id:createId(),stepNumber:t.stepNumber+1}})}function F(e){return {type:"userMessage",contents:e.map(t=>({...t,id:createId()})),id:createId()}}function U(e){return {type:"expertMessage",contents:e.map(t=>({...t,id:createId()})),id:createId()}}function C(e){return {type:"toolMessage",contents:e.map(t=>({...t,contents:t.contents.map(o=>({...o,id:createId()})),id:createId()})),id:createId()}}function W(e){switch(e.type){case "instructionMessage":return {role:"system",content:Wt(e.contents),providerOptions:e.cache?{anthropic:{cacheControl:{type:"ephemeral"}}}:void 0};case "userMessage":return {role:"user",content:Ht(e.contents),providerOptions:e.cache?{anthropic:{cacheControl:{type:"ephemeral"}}}:void 0};case "expertMessage":return {role:"assistant",content:Qt(e.contents),providerOptions:e.cache?{anthropic:{cacheControl:{type:"ephemeral"}}}:void 0};case "toolMessage":return {role:"tool",content:Zt(e.contents),providerOptions:e.cache?{anthropic:{cacheControl:{type:"ephemeral"}}}:void 0}}}function Wt(e){return e.reduce((t,o)=>dedent`
2
- ${t}
3
- ${o.text}
4
- `.trim(),"")}function Ht(e){return e.map(t=>{switch(t.type){case "textPart":return We(t);case "imageUrlPart":return Xt(t);case "imageInlinePart":return eo(t);case "imageBinaryPart":return to(t);case "fileUrlPart":return oo(t);case "fileInlinePart":return no(t);case "fileBinaryPart":return ro(t)}})}function Qt(e){return e.map(t=>{switch(t.type){case "textPart":return We(t);case "toolCallPart":return so(t)}})}function Zt(e){return e.map(t=>{switch(t.type){case "toolResultPart":return ao(t)}})}function We(e){return {type:"text",text:e.text}}function Xt(e){return {type:"image",image:e.url,mimeType:e.mimeType}}function eo(e){return {type:"image",image:e.encodedData,mimeType:e.mimeType}}function to(e){return {type:"image",image:e.data,mimeType:e.mimeType}}function oo(e){return {type:"file",data:e.url,mimeType:e.mimeType}}function no(e){return {type:"file",data:e.encodedData,mimeType:e.mimeType}}function ro(e){return {type:"file",data:e.data,mimeType:e.mimeType}}function so(e){return {type:"tool-call",toolCallId:e.toolCallId,toolName:e.toolName,args:e.args}}function ao(e){return {type:"tool-result",toolCallId:e.toolCallId,toolName:e.toolName,result:e.contents,experimental_content:e.contents.map(t=>{switch(t.type){case "textPart":return {type:"text",text:t.text};case "imageInlinePart":return {type:"image",data:t.encodedData,mimeType:t.mimeType}}}),isError:e.isError}}function H(){return {promptTokens:0,completionTokens:0,totalTokens:0,cacheCreationInputTokens:0,cacheReadInputTokens:0}}function Q(e){let t=0,o=0;if(e.providerMetadata?.anthropic){let r=e.providerMetadata.anthropic;t=r.cacheCreationInputTokens||0,o=r.cacheReadInputTokens||0;}return {promptTokens:e.usage.promptTokens,completionTokens:e.usage.completionTokens,totalTokens:e.usage.totalTokens,cacheCreationInputTokens:t,cacheReadInputTokens:o}}function v(e,t){return {promptTokens:e.promptTokens+t.promptTokens,completionTokens:e.completionTokens+t.completionTokens,totalTokens:e.totalTokens+t.totalTokens,cacheCreationInputTokens:e.cacheCreationInputTokens+t.cacheCreationInputTokens,cacheReadInputTokens:e.cacheReadInputTokens+t.cacheReadInputTokens}}async function He({setting:e,checkpoint:t,step:o}){if(!o?.toolCall||!o?.toolResult)throw new Error("No tool call or tool result found");let{id:r,toolName:a}=o.toolCall,{result:i}=o.toolResult,c=C([{type:"toolResultPart",toolCallId:r,toolName:a,contents:i.filter(f=>f.type==="textPart"||f.type==="imageInlinePart")}]),s=z(e.model),{messages:u}=t,h=await generateText({model:s,messages:[...u,c].map(W),temperature:e.temperature,maxRetries:e.maxRetries}),d=Q(h),{text:P}=h,R=[c,U(P?[{type:"textPart",text:P}]:[])];return be(e,t,{checkpoint:{...t,messages:[...u,...R],usage:v(t.usage,d),status:"completed"},step:{...o,newMessages:[...o.newMessages,...R],finishedAt:new Date().getTime(),usage:v(o.usage,d)},text:P,usage:d})}async function Qe({setting:e,checkpoint:t,skillManagers:o}){let{messages:r}=t,a=z(e.model),i=await generateText({model:a,messages:r.map(W),temperature:e.temperature,maxRetries:e.maxRetries,tools:await Ke(o),toolChoice:"required"}),c=Q(i),{text:s,toolCalls:u,finishReason:h}=i,d=u[0];if(!d)return re(e,t,{newMessages:[U(s?[{type:"textPart",text:s}]:[]),F([{type:"textPart",text:"You must generate a tool call. Try again."}])],usage:c});if(h!=="tool-calls")switch(h){case "length":return re(e,t,{newMessages:[U([{type:"toolCallPart",toolCallId:d.toolCallId,toolName:d.toolName,args:d.args}]),C([{type:"toolResultPart",toolCallId:d.toolCallId,toolName:d.toolName,contents:[{type:"textPart",text:"Error: Generation length exceeded"}]}])],usage:c});default:throw new Error(`Unexpected finish reason: ${h}`)}let P=[{type:"toolCallPart",toolCallId:d.toolCallId,toolName:d.toolName,args:d.args}];s&&P.push({type:"textPart",text:s});let R=await N(o,d.toolName),f={newMessage:U(P),toolCall:{id:d.toolCallId,skillName:R.name,toolName:d.toolName,args:d.args},usage:c};switch(R.type){case "mcp":return Re(e,t,f);case "interactive":return Se(e,t,f);case "delegate":return Pe(e,t,f)}}var po=dedent`
1
+ // src/runtime.ts
2
+ import { existsSync } from "fs";
3
+ import { mkdir as mkdir2, readFile as readFile4, writeFile as writeFile2 } from "fs/promises";
4
+ import path from "path";
5
+ import { createId as createId7 } from "@paralleldrive/cuid2";
6
+ import TOML from "smol-toml";
7
+ import { createActor } from "xstate";
8
+
9
+ // src/default-store.ts
10
+ import { mkdir, readFile, readdir, writeFile } from "fs/promises";
11
+
12
+ // src/schemas/runtime.ts
13
+ import { createId } from "@paralleldrive/cuid2";
14
+ import { z as z2 } from "zod";
15
+
16
+ // src/model.ts
17
+ import { anthropic } from "@ai-sdk/anthropic";
18
+ import { google } from "@ai-sdk/google";
19
+ import { openai } from "@ai-sdk/openai";
20
+ var DefaultModel = "claude-4-sonnet-20250514";
21
+ var AnthropicModels = [
22
+ "claude-4-opus-20250514",
23
+ "claude-4-sonnet-20250514",
24
+ "claude-3-7-sonnet-20250219",
25
+ "claude-3-5-sonnet-latest",
26
+ "claude-3-5-sonnet-20241022",
27
+ "claude-3-5-sonnet-20240620",
28
+ "claude-3-5-haiku-latest",
29
+ "claude-3-5-haiku-20241022"
30
+ // "claude-3-opus-latest", - No pdf support
31
+ // "claude-3-opus-20240229", - No pdf support
32
+ // "claude-3-sonnet-20240229", - No pdf support
33
+ // "claude-3-haiku-20240307", - No pdf support
34
+ ];
35
+ var GoogleModels = [
36
+ "gemini-2.5-pro-preview-05-06",
37
+ "gemini-2.5-pro-exp-03-25",
38
+ "gemini-2.5-flash-preview-04-17",
39
+ "gemini-2.0-pro-exp-02-05",
40
+ "gemini-2.0-flash-thinking-exp-01-21",
41
+ "gemini-2.0-flash",
42
+ "gemini-2.0-flash-001",
43
+ "gemini-2.0-flash-live-001",
44
+ "gemini-2.0-flash-lite",
45
+ "gemini-2.0-flash-exp",
46
+ "gemini-1.5-pro",
47
+ "gemini-1.5-pro-latest",
48
+ "gemini-1.5-pro-001",
49
+ "gemini-1.5-pro-002",
50
+ "gemini-1.5-flash",
51
+ "gemini-1.5-flash-latest",
52
+ "gemini-1.5-flash-001",
53
+ "gemini-1.5-flash-002",
54
+ "gemini-1.5-flash-8b",
55
+ "gemini-1.5-flash-8b-latest",
56
+ "gemini-1.5-flash-8b-001"
57
+ // "gemini-exp-1206", - Unclear model spec
58
+ // "gemma-3-27b-it", - Unclear model spec
59
+ // "learnlm-1.5-pro-experimental", - Unclear model spec
60
+ ];
61
+ var OpenAIModels = [
62
+ "o4-mini",
63
+ "o4-mini-2025-04-16",
64
+ "o3",
65
+ "o3-2025-04-16",
66
+ "o3-mini",
67
+ "o3-mini-2025-01-31",
68
+ "o1",
69
+ "o1-2024-12-17",
70
+ "o1-mini",
71
+ "o1-mini-2024-09-12",
72
+ // "o1-preview", - No tool support
73
+ // "o1-preview-2024-09-12", - No tool support
74
+ "gpt-4.5-preview",
75
+ "gpt-4.5-preview-2025-02-27",
76
+ "gpt-4.1",
77
+ "gpt-4.1-2025-04-14",
78
+ "gpt-4.1-mini",
79
+ "gpt-4.1-mini-2025-04-14",
80
+ "gpt-4.1-nano",
81
+ "gpt-4.1-nano-2025-04-14",
82
+ "gpt-4o",
83
+ "gpt-4o-2024-05-13",
84
+ "gpt-4o-2024-08-06",
85
+ "gpt-4o-2024-11-20",
86
+ "gpt-4o-audio-preview",
87
+ "gpt-4o-audio-preview-2024-10-01",
88
+ "gpt-4o-audio-preview-2024-12-17",
89
+ "gpt-4o-search-preview",
90
+ "gpt-4o-search-preview-2025-03-11",
91
+ "gpt-4o-mini-search-preview",
92
+ "gpt-4o-mini-search-preview-2025-03-11",
93
+ "gpt-4o-mini",
94
+ "gpt-4o-mini-2024-07-18"
95
+ // "gpt-4-turbo", - Legacy model
96
+ // "gpt-4-turbo-2024-04-09", - Legacy model
97
+ // "gpt-4-turbo-preview", - Legacy model
98
+ // "gpt-4-0125-preview", - No image input support
99
+ // "gpt-4-1106-preview", - No image input support
100
+ // "gpt-4", - No image input support
101
+ // "gpt-4-0613", - No image input support
102
+ // "gpt-3.5-turbo-0125", - Legacy model
103
+ // "gpt-3.5-turbo", - Legacy model
104
+ // "gpt-3.5-turbo-1106", - Legacy model
105
+ // "chatgpt-4o-latest", - No tool support
106
+ ];
107
+ var SupportedModels = Object.fromEntries(
108
+ [...AnthropicModels, ...GoogleModels, ...OpenAIModels].map((model) => [
109
+ model,
110
+ { default: model === DefaultModel, model }
111
+ ])
112
+ );
113
+ function getDefaultModelName() {
114
+ const model = Object.values(SupportedModels).find((model2) => model2.default);
115
+ if (!model) {
116
+ throw new Error("No default model found");
117
+ }
118
+ return model.model;
119
+ }
120
+ function getModel(modelId) {
121
+ const unwrappedModelId = modelId ?? getDefaultModelName();
122
+ if (AnthropicModels.includes(unwrappedModelId)) {
123
+ return anthropic(unwrappedModelId);
124
+ }
125
+ if (GoogleModels.includes(unwrappedModelId)) {
126
+ return google(unwrappedModelId);
127
+ }
128
+ if (OpenAIModels.includes(unwrappedModelId)) {
129
+ return openai(unwrappedModelId);
130
+ }
131
+ throw new Error(`Unsupported model: ${unwrappedModelId}`);
132
+ }
133
+
134
+ // src/schemas/messages.ts
135
+ import { z } from "zod";
136
+ var BasePartSchema = z.object({
137
+ id: z.string()
138
+ });
139
+ var TextPartSchema = BasePartSchema.extend({
140
+ type: z.literal("textPart"),
141
+ text: z.string()
142
+ });
143
+ var ImageUrlPartSchema = BasePartSchema.extend({
144
+ type: z.literal("imageUrlPart"),
145
+ url: z.string().url(),
146
+ mimeType: z.string()
147
+ });
148
+ var ImageInlinePartSchema = BasePartSchema.extend({
149
+ type: z.literal("imageInlinePart"),
150
+ encodedData: z.string(),
151
+ mimeType: z.string()
152
+ });
153
+ var ImageBinaryPartSchema = BasePartSchema.extend({
154
+ type: z.literal("imageBinaryPart"),
155
+ data: z.string(),
156
+ mimeType: z.string()
157
+ });
158
+ var FileUrlPartSchema = BasePartSchema.extend({
159
+ type: z.literal("fileUrlPart"),
160
+ url: z.string().url(),
161
+ mimeType: z.string()
162
+ });
163
+ var FileInlinePartSchema = BasePartSchema.extend({
164
+ type: z.literal("fileInlinePart"),
165
+ encodedData: z.string(),
166
+ mimeType: z.string()
167
+ });
168
+ var FileBinaryPartSchema = BasePartSchema.extend({
169
+ type: z.literal("fileBinaryPart"),
170
+ data: z.string(),
171
+ mimeType: z.string()
172
+ });
173
+ var ToolCallPartSchema = BasePartSchema.extend({
174
+ type: z.literal("toolCallPart"),
175
+ toolCallId: z.string(),
176
+ toolName: z.string(),
177
+ args: z.unknown()
178
+ });
179
+ var ToolResultPartSchema = BasePartSchema.extend({
180
+ type: z.literal("toolResultPart"),
181
+ toolCallId: z.string(),
182
+ toolName: z.string(),
183
+ contents: z.array(z.union([TextPartSchema, ImageInlinePartSchema])),
184
+ isError: z.boolean().optional()
185
+ });
186
+ var BaseMessageSchema = z.object({
187
+ id: z.string()
188
+ });
189
+ var InstructionMessageSchema = BaseMessageSchema.extend({
190
+ type: z.literal("instructionMessage"),
191
+ contents: z.array(TextPartSchema),
192
+ cache: z.boolean().optional()
193
+ });
194
+ var UserMessageSchema = BaseMessageSchema.extend({
195
+ type: z.literal("userMessage"),
196
+ contents: z.array(
197
+ z.union([
198
+ TextPartSchema,
199
+ ImageUrlPartSchema,
200
+ ImageInlinePartSchema,
201
+ ImageBinaryPartSchema,
202
+ FileUrlPartSchema,
203
+ FileInlinePartSchema,
204
+ FileBinaryPartSchema
205
+ ])
206
+ ),
207
+ cache: z.boolean().optional()
208
+ });
209
+ var ExpertMessageSchema = BaseMessageSchema.extend({
210
+ type: z.literal("expertMessage"),
211
+ contents: z.array(z.union([TextPartSchema, ToolCallPartSchema])),
212
+ cache: z.boolean().optional()
213
+ });
214
+ var ToolMessageSchema = BaseMessageSchema.extend({
215
+ type: z.literal("toolMessage"),
216
+ contents: z.array(ToolResultPartSchema),
217
+ cache: z.boolean().optional()
218
+ });
219
+ var MessageSchema = z.union([
220
+ InstructionMessageSchema,
221
+ UserMessageSchema,
222
+ ExpertMessageSchema,
223
+ ToolMessageSchema
224
+ ]);
225
+
226
+ // src/schemas/runtime.ts
227
+ var expertNameRegex = /^(@[a-z0-9][a-z0-9_-]*\/)?[a-z0-9][a-z0-9_-]*$/;
228
+ var versionRegex = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?$/;
229
+ var tagNameRegex = /^[a-z0-9][a-z0-9_-]*$/;
230
+ var expertKeyRegex = /^((?:@[a-z0-9][a-z0-9_\.-]*\/)?[a-z0-9][a-z0-9_\.-]*)(?:@((?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[\w.-]+)?(?:\+[\w.-]+)?)|@([a-z0-9][a-z0-9_\.-]*))?$/;
231
+ var skillNameRegex = /^[a-z0-9][a-z0-9._-]*$/;
232
+ var maxNameLength = 214;
233
+ function parseExpertKey(expertKey) {
234
+ const match = expertKey.match(expertKeyRegex);
235
+ if (!match) {
236
+ throw new Error(`Invalid expert key format: ${expertKey}`);
237
+ }
238
+ const [key, name, version, tag] = match;
239
+ return {
240
+ key,
241
+ name,
242
+ version,
243
+ tag
244
+ };
245
+ }
246
+ var McpStdioSkillSchema = z2.object({
247
+ type: z2.literal("mcpStdioSkill"),
248
+ name: z2.string(),
249
+ description: z2.string().optional(),
250
+ rule: z2.string().optional(),
251
+ pick: z2.array(z2.string()).optional().default([]),
252
+ omit: z2.array(z2.string()).optional().default([]),
253
+ command: z2.string(),
254
+ packageName: z2.string().optional(),
255
+ args: z2.array(z2.string()).optional().default([]),
256
+ requiredEnv: z2.array(z2.string()).optional().default([])
257
+ });
258
+ var McpSseSkillSchema = z2.object({
259
+ type: z2.literal("mcpSseSkill"),
260
+ name: z2.string(),
261
+ description: z2.string().optional(),
262
+ rule: z2.string().optional(),
263
+ pick: z2.array(z2.string()).optional().default([]),
264
+ omit: z2.array(z2.string()).optional().default([]),
265
+ endpoint: z2.string()
266
+ });
267
+ var InteractiveToolSchema = z2.object({
268
+ name: z2.string(),
269
+ description: z2.string().optional(),
270
+ inputJsonSchema: z2.string()
271
+ });
272
+ var InteractiveSkillSchema = z2.object({
273
+ type: z2.literal("interactiveSkill"),
274
+ name: z2.string(),
275
+ description: z2.string().optional(),
276
+ rule: z2.string().optional(),
277
+ tools: z2.record(z2.string(), InteractiveToolSchema.omit({ name: true })).transform((tools) => {
278
+ return Object.fromEntries(
279
+ Object.entries(tools).map(([key, toolWithoutName]) => [
280
+ key,
281
+ InteractiveToolSchema.parse({ ...toolWithoutName, name: key })
282
+ ])
283
+ );
284
+ })
285
+ });
286
+ var ExpertSchema = z2.object({
287
+ key: z2.string().regex(expertKeyRegex).min(1),
288
+ name: z2.string().regex(expertNameRegex).min(1).max(maxNameLength),
289
+ version: z2.string().regex(versionRegex),
290
+ description: z2.string().min(1).max(1024 * 2).optional(),
291
+ instruction: z2.string().min(1).max(1024 * 20),
292
+ skills: z2.record(
293
+ z2.string(),
294
+ z2.discriminatedUnion("type", [
295
+ McpStdioSkillSchema.omit({ name: true }),
296
+ McpSseSkillSchema.omit({ name: true }),
297
+ InteractiveSkillSchema.omit({ name: true })
298
+ ])
299
+ ).optional().default({
300
+ "@perstack/base": {
301
+ type: "mcpStdioSkill",
302
+ description: "Base skill",
303
+ command: "npx",
304
+ args: ["-y", "@perstack/base"]
305
+ }
306
+ }).transform((skills) => {
307
+ return Object.fromEntries(
308
+ Object.entries(skills).map(([key, skillWithoutName]) => [
309
+ key,
310
+ z2.discriminatedUnion("type", [
311
+ McpStdioSkillSchema,
312
+ McpSseSkillSchema,
313
+ InteractiveSkillSchema
314
+ ]).parse({ ...skillWithoutName, name: key })
315
+ ])
316
+ );
317
+ }),
318
+ delegates: z2.array(z2.string().regex(expertKeyRegex).min(1)).optional().default([]),
319
+ tags: z2.array(z2.string().regex(tagNameRegex).min(1)).optional().default([])
320
+ });
321
+ var UsageSchema = z2.object({
322
+ promptTokens: z2.number(),
323
+ completionTokens: z2.number(),
324
+ totalTokens: z2.number(),
325
+ cacheCreationInputTokens: z2.number(),
326
+ cacheReadInputTokens: z2.number()
327
+ });
328
+ var CheckpointStatusSchema = z2.enum([
329
+ "init",
330
+ "proceeding",
331
+ "completed",
332
+ "stoppedByInteractiveTool",
333
+ "stoppedByDelegate",
334
+ "stoppedByExceededMaxSteps",
335
+ "stoppedByError"
336
+ ]);
337
+ var CheckpointSchema = z2.object({
338
+ id: z2.string(),
339
+ runId: z2.string(),
340
+ status: CheckpointStatusSchema,
341
+ stepNumber: z2.number(),
342
+ messages: z2.array(MessageSchema),
343
+ expert: z2.object({
344
+ key: z2.string(),
345
+ name: z2.string(),
346
+ version: z2.string()
347
+ }),
348
+ delegateTo: z2.object({
349
+ expert: z2.object({
350
+ key: z2.string(),
351
+ name: z2.string(),
352
+ version: z2.string()
353
+ }),
354
+ toolCallId: z2.string(),
355
+ toolName: z2.string(),
356
+ query: z2.string()
357
+ }).optional(),
358
+ delegatedBy: z2.object({
359
+ expert: z2.object({
360
+ key: z2.string(),
361
+ name: z2.string(),
362
+ version: z2.string()
363
+ }),
364
+ toolCallId: z2.string(),
365
+ toolName: z2.string(),
366
+ checkpointId: z2.string()
367
+ }).optional(),
368
+ usage: UsageSchema
369
+ });
370
+ var RunParamsSchema = z2.object({
371
+ setting: z2.object({
372
+ runId: z2.string().optional().transform((value) => value ?? createId()),
373
+ expertKey: z2.string().regex(expertKeyRegex).min(1),
374
+ input: z2.object({
375
+ text: z2.string().optional(),
376
+ interactiveToolCallResult: z2.object({
377
+ toolCallId: z2.string(),
378
+ toolName: z2.string(),
379
+ text: z2.string()
380
+ }).optional()
381
+ }),
382
+ experts: z2.record(z2.string().regex(expertKeyRegex).min(1), ExpertSchema.omit({ key: true })).optional().default({}).transform(
383
+ (experts) => Object.fromEntries(
384
+ Object.entries(experts).map(([key, expertWithoutKey]) => [
385
+ key,
386
+ ExpertSchema.parse({
387
+ ...expertWithoutKey,
388
+ key
389
+ })
390
+ ])
391
+ )
392
+ ),
393
+ model: z2.string().optional().default(getDefaultModelName()),
394
+ temperature: z2.number().min(0).max(1).optional().default(0.3),
395
+ maxSteps: z2.number().min(1).optional(),
396
+ maxRetries: z2.number().min(0).optional().default(10),
397
+ /** Optional workspace directory path. If provided, sets WORKSPACE_DIR environment variable for skill execution. */
398
+ workspace: z2.string().optional(),
399
+ startedAt: z2.number().optional().default(Date.now()),
400
+ updatedAt: z2.number().optional().default(Date.now())
401
+ }),
402
+ checkpoint: CheckpointSchema.optional()
403
+ });
404
+ function createEvent(type) {
405
+ return (setting, checkpoint, data) => {
406
+ return {
407
+ type,
408
+ id: createId(),
409
+ expertKey: checkpoint.expert.key,
410
+ timestamp: Date.now(),
411
+ runId: setting.runId,
412
+ stepNumber: checkpoint.stepNumber,
413
+ ...data
414
+ };
415
+ };
416
+ }
417
+ var startRun = createEvent("startRun");
418
+ var startGeneration = createEvent("startGeneration");
419
+ var retry = createEvent("retry");
420
+ var callTool = createEvent("callTool");
421
+ var callInteractiveTool = createEvent("callInteractiveTool");
422
+ var callDelegate = createEvent("callDelegate");
423
+ var resolveToolResult = createEvent("resolveToolResult");
424
+ var resolveThought = createEvent("resolveThought");
425
+ var resolvePdfFile = createEvent("resolvePdfFile");
426
+ var resolveImageFile = createEvent("resolveImageFile");
427
+ var attemptCompletion = createEvent("attemptCompletion");
428
+ var finishToolCall = createEvent("finishToolCall");
429
+ var completeRun = createEvent("completeRun");
430
+ var stopRunByInteractiveTool = createEvent("stopRunByInteractiveTool");
431
+ var stopRunByDelegate = createEvent("stopRunByDelegate");
432
+ var stopRunByExceededMaxSteps = createEvent("stopRunByExceededMaxSteps");
433
+ var continueToNextStep = createEvent("continueToNextStep");
434
+
435
+ // src/default-store.ts
436
+ async function defaultRetrieveCheckpoint(runId, checkpointId) {
437
+ const runDir = getRunDir(runId);
438
+ const checkpointFiles = await readdir(runDir, { withFileTypes: true }).then(
439
+ (files) => files.filter((file) => file.isFile() && file.name.startsWith("checkpoint-"))
440
+ );
441
+ const checkpointFile = checkpointFiles.find((file) => file.name.endsWith(`-${checkpointId}.json`));
442
+ if (!checkpointFile) {
443
+ throw new Error(`checkpoint not found: ${runId} ${checkpointId}`);
444
+ }
445
+ const checkpointPath = `${runDir}/${checkpointFile.name}`;
446
+ const checkpoint = await readFile(checkpointPath, "utf8");
447
+ return CheckpointSchema.parse(JSON.parse(checkpoint));
448
+ }
449
+ async function defaultStoreCheckpoint(checkpoint, timestamp) {
450
+ const { id, runId, stepNumber } = checkpoint;
451
+ const runDir = getRunDir(runId);
452
+ const checkpointPath = `${runDir}/checkpoint-${timestamp}-${stepNumber}-${id}.json`;
453
+ await mkdir(runDir, { recursive: true });
454
+ await writeFile(checkpointPath, JSON.stringify(checkpoint, null, 2));
455
+ }
456
+ async function defaultStoreEvent(event) {
457
+ const { timestamp, runId, stepNumber, type } = event;
458
+ const runDir = getRunDir(runId);
459
+ const eventPath = `${runDir}/event-${timestamp}-${stepNumber}-${type}.json`;
460
+ await mkdir(runDir, { recursive: true });
461
+ await writeFile(eventPath, JSON.stringify(event, null, 2));
462
+ }
463
+
464
+ // package.json
465
+ var package_default = {
466
+ name: "@perstack/runtime",
467
+ version: "0.0.11",
468
+ description: "PerStack Runtime",
469
+ author: "Wintermute Technologies, Inc.",
470
+ license: "Apache-2.0",
471
+ type: "module",
472
+ exports: {
473
+ ".": "./src/index.ts"
474
+ },
475
+ publishConfig: {
476
+ exports: {
477
+ ".": "./dist/index.js"
478
+ },
479
+ types: "./dist/index.d.ts"
480
+ },
481
+ files: [
482
+ "dist"
483
+ ],
484
+ scripts: {
485
+ clean: "rm -rf dist",
486
+ dev: "tsup --watch --config ../../tsup.config.ts",
487
+ build: "npm run clean && tsup --config ../../tsup.config.ts",
488
+ prepublishOnly: "npm run clean && npm run build"
489
+ },
490
+ dependencies: {
491
+ "@ai-sdk/anthropic": "^1.2.12",
492
+ "@ai-sdk/google": "^1.2.19",
493
+ "@ai-sdk/openai": "^1.3.22",
494
+ "@modelcontextprotocol/sdk": "^1.12.3",
495
+ "@paralleldrive/cuid2": "^2.2.2",
496
+ ai: "^4.3.16",
497
+ "smol-toml": "^1.3.4",
498
+ "ts-dedent": "^2.2.0",
499
+ xstate: "^5.19.4",
500
+ zod: "^3.25.67"
501
+ },
502
+ devDependencies: {
503
+ "@tsconfig/node22": "^22.0.2",
504
+ "@types/node": "^24.0.3",
505
+ tsup: "^8.5.0",
506
+ typescript: "^5.8.3",
507
+ vitest: "^3.2.3"
508
+ },
509
+ engines: {
510
+ node: ">=22.0.0"
511
+ }
512
+ };
513
+
514
+ // src/events/default-event-listener.ts
515
+ var log = console.info;
516
+ var debug = console.debug;
517
+ var header = (e) => {
518
+ const t = (/* @__PURE__ */ new Date()).toISOString();
519
+ const stepNumber = e.stepNumber;
520
+ const key = e.expertKey;
521
+ return `${t} ${stepNumber} ${key}`;
522
+ };
523
+ async function defaultEventListener(e) {
524
+ await defaultStoreEvent(e);
525
+ switch (e.type) {
526
+ case "startRun": {
527
+ log(`${header(e)} \u{1F99C} Perstack@${package_default.version} started`);
528
+ const { inputMessages } = e;
529
+ for (const message of inputMessages) {
530
+ if (message.type === "userMessage") {
531
+ logUserMessage(message);
532
+ } else if (message.type === "toolMessage") {
533
+ logToolMessage(message);
534
+ }
535
+ }
536
+ break;
537
+ }
538
+ case "startGeneration": {
539
+ log(`${header(e)} \u{1F99C} Generating tool call`);
540
+ break;
541
+ }
542
+ case "retry": {
543
+ logUsage(e);
544
+ log(`${header(e)} \u{1F99C} Retrying tool call generation`);
545
+ break;
546
+ }
547
+ case "callTool": {
548
+ logUsage(e);
549
+ log(`${header(e)} \u{1F99C} Calling tool`);
550
+ if (e.toolCall.skillName === "@perstack/base") {
551
+ switch (e.toolCall.toolName) {
552
+ case "think": {
553
+ const thought = e.toolCall.args.thought;
554
+ log(`${header(e)} \u{1F4AD} Thought Updated:`);
555
+ debug(thought);
556
+ break;
557
+ }
558
+ case "readPdfFile": {
559
+ const path2 = e.toolCall.args.path;
560
+ log(`${header(e)} \u{1F4C4} Reading PDF: ${path2}`);
561
+ break;
562
+ }
563
+ case "readImageFile": {
564
+ const path2 = e.toolCall.args.path;
565
+ log(`${header(e)} \u{1F5BC}\uFE0F Reading Image: ${path2}`);
566
+ break;
567
+ }
568
+ default: {
569
+ log(`${header(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
570
+ log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
571
+ break;
572
+ }
573
+ }
574
+ } else {
575
+ log(`${header(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
576
+ log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
577
+ }
578
+ break;
579
+ }
580
+ case "callInteractiveTool": {
581
+ logUsage(e);
582
+ log(`${header(e)} \u{1F99C} Calling interactive tool`);
583
+ log(`${header(e)} \u{1F527} Tool: ${e.toolCall.skillName}/${e.toolCall.toolName}`);
584
+ log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
585
+ break;
586
+ }
587
+ case "callDelegate": {
588
+ logUsage(e);
589
+ log(`${header(e)} \u{1F99C} Calling delegate`);
590
+ log(`${header(e)} \u{1F527} Tool: ${e.toolCall.toolName}`);
591
+ log(`${header(e)} \u{1F527} Args: ${e.toolCall.args}`);
592
+ break;
593
+ }
594
+ case "resolveToolResult": {
595
+ log(`${header(e)} \u{1F527} Resolved Tool Result`);
596
+ if (e.toolResult.skillName === "@perstack/base") {
597
+ switch (e.toolResult.toolName) {
598
+ case "todo": {
599
+ const text = e.toolResult.result.find((r) => r.type === "textPart")?.text;
600
+ const { todos } = JSON.parse(text ?? "{}");
601
+ log(`${header(e)} \u{1F4C4} Todo:`);
602
+ for (const todo of todos) {
603
+ debug(`${todo.completed ? "[x]" : "[ ]"} ${todo.id}: ${todo.title}`);
604
+ }
605
+ break;
606
+ }
607
+ default: {
608
+ log(`${header(e)} \u{1F527} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
609
+ log(`${header(e)} \u{1F527} Result: ${e.toolResult.result}`);
610
+ break;
611
+ }
612
+ }
613
+ } else {
614
+ log(`${header(e)} \u{1F527} Tool: ${e.toolResult.skillName}/${e.toolResult.toolName}`);
615
+ log(`${header(e)} \u{1F527} Result: ${e.toolResult.result}`);
616
+ }
617
+ break;
618
+ }
619
+ case "resolveThought": {
620
+ log(`${header(e)} \u{1F4AD} Resolved Thought:`, e.toolResult);
621
+ break;
622
+ }
623
+ case "resolvePdfFile": {
624
+ log(`${header(e)} \u{1F4C4} Resolved PDF:`, e.toolResult);
625
+ break;
626
+ }
627
+ case "resolveImageFile": {
628
+ log(`${header(e)} \u{1F5BC}\uFE0F Resolved Image:`, e.toolResult);
629
+ break;
630
+ }
631
+ case "attemptCompletion": {
632
+ log(`${header(e)} \u2705 Attempting completion`);
633
+ break;
634
+ }
635
+ case "completeRun": {
636
+ logUsage(e);
637
+ log(`${header(e)} \u{1F99C} Completing run`);
638
+ log(`${header(e)} \u{1F99C} Result:`, e.text);
639
+ break;
640
+ }
641
+ case "stopRunByInteractiveTool": {
642
+ log(`${header(e)} \u{1F99C} Stopping run by interactive tool`);
643
+ break;
644
+ }
645
+ case "stopRunByDelegate": {
646
+ log(`${header(e)} \u{1F99C} Stopping run by delegate`);
647
+ break;
648
+ }
649
+ case "stopRunByExceededMaxSteps": {
650
+ log(`${header(e)} \u{1F99C} Stopping run by exceeded max steps`);
651
+ break;
652
+ }
653
+ case "continueToNextStep": {
654
+ log(`${header(e)} \u{1F99C} Continuing to next step`);
655
+ break;
656
+ }
657
+ }
658
+ }
659
+ function logUserMessage(message) {
660
+ const t = (/* @__PURE__ */ new Date()).toISOString();
661
+ const contents = message.contents;
662
+ for (const content of contents) {
663
+ if (content.type === "textPart") {
664
+ log(`${t} \u{1F4AC} User: ${content.text}`);
665
+ } else if (content.type === "imageUrlPart") {
666
+ log(`${t} \u{1F5BC}\uFE0F User: ${content.url}`);
667
+ } else if (content.type === "imageInlinePart") {
668
+ log(`${t} \u{1F5BC}\uFE0F User: Inline image`);
669
+ } else if (content.type === "imageBinaryPart") {
670
+ log(`${t} \u{1F5BC}\uFE0F User: Binary image`);
671
+ } else if (content.type === "fileUrlPart") {
672
+ log(`${t} \u{1F4C4} User: ${content.url}`);
673
+ } else if (content.type === "fileInlinePart") {
674
+ log(`${t} \u{1F4C4} User: Inline file`);
675
+ } else if (content.type === "fileBinaryPart") {
676
+ log(`${t} \u{1F4C4} User: Binary file`);
677
+ }
678
+ }
679
+ }
680
+ function logToolMessage(message) {
681
+ const t = (/* @__PURE__ */ new Date()).toISOString();
682
+ const contents = message.contents;
683
+ for (const content of contents) {
684
+ if (content.type === "toolResultPart") {
685
+ const { contents: contents2 } = content;
686
+ for (const content2 of contents2) {
687
+ if (content2.type === "textPart") {
688
+ log(`${t} \u{1F4AC} Tool Result: ${content2.text}`);
689
+ } else if (content2.type === "imageInlinePart") {
690
+ log(`${t} \u{1F5BC}\uFE0F Tool Result: Inline image`);
691
+ }
692
+ }
693
+ }
694
+ }
695
+ }
696
+ function logUsage(e) {
697
+ const usageByGeneration = [
698
+ `In: ${e.usage.promptTokens.toLocaleString()}`,
699
+ `Out: ${e.usage.completionTokens.toLocaleString()}`,
700
+ `Total: ${e.usage.totalTokens.toLocaleString()}`,
701
+ `Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,
702
+ `Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`
703
+ ].join(", ");
704
+ log(`${header(e)} \u{1F4CA} Tokens usage: ${usageByGeneration}`);
705
+ const usageByRun = [
706
+ `In: ${e.usage.promptTokens.toLocaleString()}`,
707
+ `Out: ${e.usage.completionTokens.toLocaleString()}`,
708
+ `Total: ${e.usage.totalTokens.toLocaleString()}`,
709
+ `Cache-read: ${e.usage.cacheReadInputTokens.toLocaleString()}`,
710
+ `Cache-write: ${e.usage.cacheCreationInputTokens.toLocaleString()}`
711
+ ].join(", ");
712
+ log(`${header(e)} \u{1F4CA} Total usage: ${usageByRun}`);
713
+ }
714
+
715
+ // src/events/event-emitter.ts
716
+ import { createId as createId2 } from "@paralleldrive/cuid2";
717
+ var RunEventEmitter = class {
718
+ listeners = [];
719
+ subscribe(listener) {
720
+ this.listeners.push(listener);
721
+ }
722
+ async emit(event) {
723
+ for (const listener of this.listeners) {
724
+ await listener({
725
+ ...event,
726
+ id: createId2(),
727
+ timestamp: Date.now()
728
+ });
729
+ }
730
+ }
731
+ };
732
+
733
+ // src/schemas/api-registry.ts
734
+ import { z as z3 } from "zod";
735
+ var RegistryV1ExpertSchema = z3.object({
736
+ name: z3.string(),
737
+ version: z3.string(),
738
+ minRuntimeVersion: z3.string(),
739
+ description: z3.string(),
740
+ instruction: z3.string(),
741
+ skills: z3.record(
742
+ z3.string(),
743
+ z3.discriminatedUnion("type", [
744
+ McpStdioSkillSchema.omit({ name: true }),
745
+ McpSseSkillSchema.omit({ name: true }),
746
+ InteractiveSkillSchema.omit({ name: true })
747
+ ])
748
+ ),
749
+ delegates: z3.array(z3.string()),
750
+ tags: z3.array(z3.string()),
751
+ status: z3.string(),
752
+ owner: z3.object({ name: z3.string() }),
753
+ createdAt: z3.string().datetime(),
754
+ updatedAt: z3.string().datetime()
755
+ });
756
+ var RegistryV1ExpertsGetResponseSchema = z3.object({
757
+ data: z3.object({
758
+ expert: RegistryV1ExpertSchema
759
+ })
760
+ });
761
+
762
+ // src/api-clinent.ts
763
+ var Perstack = class {
764
+ baseUrl;
765
+ registry;
766
+ apiKey;
767
+ constructor(params) {
768
+ this.baseUrl = params?.baseUrl ?? process.env.PERSTACK_API_BASE_URL ?? "https://api.perstack.ai";
769
+ this.apiKey = params?.apiKey ?? process.env.PERSTACK_API_KEY;
770
+ this.registry = new RegistryClientV1(this);
771
+ }
772
+ };
773
+ var RegistryClientV1 = class {
774
+ client;
775
+ endpoint;
776
+ constructor(client) {
777
+ this.client = client;
778
+ this.endpoint = "/api/registry/v1/experts";
779
+ }
780
+ async get(expertKey) {
781
+ const safeExpertKey = encodeURIComponent(expertKey);
782
+ const url = new URL(`${this.endpoint}/${safeExpertKey}`, this.client.baseUrl);
783
+ const headers = {
784
+ "Content-Type": "application/json",
785
+ Authorization: `Bearer ${this.client.apiKey}`
786
+ };
787
+ const result = await fetch(url.toString(), { headers });
788
+ if (!result.ok) {
789
+ throw new Error(
790
+ `Registry returned non-200 status code: ${result.status}, reason: ${result.statusText}`
791
+ );
792
+ }
793
+ const json = await result.json();
794
+ return RegistryV1ExpertsGetResponseSchema.parse(json);
795
+ }
796
+ };
797
+
798
+ // src/resolve-expert-to-run.ts
799
+ async function resolveExpertToRun(expertKey, experts) {
800
+ if (experts[expertKey]) {
801
+ return experts[expertKey];
802
+ }
803
+ const client = new Perstack();
804
+ const { data } = await client.registry.get(expertKey);
805
+ const expert = ExpertSchema.parse({
806
+ ...data.expert,
807
+ key: expertKey
808
+ });
809
+ experts[expertKey] = expert;
810
+ return expert;
811
+ }
812
+
813
+ // src/runtime-state-machine.ts
814
+ import { assign, setup } from "xstate";
815
+
816
+ // src/skill-manager.ts
817
+ import { Client as McpClient } from "@modelcontextprotocol/sdk/client/index.js";
818
+ import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
819
+ import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
820
+ import { McpError } from "@modelcontextprotocol/sdk/types.js";
821
+ import { createId as createId3 } from "@paralleldrive/cuid2";
822
+ import { jsonSchema } from "ai";
823
+ import { ZodError } from "zod";
824
+ var SkillManager = class {
825
+ _toolDefinitions = [];
826
+ _initialized = false;
827
+ name;
828
+ type;
829
+ skill;
830
+ interactiveSkill;
831
+ expert;
832
+ _mcpClient;
833
+ _params;
834
+ constructor(params) {
835
+ this._params = params;
836
+ this.type = params.type;
837
+ switch (params.type) {
838
+ case "mcp":
839
+ this.name = params.skill.name;
840
+ this.skill = params.skill;
841
+ break;
842
+ case "interactive":
843
+ this.name = params.interactiveSkill.name;
844
+ this.interactiveSkill = params.interactiveSkill;
845
+ break;
846
+ case "delegate":
847
+ this.name = params.expert.name;
848
+ this.expert = params.expert;
849
+ break;
850
+ }
851
+ }
852
+ async init() {
853
+ switch (this._params.type) {
854
+ case "mcp": {
855
+ await this._initMcpSkill(this._params);
856
+ break;
857
+ }
858
+ case "interactive": {
859
+ await this._initInteractiveSkill(this._params);
860
+ break;
861
+ }
862
+ case "delegate": {
863
+ await this._initDelegate(this._params);
864
+ break;
865
+ }
866
+ }
867
+ }
868
+ async _initMcpSkill(params) {
869
+ this._mcpClient = new McpClient({
870
+ name: `${params.skill.name}-mcp-client`,
871
+ version: "1.0.0"
872
+ });
873
+ switch (params.skill.type) {
874
+ case "mcpStdioSkill": {
875
+ if (!params.skill.command) {
876
+ throw new Error(`Skill ${params.skill.name} has no command`);
877
+ }
878
+ const { command, args } = this._getCommandArgs(params.skill);
879
+ console.error(command, args);
880
+ const transport = new StdioClientTransport({
881
+ command,
882
+ args,
883
+ env: Object.fromEntries(
884
+ Object.entries(process.env).filter(([_, value]) => value !== void 0 && value !== "").map(([key, value]) => [key, value])
885
+ )
886
+ });
887
+ await this._mcpClient.connect(transport);
888
+ break;
889
+ }
890
+ case "mcpSseSkill": {
891
+ if (!params.skill.endpoint) {
892
+ throw new Error(`Skill ${params.skill.name} has no endpoint`);
893
+ }
894
+ const transport = new SSEClientTransport(new URL(params.skill.endpoint));
895
+ await this._mcpClient.connect(transport);
896
+ break;
897
+ }
898
+ }
899
+ const { tools } = await this._mcpClient.listTools();
900
+ this._toolDefinitions = tools.map((tool) => ({
901
+ skillName: params.skill.name,
902
+ name: tool.name,
903
+ description: tool.description,
904
+ inputSchema: tool.inputSchema,
905
+ interactive: false
906
+ }));
907
+ this._initialized = true;
908
+ }
909
+ _getCommandArgs(skill) {
910
+ const { name, command, packageName, args } = skill;
911
+ if (!packageName && (!args || args.length === 0)) {
912
+ throw new Error(`Skill ${name} has no packageName or args. Please provide one of them.`);
913
+ }
914
+ if (packageName && args && args.length > 0) {
915
+ throw new Error(
916
+ `Skill ${name} has both packageName and args. Please provide only one of them.`
917
+ );
918
+ }
919
+ let newArgs = args && args.length > 0 ? args : [packageName];
920
+ if (command === "npx" && !newArgs.includes("-y")) {
921
+ newArgs = ["-y", ...newArgs];
922
+ }
923
+ return { command, args: newArgs };
924
+ }
925
+ async _initInteractiveSkill(params) {
926
+ this._toolDefinitions = Object.values(params.interactiveSkill.tools).map((tool) => ({
927
+ skillName: params.interactiveSkill.name,
928
+ name: tool.name,
929
+ description: tool.description,
930
+ inputSchema: JSON.parse(tool.inputJsonSchema),
931
+ interactive: true
932
+ }));
933
+ this._initialized = true;
934
+ }
935
+ async _initDelegate(params) {
936
+ this._toolDefinitions = [
937
+ {
938
+ skillName: params.expert.name,
939
+ name: params.expert.name.split("/").pop() ?? params.expert.name,
940
+ description: params.expert.description,
941
+ inputSchema: {
942
+ type: "object",
943
+ properties: { query: { type: "string" } },
944
+ required: ["query"]
945
+ },
946
+ interactive: false
947
+ }
948
+ ];
949
+ this._initialized = true;
950
+ }
951
+ async close() {
952
+ if (this._mcpClient) {
953
+ await this._mcpClient.close();
954
+ }
955
+ }
956
+ async getToolDefinitions() {
957
+ if (!this._initialized) {
958
+ throw new Error(`${this.name} is not initialized`);
959
+ }
960
+ if (this._params.type === "mcp") {
961
+ const omit = this._params.skill.omit ?? [];
962
+ const pick = this._params.skill.pick ?? [];
963
+ return this._toolDefinitions.filter((tool) => omit.length > 0 ? !omit.includes(tool.name) : true).filter((tool) => pick.length > 0 ? pick.includes(tool.name) : true);
964
+ }
965
+ return this._toolDefinitions;
966
+ }
967
+ async callTool(toolName, input) {
968
+ switch (this._params.type) {
969
+ case "mcp": {
970
+ if (!this._mcpClient) {
971
+ throw new Error(`${this.name} is not initialized`);
972
+ }
973
+ try {
974
+ const result = await this._mcpClient.callTool({
975
+ name: toolName,
976
+ arguments: input
977
+ });
978
+ return this._convertToolResult(result, toolName, input);
979
+ } catch (error) {
980
+ return this._handleToolError(error, toolName);
981
+ }
982
+ }
983
+ case "interactive": {
984
+ return [];
985
+ }
986
+ case "delegate": {
987
+ return [];
988
+ }
989
+ }
990
+ }
991
+ _handleToolError(error, toolName) {
992
+ if (error instanceof McpError) {
993
+ return [
994
+ {
995
+ type: "textPart",
996
+ text: `Error calling tool ${toolName}: ${error.message}`,
997
+ id: createId3()
998
+ }
999
+ ];
1000
+ }
1001
+ if (error instanceof ZodError) {
1002
+ return [{ type: "textPart", text: `Invalid tool call arguments: ${error}`, id: createId3() }];
1003
+ }
1004
+ throw error;
1005
+ }
1006
+ _convertToolResult(result, toolName, input) {
1007
+ if (!result.content || result.content.length === 0) {
1008
+ return [
1009
+ {
1010
+ type: "textPart",
1011
+ text: `Tool ${toolName} returned nothing with arguments: ${JSON.stringify(input)}`,
1012
+ id: createId3()
1013
+ }
1014
+ ];
1015
+ }
1016
+ return result.content.filter((part) => part.type !== "audio" && part.type !== "resource_link").map((part) => this._convertPart(part));
1017
+ }
1018
+ _convertPart(part) {
1019
+ switch (part.type) {
1020
+ case "text":
1021
+ if (!part.text || part.text === "") {
1022
+ return { type: "textPart", text: "Error: No content", id: createId3() };
1023
+ }
1024
+ return { type: "textPart", text: part.text, id: createId3() };
1025
+ case "image":
1026
+ if (!part.data || !part.mimeType) {
1027
+ throw new Error("Image part must have both data and mimeType");
1028
+ }
1029
+ return {
1030
+ type: "imageInlinePart",
1031
+ encodedData: part.data,
1032
+ mimeType: part.mimeType,
1033
+ id: createId3()
1034
+ };
1035
+ case "resource":
1036
+ if (!part.resource) {
1037
+ throw new Error("Resource part must have resource content");
1038
+ }
1039
+ return this._convertResource(part.resource);
1040
+ }
1041
+ }
1042
+ _convertResource(resource) {
1043
+ if (!resource.mimeType) {
1044
+ throw new Error(`Resource ${JSON.stringify(resource)} has no mimeType`);
1045
+ }
1046
+ if (resource.text && typeof resource.text === "string") {
1047
+ return { type: "textPart", text: resource.text, id: createId3() };
1048
+ }
1049
+ if (resource.blob && typeof resource.blob === "string") {
1050
+ return {
1051
+ type: "fileInlinePart",
1052
+ encodedData: resource.blob,
1053
+ mimeType: resource.mimeType,
1054
+ id: createId3()
1055
+ };
1056
+ }
1057
+ throw new Error(`Unsupported resource type: ${JSON.stringify(resource)}`);
1058
+ }
1059
+ };
1060
+ async function getSkillManagers(expert, experts) {
1061
+ const skillManagers = {};
1062
+ const { skills } = expert;
1063
+ if (!skills["@perstack/base"]) {
1064
+ skills["@perstack/base"] = {
1065
+ type: "mcpStdioSkill",
1066
+ name: "@perstack/base",
1067
+ description: "The base skill for Perstack",
1068
+ pick: [],
1069
+ omit: [],
1070
+ command: "npx",
1071
+ args: ["-y", "@perstack/base"],
1072
+ requiredEnv: []
1073
+ };
1074
+ }
1075
+ const mcpSkillManagers = await Promise.all(
1076
+ Object.values(skills).filter((skill) => skill.type === "mcpStdioSkill" || skill.type === "mcpSseSkill").map(async (skill) => {
1077
+ const skillManager = new SkillManager({
1078
+ type: "mcp",
1079
+ skill
1080
+ });
1081
+ await skillManager.init();
1082
+ return skillManager;
1083
+ })
1084
+ );
1085
+ const interactiveSkillManagers = await Promise.all(
1086
+ Object.values(skills).filter((skill) => skill.type === "interactiveSkill").map(async (interactiveSkill) => {
1087
+ const skillManager = new SkillManager({
1088
+ type: "interactive",
1089
+ interactiveSkill
1090
+ });
1091
+ await skillManager.init();
1092
+ return skillManager;
1093
+ })
1094
+ );
1095
+ const delegateSkillManagers = await Promise.all(
1096
+ expert.delegates.map(async (delegateExpertName) => {
1097
+ const delegate = experts[delegateExpertName];
1098
+ const skillManager = new SkillManager({
1099
+ type: "delegate",
1100
+ expert: delegate
1101
+ });
1102
+ await skillManager.init();
1103
+ return skillManager;
1104
+ })
1105
+ );
1106
+ for (const skillManager of mcpSkillManagers) {
1107
+ skillManagers[skillManager.name] = skillManager;
1108
+ }
1109
+ for (const skillManager of interactiveSkillManagers) {
1110
+ skillManagers[skillManager.name] = skillManager;
1111
+ }
1112
+ for (const skillManager of delegateSkillManagers) {
1113
+ skillManagers[skillManager.name] = skillManager;
1114
+ }
1115
+ return skillManagers;
1116
+ }
1117
+ async function closeSkillManagers(skillManagers) {
1118
+ for (const skillManager of Object.values(skillManagers)) {
1119
+ await skillManager.close();
1120
+ }
1121
+ }
1122
+ async function getSkillManagerByToolName(skillManagers, toolName) {
1123
+ for (const skillManager of Object.values(skillManagers)) {
1124
+ const toolDefinitions = await skillManager.getToolDefinitions();
1125
+ for (const toolDefinition of toolDefinitions) {
1126
+ if (toolDefinition.name === toolName) {
1127
+ return skillManager;
1128
+ }
1129
+ }
1130
+ }
1131
+ throw new Error(`Tool ${toolName} not found`);
1132
+ }
1133
+ async function getToolSet(skillManagers) {
1134
+ const tools = {};
1135
+ for (const skillManager of Object.values(skillManagers)) {
1136
+ const toolDefinitions = await skillManager.getToolDefinitions();
1137
+ for (const toolDefinition of toolDefinitions) {
1138
+ tools[toolDefinition.name] = {
1139
+ description: toolDefinition.description,
1140
+ parameters: jsonSchema(toolDefinition.inputSchema)
1141
+ };
1142
+ }
1143
+ }
1144
+ return tools;
1145
+ }
1146
+
1147
+ // src/states/calling-delegate.ts
1148
+ async function callingDelegateLogic({
1149
+ setting,
1150
+ checkpoint,
1151
+ step,
1152
+ skillManagers
1153
+ }) {
1154
+ if (!step?.toolCall) {
1155
+ throw new Error("No tool call found");
1156
+ }
1157
+ const { id, toolName, args } = step.toolCall;
1158
+ const skillManager = await getSkillManagerByToolName(skillManagers, toolName);
1159
+ if (!skillManager || !skillManager.expert) {
1160
+ throw new Error(`Delegation error: skill manager "${toolName}" not found`);
1161
+ }
1162
+ if (!args || !args.query || typeof args.query !== "string") {
1163
+ throw new Error("Delegation error: query is undefined");
1164
+ }
1165
+ return stopRunByDelegate(setting, checkpoint, {
1166
+ checkpoint: {
1167
+ ...checkpoint,
1168
+ status: "stoppedByDelegate",
1169
+ delegateTo: {
1170
+ expert: {
1171
+ key: skillManager.expert.key,
1172
+ name: skillManager.expert.name,
1173
+ version: skillManager.expert.version
1174
+ },
1175
+ toolCallId: id,
1176
+ toolName,
1177
+ query: args.query
1178
+ }
1179
+ },
1180
+ step: {
1181
+ ...step,
1182
+ finishedAt: (/* @__PURE__ */ new Date()).getTime()
1183
+ }
1184
+ });
1185
+ }
1186
+
1187
+ // src/states/calling-interactive-tool.ts
1188
+ async function callingInteractiveToolLogic({
1189
+ setting,
1190
+ checkpoint,
1191
+ step
1192
+ }) {
1193
+ return stopRunByInteractiveTool(setting, checkpoint, {
1194
+ checkpoint: {
1195
+ ...checkpoint,
1196
+ status: "stoppedByInteractiveTool"
1197
+ },
1198
+ step: {
1199
+ ...step,
1200
+ finishedAt: (/* @__PURE__ */ new Date()).getTime()
1201
+ }
1202
+ });
1203
+ }
1204
+
1205
+ // src/states/calling-tool.ts
1206
+ async function callingToolLogic({
1207
+ setting,
1208
+ checkpoint,
1209
+ step,
1210
+ skillManagers
1211
+ }) {
1212
+ if (!step?.toolCall) {
1213
+ throw new Error("No tool call found");
1214
+ }
1215
+ const { id, skillName, toolName, args } = step.toolCall;
1216
+ const skillManager = await getSkillManagerByToolName(skillManagers, toolName);
1217
+ if (skillManager.type !== "mcp") {
1218
+ throw new Error(`Incorrect SkillType, required MCP, got ${skillManager.type}`);
1219
+ }
1220
+ const result = await skillManager.callTool(toolName, args);
1221
+ const toolResult = { id, skillName, toolName, result };
1222
+ if (skillName === "@perstack/base") {
1223
+ if (toolName === "think") {
1224
+ return resolveThought(setting, checkpoint, { toolResult });
1225
+ }
1226
+ if (toolName === "attemptCompletion") {
1227
+ return attemptCompletion(setting, checkpoint, { toolResult });
1228
+ }
1229
+ if (toolName === "readPdfFile") {
1230
+ return resolvePdfFile(setting, checkpoint, { toolResult });
1231
+ }
1232
+ if (toolName === "readImageFile") {
1233
+ return resolveImageFile(setting, checkpoint, { toolResult });
1234
+ }
1235
+ }
1236
+ return resolveToolResult(setting, checkpoint, { toolResult });
1237
+ }
1238
+
1239
+ // src/states/finishing-step.ts
1240
+ import { createId as createId4 } from "@paralleldrive/cuid2";
1241
+ async function finishingStepLogic({
1242
+ setting,
1243
+ checkpoint,
1244
+ step
1245
+ }) {
1246
+ if (setting.maxSteps !== void 0 && checkpoint.stepNumber > setting.maxSteps) {
1247
+ return stopRunByExceededMaxSteps(setting, checkpoint, {
1248
+ checkpoint: {
1249
+ ...checkpoint,
1250
+ status: "stoppedByExceededMaxSteps"
1251
+ },
1252
+ step: {
1253
+ ...step,
1254
+ finishedAt: (/* @__PURE__ */ new Date()).getTime()
1255
+ }
1256
+ });
1257
+ }
1258
+ return continueToNextStep(setting, checkpoint, {
1259
+ checkpoint: {
1260
+ ...checkpoint
1261
+ },
1262
+ step: {
1263
+ ...step,
1264
+ finishedAt: (/* @__PURE__ */ new Date()).getTime()
1265
+ },
1266
+ nextCheckpoint: {
1267
+ ...checkpoint,
1268
+ id: createId4(),
1269
+ stepNumber: checkpoint.stepNumber + 1
1270
+ }
1271
+ });
1272
+ }
1273
+
1274
+ // src/states/generating-run-result.ts
1275
+ import { generateText } from "ai";
1276
+
1277
+ // src/messages/message.ts
1278
+ import { createId as createId5 } from "@paralleldrive/cuid2";
1279
+ import { dedent } from "ts-dedent";
1280
+ function createUserMessage(contents) {
1281
+ return {
1282
+ type: "userMessage",
1283
+ contents: contents.map((part) => ({
1284
+ ...part,
1285
+ id: createId5()
1286
+ })),
1287
+ id: createId5()
1288
+ };
1289
+ }
1290
+ function createExpertMessage(contents) {
1291
+ return {
1292
+ type: "expertMessage",
1293
+ contents: contents.map((part) => ({
1294
+ ...part,
1295
+ id: createId5()
1296
+ })),
1297
+ id: createId5()
1298
+ };
1299
+ }
1300
+ function createToolMessage(contents) {
1301
+ return {
1302
+ type: "toolMessage",
1303
+ contents: contents.map((part) => ({
1304
+ ...part,
1305
+ contents: part.contents.map((part2) => ({
1306
+ ...part2,
1307
+ id: createId5()
1308
+ })),
1309
+ id: createId5()
1310
+ })),
1311
+ id: createId5()
1312
+ };
1313
+ }
1314
+ function messageToCoreMessage(message) {
1315
+ switch (message.type) {
1316
+ case "instructionMessage":
1317
+ return {
1318
+ role: "system",
1319
+ content: instructionContentsToCoreContent(message.contents),
1320
+ providerOptions: message.cache ? {
1321
+ anthropic: { cacheControl: { type: "ephemeral" } }
1322
+ } : void 0
1323
+ };
1324
+ case "userMessage":
1325
+ return {
1326
+ role: "user",
1327
+ content: userContentsToCoreContent(message.contents),
1328
+ providerOptions: message.cache ? {
1329
+ anthropic: { cacheControl: { type: "ephemeral" } }
1330
+ } : void 0
1331
+ };
1332
+ case "expertMessage":
1333
+ return {
1334
+ role: "assistant",
1335
+ content: expertContentsToCoreContent(message.contents),
1336
+ providerOptions: message.cache ? {
1337
+ anthropic: { cacheControl: { type: "ephemeral" } }
1338
+ } : void 0
1339
+ };
1340
+ case "toolMessage":
1341
+ return {
1342
+ role: "tool",
1343
+ content: toolContentsToCoreContent(message.contents),
1344
+ providerOptions: message.cache ? {
1345
+ anthropic: { cacheControl: { type: "ephemeral" } }
1346
+ } : void 0
1347
+ };
1348
+ }
1349
+ }
1350
+ function instructionContentsToCoreContent(contents) {
1351
+ return contents.reduce((acc, part) => {
1352
+ return dedent`
1353
+ ${acc}
1354
+ ${part.text}
1355
+ `.trim();
1356
+ }, "");
1357
+ }
1358
+ function userContentsToCoreContent(contents) {
1359
+ return contents.map((part) => {
1360
+ switch (part.type) {
1361
+ case "textPart":
1362
+ return textPartToCoreTextPart(part);
1363
+ case "imageUrlPart":
1364
+ return imageUrlPartToCoreImagePart(part);
1365
+ case "imageInlinePart":
1366
+ return imageInlinePartToCoreImagePart(part);
1367
+ case "imageBinaryPart":
1368
+ return imageBinaryPartToCoreImagePart(part);
1369
+ case "fileUrlPart":
1370
+ return fileUrlPartToCoreFilePart(part);
1371
+ case "fileInlinePart":
1372
+ return fileInlinePartToCoreFilePart(part);
1373
+ case "fileBinaryPart":
1374
+ return fileBinaryPartToCoreFilePart(part);
1375
+ }
1376
+ });
1377
+ }
1378
+ function expertContentsToCoreContent(contents) {
1379
+ return contents.map((part) => {
1380
+ switch (part.type) {
1381
+ case "textPart":
1382
+ return textPartToCoreTextPart(part);
1383
+ case "toolCallPart":
1384
+ return toolCallPartToCoreToolCallPart(part);
1385
+ }
1386
+ });
1387
+ }
1388
+ function toolContentsToCoreContent(contents) {
1389
+ return contents.map((part) => {
1390
+ switch (part.type) {
1391
+ case "toolResultPart":
1392
+ return toolResultPartToCoreToolResultPart(part);
1393
+ }
1394
+ });
1395
+ }
1396
+ function textPartToCoreTextPart(part) {
1397
+ return {
1398
+ type: "text",
1399
+ text: part.text
1400
+ };
1401
+ }
1402
+ function imageUrlPartToCoreImagePart(part) {
1403
+ return {
1404
+ type: "image",
1405
+ image: part.url,
1406
+ mimeType: part.mimeType
1407
+ };
1408
+ }
1409
+ function imageInlinePartToCoreImagePart(part) {
1410
+ return {
1411
+ type: "image",
1412
+ image: part.encodedData,
1413
+ mimeType: part.mimeType
1414
+ };
1415
+ }
1416
+ function imageBinaryPartToCoreImagePart(part) {
1417
+ return {
1418
+ type: "image",
1419
+ image: part.data,
1420
+ mimeType: part.mimeType
1421
+ };
1422
+ }
1423
+ function fileUrlPartToCoreFilePart(part) {
1424
+ return {
1425
+ type: "file",
1426
+ data: part.url,
1427
+ mimeType: part.mimeType
1428
+ };
1429
+ }
1430
+ function fileInlinePartToCoreFilePart(part) {
1431
+ return {
1432
+ type: "file",
1433
+ data: part.encodedData,
1434
+ mimeType: part.mimeType
1435
+ };
1436
+ }
1437
+ function fileBinaryPartToCoreFilePart(part) {
1438
+ return {
1439
+ type: "file",
1440
+ data: part.data,
1441
+ mimeType: part.mimeType
1442
+ };
1443
+ }
1444
+ function toolCallPartToCoreToolCallPart(part) {
1445
+ return {
1446
+ type: "tool-call",
1447
+ toolCallId: part.toolCallId,
1448
+ toolName: part.toolName,
1449
+ args: part.args
1450
+ };
1451
+ }
1452
+ function toolResultPartToCoreToolResultPart(part) {
1453
+ return {
1454
+ type: "tool-result",
1455
+ toolCallId: part.toolCallId,
1456
+ toolName: part.toolName,
1457
+ result: part.contents,
1458
+ experimental_content: part.contents.map((part2) => {
1459
+ switch (part2.type) {
1460
+ case "textPart":
1461
+ return {
1462
+ type: "text",
1463
+ text: part2.text
1464
+ };
1465
+ case "imageInlinePart":
1466
+ return {
1467
+ type: "image",
1468
+ data: part2.encodedData,
1469
+ mimeType: part2.mimeType
1470
+ };
1471
+ }
1472
+ }),
1473
+ isError: part.isError
1474
+ };
1475
+ }
1476
+
1477
+ // src/usage.ts
1478
+ function createEmptyUsage() {
1479
+ return {
1480
+ promptTokens: 0,
1481
+ completionTokens: 0,
1482
+ totalTokens: 0,
1483
+ cacheCreationInputTokens: 0,
1484
+ cacheReadInputTokens: 0
1485
+ };
1486
+ }
1487
+ function usageFromGenerateTextResult(result) {
1488
+ let cacheCreationInputTokens = 0;
1489
+ let cacheReadInputTokens = 0;
1490
+ if (result.providerMetadata?.anthropic) {
1491
+ const anthropicMetadata = result.providerMetadata.anthropic;
1492
+ cacheCreationInputTokens = anthropicMetadata.cacheCreationInputTokens || 0;
1493
+ cacheReadInputTokens = anthropicMetadata.cacheReadInputTokens || 0;
1494
+ }
1495
+ return {
1496
+ promptTokens: result.usage.promptTokens,
1497
+ completionTokens: result.usage.completionTokens,
1498
+ totalTokens: result.usage.totalTokens,
1499
+ cacheCreationInputTokens,
1500
+ cacheReadInputTokens
1501
+ };
1502
+ }
1503
+ function sumUsage(a, b) {
1504
+ return {
1505
+ promptTokens: a.promptTokens + b.promptTokens,
1506
+ completionTokens: a.completionTokens + b.completionTokens,
1507
+ totalTokens: a.totalTokens + b.totalTokens,
1508
+ cacheCreationInputTokens: a.cacheCreationInputTokens + b.cacheCreationInputTokens,
1509
+ cacheReadInputTokens: a.cacheReadInputTokens + b.cacheReadInputTokens
1510
+ };
1511
+ }
1512
+
1513
+ // src/states/generating-run-result.ts
1514
+ async function generatingRunResultLogic({
1515
+ setting,
1516
+ checkpoint,
1517
+ step
1518
+ }) {
1519
+ if (!step?.toolCall || !step?.toolResult) {
1520
+ throw new Error("No tool call or tool result found");
1521
+ }
1522
+ const { id, toolName } = step.toolCall;
1523
+ const { result } = step.toolResult;
1524
+ const toolMessage = createToolMessage([
1525
+ {
1526
+ type: "toolResultPart",
1527
+ toolCallId: id,
1528
+ toolName,
1529
+ contents: result.filter(
1530
+ (part) => part.type === "textPart" || part.type === "imageInlinePart"
1531
+ )
1532
+ }
1533
+ ]);
1534
+ const model = getModel(setting.model);
1535
+ const { messages } = checkpoint;
1536
+ const generationResult = await generateText({
1537
+ model,
1538
+ messages: [...messages, toolMessage].map(messageToCoreMessage),
1539
+ temperature: setting.temperature,
1540
+ maxRetries: setting.maxRetries
1541
+ });
1542
+ const usage = usageFromGenerateTextResult(generationResult);
1543
+ const { text } = generationResult;
1544
+ const newMessages = [toolMessage, createExpertMessage(text ? [{ type: "textPart", text }] : [])];
1545
+ return completeRun(setting, checkpoint, {
1546
+ checkpoint: {
1547
+ ...checkpoint,
1548
+ messages: [...messages, ...newMessages],
1549
+ usage: sumUsage(checkpoint.usage, usage),
1550
+ status: "completed"
1551
+ },
1552
+ step: {
1553
+ ...step,
1554
+ newMessages: [...step.newMessages, ...newMessages],
1555
+ finishedAt: (/* @__PURE__ */ new Date()).getTime(),
1556
+ usage: sumUsage(step.usage, usage)
1557
+ },
1558
+ text,
1559
+ usage
1560
+ });
1561
+ }
1562
+
1563
+ // src/states/generating-tool-call.ts
1564
+ import { generateText as generateText2 } from "ai";
1565
+ async function generatingToolCallLogic({
1566
+ setting,
1567
+ checkpoint,
1568
+ skillManagers
1569
+ }) {
1570
+ const { messages } = checkpoint;
1571
+ const model = getModel(setting.model);
1572
+ const result = await generateText2({
1573
+ model,
1574
+ messages: messages.map(messageToCoreMessage),
1575
+ temperature: setting.temperature,
1576
+ maxRetries: setting.maxRetries,
1577
+ tools: await getToolSet(skillManagers),
1578
+ toolChoice: "required"
1579
+ });
1580
+ const usage = usageFromGenerateTextResult(result);
1581
+ const { text, toolCalls, finishReason } = result;
1582
+ const toolCall = toolCalls[0];
1583
+ if (!toolCall) {
1584
+ return retry(setting, checkpoint, {
1585
+ newMessages: [
1586
+ createExpertMessage(text ? [{ type: "textPart", text }] : []),
1587
+ createUserMessage([
1588
+ {
1589
+ type: "textPart",
1590
+ text: "You must generate a tool call. Try again."
1591
+ }
1592
+ ])
1593
+ ],
1594
+ usage
1595
+ });
1596
+ }
1597
+ if (finishReason !== "tool-calls") {
1598
+ switch (finishReason) {
1599
+ case "length": {
1600
+ return retry(setting, checkpoint, {
1601
+ newMessages: [
1602
+ createExpertMessage([
1603
+ {
1604
+ type: "toolCallPart",
1605
+ toolCallId: toolCall.toolCallId,
1606
+ toolName: toolCall.toolName,
1607
+ args: toolCall.args
1608
+ }
1609
+ ]),
1610
+ createToolMessage([
1611
+ {
1612
+ type: "toolResultPart",
1613
+ toolCallId: toolCall.toolCallId,
1614
+ toolName: toolCall.toolName,
1615
+ contents: [{ type: "textPart", text: "Error: Generation length exceeded" }]
1616
+ }
1617
+ ])
1618
+ ],
1619
+ usage
1620
+ });
1621
+ }
1622
+ default:
1623
+ throw new Error(`Unexpected finish reason: ${finishReason}`);
1624
+ }
1625
+ }
1626
+ const contents = [
1627
+ {
1628
+ type: "toolCallPart",
1629
+ toolCallId: toolCall.toolCallId,
1630
+ toolName: toolCall.toolName,
1631
+ args: toolCall.args
1632
+ }
1633
+ ];
1634
+ if (text) {
1635
+ contents.push({
1636
+ type: "textPart",
1637
+ text
1638
+ });
1639
+ }
1640
+ const skillManager = await getSkillManagerByToolName(skillManagers, toolCall.toolName);
1641
+ const eventPayload = {
1642
+ newMessage: createExpertMessage(contents),
1643
+ toolCall: {
1644
+ id: toolCall.toolCallId,
1645
+ skillName: skillManager.name,
1646
+ toolName: toolCall.toolName,
1647
+ args: toolCall.args
1648
+ },
1649
+ usage
1650
+ };
1651
+ switch (skillManager.type) {
1652
+ case "mcp":
1653
+ return callTool(setting, checkpoint, eventPayload);
1654
+ case "interactive":
1655
+ return callInteractiveTool(setting, checkpoint, eventPayload);
1656
+ case "delegate":
1657
+ return callDelegate(setting, checkpoint, eventPayload);
1658
+ }
1659
+ }
1660
+
1661
+ // src/messages/instruction-message.ts
1662
+ import { createId as createId6 } from "@paralleldrive/cuid2";
1663
+ import { dedent as dedent2 } from "ts-dedent";
1664
+ var metaInstruction = dedent2`
5
1665
  IMPORTANT:
6
1666
  You are NOT an "interactive" AI agent.
7
1667
  From the start of the agent loop until the completion of the task,
@@ -41,40 +1701,925 @@ import {existsSync}from'fs';import {readFile,writeFile,mkdir,readdir}from'fs/pro
41
1701
  - 専門家である以上、ユーザーが期待する以上の品質のアウトプットを行ってください
42
1702
 
43
1703
  Environment information:
44
- - Current time is ${new Date().toISOString()}
1704
+ - Current time is ${(/* @__PURE__ */ new Date()).toISOString()}
45
1705
  - Current working directory is ${process.cwd()}
46
- `;function Xe(e,t){let o=dedent`
1706
+ `;
1707
+ function createInstructionMessage(expert, experts) {
1708
+ const instruction = dedent2`
47
1709
  You are Perstack, an AI expert that tackles tasks requested by users by utilizing all available tools.
48
1710
 
49
1711
  (The following information describes your nature and role as an AI, the mechanisms of the AI system, and other meta-cognitive aspects.)
50
1712
 
51
- ${po}
1713
+ ${metaInstruction}
52
1714
 
53
1715
  ---
54
1716
  (The following describes the objective, steps, rules, etc. regarding your expert task.)
55
1717
 
56
- ${e.instruction}
1718
+ ${expert.instruction}
57
1719
 
58
1720
  ---
59
1721
  (The following is an overview of each skill and the rules for calling tools.)
60
1722
 
61
- ${co(e)}
1723
+ ${getSkillRules(expert)}
62
1724
 
63
1725
  ---
64
1726
  (The following is an overview of each delegate expert and the rules for calling tools.)
65
1727
 
66
1728
  You can delegate tasks to the following experts by calling delegate expert name as a tool:
67
1729
 
68
- ${mo(e,t)}
69
- `;return {type:"instructionMessage",contents:[{id:createId(),type:"textPart",text:o}],id:createId(),cache:true}}function co(e){return Object.values(e.skills).reduce((t,o)=>o.rule?dedent`
70
- ${t}
1730
+ ${getDelegateRules(expert, experts)}
1731
+ `;
1732
+ return {
1733
+ type: "instructionMessage",
1734
+ contents: [
1735
+ {
1736
+ id: createId6(),
1737
+ type: "textPart",
1738
+ text: instruction
1739
+ }
1740
+ ],
1741
+ id: createId6(),
1742
+ cache: true
1743
+ };
1744
+ }
1745
+ function getSkillRules(expert) {
1746
+ return Object.values(expert.skills).reduce((acc, skill) => {
1747
+ if (!skill.rule) {
1748
+ return acc;
1749
+ }
1750
+ return dedent2`
1751
+ ${acc}
1752
+
1753
+ "${skill.name}" skill rules:
1754
+ ${skill.rule}
1755
+ `.trim();
1756
+ }, "");
1757
+ }
1758
+ function getDelegateRules(expert, experts) {
1759
+ return expert.delegates.reduce((acc, delegateExpertName) => {
1760
+ const delegate = experts[delegateExpertName];
1761
+ if (!delegate) {
1762
+ return acc;
1763
+ }
1764
+ return dedent2`
1765
+ ${acc}
1766
+
1767
+ About "${delegate.name}":
1768
+ ${delegate.description}
1769
+ `.trim();
1770
+ }, "");
1771
+ }
1772
+
1773
+ // src/states/init.ts
1774
+ async function initLogic({
1775
+ setting,
1776
+ checkpoint
1777
+ }) {
1778
+ const { expertKey, experts } = setting;
1779
+ const expert = experts[expertKey];
1780
+ switch (checkpoint.status) {
1781
+ case "init":
1782
+ return startRun(setting, checkpoint, {
1783
+ initialCheckpoint: checkpoint,
1784
+ inputMessages: [createInstructionMessage(expert, experts), getInputMessage(setting.input)]
1785
+ });
1786
+ default:
1787
+ return startRun(setting, checkpoint, {
1788
+ initialCheckpoint: checkpoint,
1789
+ inputMessages: [getInputMessage(setting.input)]
1790
+ });
1791
+ }
1792
+ }
1793
+ function getInputMessage(input) {
1794
+ if (input.text) {
1795
+ return createUserMessage([{ type: "textPart", text: input.text }]);
1796
+ }
1797
+ if (input.interactiveToolCallResult) {
1798
+ return createToolMessage([
1799
+ {
1800
+ type: "toolResultPart",
1801
+ toolCallId: input.interactiveToolCallResult.toolCallId,
1802
+ toolName: input.interactiveToolCallResult.toolName,
1803
+ contents: [{ type: "textPart", text: input.interactiveToolCallResult.text }]
1804
+ }
1805
+ ]);
1806
+ }
1807
+ throw new Error("Input message is undefined");
1808
+ }
1809
+
1810
+ // src/states/preparing-for-step.ts
1811
+ async function preparingForStepLogic({
1812
+ setting,
1813
+ checkpoint
1814
+ }) {
1815
+ return startGeneration(setting, checkpoint, {
1816
+ messages: checkpoint.messages
1817
+ });
1818
+ }
1819
+
1820
+ // src/states/resolving-image-file.ts
1821
+ import { readFile as readFile2 } from "fs/promises";
1822
+ async function resolvingImageFileLogic({
1823
+ setting,
1824
+ checkpoint,
1825
+ step
1826
+ }) {
1827
+ if (!step?.toolCall || !step?.toolResult) {
1828
+ throw new Error("No tool call or tool result found");
1829
+ }
1830
+ const { id, toolName } = step.toolCall;
1831
+ const { result } = step.toolResult;
1832
+ const textParts = result.filter((part) => part.type === "textPart");
1833
+ const files = [];
1834
+ for (const textPart of textParts) {
1835
+ let imageInfo;
1836
+ try {
1837
+ imageInfo = JSON.parse(textPart.text);
1838
+ } catch {
1839
+ files.push({
1840
+ type: "textPart",
1841
+ text: textPart.text
1842
+ });
1843
+ continue;
1844
+ }
1845
+ const { path: path2, mimeType, size } = imageInfo;
1846
+ const file = await readFile2(path2).then((buffer) => ({
1847
+ encodedData: buffer.toString("base64"),
1848
+ mimeType,
1849
+ size
1850
+ }));
1851
+ files.push({
1852
+ type: "imageInlinePart",
1853
+ encodedData: file.encodedData,
1854
+ mimeType: file.mimeType
1855
+ });
1856
+ }
1857
+ return finishToolCall(setting, checkpoint, {
1858
+ newMessages: [
1859
+ createToolMessage([
1860
+ {
1861
+ type: "toolResultPart",
1862
+ toolCallId: id,
1863
+ toolName,
1864
+ contents: files
1865
+ }
1866
+ ])
1867
+ ]
1868
+ });
1869
+ }
1870
+
1871
+ // src/states/resolving-pdf-file.ts
1872
+ import { readFile as readFile3 } from "fs/promises";
1873
+ async function resolvingPdfFileLogic({
1874
+ setting,
1875
+ checkpoint,
1876
+ step
1877
+ }) {
1878
+ if (!step?.toolCall || !step?.toolResult) {
1879
+ throw new Error("No tool call or tool result found");
1880
+ }
1881
+ const { id, toolName } = step.toolCall;
1882
+ const { result } = step.toolResult;
1883
+ const textParts = result.filter((part) => part.type === "textPart");
1884
+ const files = [];
1885
+ for (const textPart of textParts) {
1886
+ let pdfInfo;
1887
+ try {
1888
+ pdfInfo = JSON.parse(textPart.text);
1889
+ } catch {
1890
+ files.push({
1891
+ type: "textPart",
1892
+ text: textPart.text
1893
+ });
1894
+ continue;
1895
+ }
1896
+ const { path: path2, mimeType, size } = pdfInfo;
1897
+ const file = await readFile3(path2).then((buffer) => ({
1898
+ encodedData: buffer.toString("base64"),
1899
+ mimeType,
1900
+ size
1901
+ }));
1902
+ files.push({
1903
+ type: "fileInlinePart",
1904
+ encodedData: file.encodedData,
1905
+ mimeType: file.mimeType
1906
+ });
1907
+ }
1908
+ return finishToolCall(setting, checkpoint, {
1909
+ newMessages: [
1910
+ createToolMessage([
1911
+ {
1912
+ type: "toolResultPart",
1913
+ toolCallId: id,
1914
+ toolName,
1915
+ contents: [
1916
+ {
1917
+ type: "textPart",
1918
+ text: "User uploads PDF file as follows."
1919
+ }
1920
+ ]
1921
+ }
1922
+ ]),
1923
+ createUserMessage(files)
1924
+ ]
1925
+ });
1926
+ }
1927
+
1928
+ // src/states/resolving-tool-result.ts
1929
+ async function resolvingToolResultLogic({
1930
+ setting,
1931
+ checkpoint,
1932
+ step
1933
+ }) {
1934
+ if (!step?.toolCall || !step?.toolResult) {
1935
+ throw new Error("No tool call or tool result found");
1936
+ }
1937
+ const { id, toolName } = step.toolCall;
1938
+ const { result } = step.toolResult;
1939
+ return finishToolCall(setting, checkpoint, {
1940
+ newMessages: [
1941
+ createToolMessage([
1942
+ {
1943
+ type: "toolResultPart",
1944
+ toolCallId: id,
1945
+ toolName,
1946
+ contents: result.filter(
1947
+ (part) => part.type === "textPart" || part.type === "imageInlinePart"
1948
+ )
1949
+ }
1950
+ ])
1951
+ ]
1952
+ });
1953
+ }
1954
+
1955
+ // src/states/resolving-thought.ts
1956
+ async function resolvingThoughtLogic(context) {
1957
+ return resolvingToolResultLogic(context);
1958
+ }
1959
+
1960
+ // src/runtime-state-machine.ts
1961
+ var runtimeStateMachine = setup({
1962
+ types: {
1963
+ input: {},
1964
+ context: {},
1965
+ events: {}
1966
+ }
1967
+ }).createMachine({
1968
+ /** @xstate-layout N4IgpgJg5mDOIC5QCUCuA7AdASXQSwBcBiWAgQwCcC10BtABgF1FQAHAe1kL3fRZAAeiAKz0AzJgDsAJgAsksZNlixs+gDZZAGhABPRIszCAjGIAcY4crPHhJyQF8HOmpgAKFMK0p50UAGLsFADKBF4k5FQA4mDoYBRkBDx0TPwcXEm8-EIIZmaymPRK8saSopL00tI6+gjq9JjSltLG9HnqZkqdTi4YmDFxCUl+ACrs7AA2AMJkExNEngQUugzMSCDp3FnrOcam0pgAnHbS9GeSZsIq6jWIh2KHUsYd9MbSwl2S6j0grgPxiV8UDGkxmcyIAGNZhMQRNVmlOFs+DtEPt1Jg3odpGVbFcrLcENIzOjbGYipIZMpnmYfn9YgDhsDxtNoZDobgwgkIUkAG5gWHw9abTLI0C7ImSTDqYTY2S45TCCwE54HUr1WRXSqHcRVWl9f5DIGwsHzKFzAAiYAmYCgiTAgrYiJF2VRYnoj1ehwskkOZTEz2EBMMJnMFnezxUF2+zl+fRNRuZCzgkz5sOQcFQEwIDo2TuSLoQpWJUvowl9Flk0sqBLlZik2Mkpjyan90d6WHjo0TnlgKf5AAt2KgoP3s6khXntmLUT6JL6PkoFJX1MZtHoRKIpdrK3sqorpG3Yx3oQnJknexM+W4IAAzfx4a054X5lGFn2PMTYlSyWQH32WAl1DKKV1Q6L1V1EWQ9WPOZT3mHs+2wABbMgYHvR9x0dDIX2nN8zEeOVjGORsmgsMQCTJYRMGJORwP9MwDxpGNXE7Jkz0SMIkNYAgpnYLjrRFJ9J1FQQZzJTBPxUfDDjlN1OgJIkSUVUtDlXCpsUPVx0wvHk4O0zNiBvXw8FgftjWhITsKnUTCU-SU92JMlfSaGtjDrGQKSbfJxGeaDMG0lMjUHYdRyIIz8FM8y5kspECyabFGneRz3RkN011qOwGnUbcVzeJKDz8gLLyBa87wfMAwuMyLmRNGLnVfeL7KSl5nPI9c6mA9RQPwmwNVLQrk2KvxkNQsB0Iq8KTLMmqLMw3MrJEnJGsSxUWtSgkfSU-JDmIqNKj8g1AT8Gh9KzSE+NYASwBoOqcJs+K61sDo5SKBifwU4tSRUtTKi+KDmLjE9hvQTkyG5PBU0TUh2FYGgACFdA5AFwchyZbus3YyklYRst-DUlDEaU2tqFUMS+NyPmlPZDiAvzWMta1bTCCIYfh3QGZtO10cWmcLiOQnG3qHHiSDbGvM-Ex1EjYk-PvCL+yBUJwghXhhlQfl2AAOTAAQCCV1hubiqxjCMRUZXMGSvVUZV6A1LcuorDp8I0WWqoVvx9ZZ2GMARgBRAQITASBIAAWTIAR9dgQ2Gs0Ki8nyK4bCuDVRZNzRwxse4GK6pwY3QdgIDgfgaARBaCxUBosU0cw5TLUiCQAWlkR4nPdbVCeyld-vbHB8AIUvYtfRQ6yr6xa6xcwCTLaiadj1dKxk1phD8jwvB8PxAhCMJWAH+rcKAyuyVaa5Wi+KeW9njV59xpeDvpQ0u1BaFd7u3Y2keDpO7LW2FDLc+Z6AnsPEO4ZYAxghMOCL8MaojsJKYi8cHZ5C9EGNoRg1CdH3GcZeYD-KDV0o-CYp1+4TjLg1cQkp-SfjDE9Ew1R2o-hNnsUs1MfR-UuANHSQUhwjmIVhQeuFTg-ilF8GUblTgKDoRlBQhQJEaiJMnfCHDAp+FKuNKBPNCSlgaOIeQttWxS0DO1bKdY9HvH9D+FotMcFFXwVAEaaFyrqLirbBo1M7KvFUDJCiRJGgalUM3LEMk5R30GEdKAJ0MxZicWQlQEklAyillWVoZgUF1isG0MoDEsF0yBnYkGyNeQa0mNE3CtgiIYnEEBToFwvS+mVPkU20l8JWG1OIHJsE-AcyZmAEpNlbBqEwLo7yVRbY3HatPfCXUOgfCsGSTQmk+hyymorbevSloykeFYCkrxfqrmJiIaRRQ7JbP8Q8PyoQYasEgGsxA2JWiNB-jjdQTRqb1IkP6OwRF8KMSAbnBwQA */
1969
+ id: "Run",
1970
+ initial: "Init",
1971
+ context: ({ input }) => ({
1972
+ setting: input.setting,
1973
+ checkpoint: input.initialCheckpoint,
1974
+ eventListener: input.eventListener,
1975
+ skillManagers: input.skillManagers
1976
+ }),
1977
+ states: {
1978
+ Init: {
1979
+ on: {
1980
+ startRun: {
1981
+ target: "PreparingForStep",
1982
+ actions: assign({
1983
+ checkpoint: ({ event }) => ({
1984
+ ...event.initialCheckpoint,
1985
+ messages: [...event.initialCheckpoint.messages, ...event.inputMessages],
1986
+ status: "proceeding"
1987
+ })
1988
+ })
1989
+ }
1990
+ }
1991
+ },
1992
+ PreparingForStep: {
1993
+ on: {
1994
+ startGeneration: {
1995
+ target: "GeneratingToolCall",
1996
+ actions: assign({
1997
+ step: ({ context, event }) => ({
1998
+ stepNumber: context.checkpoint.stepNumber,
1999
+ newMessages: [],
2000
+ usage: createEmptyUsage(),
2001
+ startedAt: event.timestamp
2002
+ })
2003
+ })
2004
+ }
2005
+ }
2006
+ },
2007
+ GeneratingToolCall: {
2008
+ on: {
2009
+ retry: {
2010
+ target: "FinishingStep",
2011
+ actions: assign({
2012
+ checkpoint: ({ context, event }) => ({
2013
+ ...context.checkpoint,
2014
+ messages: [...context.checkpoint.messages, ...event.newMessages],
2015
+ usage: sumUsage(context.checkpoint.usage, event.usage)
2016
+ }),
2017
+ step: ({ context, event }) => ({
2018
+ ...context.step,
2019
+ newMessages: event.newMessages,
2020
+ usage: sumUsage(context.step.usage, event.usage)
2021
+ })
2022
+ })
2023
+ },
2024
+ callTool: {
2025
+ target: "CallingTool",
2026
+ actions: assign({
2027
+ checkpoint: ({ context, event }) => ({
2028
+ ...context.checkpoint,
2029
+ messages: [...context.checkpoint.messages, event.newMessage],
2030
+ usage: sumUsage(context.checkpoint.usage, event.usage)
2031
+ }),
2032
+ step: ({ context, event }) => ({
2033
+ ...context.step,
2034
+ newMessages: [event.newMessage],
2035
+ toolCall: event.toolCall,
2036
+ usage: sumUsage(context.step.usage, event.usage)
2037
+ })
2038
+ })
2039
+ },
2040
+ callInteractiveTool: {
2041
+ target: "CallingInteractiveTool",
2042
+ actions: assign({
2043
+ checkpoint: ({ context, event }) => ({
2044
+ ...context.checkpoint,
2045
+ messages: [...context.checkpoint.messages, event.newMessage],
2046
+ usage: sumUsage(context.checkpoint.usage, event.usage)
2047
+ }),
2048
+ step: ({ context, event }) => ({
2049
+ ...context.step,
2050
+ newMessages: [event.newMessage],
2051
+ toolCall: event.toolCall,
2052
+ usage: sumUsage(context.step.usage, event.usage)
2053
+ })
2054
+ })
2055
+ },
2056
+ callDelegate: {
2057
+ target: "CallingDelegate",
2058
+ actions: assign({
2059
+ checkpoint: ({ context, event }) => ({
2060
+ ...context.checkpoint,
2061
+ messages: [...context.checkpoint.messages, event.newMessage],
2062
+ usage: sumUsage(context.checkpoint.usage, event.usage)
2063
+ }),
2064
+ step: ({ context, event }) => ({
2065
+ ...context.step,
2066
+ newMessages: [event.newMessage],
2067
+ toolCall: event.toolCall,
2068
+ usage: sumUsage(context.step.usage, event.usage)
2069
+ })
2070
+ })
2071
+ }
2072
+ }
2073
+ },
2074
+ CallingTool: {
2075
+ on: {
2076
+ resolveToolResult: {
2077
+ target: "ResolvingToolResult",
2078
+ actions: assign({
2079
+ step: ({ context, event }) => ({
2080
+ ...context.step,
2081
+ toolResult: event.toolResult
2082
+ })
2083
+ })
2084
+ },
2085
+ resolveThought: {
2086
+ target: "ResolvingThought",
2087
+ actions: assign({
2088
+ step: ({ context, event }) => ({
2089
+ ...context.step,
2090
+ toolResult: event.toolResult
2091
+ })
2092
+ })
2093
+ },
2094
+ resolvePdfFile: {
2095
+ target: "ResolvingPdfFile",
2096
+ actions: assign({
2097
+ step: ({ context, event }) => ({
2098
+ ...context.step,
2099
+ toolResult: event.toolResult
2100
+ })
2101
+ })
2102
+ },
2103
+ resolveImageFile: {
2104
+ target: "ResolvingImageFile",
2105
+ actions: assign({
2106
+ step: ({ context, event }) => ({
2107
+ ...context.step,
2108
+ toolResult: event.toolResult
2109
+ })
2110
+ })
2111
+ },
2112
+ attemptCompletion: {
2113
+ target: "GeneratingRunResult",
2114
+ actions: assign({
2115
+ step: ({ context, event }) => ({
2116
+ ...context.step,
2117
+ toolResult: event.toolResult
2118
+ })
2119
+ })
2120
+ }
2121
+ }
2122
+ },
2123
+ ResolvingToolResult: {
2124
+ on: {
2125
+ finishToolCall: {
2126
+ target: "FinishingStep",
2127
+ actions: assign({
2128
+ checkpoint: ({ context, event }) => ({
2129
+ ...context.checkpoint,
2130
+ messages: [...context.checkpoint.messages, ...event.newMessages]
2131
+ }),
2132
+ step: ({ context, event }) => ({
2133
+ ...context.step,
2134
+ newMessages: [...context.step.newMessages, ...event.newMessages]
2135
+ })
2136
+ })
2137
+ }
2138
+ }
2139
+ },
2140
+ ResolvingThought: {
2141
+ on: {
2142
+ finishToolCall: {
2143
+ target: "FinishingStep",
2144
+ actions: assign({
2145
+ checkpoint: ({ context, event }) => ({
2146
+ ...context.checkpoint,
2147
+ messages: [...context.checkpoint.messages, ...event.newMessages]
2148
+ }),
2149
+ step: ({ context, event }) => ({
2150
+ ...context.step,
2151
+ newMessages: [...context.step.newMessages, ...event.newMessages]
2152
+ })
2153
+ })
2154
+ }
2155
+ }
2156
+ },
2157
+ ResolvingPdfFile: {
2158
+ on: {
2159
+ finishToolCall: {
2160
+ target: "FinishingStep",
2161
+ actions: assign({
2162
+ checkpoint: ({ context, event }) => ({
2163
+ ...context.checkpoint,
2164
+ messages: [...context.checkpoint.messages, ...event.newMessages]
2165
+ }),
2166
+ step: ({ context, event }) => ({
2167
+ ...context.step,
2168
+ newMessages: [...context.step.newMessages, ...event.newMessages]
2169
+ })
2170
+ })
2171
+ }
2172
+ }
2173
+ },
2174
+ ResolvingImageFile: {
2175
+ on: {
2176
+ finishToolCall: {
2177
+ target: "FinishingStep",
2178
+ actions: assign({
2179
+ checkpoint: ({ context, event }) => ({
2180
+ ...context.checkpoint,
2181
+ messages: [...context.checkpoint.messages, ...event.newMessages]
2182
+ }),
2183
+ step: ({ context, event }) => ({
2184
+ ...context.step,
2185
+ newMessages: [...context.step.newMessages, ...event.newMessages]
2186
+ })
2187
+ })
2188
+ }
2189
+ }
2190
+ },
2191
+ GeneratingRunResult: {
2192
+ on: {
2193
+ completeRun: {
2194
+ target: "Stopped",
2195
+ actions: assign({
2196
+ checkpoint: ({ event }) => event.checkpoint,
2197
+ step: ({ event }) => event.step
2198
+ })
2199
+ }
2200
+ }
2201
+ },
2202
+ CallingInteractiveTool: {
2203
+ on: {
2204
+ stopRunByInteractiveTool: {
2205
+ target: "Stopped",
2206
+ actions: assign({
2207
+ checkpoint: ({ event }) => event.checkpoint,
2208
+ step: ({ event }) => event.step
2209
+ })
2210
+ }
2211
+ }
2212
+ },
2213
+ CallingDelegate: {
2214
+ on: {
2215
+ stopRunByDelegate: {
2216
+ target: "Stopped",
2217
+ actions: assign({
2218
+ checkpoint: ({ event }) => event.checkpoint,
2219
+ step: ({ event }) => event.step
2220
+ })
2221
+ }
2222
+ }
2223
+ },
2224
+ FinishingStep: {
2225
+ on: {
2226
+ continueToNextStep: {
2227
+ target: "PreparingForStep",
2228
+ actions: assign({
2229
+ checkpoint: ({ event }) => event.nextCheckpoint,
2230
+ step: ({ event }) => event.step
2231
+ }),
2232
+ reenter: true
2233
+ },
2234
+ stopRunByExceededMaxSteps: {
2235
+ target: "Stopped",
2236
+ actions: assign({
2237
+ checkpoint: ({ event }) => event.checkpoint,
2238
+ step: ({ event }) => event.step
2239
+ })
2240
+ }
2241
+ }
2242
+ },
2243
+ Stopped: {
2244
+ type: "final"
2245
+ }
2246
+ }
2247
+ });
2248
+ var StateMachineLogics = {
2249
+ Init: initLogic,
2250
+ PreparingForStep: preparingForStepLogic,
2251
+ GeneratingToolCall: generatingToolCallLogic,
2252
+ CallingTool: callingToolLogic,
2253
+ ResolvingToolResult: resolvingToolResultLogic,
2254
+ ResolvingThought: resolvingThoughtLogic,
2255
+ ResolvingPdfFile: resolvingPdfFileLogic,
2256
+ ResolvingImageFile: resolvingImageFileLogic,
2257
+ GeneratingRunResult: generatingRunResultLogic,
2258
+ CallingInteractiveTool: callingInteractiveToolLogic,
2259
+ CallingDelegate: callingDelegateLogic,
2260
+ FinishingStep: finishingStepLogic
2261
+ };
2262
+
2263
+ // src/schemas/perstack-toml.ts
2264
+ import { z as z4 } from "zod";
2265
+ var PerstackConfigSchema = z4.object({
2266
+ model: z4.string().optional(),
2267
+ temperature: z4.number().optional(),
2268
+ maxSteps: z4.number().optional(),
2269
+ maxRetries: z4.number().optional(),
2270
+ experts: z4.record(
2271
+ z4.string(),
2272
+ z4.object({
2273
+ version: z4.string().optional(),
2274
+ minRuntimeVersion: z4.string().optional(),
2275
+ description: z4.string().optional(),
2276
+ instruction: z4.string(),
2277
+ skills: z4.record(
2278
+ z4.string(),
2279
+ z4.discriminatedUnion("type", [
2280
+ z4.object({
2281
+ type: z4.literal("mcpStdioSkill"),
2282
+ description: z4.string().optional(),
2283
+ rule: z4.string().optional(),
2284
+ pick: z4.array(z4.string()).optional(),
2285
+ omit: z4.array(z4.string()).optional(),
2286
+ command: z4.string(),
2287
+ packageName: z4.string().optional(),
2288
+ args: z4.array(z4.string()).optional(),
2289
+ requiredEnv: z4.array(z4.string()).optional()
2290
+ }),
2291
+ z4.object({
2292
+ type: z4.literal("mcpSseSkill"),
2293
+ description: z4.string().optional(),
2294
+ rule: z4.string().optional(),
2295
+ pick: z4.array(z4.string()).optional(),
2296
+ omit: z4.array(z4.string()).optional(),
2297
+ endpoint: z4.string()
2298
+ }),
2299
+ z4.object({
2300
+ type: z4.literal("interactiveSkill"),
2301
+ description: z4.string().optional(),
2302
+ rule: z4.string().optional(),
2303
+ tools: z4.record(
2304
+ z4.string(),
2305
+ z4.object({
2306
+ description: z4.string().optional(),
2307
+ inputJsonSchema: z4.string()
2308
+ })
2309
+ )
2310
+ })
2311
+ ])
2312
+ ).optional(),
2313
+ delegates: z4.array(z4.string()).optional()
2314
+ })
2315
+ ).optional()
2316
+ });
71
2317
 
72
- "${o.name}" skill rules:
73
- ${o.rule}
74
- `.trim():t,"")}function mo(e,t){return e.delegates.reduce((o,r)=>{let a=t[r];return a?dedent`
75
- ${o}
2318
+ // src/runtime.ts
2319
+ async function run(runInput, options) {
2320
+ const runParams = RunParamsSchema.parse(runInput);
2321
+ const eventListener = options?.eventListener ?? defaultEventListener;
2322
+ const retrieveCheckpoint = options?.retrieveCheckpoint ?? defaultRetrieveCheckpoint;
2323
+ const storeCheckpoint = options?.storeCheckpoint ?? defaultStoreCheckpoint;
2324
+ const eventEmitter = new RunEventEmitter();
2325
+ eventEmitter.subscribe(eventListener);
2326
+ let { setting, checkpoint } = runParams;
2327
+ if (setting.workspace) {
2328
+ if (!path.isAbsolute(setting.workspace)) {
2329
+ throw new Error(`Workspace path must be absolute: ${setting.workspace}`);
2330
+ }
2331
+ process.chdir(setting.workspace);
2332
+ }
2333
+ await storeRunSetting(setting);
2334
+ while (true) {
2335
+ const { expertToRun, experts } = await setupExperts(setting);
2336
+ printRunSetting(expertToRun.name, experts, setting);
2337
+ const skillManagers = await getSkillManagers(expertToRun, experts);
2338
+ const runActor = createActor(runtimeStateMachine, {
2339
+ input: {
2340
+ setting: {
2341
+ ...setting,
2342
+ experts
2343
+ },
2344
+ initialCheckpoint: checkpoint ?? {
2345
+ id: createId7(),
2346
+ runId: setting.runId,
2347
+ expert: {
2348
+ key: setting.expertKey,
2349
+ name: expertToRun.name,
2350
+ version: expertToRun.version
2351
+ },
2352
+ stepNumber: 1,
2353
+ status: "init",
2354
+ messages: [],
2355
+ usage: createEmptyUsage()
2356
+ },
2357
+ eventListener,
2358
+ skillManagers
2359
+ }
2360
+ });
2361
+ const runResultCheckpoint = await new Promise((resolve, reject) => {
2362
+ runActor.subscribe(async (runState) => {
2363
+ try {
2364
+ if (runState.value === "Stopped") {
2365
+ const { checkpoint: checkpoint2, skillManagers: skillManagers2 } = runState.context;
2366
+ if (!checkpoint2) {
2367
+ throw new Error("Checkpoint is undefined");
2368
+ }
2369
+ await closeSkillManagers(skillManagers2);
2370
+ resolve(checkpoint2);
2371
+ } else {
2372
+ const event = await StateMachineLogics[runState.value](runState.context);
2373
+ if ("checkpoint" in event) {
2374
+ await storeCheckpoint(event.checkpoint, event.timestamp);
2375
+ }
2376
+ await eventEmitter.emit(event);
2377
+ runActor.send(event);
2378
+ }
2379
+ } catch (error) {
2380
+ reject(error);
2381
+ }
2382
+ });
2383
+ runActor.start();
2384
+ });
2385
+ switch (runResultCheckpoint.status) {
2386
+ case "completed": {
2387
+ if (runResultCheckpoint.delegatedBy) {
2388
+ const { messages, delegatedBy } = runResultCheckpoint;
2389
+ const { expert, toolCallId, toolName, checkpointId } = delegatedBy;
2390
+ const delegateResultMessage = messages[messages.length - 1];
2391
+ if (delegateResultMessage.type !== "expertMessage") {
2392
+ throw new Error("Delegation error: delegation result message is incorrect");
2393
+ }
2394
+ const delegateText = delegateResultMessage.contents.find(
2395
+ (content) => content.type === "textPart"
2396
+ );
2397
+ if (!delegateText) {
2398
+ throw new Error("Delegation error: delegation result message does not contain a text");
2399
+ }
2400
+ setting = {
2401
+ ...setting,
2402
+ expertKey: expert.key,
2403
+ input: {
2404
+ interactiveToolCallResult: {
2405
+ toolCallId,
2406
+ toolName,
2407
+ text: delegateText.text
2408
+ }
2409
+ }
2410
+ };
2411
+ checkpoint = {
2412
+ ...await retrieveCheckpoint(setting.runId, checkpointId),
2413
+ id: createId7(),
2414
+ stepNumber: runResultCheckpoint.stepNumber + 1,
2415
+ usage: runResultCheckpoint.usage
2416
+ };
2417
+ break;
2418
+ }
2419
+ return runResultCheckpoint;
2420
+ }
2421
+ case "stoppedByInteractiveTool": {
2422
+ return runResultCheckpoint;
2423
+ }
2424
+ case "stoppedByDelegate": {
2425
+ if (!runResultCheckpoint.delegateTo) {
2426
+ throw new Error("Delegation error: delegate to is undefined");
2427
+ }
2428
+ const { expert, toolCallId, toolName, query } = runResultCheckpoint.delegateTo;
2429
+ setting = {
2430
+ ...setting,
2431
+ expertKey: expert.key,
2432
+ input: {
2433
+ text: query
2434
+ }
2435
+ };
2436
+ checkpoint = {
2437
+ id: createId7(),
2438
+ runId: setting.runId,
2439
+ status: "init",
2440
+ stepNumber: runResultCheckpoint.stepNumber + 1,
2441
+ messages: [],
2442
+ expert: {
2443
+ key: expert.key,
2444
+ name: expert.name,
2445
+ version: expert.version
2446
+ },
2447
+ delegatedBy: {
2448
+ expert: {
2449
+ key: expertToRun.key,
2450
+ name: expertToRun.name,
2451
+ version: expertToRun.version
2452
+ },
2453
+ toolCallId,
2454
+ toolName,
2455
+ checkpointId: runResultCheckpoint.id
2456
+ },
2457
+ usage: runResultCheckpoint.usage
2458
+ };
2459
+ break;
2460
+ }
2461
+ case "stoppedByExceededMaxSteps": {
2462
+ return runResultCheckpoint;
2463
+ }
2464
+ case "stoppedByError": {
2465
+ return runResultCheckpoint;
2466
+ }
2467
+ default:
2468
+ throw new Error("Run stopped by unknown reason");
2469
+ }
2470
+ }
2471
+ }
2472
+ async function setupExperts(setting) {
2473
+ const { expertKey } = setting;
2474
+ const experts = { ...setting.experts };
2475
+ const expertToRun = await resolveExpertToRun(expertKey, experts);
2476
+ for (const delegateName of expertToRun.delegates) {
2477
+ const delegate = await resolveExpertToRun(delegateName, experts);
2478
+ if (!delegate) {
2479
+ throw new Error(`Delegate ${delegateName} not found`);
2480
+ }
2481
+ }
2482
+ return { expertToRun, experts };
2483
+ }
2484
+ function printRunSetting(expertName, experts, setting) {
2485
+ console.log("\u{1F99C} Starting Perstack \u{1F99C}");
2486
+ console.log(`Expert To Run: ${expertName}`);
2487
+ console.log(`Experts: ${Object.keys(experts).join(", ")}`);
2488
+ console.log(`Model: ${setting.model}`);
2489
+ console.log(`Temperature: ${setting.temperature}`);
2490
+ console.log(`Max Steps: ${setting.maxSteps}`);
2491
+ console.log(`Max Retries: ${setting.maxRetries}`);
2492
+ if (setting.input.text) {
2493
+ console.log(`Query: ${setting.input.text}`);
2494
+ }
2495
+ if (setting.input.interactiveToolCallResult) {
2496
+ console.log(`Tool: ${setting.input.interactiveToolCallResult.toolName}`);
2497
+ console.log(`Tool Call ID: ${setting.input.interactiveToolCallResult.toolCallId}`);
2498
+ console.log(`Tool Result: ${setting.input.interactiveToolCallResult.text}`);
2499
+ }
2500
+ }
2501
+ async function storeRunSetting(setting) {
2502
+ const runDir = getRunDir(setting.runId);
2503
+ if (existsSync(runDir)) {
2504
+ const runSettingPath = path.resolve(runDir, "run-setting.json");
2505
+ const runSetting = JSON.parse(await readFile4(runSettingPath, "utf-8"));
2506
+ runSetting.updatedAt = Date.now();
2507
+ await writeFile2(runSettingPath, JSON.stringify(runSetting, null, 2), "utf-8");
2508
+ } else {
2509
+ await mkdir2(runDir, { recursive: true });
2510
+ await writeFile2(
2511
+ path.resolve(runDir, "run-setting.json"),
2512
+ JSON.stringify(setting, null, 2),
2513
+ "utf-8"
2514
+ );
2515
+ }
2516
+ }
2517
+ function getRunDir(runId) {
2518
+ return `${process.cwd()}/perstack/runs/${runId}`;
2519
+ }
2520
+ async function parseConfig(config) {
2521
+ const toml = TOML.parse(config ?? "");
2522
+ return PerstackConfigSchema.parse(toml);
2523
+ }
76
2524
 
77
- About "${a.name}":
78
- ${a.description}
79
- `.trim():o},"")}async function tt({setting:e,checkpoint:t}){let{expertKey:o,experts:r}=e,a=r[o];switch(t.status){case "init":return ne(e,t,{initialCheckpoint:t,inputMessages:[Xe(a,r),et(e.input)]});default:return ne(e,t,{initialCheckpoint:t,inputMessages:[et(e.input)]})}}function et(e){if(e.text)return F([{type:"textPart",text:e.text}]);if(e.interactiveToolCallResult)return C([{type:"toolResultPart",toolCallId:e.interactiveToolCallResult.toolCallId,toolName:e.interactiveToolCallResult.toolName,contents:[{type:"textPart",text:e.interactiveToolCallResult.text}]}]);throw new Error("Input message is undefined")}async function ot({setting:e,checkpoint:t}){return Te(e,t,{messages:t.messages})}async function nt({setting:e,checkpoint:t,step:o}){if(!o?.toolCall||!o?.toolResult)throw new Error("No tool call or tool result found");let{id:r,toolName:a}=o.toolCall,{result:i}=o.toolResult,c=i.filter(u=>u.type==="textPart"),s=[];for(let u of c){let h;try{h=JSON.parse(u.text);}catch{s.push({type:"textPart",text:u.text});continue}let{path:d,mimeType:P,size:R}=h,f=await readFile(d).then(S=>({encodedData:S.toString("base64"),mimeType:P,size:R}));s.push({type:"imageInlinePart",encodedData:f.encodedData,mimeType:f.mimeType});}return $(e,t,{newMessages:[C([{type:"toolResultPart",toolCallId:r,toolName:a,contents:s}])]})}async function rt({setting:e,checkpoint:t,step:o}){if(!o?.toolCall||!o?.toolResult)throw new Error("No tool call or tool result found");let{id:r,toolName:a}=o.toolCall,{result:i}=o.toolResult,c=i.filter(u=>u.type==="textPart"),s=[];for(let u of c){let h;try{h=JSON.parse(u.text);}catch{s.push({type:"textPart",text:u.text});continue}let{path:d,mimeType:P,size:R}=h,f=await readFile(d).then(S=>({encodedData:S.toString("base64"),mimeType:P,size:R}));s.push({type:"fileInlinePart",encodedData:f.encodedData,mimeType:f.mimeType});}return $(e,t,{newMessages:[C([{type:"toolResultPart",toolCallId:r,toolName:a,contents:[{type:"textPart",text:"User uploads PDF file as follows."}]}]),F(s)]})}async function X({setting:e,checkpoint:t,step:o}){if(!o?.toolCall||!o?.toolResult)throw new Error("No tool call or tool result found");let{id:r,toolName:a}=o.toolCall,{result:i}=o.toolResult;return $(e,t,{newMessages:[C([{type:"toolResultPart",toolCallId:r,toolName:a,contents:i.filter(c=>c.type==="textPart"||c.type==="imageInlinePart")}])]})}async function st(e){return X(e)}var at=setup({types:{input:{},context:{},events:{}}}).createMachine({id:"Run",initial:"Init",context:({input:e})=>({setting:e.setting,checkpoint:e.initialCheckpoint,eventListener:e.eventListener,skillManagers:e.skillManagers}),states:{Init:{on:{startRun:{target:"PreparingForStep",actions:assign({checkpoint:({event:e})=>({...e.initialCheckpoint,messages:[...e.initialCheckpoint.messages,...e.inputMessages],status:"proceeding"})})}}},PreparingForStep:{on:{startGeneration:{target:"GeneratingToolCall",actions:assign({step:({context:e,event:t})=>({stepNumber:e.checkpoint.stepNumber,newMessages:[],usage:H(),startedAt:t.timestamp})})}}},GeneratingToolCall:{on:{retry:{target:"FinishingStep",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,...t.newMessages],usage:v(e.checkpoint.usage,t.usage)}),step:({context:e,event:t})=>({...e.step,newMessages:t.newMessages,usage:v(e.step.usage,t.usage)})})},callTool:{target:"CallingTool",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,t.newMessage],usage:v(e.checkpoint.usage,t.usage)}),step:({context:e,event:t})=>({...e.step,newMessages:[t.newMessage],toolCall:t.toolCall,usage:v(e.step.usage,t.usage)})})},callInteractiveTool:{target:"CallingInteractiveTool",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,t.newMessage],usage:v(e.checkpoint.usage,t.usage)}),step:({context:e,event:t})=>({...e.step,newMessages:[t.newMessage],toolCall:t.toolCall,usage:v(e.step.usage,t.usage)})})},callDelegate:{target:"CallingDelegate",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,t.newMessage],usage:v(e.checkpoint.usage,t.usage)}),step:({context:e,event:t})=>({...e.step,newMessages:[t.newMessage],toolCall:t.toolCall,usage:v(e.step.usage,t.usage)})})}}},CallingTool:{on:{resolveToolResult:{target:"ResolvingToolResult",actions:assign({step:({context:e,event:t})=>({...e.step,toolResult:t.toolResult})})},resolveThought:{target:"ResolvingThought",actions:assign({step:({context:e,event:t})=>({...e.step,toolResult:t.toolResult})})},resolvePdfFile:{target:"ResolvingPdfFile",actions:assign({step:({context:e,event:t})=>({...e.step,toolResult:t.toolResult})})},resolveImageFile:{target:"ResolvingImageFile",actions:assign({step:({context:e,event:t})=>({...e.step,toolResult:t.toolResult})})},attemptCompletion:{target:"GeneratingRunResult",actions:assign({step:({context:e,event:t})=>({...e.step,toolResult:t.toolResult})})}}},ResolvingToolResult:{on:{finishToolCall:{target:"FinishingStep",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,...t.newMessages]}),step:({context:e,event:t})=>({...e.step,newMessages:[...e.step.newMessages,...t.newMessages]})})}}},ResolvingThought:{on:{finishToolCall:{target:"FinishingStep",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,...t.newMessages]}),step:({context:e,event:t})=>({...e.step,newMessages:[...e.step.newMessages,...t.newMessages]})})}}},ResolvingPdfFile:{on:{finishToolCall:{target:"FinishingStep",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,...t.newMessages]}),step:({context:e,event:t})=>({...e.step,newMessages:[...e.step.newMessages,...t.newMessages]})})}}},ResolvingImageFile:{on:{finishToolCall:{target:"FinishingStep",actions:assign({checkpoint:({context:e,event:t})=>({...e.checkpoint,messages:[...e.checkpoint.messages,...t.newMessages]}),step:({context:e,event:t})=>({...e.step,newMessages:[...e.step.newMessages,...t.newMessages]})})}}},GeneratingRunResult:{on:{completeRun:{target:"Stopped",actions:assign({checkpoint:({event:e})=>e.checkpoint,step:({event:e})=>e.step})}}},CallingInteractiveTool:{on:{stopRunByInteractiveTool:{target:"Stopped",actions:assign({checkpoint:({event:e})=>e.checkpoint,step:({event:e})=>e.step})}}},CallingDelegate:{on:{stopRunByDelegate:{target:"Stopped",actions:assign({checkpoint:({event:e})=>e.checkpoint,step:({event:e})=>e.step})}}},FinishingStep:{on:{continueToNextStep:{target:"PreparingForStep",actions:assign({checkpoint:({event:e})=>e.nextCheckpoint,step:({event:e})=>e.step}),reenter:true},stopRunByExceededMaxSteps:{target:"Stopped",actions:assign({checkpoint:({event:e})=>e.checkpoint,step:({event:e})=>e.step})}}},Stopped:{type:"final"}}}),it={Init:tt,PreparingForStep:ot,GeneratingToolCall:Qe,CallingTool:Ve,ResolvingToolResult:X,ResolvingThought:st,ResolvingPdfFile:rt,ResolvingImageFile:nt,GeneratingRunResult:He,CallingInteractiveTool:Je,CallingDelegate:qe,FinishingStep:Ye};var lt=z$1.object({model:z$1.string().optional(),temperature:z$1.number().optional(),maxSteps:z$1.number().optional(),maxRetries:z$1.number().optional(),experts:z$1.record(z$1.string(),z$1.object({version:z$1.string().optional(),minRuntimeVersion:z$1.string().optional(),description:z$1.string().optional(),instruction:z$1.string(),skills:z$1.record(z$1.string(),z$1.discriminatedUnion("type",[z$1.object({type:z$1.literal("mcpStdioSkill"),description:z$1.string().optional(),rule:z$1.string().optional(),pick:z$1.array(z$1.string()).optional(),omit:z$1.array(z$1.string()).optional(),command:z$1.string(),packageName:z$1.string().optional(),args:z$1.array(z$1.string()).optional(),requiredEnv:z$1.array(z$1.string()).optional()}),z$1.object({type:z$1.literal("mcpSseSkill"),description:z$1.string().optional(),rule:z$1.string().optional(),pick:z$1.array(z$1.string()).optional(),omit:z$1.array(z$1.string()).optional(),endpoint:z$1.string()}),z$1.object({type:z$1.literal("interactiveSkill"),description:z$1.string().optional(),rule:z$1.string().optional(),tools:z$1.record(z$1.string(),z$1.object({description:z$1.string().optional(),inputJsonSchema:z$1.string()}))})])).optional(),delegates:z$1.array(z$1.string()).optional()})).optional()});async function Br(e,t){let o=ke.parse(e),r=t?.eventListener??se,a=t?.retrieveCheckpoint??De,i=t?.storeCheckpoint??Oe,c=new V;c.subscribe(r);let{setting:s,checkpoint:u}=o;if(s.workspace){if(!pe.isAbsolute(s.workspace))throw new Error(`Workspace path must be absolute: ${s.workspace}`);process.chdir(s.workspace);}for(await Po(s);;){let{expertToRun:h,experts:d}=await Ro(s);So(h.name,d,s);let P=await Le(h,d),R=createActor(at,{input:{setting:{...s,experts:d},initialCheckpoint:u??{id:createId(),runId:s.runId,expert:{key:s.expertKey,name:h.name,version:h.version},stepNumber:1,status:"init",messages:[],usage:H()},eventListener:r,skillManagers:P}}),f=await new Promise((S,j)=>{R.subscribe(async M=>{try{if(M.value==="Stopped"){let{checkpoint:T,skillManagers:ee}=M.context;if(!T)throw new Error("Checkpoint is undefined");await Ge(ee),S(T);}else {let T=await it[M.value](M.context);"checkpoint"in T&&await i(T.checkpoint,T.timestamp),await c.emit(T),R.send(T);}}catch(T){j(T);}}),R.start();});switch(f.status){case "completed":{if(f.delegatedBy){let{messages:S,delegatedBy:j}=f,{expert:M,toolCallId:T,toolName:ee,checkpointId:ct}=j,ce=S[S.length-1];if(ce.type!=="expertMessage")throw new Error("Delegation error: delegation result message is incorrect");let me=ce.contents.find(mt=>mt.type==="textPart");if(!me)throw new Error("Delegation error: delegation result message does not contain a text");s={...s,expertKey:M.key,input:{interactiveToolCallResult:{toolCallId:T,toolName:ee,text:me.text}}},u={...await a(s.runId,ct),id:createId(),stepNumber:f.stepNumber+1,usage:f.usage};break}return f}case "stoppedByInteractiveTool":return f;case "stoppedByDelegate":{if(!f.delegateTo)throw new Error("Delegation error: delegate to is undefined");let{expert:S,toolCallId:j,toolName:M,query:T}=f.delegateTo;s={...s,expertKey:S.key,input:{text:T}},u={id:createId(),runId:s.runId,status:"init",stepNumber:f.stepNumber+1,messages:[],expert:{key:S.key,name:S.name,version:S.version},delegatedBy:{expert:{key:h.key,name:h.name,version:h.version},toolCallId:j,toolName:M,checkpointId:f.id},usage:f.usage};break}case "stoppedByExceededMaxSteps":return f;case "stoppedByError":return f;default:throw new Error("Run stopped by unknown reason")}}}async function Ro(e){let{expertKey:t}=e,o={...e.experts},r=await ie(t,o);for(let a of r.delegates)if(!await ie(a,o))throw new Error(`Delegate ${a} not found`);return {expertToRun:r,experts:o}}function So(e,t,o){console.log("\u{1F99C} Starting Perstack \u{1F99C}"),console.log(`Expert To Run: ${e}`),console.log(`Experts: ${Object.keys(t).join(", ")}`),console.log(`Model: ${o.model}`),console.log(`Temperature: ${o.temperature}`),console.log(`Max Steps: ${o.maxSteps}`),console.log(`Max Retries: ${o.maxRetries}`),o.input.text&&console.log(`Query: ${o.input.text}`),o.input.interactiveToolCallResult&&(console.log(`Tool: ${o.input.interactiveToolCallResult.toolName}`),console.log(`Tool Call ID: ${o.input.interactiveToolCallResult.toolCallId}`),console.log(`Tool Result: ${o.input.interactiveToolCallResult.text}`));}async function Po(e){let t=O(e.runId);if(existsSync(t)){let o=pe.resolve(t,"run-setting.json"),r=JSON.parse(await readFile(o,"utf-8"));r.updatedAt=Date.now(),await writeFile(o,JSON.stringify(r,null,2),"utf-8");}else await mkdir(t,{recursive:true}),await writeFile(pe.resolve(t,"run-setting.json"),JSON.stringify(e,null,2),"utf-8");}function O(e){return `${process.cwd()}/perstack/runs/${e}`}async function _r(e){let t=ko.parse(e??"");return lt.parse(t)}var Lr=z$1.object({expertKey:z$1.string(),query:z$1.string(),options:z$1.object({config:z$1.string().optional(),model:z$1.string().optional(),temperature:z$1.string().optional().transform(e=>{if(e===void 0)return;let t=Number.parseFloat(e);if(!Number.isNaN(t))return t}),maxSteps:z$1.string().optional().transform(e=>{if(e===void 0)return;let t=Number.parseInt(e);if(!Number.isNaN(t))return t}),maxRetries:z$1.string().optional().transform(e=>{if(e===void 0)return;let t=Number.parseInt(e);if(!Number.isNaN(t))return t}),runId:z$1.string().optional()})});export{oe as CheckpointSchema,Ft as CheckpointStatusSchema,wt as ExpertMessageSchema,J as ExpertSchema,Rt as FileBinaryPartSchema,Tt as FileInlinePartSchema,kt as FileUrlPartSchema,xt as ImageBinaryPartSchema,fe as ImageInlinePartSchema,yt as ImageUrlPartSchema,Ct as InstructionMessageSchema,q as InteractiveSkillSchema,ye as InteractiveToolSchema,K as McpSseSkillSchema,G as McpStdioSkillSchema,he as MessageSchema,lt as PerstackConfigSchema,Ae as RegistryV1ExpertsGetResponseSchema,Lr as RunInputSchema,ke as RunParamsSchema,it as StateMachineLogics,A as TextPartSchema,St as ToolCallPartSchema,It as ToolMessageSchema,Pt as ToolResultPartSchema,Nt as UsageSchema,vt as UserMessageSchema,Me as attemptCompletion,Pe as callDelegate,Se as callInteractiveTool,Re as callTool,be as completeRun,Fe as continueToNextStep,k as createEvent,se as defaultEventListener,D as expertKeyRegex,Mt as expertNameRegex,$ as finishToolCall,O as getRunDir,$t as maxNameLength,_r as parseConfig,jo as parseExpertKey,Ie as resolveImageFile,we as resolvePdfFile,ve as resolveThought,Ce as resolveToolResult,re as retry,Br as run,at as runtimeStateMachine,Uo as skillNameRegex,Te as startGeneration,ne as startRun,$e as stopRunByDelegate,Ne as stopRunByExceededMaxSteps,Ee as stopRunByInteractiveTool,Et as tagNameRegex,bt as versionRegex};//# sourceMappingURL=index.js.map
2525
+ // src/schemas/command-run.ts
2526
+ import { z as z5 } from "zod";
2527
+ var RunInputSchema = z5.object({
2528
+ expertKey: z5.string(),
2529
+ query: z5.string(),
2530
+ options: z5.object({
2531
+ config: z5.string().optional(),
2532
+ model: z5.string().optional(),
2533
+ temperature: z5.string().optional().transform((value) => {
2534
+ if (value === void 0) {
2535
+ return void 0;
2536
+ }
2537
+ const parsedValue = Number.parseFloat(value);
2538
+ if (Number.isNaN(parsedValue)) {
2539
+ return void 0;
2540
+ }
2541
+ return parsedValue;
2542
+ }),
2543
+ maxSteps: z5.string().optional().transform((value) => {
2544
+ if (value === void 0) {
2545
+ return void 0;
2546
+ }
2547
+ const parsedValue = Number.parseInt(value);
2548
+ if (Number.isNaN(parsedValue)) {
2549
+ return void 0;
2550
+ }
2551
+ return parsedValue;
2552
+ }),
2553
+ maxRetries: z5.string().optional().transform((value) => {
2554
+ if (value === void 0) {
2555
+ return void 0;
2556
+ }
2557
+ const parsedValue = Number.parseInt(value);
2558
+ if (Number.isNaN(parsedValue)) {
2559
+ return void 0;
2560
+ }
2561
+ return parsedValue;
2562
+ }),
2563
+ runId: z5.string().optional()
2564
+ })
2565
+ });
2566
+ export {
2567
+ CheckpointSchema,
2568
+ CheckpointStatusSchema,
2569
+ ExpertMessageSchema,
2570
+ ExpertSchema,
2571
+ FileBinaryPartSchema,
2572
+ FileInlinePartSchema,
2573
+ FileUrlPartSchema,
2574
+ ImageBinaryPartSchema,
2575
+ ImageInlinePartSchema,
2576
+ ImageUrlPartSchema,
2577
+ InstructionMessageSchema,
2578
+ InteractiveSkillSchema,
2579
+ InteractiveToolSchema,
2580
+ McpSseSkillSchema,
2581
+ McpStdioSkillSchema,
2582
+ MessageSchema,
2583
+ PerstackConfigSchema,
2584
+ RegistryV1ExpertsGetResponseSchema,
2585
+ RunInputSchema,
2586
+ RunParamsSchema,
2587
+ StateMachineLogics,
2588
+ TextPartSchema,
2589
+ ToolCallPartSchema,
2590
+ ToolMessageSchema,
2591
+ ToolResultPartSchema,
2592
+ UsageSchema,
2593
+ UserMessageSchema,
2594
+ attemptCompletion,
2595
+ callDelegate,
2596
+ callInteractiveTool,
2597
+ callTool,
2598
+ completeRun,
2599
+ continueToNextStep,
2600
+ createEvent,
2601
+ defaultEventListener,
2602
+ expertKeyRegex,
2603
+ expertNameRegex,
2604
+ finishToolCall,
2605
+ getRunDir,
2606
+ maxNameLength,
2607
+ parseConfig,
2608
+ parseExpertKey,
2609
+ resolveImageFile,
2610
+ resolvePdfFile,
2611
+ resolveThought,
2612
+ resolveToolResult,
2613
+ retry,
2614
+ run,
2615
+ runtimeStateMachine,
2616
+ skillNameRegex,
2617
+ startGeneration,
2618
+ startRun,
2619
+ stopRunByDelegate,
2620
+ stopRunByExceededMaxSteps,
2621
+ stopRunByInteractiveTool,
2622
+ tagNameRegex,
2623
+ versionRegex
2624
+ };
80
2625
  //# sourceMappingURL=index.js.map