toolpack-sdk 3.5.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Toolpack SDK
2
2
 
3
- The TypeScript SDK for building production AI agents — 100+ built-in tools, 8 channel integrations, a persistent cognitive layer, and full Knowledge/RAG, all in one package.
3
+ The TypeScript SDK for building production AI agents — 100+ built-in tools, 9 channel integrations, a persistent cognitive layer, and full Knowledge/RAG, all in one package.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/toolpack-sdk.svg)](https://www.npmjs.com/package/toolpack-sdk)
6
6
  [![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)
@@ -206,7 +206,7 @@ const sdk = await Toolpack.init({
206
206
  ```
207
207
 
208
208
  See `docs/MCP_INTEGRATION.md` and `docs/examples/mcp-integration-example.ts` for full instructions and best practices.
209
- - **Gemini**: Uses synthetic tool call IDs (`gemini_<timestamp>_<random>`) since the Gemini API doesn't return tool call IDs natively. Tool results are converted to `functionResponse` parts in chat history automatically. API key read from `GOOGLE_GENERATIVE_AI_KEY` or `TOOLPACK_GEMINI_KEY`.
209
+ - **Gemini**: Uses synthetic tool call IDs (`gemini_<timestamp>_<random>`) since the Gemini API doesn't return tool call IDs natively. Tool results are converted to `functionResponse` parts in chat history automatically. API key read from `GEMINI_API_KEY` or `TOOLPACK_GEMINI_KEY`.
210
210
  - **Ollama**: Auto-discovers all locally pulled models when registered as `{ ollama: {} }`. Uses `/api/show` and tool probing to detect capabilities (tool calling, vision, embeddings) per model. Models without tool support are automatically stripped of tools and given a system instruction to prevent hallucinated tool usage. Uses synthetic tool call IDs (`ollama_<timestamp>_<random>`). Embeddings use the modern `/api/embed` batch endpoint. Legacy per-model registration (`{ 'ollama-llama3': {} }`) is also supported.
211
211
  - **OpenRouter**: Routes requests to any of the 300+ models available on [openrouter.ai](https://openrouter.ai) via an OpenAI-compatible API. Models are discovered dynamically from the `/models` endpoint. Tool calling is fully supported; models that reject `tool_choice: 'none'` have tools stripped gracefully instead. No embeddings support. Optional `siteUrl` and `siteName` config for OpenRouter's attribution leaderboard. API key read from `OPENROUTER_API_KEY` or `TOOLPACK_OPENROUTER_KEY`.
212
212
 
@@ -612,6 +612,26 @@ for await (const chunk of sdk.stream({ model, messages, signal: controller.signa
612
612
  - `generate()` rejects with an `AbortedError` (`name` is `'AbortError'`, exported from the package root)
613
613
  - Tools that have not started are not run. A tool can read `ctx.signal` to end its own long work early, for example `fetch(url, { signal: ctx.signal })`
614
614
 
615
+ ### Stopping or changing a tool call
616
+
617
+ Pass `interceptTool` on a request to wrap every tool call of that request (request, mode and registry tools, and `tool.search`). Call `run()` to run the tool and use or change its result, or return text without calling it to stop the call: the model then sees that text as the tool's result.
618
+
619
+ ```typescript
620
+ import type { ToolInterceptor } from 'toolpack-sdk';
621
+
622
+ const interceptTool: ToolInterceptor = async (call, run) => {
623
+ // call: { toolName, args, round }
624
+ if (call.toolName === 'fs.delete_file') return 'Deleting files is not allowed here.'; // not run
625
+ return run();
626
+ };
627
+
628
+ const response = await sdk.generate({ model, messages, interceptTool });
629
+ ```
630
+
631
+ - The tool's `tool:started`, `tool:completed` and log events are sent only when `run()` is called
632
+ - After a stop (`signal`), the interceptor is not asked and no tool is started
633
+ - `interceptTool` is never sent to the provider
634
+
615
635
  ### Returning files from tools
616
636
 
617
637
  A tool can return a file by URL with `{ "type": "file", "mimeType": "application/pdf", "url": "https://..." }`. Anthropic and Vertex AI receive it as a native file part, and OpenAI receives images (other files get a placeholder). `data:` URIs keep working as before.
@@ -1150,7 +1170,7 @@ A data URI (`data:<mime>;base64,<data>`) is also accepted in `file.url` for inli
1150
1170
  # Provider API keys (at least one required)
1151
1171
  export OPENAI_API_KEY="sk-..."
1152
1172
  export ANTHROPIC_API_KEY="sk-ant-..."
1153
- export GOOGLE_GENERATIVE_AI_KEY="AIza..."
1173
+ export GEMINI_API_KEY="AIza..."
1154
1174
  export OPENROUTER_API_KEY="sk-or-..."
1155
1175
 
1156
1176
  # SDK logging (override programmatic config)
@@ -1345,7 +1365,9 @@ interface CompletionRequest {
1345
1365
  max_tokens?: number;
1346
1366
  tools?: ToolCallRequest[];
1347
1367
  requestTools?: RequestToolDefinition[]; // Request-scoped tools
1368
+ interceptTool?: ToolInterceptor; // Wraps every tool call: stop it or change its result
1348
1369
  tool_choice?: 'auto' | 'none' | 'required';
1370
+ signal?: AbortSignal; // Stops the request
1349
1371
  }
1350
1372
 
1351
1373
  interface CompletionResponse {
package/dist/index.cjs CHANGED
@@ -410,17 +410,17 @@ When the user asks you to do something, be proactive:
410
410
  ${l.join(`
411
411
 
412
412
  `)}
413
- </rules>`;return this.modeCache.set(n,{value:p,cachedAt:Date.now()}),p}clearCache(){this.modeCache.clear()}async collectFromFolder(e,t){let o=(0,Ze.resolve)(e);try{await this.collectRecursive(o,t)}catch{}}async collectRecursive(e,t){let o=await(0,jr.readdir)(e,{withFileTypes:!0});for(let n of o){let s=(0,Ze.join)(e,n.name);n.isDirectory()?await this.collectRecursive(s,t):n.isFile()&&(0,Ze.extname)(n.name)===".md"&&t.add(s)}}async readFile(e,t){if(t.has(e))return t.get(e);try{let o=await(0,jr.readFile)(e,"utf-8");return t.set(e,o),o}catch{return""}}};function Fr(r,e){gt("debug")&&(y(`[AIClient][${r}] Messages (${e.length}):`),e.forEach((t,o)=>{let n=t,s=typeof n.content=="string"?n.content:N(n.content,1e4);y(`[AIClient][${r}] #${o} role=${n.role} content=${s}`)}))}function Ql(r){let e=ut(r).toLowerCase();return e?[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/,/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b.*\b(file|folder|directory)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl|map)\b/,/https?:\/\//].some(o=>o.test(e)):!1}function Xl(r){let e=ut(r).toLowerCase();if(!e)return!1;let t=[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/],o=[/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl)\b/];return t.some(n=>n.test(e))&&!o.some(n=>n.test(e))}var Pn=class extends Yl.EventEmitter{providers;defaultProvider;toolRegistry;toolsConfig;toolRouter;bm25Engine;queryClassifier;toolOrchestrator;activeMode=null;overrideSystemPrompt;disableBaseContext;disableToolGuidance;toolResultMaxChars;hitlConfig;onToolConfirm;conversationId;contextWindowConfig;actor;contextWindowStateManager;providerModelCache=new Map;ruleLoader;requestSeq=0;constructor(e){super(),this.providers=new Map(Object.entries(e.providers)),this.defaultProvider=e.defaultProvider,this.toolRegistry=e.toolRegistry,this.toolsConfig=e.toolsConfig||oe,this.toolRouter=new Mt,this.bm25Engine=new At,this.queryClassifier=new Nt,this.toolOrchestrator=new Lr,this.overrideSystemPrompt=e.systemPrompt,this.disableBaseContext=e.disableBaseContext||!1,this.disableToolGuidance=e.disableToolGuidance||!1;let t=this.toolsConfig.resultMaxChars??oe.resultMaxChars??2e4;this.toolResultMaxChars=Number.isFinite(t)&&t>0?t:2e4,this.hitlConfig=e.hitlConfig,this.onToolConfirm=e.onToolConfirm,this.conversationId=e.conversationId,this.contextWindowConfig=e.contextWindowConfig,this.actor=e.actor,this.providerModelCache=new Map,this.ruleLoader=new ht,this.contextWindowConfig&&this.contextWindowConfig.enabled!==!1&&(this.contextWindowStateManager=Ws(this.contextWindowConfig)),this.toolRegistry&&this.bm25Engine.index(this.toolRegistry.getAll())}getConversationId(){return this.conversationId||"global"}async getModelInfo(e,t){let o=e.name||e.constructor.name,n=this.providerModelCache.get(o);if(!n){try{n=await e.getModels()}catch{n=[]}this.providerModelCache.set(o,n)}return n.find(s=>s.id===t||s.displayName===t)}async countRequestTokens(e,t,o){let n=await t.countTokens(e.messages,o);return typeof n=="number"&&Number.isFinite(n)?n:Ms(e.messages,o,t.getDisplayName().toLowerCase())}async pruneConversation(e,t,o){let n=this.contextWindowConfig?.retainSystemMessages??!0,s=e;for(let i=0;i<3;i+=1){let a=await this.countRequestTokens(s,t,s.model);if(a<=o)return s;let l=a-o,p=Is(s.messages,l,n),d=new Set(p.pruneInfo.removedMessages),m=s.messages.filter(h=>!d.has(h)),u={...s,messages:m};if(this.contextWindowStateManager&&this.contextWindowStateManager.recordPruneOperation(this.getConversationId(),p.tokensReclaimed),await this.countRequestTokens(u,t,u.model)<=o||m.length===s.messages.length)return u;s=u}return e}async pruneToMaxMessageHistory(e){let t=this.contextWindowConfig?.maxMessageHistoryLength;if(!t||e.messages.length<=t)return e;let o=this.contextWindowConfig?.retainSystemMessages??!0,n=[];e.messages.forEach((l,p)=>{o&&l.role==="system"||l.role!=="tool"&&n.push(p)});let s=Math.max(0,e.messages.length-t);if(s===0)return e;let i=new Set(n.slice(0,s)),a=e.messages.filter((l,p)=>!i.has(p));return{...e,messages:a}}async summarizeConversation(e,t){let o=e.messages,n=o.filter(C=>C.role==="system"),s=o.filter(C=>C.role!=="system");if(s.length<4)return e;let i=s.slice(-4),a=s.slice(0,-4);if(a.length<2)return e;let l=this.contextWindowConfig?.summarizerModel||e.model,p=Fs(a,{model:l,maxSummaryTokens:500}),d=await Fe(t.generate({model:l,messages:p,max_tokens:500,temperature:0,response_format:"text",signal:e.signal}),e.signal);if(!d.content)throw new kn("Summarization provider returned no summary",this.getConversationId(),a.length,"invalid_response");let m=await this.countRequestTokens({...e,messages:a},t,l),u=qs(d.content,a,m),b=js(u);if(!b.valid)throw new kn(`Summarization result is invalid: ${b.issues.join("; ")}`,this.getConversationId(),a.length,"invalid_quality",d.content);let h=Nr(u.summary,a.length),T=[...n,h,...i];return this.contextWindowStateManager&&this.contextWindowStateManager.recordSummarization(this.getConversationId(),u.tokensSaved),{...e,messages:T}}async enforceContextWindow(e,t){if(!this.contextWindowConfig||this.contextWindowConfig.enabled===!1)return e;let o=await this.pruneToMaxMessageHistory(e),n=await this.getModelInfo(t,o.model),s=n?.contextWindow??1e5,i=o.max_tokens??n?.maxOutputTokens??1024,a=this.contextWindowConfig.outputTokenBuffer??1.15,l=Ns(i,a),p=Math.max(0,s-l),d=Math.floor(s*((this.contextWindowConfig.pruneThreshold??85)/100)),m=Math.min(p,d),u=await this.countRequestTokens(o,t,o.model);if(this.contextWindowStateManager&&(this.contextWindowStateManager.updateTokenCount(this.getConversationId(),u),u>m&&this.contextWindowStateManager.recordWarning(this.getConversationId())),u<=m)return o;let b=this.contextWindowConfig.strategy??"prune";if(b==="fail"&&u>p)throw new Cn("Context window exceeded by request messages",this.getConversationId(),u,p,b);if(b==="summarize")try{let T=await this.summarizeConversation(o,t);if(await this.countRequestTokens(T,t,T.model)<=p)return T;o=await this.pruneConversation(T,t,p)}catch(T){if(T instanceof A)throw T;o=await this.pruneConversation(o,t,p)}else o=await this.pruneConversation(o,t,p);let h=await this.countRequestTokens(o,t,o.model);if(h>p&&b==="fail")throw new Cn("Context window exceeded after attempted cleanup",this.getConversationId(),h,p,b);return o}isBypassed(e){let t=this.hitlConfig;if(!t||t.enabled===!1)return!0;let o=t.confirmationMode??"all";if(o==="off"||o==="high-only"&&e.confirmation?.level==="medium")return!0;let n=t.bypass??{};return!!(n.tools?.includes(e.name)||n.categories?.includes(e.category)||e.confirmation&&n.levels?.includes(e.confirmation.level))}registerProvider(e,t){this.providers.set(e,t)}getProvider(e){let t=e||this.defaultProvider;if(!t)throw new M("No provider specified and no default provider configured","NO_PROVIDER_CONFIGURED",400);let o=this.providers.get(t);if(!o)throw new M(`Provider '${t}' not found`,"PROVIDER_NOT_FOUND",404);return o}updateHitlConfig(e){this.hitlConfig=e}getHitlConfig(){return this.hitlConfig}setDefaultProvider(e){if(!this.providers.has(e))throw new M(`Provider '${e}' not found`,"PROVIDER_NOT_FOUND",404);this.defaultProvider=e}getToolRegistry(){return this.toolRegistry}getProviders(){return new Map(this.providers)}setToolRegistry(e){this.toolRegistry=e}setToolsConfig(e){this.toolsConfig=e}setSystemPrompt(e){this.overrideSystemPrompt=e}setMode(e){this.activeMode=e,k(`[AIClient] Mode set to: ${e?e.displayName:"none (cleared)"}`)}getMode(){return this.activeMode}getQueryClassifier(){return this.queryClassifier}reindexTools(){this.toolRegistry&&(this.bm25Engine.index(this.toolRegistry.getAll()),k(`[AIClient] Re-indexed ${this.bm25Engine.getIndexedCount()} tools for BM25 search`))}clearToolDiscoveryCache(){this.toolRouter.clearDiscoveryCache()}async generate(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=this.resolveRequestMode(e),a=i?.toolsConfig?{...this.toolsConfig,...i.toolsConfig}:this.toolsConfig,l=this.injectBaseAgentContext(e,i);l=this.injectOverrideSystemPrompt(l),l=this.injectModeSystemPrompt(l,i),l=await this.injectModeRules(l,i);let p=t||this.defaultProvider,d=await this.enrichRequestWithTools(l,i),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let b=a.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",h=(m.tools?.length||0)>0,T=m.tool_choice!=null,C=Ql(m.messages),S=Xl(m.messages);!T&&h&&(b==="required"||b==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",_=i?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,..._?{response_format:_}:{}};k(`[AIClient][${s}] generate() start provider=${p} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${b} needsTools=${C} autoExecute=${a.enabled&&a.autoExecute}`),Bs(s,m.tools),Fr(s,m.messages);let j=re=>Fe(Il(()=>n.generate(re),{signal:e.signal,onRetry:(H,ee)=>k(`[AIClient][${s}] Rate limited \u2014 retrying in ${ee/1e3}s (attempt ${H}/3)`)}),e.signal),R=await j(E);if(y(`[AIClient][${s}] generate() initial response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`),a.autoExecute&&(this.toolRegistry||u.size>0||(i?.customTools?.length??0)>0)){let re=ut(m.messages),H=this.queryClassifier.classify(re),ee=a.maxToolRounds,xe=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(H,ee);m.maxToolRounds!==void 0?y(`[AIClient][${s}] maxToolRounds overridden per-request: ${xe} (classifier bypassed)`):xe!==ee?k(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), adjusted maxToolRounds: ${ee} \u2192 ${xe}`):y(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), keeping maxToolRounds: ${xe}`);let pe=0,Q=[...m.messages];for(R.tool_calls&&R.tool_calls.length>0&&k(`[AIClient] Received ${R.tool_calls.length} tool call(s): ${R.tool_calls.map(G=>G.name).join(", ")}`);R.tool_calls&&R.tool_calls.length>0&&pe<xe;){if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal`),new A;pe++,k(`[AIClient][${s}] generate() tool round ${pe}/${xe} tool_calls=${R.tool_calls.length}`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(B=>({id:B.id,type:"function",function:{name:B.name,arguments:JSON.stringify(B.arguments)}}))});let G=this.toolOrchestrator.shouldUseParallelExecution(R.tool_calls),K=3,Ae=R.tool_calls,ze=R.tool_calls.filter(B=>B.name==="web.fetch");if(ze.length>K){k(`[AIClient][${s}] Limiting web.fetch calls from ${ze.length} \u2192 ${K} to prevent context overflow`);let B=ze.slice(0,K);Ae=[...R.tool_calls.filter(be=>be.name!=="web.fetch"),...B];let J=ze.slice(K);for(let be of J)Q.push({role:"tool",tool_call_id:be.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let me=5e4,ye=0;if(G){k(`[AIClient][${s}] Using parallel execution for ${Ae.length} tools`);let B;try{B=await Fe(this.toolOrchestrator.executeWithDependencies(Ae,D=>this.executeTool(D,u,i,pe,e.signal),5),e.signal)}catch(D){if(D instanceof A)throw D;ge(`[AIClient][${s}] Parallel tool execution failed: ${D.message}`),B=new Map(Ae.map(J=>[J.id,JSON.stringify({error:D.message??"Tool execution failed"})]))}for(let D of Ae){let J=B.get(D.id)??JSON.stringify({error:"Tool execution result missing"}),be=typeof J=="string"?J:JSON.stringify(J),Et=me-ye,se=be.startsWith("data:image/"),ie;se?ie=be:ye+be.length>me?(I(`[AIClient][${s}] Tool output budget exceeded (${me} chars)`),ie=this.budgetTruncate(be,Et)):typeof J=="string"&&J.length>this.toolResultMaxChars?ie=`${J.slice(0,this.toolResultMaxChars)}
414
- [TRUNCATED tool result: ${J.length} chars]`:ie=be;let $=typeof ie=="string"?ie:JSON.stringify(ie);se||(ye+=$.length),Q.push({role:"tool",tool_call_id:D.id,content:ie})}y(`[AIClient][${s}] Round tool output size: ${ye} chars (budget: ${me})`)}else{k(`[AIClient][${s}] Using sequential execution for ${Ae.length} tools`);for(let B of Ae){let D;try{D=await this.executeTool(B,u,i,pe,e.signal)}catch($){if($ instanceof A)throw $;D=JSON.stringify({error:$.message??"Tool execution failed"})}let J=typeof D=="string"?D:JSON.stringify(D),be=me-ye,Et=J.startsWith("data:image/"),se;Et?se=J:ye+J.length>me?(I(`[AIClient][${s}] Tool output budget exceeded (${me} chars)`),se=this.budgetTruncate(J,be)):typeof D=="string"&&D.length>this.toolResultMaxChars?se=`${D.slice(0,this.toolResultMaxChars)}
415
- [TRUNCATED tool result: ${D.length} chars]`:se=J;let ie=typeof se=="string"?se:JSON.stringify(se);Et||(ye+=ie.length),Q.push({role:"tool",tool_call_id:B.id,content:se})}y(`[AIClient][${s}] Round tool output size: ${ye} chars (budget: ${me})`)}if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal during tool execution`),new A;let je={...m,messages:Q,__toolpack_request_id:s,..._?{response_format:_}:{}},He=o?.getLatestRequestTools?.()??[];if(He.length>0){let B=new Map((m.requestTools??[]).map(D=>[D.name,D]));for(let D of He)B.set(D.name,D);je.requestTools=Array.from(B.values());for(let D of He)u.set(D.name,D)}let _e=this.stripRequestTools((await this.enrichRequestWithTools(je,i)).request);_e=await this.enforceContextWindow(_e,n),_e.tool_choice==="required"&&(_e.tool_choice=S?"none":"auto",k(`[AIClient][${s}] generate() followup tool_choice override required->${_e.tool_choice}`)),gt("debug")&&(y(`[AIClient][${s}] generate() followup request messages=${Q.length}`),Fr(s,Q)),R=await j(_e),y(`[AIClient][${s}] generate() followup response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`)}if(pe>=xe&&!e.signal?.aborted&&R.tool_calls&&R.tool_calls.length>0){k(`[AIClient][${s}] Tool-round cap (${xe}) hit with pending tool calls; requesting graceful conclusion`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(K=>({id:K.id,type:"function",function:{name:K.name,arguments:JSON.stringify(K.arguments)}}))});for(let K of R.tool_calls)Q.push({role:"tool",tool_call_id:K.id,content:"[Tool call skipped: maximum tool rounds reached]"});Q.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let G={...m,messages:Q,__toolpack_request_id:s,tools:[],requestTools:[],tool_choice:void 0};try{R=await j(await this.enforceContextWindow(G,n)),k(`[AIClient][${s}] Graceful conclusion received content_length=${R.content?.length??0}`)}catch(K){if(K instanceof A)throw K;I(`[AIClient][${s}] Graceful conclusion call failed: ${K?.message??K}; returning last response`)}}}return R.data===void 0&&R.content&&e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format&&(R.data=e.response_format.parse(JSON.parse(R.content))),R}catch(s){throw this.wrapError(s)}}async*stream(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=t||this.defaultProvider,a=this.resolveRequestMode(e),l=a?.toolsConfig?{...this.toolsConfig,...a.toolsConfig}:this.toolsConfig,p=this.injectBaseAgentContext(e,a);p=this.injectOverrideSystemPrompt(p),p=this.injectModeSystemPrompt(p,a),p=await this.injectModeRules(p,a);let d=await this.enrichRequestWithTools(p,a),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let b=l.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",h=(m.tools?.length||0)>0,T=m.tool_choice!=null,C=Ql(m.messages),S=Xl(m.messages);!T&&h&&(b==="required"||b==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",_=a?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,..._?{response_format:_}:{}};if(k(`[AIClient][${s}] stream() start provider=${i} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${b} needsTools=${C} autoExecute=${l.enabled&&l.autoExecute}`),Bs(s,m.tools),Fr(s,m.messages),!l.autoExecute||!this.toolRegistry&&u.size===0&&(a?.customTools?.length??0)===0){if(yield*vn(n.stream(E),e.signal),e.signal?.aborted)throw new A;return}let j=[...m.messages],R=0,re=!1,H=ut(m.messages),ee=this.queryClassifier.classify(H),xe=l.maxToolRounds,pe=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(ee,xe);for(m.maxToolRounds!==void 0?y(`[AIClient][${s}] stream() maxToolRounds overridden per-request: ${pe} (classifier bypassed)`):pe!==xe&&k(`[AIClient][${s}] stream() Query classified as ${ee.type} (confidence: ${ee.confidence.toFixed(2)}), adjusted maxToolRounds: ${xe} \u2192 ${pe}`);R<=pe;){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal`),new A;let Q="",G=[];R++,k(`[AIClient][${s}] stream() round_start ${R}/${pe}`);let K=null,Ae={...m,messages:j,..._?{response_format:_}:{}},ze=o?.getLatestRequestTools?.()??[];if(ze.length>0){let $=new Map((m.requestTools??[]).map(q=>[q.name,q]));for(let q of ze)$.set(q.name,q);Ae.requestTools=Array.from($.values());for(let q of ze)u.set(q.name,q)}let me=this.stripRequestTools((await this.enrichRequestWithTools(Ae,a)).request);me=await this.enforceContextWindow(me,n),R>1&&me.tool_choice==="required"&&(me.tool_choice=S?"none":"auto",k(`[AIClient][${s}] stream() round_${R} tool_choice override required->${me.tool_choice}`));for await(let $ of vn(n.stream(me),e.signal)){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during chunk processing`),new A;$.tool_calls&&$.tool_calls.length>0&&(G.push(...$.tool_calls),y(`[AIClient][${s}] stream() tool_calls_chunk count=${$.tool_calls.length} names=${$.tool_calls.map(q=>q.name).join(", ")}`),yield $),$.delta&&(Q+=$.delta,yield $),$.finish_reason&&(K=$.finish_reason),$.finish_reason==="stop"&&(yield $)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal while waiting for the provider`),new A;if(y(`[AIClient][${s}] stream() round_end finish_reason=${K??"unknown"} accumulated_len=${Q.length} tool_calls_total=${G.length} content=${Q}`),G.length===0)break;k(`[AIClient][${s}] stream() received ${G.length} tool call(s): ${G.map($=>$.name).join(", ")}`),k(`[AIClient][${s}] stream() tool round ${R}/${pe}`),j.push({role:"assistant",content:Q||"",tool_calls:G.map($=>({id:$.id,type:"function",function:{name:$.name,arguments:JSON.stringify($.arguments)}}))});let ye=3,je=G,He=G.filter($=>$.name==="web.fetch");if(He.length>ye){k(`[AIClient][${s}] Limiting web.fetch calls from ${He.length} \u2192 ${ye} to prevent context overflow`);let $=He.slice(0,ye);je=[...G.filter(xn=>xn.name!=="web.fetch"),...$];let Pe=He.slice(ye);for(let xn of Pe)j.push({role:"tool",tool_call_id:xn.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let _e=5e4,B=0,D=[],J=!1,be=setInterval(()=>{J||D.push({delta:""})},500),Et=Date.now(),se,ie;try{if(je.length>=2)k(`[AIClient][${s}] stream() using parallel execution for ${je.length} tools`),ie=new Map,se=await Fe(this.toolOrchestrator.executeWithDependencies(je,async $=>{let q=Date.now(),Pe=await this.executeTool($,u,a,R,e.signal);return ie.set($.id,Date.now()-q),Pe},5),e.signal);else{k(`[AIClient][${s}] stream() executing single tool sequentially`),ie=new Map,se=new Map;for(let $ of je){let q=Date.now(),Pe=await this.executeTool($,u,a,R,e.signal);ie.set($.id,Date.now()-q),se.set($.id,Pe)}}}finally{J=!0,clearInterval(be)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during tool execution`),new A;for(;D.length>0;)yield D.shift();await new Promise($=>setTimeout($,0)),y(`[AIClient][${s}] stream() tool batch completed in ${Date.now()-Et}ms`);for(let $ of je){let q=se.get($.id),Pe=typeof q=="string"?q:JSON.stringify(q),xn=_e-B,sx=ie.get($.id)??0,Ml=Pe.startsWith("data:image/"),Ke;Ml?Ke=Pe:B+Pe.length>_e?(I(`[AIClient][${s}] Tool output budget exceeded (${_e} chars)`),Ke=this.budgetTruncate(Pe,xn)):typeof q=="string"&&q.length>this.toolResultMaxChars?Ke=`${q.slice(0,this.toolResultMaxChars)}
416
- [TRUNCATED tool result: ${q.length} chars]`:Ke=Pe;let Nl=typeof Ke=="string"?Ke:JSON.stringify(Ke);Ml||(B+=Nl.length),j.push({role:"tool",tool_call_id:$.id,content:Ke}),yield{delta:"",tool_calls:[{...$,result:Nl,duration:sx}]}}y(`[AIClient][${s}] Round tool output size: ${B} chars (budget: ${_e})`),gt("debug")&&(y(`[AIClient][${s}] stream() after_tools messages=${j.length}`),Fr(s,j)),R>pe&&(re=!0)}if(re&&!e.signal?.aborted){k(`[AIClient][${s}] Tool-round cap (${pe}) hit; requesting graceful conclusion`),j.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let Q={...m,messages:j,tools:[],requestTools:[],tool_choice:void 0};try{let G=await this.enforceContextWindow(Q,n);for await(let K of vn(n.stream(G),e.signal))yield K;if(e.signal?.aborted)throw new A;k(`[AIClient][${s}] Graceful conclusion stream complete`)}catch(G){if(G instanceof A)throw G;I(`[AIClient][${s}] Graceful conclusion stream failed: ${G?.message??G}`)}}}catch(s){if(s instanceof A){yield{delta:"",finish_reason:"aborted"};return}throw this.wrapError(s)}}async embed(e,t){let o=this.getProvider(t);try{return await o.embed(e)}catch(n){throw this.wrapError(n)}}async enrichRequestWithTools(e,t){if(t?.blockAllTools)return k(`[AIClient] Mode "${t.displayName}" blocks all tools`),{request:e,requestToolMap:new Map};let o=this.buildRequestToolMap(e.requestTools),n=Array.from(o.values()).map(h=>this.requestToolToSchema(h)),s=o.size>0,i=t?.toolsConfig?{...this.toolsConfig,...t.toolsConfig}:this.toolsConfig,a=this.toolDefinitionsToSchemas(t?.customTools??[]),l=this.mergeSchemas(a,n);if(!i.enabled&&!s&&a.length===0)return y("[AIClient] Tools disabled and no request-scoped or mode tools"),{request:e,requestToolMap:o};let p=i;if(t?.toolSearch&&i.toolSearch&&(p={...i,toolSearch:{...i.toolSearch,...t.toolSearch.enabled!==void 0?{enabled:t.toolSearch.enabled}:{},...t.toolSearch.alwaysLoadedTools?{alwaysLoadedTools:t.toolSearch.alwaysLoadedTools}:{},...t.toolSearch.alwaysLoadedCategories?{alwaysLoadedCategories:t.toolSearch.alwaysLoadedCategories}:{}}},y(`[AIClient] Merged mode toolSearch config: enabled=${p.toolSearch?.enabled}, alwaysLoadedTools=${p.toolSearch?.alwaysLoadedTools?.length||0}`)),e.tools&&e.tools.length>0){if(!p.toolSearch?.enabled||!this.toolRegistry){y(`[AIClient] Request already has ${e.tools.length} tools`);let w=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=w===e.tools?e:{...e,tools:w};return{request:this.injectRequestToolGuidance(v,w),requestToolMap:o}}let h=await this.toolRouter.resolve(e.messages,this.toolRegistry,p);if(y(`[AIClient] Resolved ${h.length} tools to send: ${h.map(w=>w.name).join(", ")||"none"}`),t&&h.length>0){let w=h.length;h=this.filterSchemasByMode(h,t);let v=w-h.length;v>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${v} tools`)}let T=new Set(e.tools.map(w=>w.function.name)),C=h.filter(w=>!T.has(w.name)).map(w=>({type:"function",function:{name:w.name,description:w.description,parameters:w.parameters}}));if(C.length===0){y(`[AIClient] Request already has ${e.tools.length} tools (no new discoveries)`);let w=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=w===e.tools?e:{...e,tools:w};return{request:this.injectRequestToolGuidance(v,w),requestToolMap:o}}let S={...e,tools:this.mergeToolCallRequests([...e.tools,...C],this.schemasToToolCallRequests(l))};return p.toolSearch?.enabled&&this.toolRegistry&&(S=this.injectToolSearchPrompt(S)),{request:this.injectRequestToolGuidance(S,S.tools),requestToolMap:o}}if(!this.toolRegistry){y("[AIClient] Tool registry not configured, skipping tool resolution");let h=this.schemasToToolCallRequests(l),T=h.length>0?{...e,tools:h}:e;return{request:this.injectRequestToolGuidance(T,h),requestToolMap:o}}let d=this.toolRegistry,m=await this.toolRouter.resolve(e.messages,d,p);if(y(`[AIClient] Resolved ${m.length} tools to send: ${m.map(h=>h.name).join(", ")||"none"}`),t&&m.length>0){let h=m.length;m=this.filterSchemasByMode(m,t);let T=h-m.length;T>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${T} tools`)}let u=this.schemasToToolCallRequests(this.mergeSchemas(m,l));if(u.length===0)return{request:e,requestToolMap:o};let b={...e,tools:u};return i.toolSearch?.enabled&&d&&(b=this.injectToolSearchPrompt(b)),{request:this.injectRequestToolGuidance(b,u),requestToolMap:o}}toolDefinitionsToSchemas(e){return e.map(t=>({name:t.name,displayName:t.displayName,description:t.description,parameters:t.parameters,category:t.category,...t.cacheable!==void 0&&{cacheable:t.cacheable},...t.annotations!==void 0&&{annotations:t.annotations}}))}buildRequestToolMap(e){let t=new Map;for(let o of e||[])t.set(o.name,o);return t}requestToolToSchema(e){return{name:e.name,displayName:e.displayName,description:e.description,parameters:e.parameters,category:e.category,cacheable:e.cacheable}}mergeSchemas(e,t){let o=new Map;for(let n of e)o.set(n.name,n);for(let n of t)o.set(n.name,n);return Array.from(o.values())}schemasToToolCallRequests(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.parameters}}))}mergeToolCallRequests(e,t){if(t.length===0)return e;let o=new Map;for(let n of e)o.set(n.function.name,n);for(let n of t)o.set(n.function.name,n);return Array.from(o.values())}injectRequestToolGuidance(e,t){if(this.disableToolGuidance)return e;let o=new Set((t||e.tools||[]).map(p=>p.function.name));if(o.size===0)return e;let n="<!-- TOOLPACK_REQUEST_TOOL_GUIDANCE -->",s=[],i=o.has("mind_believe");if(o.has("knowledge_search")||o.has("knowledge_add")){let p=["Knowledge Base:"];if(o.has("knowledge_search")&&p.push("- Use `knowledge_search` proactively whenever the user asks about anything that could have been stored, including personal facts about the user, their preferences, names, past decisions, domain-specific information or anything that could have been stored in the memory. Search before concluding you do not know something."),o.has("knowledge_add")){let d=i?"- Use `knowledge_add` for factual domain knowledge: documents, research, technical references, or organizational information shared across agents. Do NOT use it for personal user facts or preferences \u2014 use `mind_believe` for those.":"- Use `knowledge_add` when you encounter a durable fact, user preference, or decision that future conversations should know. Do not add confidential information, routine task outputs, or context that is specific to this conversation only.";p.push(d)}s.push(p.join(`
413
+ </rules>`;return this.modeCache.set(n,{value:p,cachedAt:Date.now()}),p}clearCache(){this.modeCache.clear()}async collectFromFolder(e,t){let o=(0,Ze.resolve)(e);try{await this.collectRecursive(o,t)}catch{}}async collectRecursive(e,t){let o=await(0,jr.readdir)(e,{withFileTypes:!0});for(let n of o){let s=(0,Ze.join)(e,n.name);n.isDirectory()?await this.collectRecursive(s,t):n.isFile()&&(0,Ze.extname)(n.name)===".md"&&t.add(s)}}async readFile(e,t){if(t.has(e))return t.get(e);try{let o=await(0,jr.readFile)(e,"utf-8");return t.set(e,o),o}catch{return""}}};function Fr(r,e){gt("debug")&&(y(`[AIClient][${r}] Messages (${e.length}):`),e.forEach((t,o)=>{let n=t,s=typeof n.content=="string"?n.content:N(n.content,1e4);y(`[AIClient][${r}] #${o} role=${n.role} content=${s}`)}))}function Ql(r){let e=ut(r).toLowerCase();return e?[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/,/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b.*\b(file|folder|directory)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl|map)\b/,/https?:\/\//].some(o=>o.test(e)):!1}function Xl(r){let e=ut(r).toLowerCase();if(!e)return!1;let t=[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/],o=[/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl)\b/];return t.some(n=>n.test(e))&&!o.some(n=>n.test(e))}var Pn=class extends Yl.EventEmitter{providers;defaultProvider;toolRegistry;toolsConfig;toolRouter;bm25Engine;queryClassifier;toolOrchestrator;activeMode=null;overrideSystemPrompt;disableBaseContext;disableToolGuidance;toolResultMaxChars;hitlConfig;onToolConfirm;conversationId;contextWindowConfig;actor;contextWindowStateManager;providerModelCache=new Map;ruleLoader;requestSeq=0;constructor(e){super(),this.providers=new Map(Object.entries(e.providers)),this.defaultProvider=e.defaultProvider,this.toolRegistry=e.toolRegistry,this.toolsConfig=e.toolsConfig||oe,this.toolRouter=new Mt,this.bm25Engine=new At,this.queryClassifier=new Nt,this.toolOrchestrator=new Lr,this.overrideSystemPrompt=e.systemPrompt,this.disableBaseContext=e.disableBaseContext||!1,this.disableToolGuidance=e.disableToolGuidance||!1;let t=this.toolsConfig.resultMaxChars??oe.resultMaxChars??2e4;this.toolResultMaxChars=Number.isFinite(t)&&t>0?t:2e4,this.hitlConfig=e.hitlConfig,this.onToolConfirm=e.onToolConfirm,this.conversationId=e.conversationId,this.contextWindowConfig=e.contextWindowConfig,this.actor=e.actor,this.providerModelCache=new Map,this.ruleLoader=new ht,this.contextWindowConfig&&this.contextWindowConfig.enabled!==!1&&(this.contextWindowStateManager=Ws(this.contextWindowConfig)),this.toolRegistry&&this.bm25Engine.index(this.toolRegistry.getAll())}getConversationId(){return this.conversationId||"global"}async getModelInfo(e,t){let o=e.name||e.constructor.name,n=this.providerModelCache.get(o);if(!n){try{n=await e.getModels()}catch{n=[]}this.providerModelCache.set(o,n)}return n.find(s=>s.id===t||s.displayName===t)}async countRequestTokens(e,t,o){let n=await t.countTokens(e.messages,o);return typeof n=="number"&&Number.isFinite(n)?n:Ms(e.messages,o,t.getDisplayName().toLowerCase())}async pruneConversation(e,t,o){let n=this.contextWindowConfig?.retainSystemMessages??!0,s=e;for(let i=0;i<3;i+=1){let a=await this.countRequestTokens(s,t,s.model);if(a<=o)return s;let l=a-o,p=Is(s.messages,l,n),d=new Set(p.pruneInfo.removedMessages),m=s.messages.filter(h=>!d.has(h)),u={...s,messages:m};if(this.contextWindowStateManager&&this.contextWindowStateManager.recordPruneOperation(this.getConversationId(),p.tokensReclaimed),await this.countRequestTokens(u,t,u.model)<=o||m.length===s.messages.length)return u;s=u}return e}async pruneToMaxMessageHistory(e){let t=this.contextWindowConfig?.maxMessageHistoryLength;if(!t||e.messages.length<=t)return e;let o=this.contextWindowConfig?.retainSystemMessages??!0,n=[];e.messages.forEach((l,p)=>{o&&l.role==="system"||l.role!=="tool"&&n.push(p)});let s=Math.max(0,e.messages.length-t);if(s===0)return e;let i=new Set(n.slice(0,s)),a=e.messages.filter((l,p)=>!i.has(p));return{...e,messages:a}}async summarizeConversation(e,t){let o=e.messages,n=o.filter(C=>C.role==="system"),s=o.filter(C=>C.role!=="system");if(s.length<4)return e;let i=s.slice(-4),a=s.slice(0,-4);if(a.length<2)return e;let l=this.contextWindowConfig?.summarizerModel||e.model,p=Fs(a,{model:l,maxSummaryTokens:500}),d=await Fe(t.generate({model:l,messages:p,max_tokens:500,temperature:0,response_format:"text",signal:e.signal}),e.signal);if(!d.content)throw new kn("Summarization provider returned no summary",this.getConversationId(),a.length,"invalid_response");let m=await this.countRequestTokens({...e,messages:a},t,l),u=qs(d.content,a,m),b=js(u);if(!b.valid)throw new kn(`Summarization result is invalid: ${b.issues.join("; ")}`,this.getConversationId(),a.length,"invalid_quality",d.content);let h=Nr(u.summary,a.length),T=[...n,h,...i];return this.contextWindowStateManager&&this.contextWindowStateManager.recordSummarization(this.getConversationId(),u.tokensSaved),{...e,messages:T}}async enforceContextWindow(e,t){if(!this.contextWindowConfig||this.contextWindowConfig.enabled===!1)return e;let o=await this.pruneToMaxMessageHistory(e),n=await this.getModelInfo(t,o.model),s=n?.contextWindow??1e5,i=o.max_tokens??n?.maxOutputTokens??1024,a=this.contextWindowConfig.outputTokenBuffer??1.15,l=Ns(i,a),p=Math.max(0,s-l),d=Math.floor(s*((this.contextWindowConfig.pruneThreshold??85)/100)),m=Math.min(p,d),u=await this.countRequestTokens(o,t,o.model);if(this.contextWindowStateManager&&(this.contextWindowStateManager.updateTokenCount(this.getConversationId(),u),u>m&&this.contextWindowStateManager.recordWarning(this.getConversationId())),u<=m)return o;let b=this.contextWindowConfig.strategy??"prune";if(b==="fail"&&u>p)throw new Cn("Context window exceeded by request messages",this.getConversationId(),u,p,b);if(b==="summarize")try{let T=await this.summarizeConversation(o,t);if(await this.countRequestTokens(T,t,T.model)<=p)return T;o=await this.pruneConversation(T,t,p)}catch(T){if(T instanceof A)throw T;o=await this.pruneConversation(o,t,p)}else o=await this.pruneConversation(o,t,p);let h=await this.countRequestTokens(o,t,o.model);if(h>p&&b==="fail")throw new Cn("Context window exceeded after attempted cleanup",this.getConversationId(),h,p,b);return o}isBypassed(e){let t=this.hitlConfig;if(!t||t.enabled===!1)return!0;let o=t.confirmationMode??"all";if(o==="off"||o==="high-only"&&e.confirmation?.level==="medium")return!0;let n=t.bypass??{};return!!(n.tools?.includes(e.name)||n.categories?.includes(e.category)||e.confirmation&&n.levels?.includes(e.confirmation.level))}registerProvider(e,t){this.providers.set(e,t)}getProvider(e){let t=e||this.defaultProvider;if(!t)throw new M("No provider specified and no default provider configured","NO_PROVIDER_CONFIGURED",400);let o=this.providers.get(t);if(!o)throw new M(`Provider '${t}' not found`,"PROVIDER_NOT_FOUND",404);return o}updateHitlConfig(e){this.hitlConfig=e}getHitlConfig(){return this.hitlConfig}setDefaultProvider(e){if(!this.providers.has(e))throw new M(`Provider '${e}' not found`,"PROVIDER_NOT_FOUND",404);this.defaultProvider=e}getToolRegistry(){return this.toolRegistry}getProviders(){return new Map(this.providers)}setToolRegistry(e){this.toolRegistry=e}setToolsConfig(e){this.toolsConfig=e}setSystemPrompt(e){this.overrideSystemPrompt=e}setMode(e){this.activeMode=e,k(`[AIClient] Mode set to: ${e?e.displayName:"none (cleared)"}`)}getMode(){return this.activeMode}getQueryClassifier(){return this.queryClassifier}reindexTools(){this.toolRegistry&&(this.bm25Engine.index(this.toolRegistry.getAll()),k(`[AIClient] Re-indexed ${this.bm25Engine.getIndexedCount()} tools for BM25 search`))}clearToolDiscoveryCache(){this.toolRouter.clearDiscoveryCache()}async generate(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=this.resolveRequestMode(e),a=i?.toolsConfig?{...this.toolsConfig,...i.toolsConfig}:this.toolsConfig,l=this.injectBaseAgentContext(e,i);l=this.injectOverrideSystemPrompt(l),l=this.injectModeSystemPrompt(l,i),l=await this.injectModeRules(l,i);let p=t||this.defaultProvider,d=await this.enrichRequestWithTools(l,i),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let b=a.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",h=(m.tools?.length||0)>0,T=m.tool_choice!=null,C=Ql(m.messages),S=Xl(m.messages);!T&&h&&(b==="required"||b==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",_=i?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,..._?{response_format:_}:{}};k(`[AIClient][${s}] generate() start provider=${p} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${b} needsTools=${C} autoExecute=${a.enabled&&a.autoExecute}`),Bs(s,m.tools),Fr(s,m.messages);let j=re=>Fe(Il(()=>n.generate(re),{signal:e.signal,onRetry:(H,ee)=>k(`[AIClient][${s}] Rate limited \u2014 retrying in ${ee/1e3}s (attempt ${H}/3)`)}),e.signal),R=await j(E);if(y(`[AIClient][${s}] generate() initial response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`),a.autoExecute&&(this.toolRegistry||u.size>0||(i?.customTools?.length??0)>0)){let re=ut(m.messages),H=this.queryClassifier.classify(re),ee=a.maxToolRounds,xe=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(H,ee);m.maxToolRounds!==void 0?y(`[AIClient][${s}] maxToolRounds overridden per-request: ${xe} (classifier bypassed)`):xe!==ee?k(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), adjusted maxToolRounds: ${ee} \u2192 ${xe}`):y(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), keeping maxToolRounds: ${xe}`);let pe=0,Q=[...m.messages];for(R.tool_calls&&R.tool_calls.length>0&&k(`[AIClient] Received ${R.tool_calls.length} tool call(s): ${R.tool_calls.map(G=>G.name).join(", ")}`);R.tool_calls&&R.tool_calls.length>0&&pe<xe;){if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal`),new A;pe++,k(`[AIClient][${s}] generate() tool round ${pe}/${xe} tool_calls=${R.tool_calls.length}`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(B=>({id:B.id,type:"function",function:{name:B.name,arguments:JSON.stringify(B.arguments)}}))});let G=this.toolOrchestrator.shouldUseParallelExecution(R.tool_calls),K=3,Ae=R.tool_calls,ze=R.tool_calls.filter(B=>B.name==="web.fetch");if(ze.length>K){k(`[AIClient][${s}] Limiting web.fetch calls from ${ze.length} \u2192 ${K} to prevent context overflow`);let B=ze.slice(0,K);Ae=[...R.tool_calls.filter(be=>be.name!=="web.fetch"),...B];let J=ze.slice(K);for(let be of J)Q.push({role:"tool",tool_call_id:be.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let me=5e4,ye=0;if(G){k(`[AIClient][${s}] Using parallel execution for ${Ae.length} tools`);let B;try{B=await Fe(this.toolOrchestrator.executeWithDependencies(Ae,D=>this.executeTool(D,u,i,pe,e.signal,e.interceptTool),5),e.signal)}catch(D){if(D instanceof A)throw D;ge(`[AIClient][${s}] Parallel tool execution failed: ${D.message}`),B=new Map(Ae.map(J=>[J.id,JSON.stringify({error:D.message??"Tool execution failed"})]))}for(let D of Ae){let J=B.get(D.id)??JSON.stringify({error:"Tool execution result missing"}),be=typeof J=="string"?J:JSON.stringify(J),Et=me-ye,se=be.startsWith("data:image/"),ie;se?ie=be:ye+be.length>me?(I(`[AIClient][${s}] Tool output budget exceeded (${me} chars)`),ie=this.budgetTruncate(be,Et)):typeof J=="string"&&J.length>this.toolResultMaxChars?ie=`${J.slice(0,this.toolResultMaxChars)}
414
+ [TRUNCATED tool result: ${J.length} chars]`:ie=be;let $=typeof ie=="string"?ie:JSON.stringify(ie);se||(ye+=$.length),Q.push({role:"tool",tool_call_id:D.id,content:ie})}y(`[AIClient][${s}] Round tool output size: ${ye} chars (budget: ${me})`)}else{k(`[AIClient][${s}] Using sequential execution for ${Ae.length} tools`);for(let B of Ae){let D;try{D=await this.executeTool(B,u,i,pe,e.signal,e.interceptTool)}catch($){if($ instanceof A)throw $;D=JSON.stringify({error:$.message??"Tool execution failed"})}let J=typeof D=="string"?D:JSON.stringify(D),be=me-ye,Et=J.startsWith("data:image/"),se;Et?se=J:ye+J.length>me?(I(`[AIClient][${s}] Tool output budget exceeded (${me} chars)`),se=this.budgetTruncate(J,be)):typeof D=="string"&&D.length>this.toolResultMaxChars?se=`${D.slice(0,this.toolResultMaxChars)}
415
+ [TRUNCATED tool result: ${D.length} chars]`:se=J;let ie=typeof se=="string"?se:JSON.stringify(se);Et||(ye+=ie.length),Q.push({role:"tool",tool_call_id:B.id,content:se})}y(`[AIClient][${s}] Round tool output size: ${ye} chars (budget: ${me})`)}if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal during tool execution`),new A;let je={...m,messages:Q,__toolpack_request_id:s,..._?{response_format:_}:{}},He=o?.getLatestRequestTools?.()??[];if(He.length>0){let B=new Map((m.requestTools??[]).map(D=>[D.name,D]));for(let D of He)B.set(D.name,D);je.requestTools=Array.from(B.values());for(let D of He)u.set(D.name,D)}let _e=this.stripRequestTools((await this.enrichRequestWithTools(je,i)).request);_e=await this.enforceContextWindow(_e,n),_e.tool_choice==="required"&&(_e.tool_choice=S?"none":"auto",k(`[AIClient][${s}] generate() followup tool_choice override required->${_e.tool_choice}`)),gt("debug")&&(y(`[AIClient][${s}] generate() followup request messages=${Q.length}`),Fr(s,Q)),R=await j(_e),y(`[AIClient][${s}] generate() followup response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`)}if(pe>=xe&&!e.signal?.aborted&&R.tool_calls&&R.tool_calls.length>0){k(`[AIClient][${s}] Tool-round cap (${xe}) hit with pending tool calls; requesting graceful conclusion`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(K=>({id:K.id,type:"function",function:{name:K.name,arguments:JSON.stringify(K.arguments)}}))});for(let K of R.tool_calls)Q.push({role:"tool",tool_call_id:K.id,content:"[Tool call skipped: maximum tool rounds reached]"});Q.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let G={...m,messages:Q,__toolpack_request_id:s,tools:[],requestTools:[],interceptTool:void 0,tool_choice:void 0};try{R=await j(await this.enforceContextWindow(G,n)),k(`[AIClient][${s}] Graceful conclusion received content_length=${R.content?.length??0}`)}catch(K){if(K instanceof A)throw K;I(`[AIClient][${s}] Graceful conclusion call failed: ${K?.message??K}; returning last response`)}}}return R.data===void 0&&R.content&&e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format&&(R.data=e.response_format.parse(JSON.parse(R.content))),R}catch(s){throw this.wrapError(s)}}async*stream(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=t||this.defaultProvider,a=this.resolveRequestMode(e),l=a?.toolsConfig?{...this.toolsConfig,...a.toolsConfig}:this.toolsConfig,p=this.injectBaseAgentContext(e,a);p=this.injectOverrideSystemPrompt(p),p=this.injectModeSystemPrompt(p,a),p=await this.injectModeRules(p,a);let d=await this.enrichRequestWithTools(p,a),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let b=l.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",h=(m.tools?.length||0)>0,T=m.tool_choice!=null,C=Ql(m.messages),S=Xl(m.messages);!T&&h&&(b==="required"||b==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",_=a?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,..._?{response_format:_}:{}};if(k(`[AIClient][${s}] stream() start provider=${i} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${b} needsTools=${C} autoExecute=${l.enabled&&l.autoExecute}`),Bs(s,m.tools),Fr(s,m.messages),!l.autoExecute||!this.toolRegistry&&u.size===0&&(a?.customTools?.length??0)===0){if(yield*vn(n.stream(E),e.signal),e.signal?.aborted)throw new A;return}let j=[...m.messages],R=0,re=!1,H=ut(m.messages),ee=this.queryClassifier.classify(H),xe=l.maxToolRounds,pe=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(ee,xe);for(m.maxToolRounds!==void 0?y(`[AIClient][${s}] stream() maxToolRounds overridden per-request: ${pe} (classifier bypassed)`):pe!==xe&&k(`[AIClient][${s}] stream() Query classified as ${ee.type} (confidence: ${ee.confidence.toFixed(2)}), adjusted maxToolRounds: ${xe} \u2192 ${pe}`);R<=pe;){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal`),new A;let Q="",G=[];R++,k(`[AIClient][${s}] stream() round_start ${R}/${pe}`);let K=null,Ae={...m,messages:j,..._?{response_format:_}:{}},ze=o?.getLatestRequestTools?.()??[];if(ze.length>0){let $=new Map((m.requestTools??[]).map(q=>[q.name,q]));for(let q of ze)$.set(q.name,q);Ae.requestTools=Array.from($.values());for(let q of ze)u.set(q.name,q)}let me=this.stripRequestTools((await this.enrichRequestWithTools(Ae,a)).request);me=await this.enforceContextWindow(me,n),R>1&&me.tool_choice==="required"&&(me.tool_choice=S?"none":"auto",k(`[AIClient][${s}] stream() round_${R} tool_choice override required->${me.tool_choice}`));for await(let $ of vn(n.stream(me),e.signal)){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during chunk processing`),new A;$.tool_calls&&$.tool_calls.length>0&&(G.push(...$.tool_calls),y(`[AIClient][${s}] stream() tool_calls_chunk count=${$.tool_calls.length} names=${$.tool_calls.map(q=>q.name).join(", ")}`),yield $),$.delta&&(Q+=$.delta,yield $),$.finish_reason&&(K=$.finish_reason),$.finish_reason==="stop"&&(yield $)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal while waiting for the provider`),new A;if(y(`[AIClient][${s}] stream() round_end finish_reason=${K??"unknown"} accumulated_len=${Q.length} tool_calls_total=${G.length} content=${Q}`),G.length===0)break;k(`[AIClient][${s}] stream() received ${G.length} tool call(s): ${G.map($=>$.name).join(", ")}`),k(`[AIClient][${s}] stream() tool round ${R}/${pe}`),j.push({role:"assistant",content:Q||"",tool_calls:G.map($=>({id:$.id,type:"function",function:{name:$.name,arguments:JSON.stringify($.arguments)}}))});let ye=3,je=G,He=G.filter($=>$.name==="web.fetch");if(He.length>ye){k(`[AIClient][${s}] Limiting web.fetch calls from ${He.length} \u2192 ${ye} to prevent context overflow`);let $=He.slice(0,ye);je=[...G.filter(xn=>xn.name!=="web.fetch"),...$];let Pe=He.slice(ye);for(let xn of Pe)j.push({role:"tool",tool_call_id:xn.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let _e=5e4,B=0,D=[],J=!1,be=setInterval(()=>{J||D.push({delta:""})},500),Et=Date.now(),se,ie;try{if(je.length>=2)k(`[AIClient][${s}] stream() using parallel execution for ${je.length} tools`),ie=new Map,se=await Fe(this.toolOrchestrator.executeWithDependencies(je,async $=>{let q=Date.now(),Pe=await this.executeTool($,u,a,R,e.signal,e.interceptTool);return ie.set($.id,Date.now()-q),Pe},5),e.signal);else{k(`[AIClient][${s}] stream() executing single tool sequentially`),ie=new Map,se=new Map;for(let $ of je){let q=Date.now(),Pe=await this.executeTool($,u,a,R,e.signal,e.interceptTool);ie.set($.id,Date.now()-q),se.set($.id,Pe)}}}finally{J=!0,clearInterval(be)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during tool execution`),new A;for(;D.length>0;)yield D.shift();await new Promise($=>setTimeout($,0)),y(`[AIClient][${s}] stream() tool batch completed in ${Date.now()-Et}ms`);for(let $ of je){let q=se.get($.id),Pe=typeof q=="string"?q:JSON.stringify(q),xn=_e-B,sx=ie.get($.id)??0,Ml=Pe.startsWith("data:image/"),Ke;Ml?Ke=Pe:B+Pe.length>_e?(I(`[AIClient][${s}] Tool output budget exceeded (${_e} chars)`),Ke=this.budgetTruncate(Pe,xn)):typeof q=="string"&&q.length>this.toolResultMaxChars?Ke=`${q.slice(0,this.toolResultMaxChars)}
416
+ [TRUNCATED tool result: ${q.length} chars]`:Ke=Pe;let Nl=typeof Ke=="string"?Ke:JSON.stringify(Ke);Ml||(B+=Nl.length),j.push({role:"tool",tool_call_id:$.id,content:Ke}),yield{delta:"",tool_calls:[{...$,result:Nl,duration:sx}]}}y(`[AIClient][${s}] Round tool output size: ${B} chars (budget: ${_e})`),gt("debug")&&(y(`[AIClient][${s}] stream() after_tools messages=${j.length}`),Fr(s,j)),R>pe&&(re=!0)}if(re&&!e.signal?.aborted){k(`[AIClient][${s}] Tool-round cap (${pe}) hit; requesting graceful conclusion`),j.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let Q={...m,messages:j,tools:[],requestTools:[],interceptTool:void 0,tool_choice:void 0};try{let G=await this.enforceContextWindow(Q,n);for await(let K of vn(n.stream(G),e.signal))yield K;if(e.signal?.aborted)throw new A;k(`[AIClient][${s}] Graceful conclusion stream complete`)}catch(G){if(G instanceof A)throw G;I(`[AIClient][${s}] Graceful conclusion stream failed: ${G?.message??G}`)}}}catch(s){if(s instanceof A){yield{delta:"",finish_reason:"aborted"};return}throw this.wrapError(s)}}async embed(e,t){let o=this.getProvider(t);try{return await o.embed(e)}catch(n){throw this.wrapError(n)}}async enrichRequestWithTools(e,t){if(t?.blockAllTools)return k(`[AIClient] Mode "${t.displayName}" blocks all tools`),{request:e,requestToolMap:new Map};let o=this.buildRequestToolMap(e.requestTools),n=Array.from(o.values()).map(h=>this.requestToolToSchema(h)),s=o.size>0,i=t?.toolsConfig?{...this.toolsConfig,...t.toolsConfig}:this.toolsConfig,a=this.toolDefinitionsToSchemas(t?.customTools??[]),l=this.mergeSchemas(a,n);if(!i.enabled&&!s&&a.length===0)return y("[AIClient] Tools disabled and no request-scoped or mode tools"),{request:e,requestToolMap:o};let p=i;if(t?.toolSearch&&i.toolSearch&&(p={...i,toolSearch:{...i.toolSearch,...t.toolSearch.enabled!==void 0?{enabled:t.toolSearch.enabled}:{},...t.toolSearch.alwaysLoadedTools?{alwaysLoadedTools:t.toolSearch.alwaysLoadedTools}:{},...t.toolSearch.alwaysLoadedCategories?{alwaysLoadedCategories:t.toolSearch.alwaysLoadedCategories}:{}}},y(`[AIClient] Merged mode toolSearch config: enabled=${p.toolSearch?.enabled}, alwaysLoadedTools=${p.toolSearch?.alwaysLoadedTools?.length||0}`)),e.tools&&e.tools.length>0){if(!p.toolSearch?.enabled||!this.toolRegistry){y(`[AIClient] Request already has ${e.tools.length} tools`);let w=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=w===e.tools?e:{...e,tools:w};return{request:this.injectRequestToolGuidance(v,w),requestToolMap:o}}let h=await this.toolRouter.resolve(e.messages,this.toolRegistry,p);if(y(`[AIClient] Resolved ${h.length} tools to send: ${h.map(w=>w.name).join(", ")||"none"}`),t&&h.length>0){let w=h.length;h=this.filterSchemasByMode(h,t);let v=w-h.length;v>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${v} tools`)}let T=new Set(e.tools.map(w=>w.function.name)),C=h.filter(w=>!T.has(w.name)).map(w=>({type:"function",function:{name:w.name,description:w.description,parameters:w.parameters}}));if(C.length===0){y(`[AIClient] Request already has ${e.tools.length} tools (no new discoveries)`);let w=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=w===e.tools?e:{...e,tools:w};return{request:this.injectRequestToolGuidance(v,w),requestToolMap:o}}let S={...e,tools:this.mergeToolCallRequests([...e.tools,...C],this.schemasToToolCallRequests(l))};return p.toolSearch?.enabled&&this.toolRegistry&&(S=this.injectToolSearchPrompt(S)),{request:this.injectRequestToolGuidance(S,S.tools),requestToolMap:o}}if(!this.toolRegistry){y("[AIClient] Tool registry not configured, skipping tool resolution");let h=this.schemasToToolCallRequests(l),T=h.length>0?{...e,tools:h}:e;return{request:this.injectRequestToolGuidance(T,h),requestToolMap:o}}let d=this.toolRegistry,m=await this.toolRouter.resolve(e.messages,d,p);if(y(`[AIClient] Resolved ${m.length} tools to send: ${m.map(h=>h.name).join(", ")||"none"}`),t&&m.length>0){let h=m.length;m=this.filterSchemasByMode(m,t);let T=h-m.length;T>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${T} tools`)}let u=this.schemasToToolCallRequests(this.mergeSchemas(m,l));if(u.length===0)return{request:e,requestToolMap:o};let b={...e,tools:u};return i.toolSearch?.enabled&&d&&(b=this.injectToolSearchPrompt(b)),{request:this.injectRequestToolGuidance(b,u),requestToolMap:o}}toolDefinitionsToSchemas(e){return e.map(t=>({name:t.name,displayName:t.displayName,description:t.description,parameters:t.parameters,category:t.category,...t.cacheable!==void 0&&{cacheable:t.cacheable},...t.annotations!==void 0&&{annotations:t.annotations}}))}buildRequestToolMap(e){let t=new Map;for(let o of e||[])t.set(o.name,o);return t}requestToolToSchema(e){return{name:e.name,displayName:e.displayName,description:e.description,parameters:e.parameters,category:e.category,cacheable:e.cacheable}}mergeSchemas(e,t){let o=new Map;for(let n of e)o.set(n.name,n);for(let n of t)o.set(n.name,n);return Array.from(o.values())}schemasToToolCallRequests(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.parameters}}))}mergeToolCallRequests(e,t){if(t.length===0)return e;let o=new Map;for(let n of e)o.set(n.function.name,n);for(let n of t)o.set(n.function.name,n);return Array.from(o.values())}injectRequestToolGuidance(e,t){if(this.disableToolGuidance)return e;let o=new Set((t||e.tools||[]).map(p=>p.function.name));if(o.size===0)return e;let n="<!-- TOOLPACK_REQUEST_TOOL_GUIDANCE -->",s=[],i=o.has("mind_believe");if(o.has("knowledge_search")||o.has("knowledge_add")){let p=["Knowledge Base:"];if(o.has("knowledge_search")&&p.push("- Use `knowledge_search` proactively whenever the user asks about anything that could have been stored, including personal facts about the user, their preferences, names, past decisions, domain-specific information or anything that could have been stored in the memory. Search before concluding you do not know something."),o.has("knowledge_add")){let d=i?"- Use `knowledge_add` for factual domain knowledge: documents, research, technical references, or organizational information shared across agents. Do NOT use it for personal user facts or preferences \u2014 use `mind_believe` for those.":"- Use `knowledge_add` when you encounter a durable fact, user preference, or decision that future conversations should know. Do not add confidential information, routine task outputs, or context that is specific to this conversation only.";p.push(d)}s.push(p.join(`
417
417
  `))}if(i||o.has("mind_reflect")||o.has("mind_recall")){let p=["Agent Memory (Mind):"];i&&p.push("- Use `mind_believe` to record what you have personally learned about this user: their preferences, habits, stated personal facts (names, family, job, decisions), or anything you should remember about them across future conversations. Call it at the end of your response when you learn something personal. Always prefer `mind_believe` over `knowledge_add` for personal user facts."),o.has("mind_reflect")&&p.push("- Use `mind_reflect` to record a lesson learned, standing rule, or observation from this interaction that should influence future behaviour."),o.has("mind_recall")&&p.push("- Use `mind_recall` to search your personal memory before answering questions about the user or recalling past decisions."),s.push(p.join(`
418
418
  `))}if(o.has("conversation_search")&&s.push("Conversation History:\n- Only recent messages may be present in context.\n- Use `conversation_search` to find relevant details from earlier in this conversation when needed."),s.length===0)return e;let a=`${n}
419
419
  ${s.join(`
420
420
 
421
421
  `)}`,l=e.messages.findIndex(p=>p.role==="system");if(l>=0){let p=e.messages.map((d,m)=>{if(m!==l)return d;let u=typeof d.content=="string"?d.content:"";return u.includes(n)?d:{...d,content:`${u}
422
422
 
423
- ${a}`.trim()}});return{...e,messages:p}}return{...e,messages:[{role:"system",content:a},...e.messages]}}stripRequestTools(e){let{requestTools:t,mode:o,...n}=e;return n}newRequestId(){return`${Date.now()}-${++this.requestSeq}`}resolveRequestMode(e){return e.mode===void 0?this.activeMode:e.mode===null?null:typeof e.mode=="string"?(I(`[AIClient] Unresolved mode name "${e.mode}" on request \u2014 falling back to active mode. Pass requests through Toolpack.generate()/stream() to resolve mode names.`),this.activeMode):e.mode}filterSchemasByMode(e,t){return e.filter(o=>{if(t.blockedTools.includes(o.name)||t.blockedToolCategories.includes(o.category))return!1;if(dt(o.name)){let i=t.toolSearch?.enabled;if(i!==void 0?i:this.toolsConfig.toolSearch?.enabled??!1)return!0}let n=t.allowedTools.length>0,s=t.allowedToolCategories.length>0;if(n||s){let i=n&&t.allowedTools.includes(o.name),a=s&&t.allowedToolCategories.includes(o.category);return i||a}return!0})}injectModeSystemPrompt(e,t){if(!t||!t.systemPrompt)return y(`[AIClient] injectModeSystemPrompt: No active mode or empty systemPrompt. mode=${t?.name}, systemPrompt=${t?.systemPrompt?.substring(0,50)}`),e;let o=t.systemPrompt;if(y(`[AIClient] injectModeSystemPrompt: Injecting mode prompt for ${t.name}, length=${o.length}`),e.messages.some(s=>s.role==="system")){let s=e.messages.map(i=>{if(i.role==="system"){let a=typeof i.content=="string"?i.content:"";return{...i,content:`${o}
423
+ ${a}`.trim()}});return{...e,messages:p}}return{...e,messages:[{role:"system",content:a},...e.messages]}}stripRequestTools(e){let{requestTools:t,mode:o,interceptTool:n,...s}=e;return s}newRequestId(){return`${Date.now()}-${++this.requestSeq}`}resolveRequestMode(e){return e.mode===void 0?this.activeMode:e.mode===null?null:typeof e.mode=="string"?(I(`[AIClient] Unresolved mode name "${e.mode}" on request \u2014 falling back to active mode. Pass requests through Toolpack.generate()/stream() to resolve mode names.`),this.activeMode):e.mode}filterSchemasByMode(e,t){return e.filter(o=>{if(t.blockedTools.includes(o.name)||t.blockedToolCategories.includes(o.category))return!1;if(dt(o.name)){let i=t.toolSearch?.enabled;if(i!==void 0?i:this.toolsConfig.toolSearch?.enabled??!1)return!0}let n=t.allowedTools.length>0,s=t.allowedToolCategories.length>0;if(n||s){let i=n&&t.allowedTools.includes(o.name),a=s&&t.allowedToolCategories.includes(o.category);return i||a}return!0})}injectModeSystemPrompt(e,t){if(!t||!t.systemPrompt)return y(`[AIClient] injectModeSystemPrompt: No active mode or empty systemPrompt. mode=${t?.name}, systemPrompt=${t?.systemPrompt?.substring(0,50)}`),e;let o=t.systemPrompt;if(y(`[AIClient] injectModeSystemPrompt: Injecting mode prompt for ${t.name}, length=${o.length}`),e.messages.some(s=>s.role==="system")){let s=e.messages.map(i=>{if(i.role==="system"){let a=typeof i.content=="string"?i.content:"";return{...i,content:`${o}
424
424
 
425
425
  ${a}`}}return i});return{...e,messages:s}}else return{...e,messages:[{role:"system",content:o},...e.messages]}}async injectModeRules(e,t){if(!t)return e;let o=await this.ruleLoader.loadForMode(t.name,t.rulesDir);if(!o)return e;if(y(`[AIClient] injectModeRules: Injecting rules for mode "${t.name}", length=${o.length}`),e.messages.some(s=>s.role==="system")){let s=e.messages.map(i=>{if(i.role==="system"){let a=typeof i.content=="string"?i.content:"";return{...i,content:`${a}
426
426
 
@@ -449,7 +449,7 @@ When you need a tool:
449
449
  NEVER guess or hallucinate tool names. ALWAYS use tool.search to discover tools you don't have.
450
450
  `.trim();if(t){let i=e.messages.map(a=>{if(a.role==="system"){let l=typeof a.content=="string"?a.content:"";return{...a,content:`${l}
451
451
 
452
- ${s}`}}return a});return{...e,messages:i}}else return{...e,messages:[{role:"system",content:s},...e.messages]}}async executeTool(e,t,o,n=0,s){if(s?.aborted)throw new A;let i=Date.now();this.emit("tool:started",{toolName:e.name,toolCallId:e.id,status:"started",args:e.arguments}),k(`[AIClient] Executing tool: ${e.name} with args: ${N(e.arguments,500)}`);let a=t.get(e.name),l=a?void 0:o?.customTools?.find(m=>m.name===e.name),p=a||l?void 0:this.toolRegistry?.get(e.name);if(!a&&!l&&!this.toolRegistry){let m="No tool registry configured";return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:m,duration:Date.now()-i}),JSON.stringify({error:m})}if(dt(e.name)){let m=this.executeToolSearch(e.arguments,o),u=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof m=="string"?m.substring(0,200):JSON.stringify(m).substring(0,200),duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:m,duration:u,status:"success",timestamp:Date.now()}),m}let d=a||l||p;if(!d){I(`[AIClient] Tool '${e.name}' not found in registry or mode`);let m=this.findSimilarToolName(e.name),u=m?`Tool '${e.name}' not found. Did you mean '${m}'? Use tool.search to discover available tools.`:`Tool '${e.name}' not found. Use tool.search to discover available tools.`;return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:u,duration:Date.now()-i}),JSON.stringify({error:u})}try{let m=e.arguments,u=l??p;if(u?.confirmation&&this.onToolConfirm&&!this.isBypassed(u)){this.emit("tool:confirmation_requested",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason});let w=await Fe(this.onToolConfirm(u,m,{roundNumber:n,conversationId:this.conversationId}),s);if(this.emit("tool:confirmation_resolved",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason,decision:w}),w.action==="deny"){let v=`[Execution denied by user${w.reason?": "+w.reason:""}]`,_=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:v,duration:_}),this.emit("tool:log",{id:e.id,name:e.name,arguments:m,result:v,duration:_,status:"success",timestamp:Date.now()}),v}w.action==="modify"&&(m=w.args)}let b=o?.toolsConfig?.additionalConfigurations?{...this.toolsConfig?.additionalConfigurations,...o.toolsConfig.additionalConfigurations}:this.toolsConfig?.additionalConfigurations??{},h={workspaceRoot:process.cwd(),actor:(typeof this.actor=="function"?this.actor():this.actor)??void 0,config:b,log:w=>k(`[Tool] ${w}`),processRegistry:this.toolRegistry?.runtimeContext?.processRegistry,githubTokenStore:this.toolRegistry?.runtimeContext?.githubTokenStore,signal:s},T=await Fe(Promise.resolve(d.execute(m,h)),s),C=Date.now()-i;this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof T=="string"?T.startsWith("data:image/")?T:T.substring(0,200):JSON.stringify(T).substring(0,200),duration:C}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:T,duration:C,status:"success",timestamp:Date.now()});let S=typeof T=="string"?T.length:JSON.stringify(T).length;return k(`[AIClient] Tool ${e.name} executed successfully in ${C}ms result_len=${S}`),gt("debug")&&y(`[AIClient] Tool ${e.name} result_preview=${N(T,400)}`),typeof T=="string"?T:JSON.stringify(T)}catch(m){let u=Date.now()-i,b=m.message||"Tool execution failed";if(this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:b,duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:JSON.stringify({error:b}),duration:u,status:"error",timestamp:Date.now()}),ge(`[AIClient] Tool ${e.name} failed: ${N(b,300)}`),m instanceof A)throw m;return JSON.stringify({error:b})}}findSimilarToolName(e){if(!this.toolRegistry)return null;let t=this.toolRegistry.getAll(),o=e.replace(/_/g,".");if(t.some(l=>l.name===o))return o;let n=e.replace(/\./g,"_");if(t.some(l=>l.name===n))return n;let s=e.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase().replace(/_/g,".");if(t.some(l=>l.name===s))return s;let i=null,a=1/0;for(let l of t){let p=this.levenshteinDistance(e.toLowerCase(),l.name.toLowerCase());p<=2&&p<a&&(a=p,i=l.name)}return i}levenshteinDistance(e,t){let o=[];for(let n=0;n<=t.length;n++)o[n]=[n];for(let n=0;n<=e.length;n++)o[0][n]=n;for(let n=1;n<=t.length;n++)for(let s=1;s<=e.length;s++)t.charAt(n-1)===e.charAt(s-1)?o[n][s]=o[n-1][s-1]:o[n][s]=Math.min(o[n-1][s-1]+1,o[n][s-1]+1,o[n-1][s]+1);return o[t.length][e.length]}executeToolSearch(e,t){let{query:o,category:n}=e,s=this.toolsConfig.toolSearch?.searchResultLimit??5,i=typeof n=="string"&&n.length>0?n:void 0,a=t===void 0?this.activeMode:t;if(a&&!(this.filterSchemasByMode([Qe()],a).length>0))return I("[AIClient] tool.search blocked by active mode"),JSON.stringify({query:o,found:0,tools:[],hint:"tool.search is not allowed in the current mode."});k(`[AIClient] Executing tool.search: query="${o}" category=${i||"all"} limit=${s}`);let l=a?Math.max(s*4,s):s,p=this.bm25Engine.search(o,{limit:l,category:i});if(i&&p.length===0&&(k(`[AIClient] tool.search category="${i}" returned 0 results; retrying without category filter`),p=this.bm25Engine.search(o,{limit:l})),a&&p.length>0){let m=this.filterSchemasByMode(p.map(T=>T.tool),a),u=new Set(m.map(T=>T.name)),b=p.length;p=p.filter(T=>u.has(T.toolName));let h=b-p.length;h>0&&y(`[AIClient] tool.search filtered out ${h} disallowed results for mode "${a.displayName}"`)}p.length>s&&(p=p.slice(0,s));let d=p.map(m=>m.toolName);return this.toolRouter.getDiscoveryCache().recordDiscovery(o,d),y(`[AIClient] tool.search found ${p.length} tools: ${d.join(", ")||"none"}`),JSON.stringify({query:o,found:p.length,tools:p.map(m=>({name:m.tool.name,displayName:m.tool.displayName,description:m.tool.description,category:m.tool.category,parameters:m.tool.parameters,relevanceScore:Math.round(m.score*100)/100})),hint:p.length>0?`Found ${p.length} tools. You can now call any of these tools directly.`:`No tools found for "${o}". Try a different search term.`})}wrapError(e){return e instanceof A||e instanceof M?e:new F(e.message||"Unknown provider error","UNKNOWN_PROVIDER_ERROR",500,e)}budgetTruncate(e,t){let o=`
452
+ ${s}`}}return a});return{...e,messages:i}}else return{...e,messages:[{role:"system",content:s},...e.messages]}}async executeTool(e,t,o,n=0,s,i){if(!i)return this.runTool(e,t,o,n,s);if(s?.aborted)throw new A;return i({toolName:e.name,args:e.arguments,round:n},()=>this.runTool(e,t,o,n,s))}async runTool(e,t,o,n=0,s){if(s?.aborted)throw new A;let i=Date.now();this.emit("tool:started",{toolName:e.name,toolCallId:e.id,status:"started",args:e.arguments}),k(`[AIClient] Executing tool: ${e.name} with args: ${N(e.arguments,500)}`);let a=t.get(e.name),l=a?void 0:o?.customTools?.find(m=>m.name===e.name),p=a||l?void 0:this.toolRegistry?.get(e.name);if(!a&&!l&&!this.toolRegistry){let m="No tool registry configured";return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:m,duration:Date.now()-i}),JSON.stringify({error:m})}if(dt(e.name)){let m=this.executeToolSearch(e.arguments,o),u=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof m=="string"?m.substring(0,200):JSON.stringify(m).substring(0,200),duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:m,duration:u,status:"success",timestamp:Date.now()}),m}let d=a||l||p;if(!d){I(`[AIClient] Tool '${e.name}' not found in registry or mode`);let m=this.findSimilarToolName(e.name),u=m?`Tool '${e.name}' not found. Did you mean '${m}'? Use tool.search to discover available tools.`:`Tool '${e.name}' not found. Use tool.search to discover available tools.`;return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:u,duration:Date.now()-i}),JSON.stringify({error:u})}try{let m=e.arguments,u=l??p;if(u?.confirmation&&this.onToolConfirm&&!this.isBypassed(u)){this.emit("tool:confirmation_requested",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason});let w=await Fe(this.onToolConfirm(u,m,{roundNumber:n,conversationId:this.conversationId}),s);if(this.emit("tool:confirmation_resolved",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason,decision:w}),w.action==="deny"){let v=`[Execution denied by user${w.reason?": "+w.reason:""}]`,_=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:v,duration:_}),this.emit("tool:log",{id:e.id,name:e.name,arguments:m,result:v,duration:_,status:"success",timestamp:Date.now()}),v}w.action==="modify"&&(m=w.args)}let b=o?.toolsConfig?.additionalConfigurations?{...this.toolsConfig?.additionalConfigurations,...o.toolsConfig.additionalConfigurations}:this.toolsConfig?.additionalConfigurations??{},h={workspaceRoot:process.cwd(),actor:(typeof this.actor=="function"?this.actor():this.actor)??void 0,config:b,log:w=>k(`[Tool] ${w}`),processRegistry:this.toolRegistry?.runtimeContext?.processRegistry,githubTokenStore:this.toolRegistry?.runtimeContext?.githubTokenStore,signal:s},T=await Fe(Promise.resolve(d.execute(m,h)),s),C=Date.now()-i;this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof T=="string"?T.startsWith("data:image/")?T:T.substring(0,200):JSON.stringify(T).substring(0,200),duration:C}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:T,duration:C,status:"success",timestamp:Date.now()});let S=typeof T=="string"?T.length:JSON.stringify(T).length;return k(`[AIClient] Tool ${e.name} executed successfully in ${C}ms result_len=${S}`),gt("debug")&&y(`[AIClient] Tool ${e.name} result_preview=${N(T,400)}`),typeof T=="string"?T:JSON.stringify(T)}catch(m){let u=Date.now()-i,b=m.message||"Tool execution failed";if(this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:b,duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:JSON.stringify({error:b}),duration:u,status:"error",timestamp:Date.now()}),ge(`[AIClient] Tool ${e.name} failed: ${N(b,300)}`),m instanceof A)throw m;return JSON.stringify({error:b})}}findSimilarToolName(e){if(!this.toolRegistry)return null;let t=this.toolRegistry.getAll(),o=e.replace(/_/g,".");if(t.some(l=>l.name===o))return o;let n=e.replace(/\./g,"_");if(t.some(l=>l.name===n))return n;let s=e.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase().replace(/_/g,".");if(t.some(l=>l.name===s))return s;let i=null,a=1/0;for(let l of t){let p=this.levenshteinDistance(e.toLowerCase(),l.name.toLowerCase());p<=2&&p<a&&(a=p,i=l.name)}return i}levenshteinDistance(e,t){let o=[];for(let n=0;n<=t.length;n++)o[n]=[n];for(let n=0;n<=e.length;n++)o[0][n]=n;for(let n=1;n<=t.length;n++)for(let s=1;s<=e.length;s++)t.charAt(n-1)===e.charAt(s-1)?o[n][s]=o[n-1][s-1]:o[n][s]=Math.min(o[n-1][s-1]+1,o[n][s-1]+1,o[n-1][s]+1);return o[t.length][e.length]}executeToolSearch(e,t){let{query:o,category:n}=e,s=this.toolsConfig.toolSearch?.searchResultLimit??5,i=typeof n=="string"&&n.length>0?n:void 0,a=t===void 0?this.activeMode:t;if(a&&!(this.filterSchemasByMode([Qe()],a).length>0))return I("[AIClient] tool.search blocked by active mode"),JSON.stringify({query:o,found:0,tools:[],hint:"tool.search is not allowed in the current mode."});k(`[AIClient] Executing tool.search: query="${o}" category=${i||"all"} limit=${s}`);let l=a?Math.max(s*4,s):s,p=this.bm25Engine.search(o,{limit:l,category:i});if(i&&p.length===0&&(k(`[AIClient] tool.search category="${i}" returned 0 results; retrying without category filter`),p=this.bm25Engine.search(o,{limit:l})),a&&p.length>0){let m=this.filterSchemasByMode(p.map(T=>T.tool),a),u=new Set(m.map(T=>T.name)),b=p.length;p=p.filter(T=>u.has(T.toolName));let h=b-p.length;h>0&&y(`[AIClient] tool.search filtered out ${h} disallowed results for mode "${a.displayName}"`)}p.length>s&&(p=p.slice(0,s));let d=p.map(m=>m.toolName);return this.toolRouter.getDiscoveryCache().recordDiscovery(o,d),y(`[AIClient] tool.search found ${p.length} tools: ${d.join(", ")||"none"}`),JSON.stringify({query:o,found:p.length,tools:p.map(m=>({name:m.tool.name,displayName:m.tool.displayName,description:m.tool.description,category:m.tool.category,parameters:m.tool.parameters,relevanceScore:Math.round(m.score*100)/100})),hint:p.length>0?`Found ${p.length} tools. You can now call any of these tools directly.`:`No tools found for "${o}". Try a different search term.`})}wrapError(e){return e instanceof A||e instanceof M?e:new F(e.message||"Unknown provider error","UNKNOWN_PROVIDER_ERROR",500,e)}budgetTruncate(e,t){let o=`
453
453
  [Output truncated \u2014 round budget reached. Call the tool again with a narrower query to retrieve more.]`,s=t-o.length;return s>=100?e.slice(0,s)+o:"[Tool output omitted \u2014 round budget exhausted. Call the tool again with a narrower query.]"}};c();c();var Qs=x(require("@anthropic-ai/sdk"),1),nc=require("@anthropic-ai/sdk/helpers/zod");c();le();var X=class{name;async getModels(){return[]}getDisplayName(){return this.name||this.constructor.name.replace(/Adapter$/,"")}supportsFileUpload(){return!1}async uploadFile(e){throw new O(`File upload API is not supported by ${this.getDisplayName()}`)}async deleteFile(e){throw new O(`File deletion API is not supported by ${this.getDisplayName()}`)}async countTokens(e,t){return null}};le();P();Me();var Rn=class extends X{client;constructor(e,t){super(),this.client=new Qs.default({apiKey:e,baseURL:t})}supportsFileUpload(){return!0}async uploadFile(e){try{let t=await import("fs");if(!e.filePath)throw new O("Anthropic uploadFile requires a filePath.");return{id:(await this.client.files.create({file:t.createReadStream(e.filePath),purpose:e.purpose||"vision"})).id}}catch(t){throw this.handleError(t)}}async deleteFile(e){try{await this.client.files.delete(e)}catch(t){throw this.handleError(t)}}getDisplayName(){return"Anthropic"}async getModels(){return[{id:"claude-haiku-4-5-20251001",displayName:"Claude Haiku 4.5",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:64e3},{id:"claude-sonnet-4-5-20250929",displayName:"Claude Sonnet 4.5",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-sonnet-4-6",displayName:"Claude Sonnet 4.6",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-opus-4-5",displayName:"Claude Opus 4.5",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-opus-4-6",displayName:"Claude Opus 4.6",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384}]}sanitizeToolName(e){return e.replace(/\./g,"_")}restoreToolName(e,t){return t?.find(n=>this.sanitizeToolName(n.function.name)===e)?.function.name||e.replace(/_/g,".")}async generate(e){try{let t=e.__toolpack_request_id||`gen-${Date.now()}`,o=await this.toAnthropicMessages(e.messages,e.mediaOptions),n=o.system,s=o.userMessages,i={model:e.model,messages:s,system:n,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p,stream:!1};e.tools&&e.tools.length>0?(i.tools=e.tools.map(b=>({name:this.sanitizeToolName(b.function.name),description:b.function.description,input_schema:b.function.parameters})),e.tool_choice==="required"?i.tool_choice={type:"any"}:e.tool_choice==="none"?delete i.tools:i.tool_choice={type:"auto"},y(`[Anthropic][${t}] Sending ${i.tools?.length||0} tools with tool_choice: ${i.tool_choice?.type||"unset"}`),i.tools&&i.tools.length>0&&y(`[Anthropic][${t}] First tool: ${N(i.tools[0],800)}`)):y(`[Anthropic][${t}] NO TOOLS in request`),y(`[Anthropic][${t}] generate() request: model=${i.model}, messages=${i.messages.length}, tools=${i.tools?.length||0}, tool_choice=${i.tool_choice?.type??"unset"}`),ne(t,"Anthropic",i.messages);let a=e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format;a&&(i.output_config={format:(0,nc.zodOutputFormat)(e.response_format)});let p=a?await this.client.messages.parse(i,e.signal?{signal:e.signal}:void 0):await this.client.messages.create(i,e.signal?{signal:e.signal}:void 0),d=[],m=[];for(let b of p.content)b.type==="text"?d.push(b.text):b.type==="tool_use"&&m.push({id:b.id,name:this.restoreToolName(b.name,e.tools),arguments:b.input});y(`[Anthropic][${t}] Response finish_reason=${p.stop_reason} tool_calls=${m.length} content_preview=${N(d.join(""),200)}`);let u={content:d.length>0?d.join(""):null,usage:{prompt_tokens:p.usage.input_tokens,completion_tokens:p.usage.output_tokens,total_tokens:p.usage.input_tokens+p.usage.output_tokens},finish_reason:this.mapFinishReason(p.stop_reason),tool_calls:m.length>0?m:void 0,raw:p};return a&&p.parsed_output!==void 0&&(u.data=p.parsed_output),u}catch(t){throw this.handleError(t)}}async*stream(e){try{let t=e.__toolpack_request_id||`str-${Date.now()}`,o=await this.toAnthropicMessages(e.messages,e.mediaOptions),n={model:e.model,messages:o.userMessages,system:o.system,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p,stream:!0};e.tools&&e.tools.length>0?(n.tools=e.tools.map(d=>({name:this.sanitizeToolName(d.function.name),description:d.function.description,input_schema:d.function.parameters})),e.tool_choice==="required"?n.tool_choice={type:"any"}:e.tool_choice==="none"?delete n.tools:n.tool_choice={type:"auto"},y(`[Anthropic][${t}] Sending ${n.tools?.length||0} tools with tool_choice: ${n.tool_choice?.type||"unset"}`),n.tools&&n.tools.length>0&&y(`[Anthropic][${t}] First tool: ${N(n.tools[0],800)}`)):y(`[Anthropic][${t}] NO TOOLS in request`),y(`[Anthropic][${t}] Stream request: model=${n.model}, messages=${n.messages.length}, tools=${n.tools?.length||0}, tool_choice=${n.tool_choice?.type??"unset"}`),ne(t,"Anthropic",n.messages);let s=await this.client.messages.create(n,e.signal?{signal:e.signal}:void 0),i="",a="",l="",p=!1;for await(let d of s)d.type==="content_block_start"&&d.content_block?.type==="tool_use"&&(p=!0,i=d.content_block.id,a=d.content_block.name,l=""),d.type==="content_block_delta"&&(d.delta.type==="text_delta"?yield{delta:d.delta.text}:d.delta.type==="input_json_delta"&&p&&(l+=d.delta.partial_json)),d.type==="content_block_stop"&&p&&(y(`[Anthropic][${t}] Stream finish_reason=tool_calls accumulated_call=${a}`),yield{delta:"",finish_reason:"tool_calls",tool_calls:[{id:i,name:this.restoreToolName(a,e.tools),arguments:JSON.parse(l||"{}")}]},p=!1),d.type==="message_stop"&&(Ye(`[Anthropic][${t}] Stream chunk finish_reason=stop`),yield{delta:"",finish_reason:"stop"})}catch(t){throw this.handleError(t)}}async embed(e){throw new O("Embeddings are not strictly supported by the Anthropic API currently.")}async toAnthropicMessages(e,t={}){let o,n=[],{normalizeImagePart:s}=await Promise.resolve().then(()=>(Me(),Ot));for(let i of e)if(i.role==="system"){if(typeof i.content=="string")o=i.content;else if(i.content!==null){let a=i.content.filter(l=>typeof l=="object"&&l.type==="text").map(l=>l.text).join(`
454
454
  `);a&&(o=a)}}else if(i.role==="tool"&&i.tool_call_id){let a=typeof i.content=="string"?i.content:JSON.stringify(i.content),l=a.match(/^data:([\w/+.-]+);base64,(.+)$/s),p=l?null:et(a),d=l?l[1].startsWith("image/")?[{type:"image",source:{type:"base64",media_type:l[1],data:l[2]}}]:[{type:"document",source:{type:"base64",media_type:l[1],data:l[2]}}]:p?p.mimeType.startsWith("image/")?[{type:"image",source:{type:"url",url:p.url}}]:[{type:"document",source:{type:"url",url:p.url}}]:a;n.push({role:"user",content:[{type:"tool_result",tool_use_id:i.tool_call_id,content:d}]})}else if(i.role==="assistant"&&i.tool_calls&&i.tool_calls.length>0){let a=[];if(typeof i.content=="string"&&i.content)a.push({type:"text",text:i.content});else if(Array.isArray(i.content)){let l=i.content.filter(p=>typeof p=="object"&&p.type==="text").map(p=>p.text).join(`
455
455
  `);l&&a.push({type:"text",text:l})}for(let l of i.tool_calls)a.push({type:"tool_use",id:l.id,name:this.sanitizeToolName(l.function.name),input:typeof l.function.arguments=="string"?JSON.parse(l.function.arguments||"{}"):l.function.arguments});n.push({role:"assistant",content:a})}else{let a=[];typeof i.content=="string"?a=i.content:i.content!==null&&(a=(await Promise.all(i.content.map(async l=>{if(l.type==="text")return{type:"text",text:l.text};if(l.type==="image_url"){let p=l.image_url.url;if(p.startsWith("data:")){let d=p.match(/^data:(image\/\w+);base64,(.+)$/);if(d)return{type:"image",source:{type:"base64",media_type:d[1],data:d[2]}}}return{type:"image",source:{type:"url",url:p}}}if(l.type==="image_data"||l.type==="image_file"){let{data:p,mimeType:d}=await s(l);return{type:"image",source:{type:"base64",media_type:d,data:p}}}if(l.type==="file"){let{url:p,mimeType:d}=l.file,m=p.match(/^data:([\w/+.-]+);base64,(.+)$/s);if(m){let[,u,b]=m;return u.startsWith("image/")?{type:"image",source:{type:"base64",media_type:u,data:b}}:{type:"document",source:{type:"base64",media_type:u,data:b}}}return d.startsWith("image/")?{type:"image",source:{type:"url",url:p}}:{type:"document",source:{type:"url",url:p}}}return null}))).filter(Boolean)),n.push({role:i.role==="user"?"user":"assistant",content:a})}return{system:o,userMessages:n}}mapFinishReason(e){return e==="end_turn"?"stop":e==="max_tokens"?"length":e==="stop_sequence"?"stop":e}handleError(e){if(e instanceof Qs.default.APIError){let t=e.message;return e.status===401?new fe(t,e):e.status===429?new ae(t,void 0,e):e.status&&e.status>=400&&e.status<500?new O(t,e):new F(t,"ANTHROPIC_ERROR",e.status||500,e)}return new F("Unknown Anthropic error","UNKNOWN",500,e)}};c();var rc=x(require("@anthropic-ai/vertex-sdk"),1);le();P();var $n=class extends X{client;constructor(e={}){super(),this.name="anthropic-vertex";let t=e.projectId??process.env.ANTHROPIC_VERTEX_PROJECT_ID??process.env.GOOGLE_CLOUD_PROJECT,o=e.region??process.env.ANTHROPIC_VERTEX_REGION??"us-east5";this.client=new rc.default({projectId:t,region:o})}getDisplayName(){return"Anthropic (Vertex AI)"}async getModels(){return[{id:"claude-sonnet-4-5@20250929",displayName:"Claude Sonnet 4.5 (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-haiku-4-5@20251001",displayName:"Claude Haiku 4.5 (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-3-5-sonnet-v2@20241022",displayName:"Claude 3.5 Sonnet v2 (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:8192},{id:"claude-3-5-haiku@20241022",displayName:"Claude 3.5 Haiku (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:8192}]}async generate(e){try{let t=e.__toolpack_request_id||`anv-${Date.now()}`,{system:o,userMessages:n}=await this.toAnthropicMessages(e.messages),s={model:e.model,messages:n,system:o,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p};e.tools&&e.tools.length>0&&(s.tools=e.tools.map(p=>({name:this.sanitizeToolName(p.function.name),description:p.function.description,input_schema:p.function.parameters})),e.tool_choice==="required"?s.tool_choice={type:"any"}:e.tool_choice==="none"?delete s.tools:s.tool_choice={type:"auto"}),y(`[AnthropicVertex][${t}] generate() model=${s.model} messages=${s.messages.length} tools=${s.tools?.length??0}`),ne(t,"AnthropicVertex",s.messages);let i=await this.client.messages.create(s,e.signal?{signal:e.signal}:void 0),a=[],l=[];for(let p of i.content)p.type==="text"&&a.push(p.text),p.type==="tool_use"&&l.push({id:p.id,name:this.restoreToolName(p.name,e.tools),arguments:p.input});return y(`[AnthropicVertex][${t}] Response finish_reason=${i.stop_reason} tool_calls=${l.length} content_preview=${N(a.join(""),200)}`),{content:a.length>0?a.join(""):null,usage:{prompt_tokens:i.usage.input_tokens,completion_tokens:i.usage.output_tokens,total_tokens:i.usage.input_tokens+i.usage.output_tokens},finish_reason:this.mapFinishReason(i.stop_reason),tool_calls:l.length>0?l:void 0,raw:i}}catch(t){throw this.handleError(t)}}async*stream(e){try{let t=e.__toolpack_request_id||`anv-str-${Date.now()}`,{system:o,userMessages:n}=await this.toAnthropicMessages(e.messages),s={model:e.model,messages:n,system:o,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p,stream:!0};e.tools&&e.tools.length>0&&(s.tools=e.tools.map(m=>({name:this.sanitizeToolName(m.function.name),description:m.function.description,input_schema:m.function.parameters})),e.tool_choice==="required"?s.tool_choice={type:"any"}:e.tool_choice==="none"?delete s.tools:s.tool_choice={type:"auto"}),y(`[AnthropicVertex][${t}] stream() model=${s.model} messages=${s.messages.length} tools=${s.tools?.length??0}`);let i=await this.client.messages.create(s,e.signal?{signal:e.signal}:void 0),a="",l="",p="",d=!1;for await(let m of i)m.type==="content_block_start"&&m.content_block?.type==="tool_use"&&(d=!0,a=m.content_block.id,l=m.content_block.name,p=""),m.type==="content_block_delta"&&(m.delta.type==="text_delta"?yield{delta:m.delta.text}:m.delta.type==="input_json_delta"&&d&&(p+=m.delta.partial_json)),m.type==="content_block_stop"&&d&&(yield{delta:"",finish_reason:"tool_calls",tool_calls:[{id:a,name:this.restoreToolName(l,e.tools),arguments:JSON.parse(p||"{}")}]},d=!1),m.type==="message_stop"&&(yield{delta:"",finish_reason:"stop"})}catch(t){throw this.handleError(t)}}async embed(e){throw new O("Embeddings are not supported by the Anthropic API.")}sanitizeToolName(e){return e.replace(/\./g,"_")}restoreToolName(e,t){return t?.find(n=>this.sanitizeToolName(n.function.name)===e)?.function.name??e.replace(/_/g,".")}async toAnthropicMessages(e){let t,o=[];for(let n of e)if(n.role==="system")t=typeof n.content=="string"?n.content:"";else if(n.role==="tool"&&n.tool_call_id){let s=typeof n.content=="string"?n.content:JSON.stringify(n.content),i=s.match(/^data:([\w/+.-]+);base64,(.+)$/s),a=i?i[1].startsWith("image/")?[{type:"image",source:{type:"base64",media_type:i[1],data:i[2]}}]:[{type:"document",source:{type:"base64",media_type:i[1],data:i[2]}}]:s;o.push({role:"user",content:[{type:"tool_result",tool_use_id:n.tool_call_id,content:a}]})}else if(n.role==="assistant"&&n.tool_calls&&n.tool_calls.length>0){let s=[];typeof n.content=="string"&&n.content&&s.push({type:"text",text:n.content});for(let i of n.tool_calls)s.push({type:"tool_use",id:i.id,name:this.sanitizeToolName(i.function.name),input:typeof i.function.arguments=="string"?JSON.parse(i.function.arguments||"{}"):i.function.arguments});o.push({role:"assistant",content:s})}else{let s;typeof n.content=="string"||n.content===null?s=n.content??"":s=(await Promise.all(n.content.map(async i=>{if(i.type==="text")return{type:"text",text:i.text};if(i.type==="image_url"){let a=i.image_url.url;if(a.startsWith("data:")){let l=a.match(/^data:(image\/\w+);base64,(.+)$/);if(l)return{type:"image",source:{type:"base64",media_type:l[1],data:l[2]}}}return{type:"image",source:{type:"url",url:a}}}if(i.type==="image_data"||i.type==="image_file"){let{normalizeImagePart:a}=await Promise.resolve().then(()=>(Me(),Ot)),{data:l,mimeType:p}=await a(i);return{type:"image",source:{type:"base64",media_type:p,data:l}}}if(i.type==="file"){let{url:a,mimeType:l}=i.file,p=a.match(/^data:([\w/+.-]+);base64,(.+)$/s);if(p){let[,d,m]=p;return d.startsWith("image/")?{type:"image",source:{type:"base64",media_type:d,data:m}}:{type:"document",source:{type:"base64",media_type:d,data:m}}}return l.startsWith("image/")?{type:"image",source:{type:"url",url:a}}:{type:"document",source:{type:"url",url:a}}}return null}))).filter(Boolean),o.push({role:n.role==="user"?"user":"assistant",content:s})}return{system:t,userMessages:o}}mapFinishReason(e){return e==="end_turn"?"stop":e==="max_tokens"?"length":"stop"}handleError(e){let t=e?.message??String(e);return e?.status===401||e?.status===403?new fe(t,e):e?.status===429?new ae(t,void 0,e):e?.status>=400&&e?.status<500?new O(t,e):new F(t||"Anthropic Vertex error","ANTHROPIC_VERTEX_ERROR",e?.status??500,e)}};c();var sc=require("@google/genai"),ic=require("zod-to-json-schema");le();P();Me();var En=class r extends X{ai;location;thinkingBudget;rawContentCache=new Map;static RAW_CONTENT_CACHE_MAX=500;constructor(e={}){super(),this.name="vertexai";let t=e.projectId??process.env.TOOLPACK_VERTEXAI_PROJECT??process.env.VERTEX_AI_PROJECT??process.env.GOOGLE_CLOUD_PROJECT;if(!t)throw new fe("Vertex AI requires a GCP project ID. Pass projectId in config or set TOOLPACK_VERTEXAI_PROJECT / VERTEX_AI_PROJECT / GOOGLE_CLOUD_PROJECT.");this.location=e.location??process.env.TOOLPACK_VERTEXAI_LOCATION??process.env.VERTEX_AI_LOCATION??"us-central1",this.ai=new sc.GoogleGenAI({vertexai:!0,project:t,location:this.location,...e.googleAuthOptions?{googleAuthOptions:e.googleAuthOptions}:{}}),this.thinkingBudget=e.thinkingBudget}getDisplayName(){return"Google Vertex AI"}async getModels(){return[{id:"gemini-3.5-flash",displayName:"Gemini 3.5 Flash",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-3.1-pro-preview",displayName:"Gemini 3.1 Pro Preview",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-2.5-pro-preview-05-06",displayName:"Gemini 2.5 Pro Preview",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-2.5-flash-preview-04-17",displayName:"Gemini 2.5 Flash Preview",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-2.0-flash-001",displayName:"Gemini 2.0 Flash",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:8192},{id:"gemini-1.5-pro-002",displayName:"Gemini 1.5 Pro",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2097152,maxOutputTokens:8192},{id:"gemini-1.5-flash-002",displayName:"Gemini 1.5 Flash",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:8192}]}async generate(e){try{let t=e.__toolpack_request_id||`vtx-${Date.now()}`;y(`[VertexAI][${t}] generate() model=${e.model} messages=${e.messages.length} tools=${e.tools?.length??0}`),ne(t,"VertexAI",e.messages);let{model:o,config:n}=this.buildRequestParams(e),{history:s,lastUserMessage:i}=this.formatHistory(e.messages),a=i!==null?[...s,{role:"user",parts:typeof i=="string"?[{text:i}]:i}]:s;for(let u of a){let b=u.parts;if(Array.isArray(b))for(let h=0;h<b.length;h++){let T=b[h];T?.inlineData!==void 0&&!T.inlineData?.data&&b.splice(h--,1)}}e.signal&&(n.abortSignal=e.signal);let l=await this.ai.models.generateContent({model:o,contents:a,config:n}),{content:p,toolCalls:d,rawContent:m}=this.parseResponse(l,e.tools);if(d.length>0&&m){let u=d.map(b=>b.id).join("|");this.rawContentCache.size>=r.RAW_CONTENT_CACHE_MAX&&this.rawContentCache.delete(this.rawContentCache.keys().next().value),this.rawContentCache.set(u,m)}return y(`[VertexAI][${t}] Response finish_reason=${d.length>0?"tool_calls":"stop"} tool_calls=${d.length} content_preview=${N(p,200)}`),{content:p||null,usage:{prompt_tokens:l.usageMetadata?.promptTokenCount??0,completion_tokens:l.usageMetadata?.candidatesTokenCount??0,total_tokens:l.usageMetadata?.totalTokenCount??0},finish_reason:d.length>0?"tool_calls":"stop",tool_calls:d.length>0?d:void 0,raw:l}}catch(t){throw this.handleError(t)}}async*stream(e){try{let t=e.__toolpack_request_id||`vtx-str-${Date.now()}`;y(`[VertexAI][${t}] stream() model=${e.model} messages=${e.messages.length} tools=${e.tools?.length??0}`),ne(t,"VertexAI",e.messages);let{model:o,config:n}=this.buildRequestParams(e),{history:s,lastUserMessage:i}=this.formatHistory(e.messages),a=i!==null?[...s,{role:"user",parts:typeof i=="string"?[{text:i}]:i}]:s;for(let m of a){let u=m.parts;if(Array.isArray(u))for(let b=0;b<u.length;b++){let h=u[b];h?.inlineData!==void 0&&!h.inlineData?.data&&u.splice(b--,1)}}e.signal&&(n.abortSignal=e.signal);let l=await this.ai.models.generateContentStream({model:o,contents:a,config:n}),p=[],d=[];for await(let m of l)for(let u of m.candidates??[])for(let b of u.content?.parts??[])if(d.push(b),b.functionCall){let h=b.functionCall;y(`[VertexAI][${t}] stream tool_call name=${h.name}`);let T=`vtx_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;p.push(T),yield{delta:"",finish_reason:"tool_calls",tool_calls:[{id:T,name:this.restoreToolName(h.name,e.tools),arguments:h.args??{}}]}}else b.text&&(yield{delta:b.text});if(p.length>0&&d.length>0){let m=p.join("|"),u={role:"model",parts:d};this.rawContentCache.size>=r.RAW_CONTENT_CACHE_MAX&&this.rawContentCache.delete(this.rawContentCache.keys().next().value),this.rawContentCache.set(m,u)}}catch(t){throw this.handleError(t)}}async embed(e){throw new O("Vertex AI embeddings are not supported by this adapter. Use the Gemini adapter (gemini provider) with text-embedding-004 instead.")}buildRequestParams(e){let t=e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format,o={systemInstruction:this.extractSystemInstruction(e.messages),maxOutputTokens:e.max_tokens,temperature:e.temperature,topP:e.top_p,responseMimeType:(e.response_format==="json_object"||t)&&!e.tools?.length?"application/json":"text/plain",...t&&!e.tools?.length?{responseSchema:this.sanitizeSchema((0,ic.zodToJsonSchema)(e.response_format))}:{}};return e.tools&&e.tools.length>0&&(o.tools=[{functionDeclarations:e.tools.map(n=>({name:this.sanitizeToolName(n.function.name),description:n.function.description,parameters:this.sanitizeSchema(n.function.parameters)}))}]),this.thinkingBudget!==void 0&&this.thinkingBudget!==0&&(o.thinkingConfig={thinkingBudget:this.thinkingBudget}),{model:e.model,config:o}}formatHistory(e){let t=e.filter(l=>l.role!=="system");if(t.length===0)return{history:[],lastUserMessage:""};let o=t[t.length-1],n=o.role==="tool"&&!!o.tool_call_id,i=(n?t:t.slice(0,-1)).map(l=>{if(l.role==="tool"&&l.tool_call_id){let p=this.sanitizeToolName(l.name??l.tool_call_id),d=typeof l.content=="string"?l.content:JSON.stringify(l.content),m=d.match(/^data:([\w/+.-]+);base64,(.+)$/s),u=m?null:et(d),b=[{functionResponse:{name:p,response:{name:p,content:m||u?"File data attached as sibling part.":d}}}];return m&&b.push({inlineData:{mimeType:m[1],data:m[2]}}),u&&b.push({fileData:{mimeType:u.mimeType,fileUri:u.url}}),{role:"function",parts:b}}if(l.role==="assistant"&&l.tool_calls&&l.tool_calls.length>0){let p=l.tool_calls.map(u=>u.id).join("|"),d=this.rawContentCache.get(p);if(d)return d;let m=[];typeof l.content=="string"&&l.content&&m.push({text:l.content});for(let u of l.tool_calls)m.push({functionCall:{name:this.sanitizeToolName(u.function.name),args:typeof u.function.arguments=="string"?JSON.parse(u.function.arguments||"{}"):u.function.arguments}});return{role:"model",parts:m}}return{role:l.role==="user"?"user":"model",parts:this.contentToParts(l.content)}}),a=[];for(let l of i){let p=a[a.length-1];l.role==="function"&&p?.role==="function"?p.parts.push(...l.parts):a.push(l)}return{history:a,lastUserMessage:n?null:this.contentToParts(o.content)}}contentToParts(e){return typeof e=="string"?[{text:e}]:e?e.map(t=>{if(t.type==="text")return{text:t.text};if(t.type==="image_data"){let{data:o,mimeType:n}=t.image_data??{};return o?{inlineData:{mimeType:n??"image/jpeg",data:o}}:null}if(t.type==="image_url"){let o=t.image_url?.url??"";return o?{fileData:{mimeType:"image/jpeg",fileUri:o}}:null}if(t.type==="file"){let o=t.file.url.match(/^data:([\w/+.-]+);base64,(.+)$/s);return o?o[2]?{inlineData:{mimeType:o[1],data:o[2]}}:null:t.file.url?{fileData:{mimeType:t.file.mimeType,fileUri:t.file.url}}:null}return null}).filter(t=>t!==null):[]}parseResponse(e,t){let o=[],n="",s=null;for(let i of e.candidates??[]){i.content&&(s=i.content);for(let a of i.content?.parts??[])if(a.text&&!a.thought&&(n+=a.text),a.functionCall){let l=a.functionCall;o.push({id:`vtx_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,name:this.restoreToolName(l.name,t),arguments:l.args??{}})}}return{content:n,toolCalls:o,rawContent:s}}extractSystemInstruction(e){let t=e.filter(o=>o.role==="system");if(t.length!==0)return t.map(o=>typeof o.content=="string"?o.content:"").join(`
package/dist/index.d.cts CHANGED
@@ -654,6 +654,19 @@ interface ToolCallRequest {
654
654
  type: 'function';
655
655
  function: ToolCallFunction;
656
656
  }
657
+ /** One tool call, as a {@link ToolInterceptor} sees it. */
658
+ interface InterceptedToolCall {
659
+ toolName: string;
660
+ args: Record<string, any>;
661
+ /** The tool round of the request this call belongs to (1 for the first). Parallel calls of one round share it. */
662
+ round: number;
663
+ }
664
+ /**
665
+ * Wraps every tool call of one request. Call `run()` to run the tool (and use or change its result), or return text
666
+ * without calling it to stop the call: the model then sees that text as the tool's result. The tool's started, completed
667
+ * and log events are sent only when `run()` is called.
668
+ */
669
+ type ToolInterceptor = (call: InterceptedToolCall, run: () => Promise<string>) => Promise<string> | string;
657
670
  interface RequestToolDefinition {
658
671
  name: string;
659
672
  displayName: string;
@@ -699,6 +712,11 @@ interface CompletionRequest<T = unknown> {
699
712
  stream?: boolean;
700
713
  tools?: ToolCallRequest[];
701
714
  requestTools?: RequestToolDefinition[];
715
+ /**
716
+ * Wraps every tool call of this request, whatever the tool (request, mode or registry tool, and `tool.search`).
717
+ * It can stop a call or change its result. See {@link ToolInterceptor}. Not sent to the provider.
718
+ */
719
+ interceptTool?: ToolInterceptor;
702
720
  tool_choice?: 'auto' | 'none' | 'required';
703
721
  /** AbortSignal to cancel the request */
704
722
  signal?: AbortSignal;
@@ -1588,6 +1606,7 @@ declare class AIClient extends EventEmitter {
1588
1606
  * Emits 'tool:started', 'tool:completed', and 'tool:failed' events.
1589
1607
  */
1590
1608
  private executeTool;
1609
+ private runTool;
1591
1610
  /**
1592
1611
  * Find similar tool name to detect hallucinations.
1593
1612
  * Detects common patterns like underscore vs dot (fs_delete_file vs fs.delete_file).
@@ -4093,4 +4112,4 @@ declare class RuleLoader {
4093
4112
  private readFile;
4094
4113
  }
4095
4114
 
4096
- export { AGENT_MODE, AGENT_PLANNING_PROMPT, AGENT_WORKFLOW, AIClient, type AIClientConfig, AbortedError, type AddBypassRuleOptions, AnthropicAdapter, AnthropicVertexAdapter, type AnthropicVertexConfig, type AssembledPrompt, type AssemblerOptions, AuthenticationError, BM25Engine, BM25SearchEngine, type BM25SearchResult, BUILT_IN_MODES, type BypassRuleType, CHAT_MODE, CHAT_WORKFLOW, CODING_MODE, CODING_PLANNING_PROMPT, CODING_WORKFLOW, CONFIG_DIR_NAME, CONFIG_FILE_NAME, type CompletionChunk, type CompletionOptions, type CompletionRequest, type CompletionResponse, type ConfirmationDecision, type ConfirmationLevel$1 as ConfirmationLevel, ConnectionError, type ContextPrunedEvent, type ContextWindowConfig, ContextWindowConfigError, ContextWindowExceededError, type ContextWindowExceededEvent, type ContextWindowState, ContextWindowStateManager, type ContextWindowStrategy, type ContextWindowWarningEvent, ConversationNotFoundError, type ConversationScope, type ConversationSearchOptions, type ConversationStore, type ConversationSummarizedEvent, DEFAULT_MODE_NAME, DEFAULT_TOOLS_CONFIG, DEFAULT_TOOL_SEARCH_CONFIG, DEFAULT_WORKFLOW, DEFAULT_WORKFLOW_CONFIG, type EmbeddingRequest, type EmbeddingResponse, FILE_LIMITS, type FileEnvelope, type FilePart, type FileUploadRequest, type FileUploadResponse, GeminiAdapter, type GetOptions, type HitlConfig, type ImageDataPart, type ImageFilePart, type ImagePart, type ImageUrlPart, InMemoryConversationStore, type InMemoryConversationStoreConfig, InsufficientContextError, InvalidRequestError, type JsonRpcRequest, type JsonRpcResponse, type KnowledgeInstance, type McpAgentDefinition, type McpAuthConfig, McpClient, type McpClientConfig, McpConnectionError, type McpCustomAuthConfig, type McpJwtAuthConfig, type McpServerCapabilities, type McpServerConfig, type McpServerExposeConfig, type McpServerHandle, type McpStaticAuthConfig, McpTimeoutError, type McpTool, McpToolManager, type McpToolsConfig, type McpTransport, type MediaOptions, type MediaUploadStrategy, type Message, type MessageContent, type ModeBlockedHint, type ModeConfig, ModeRegistry, OllamaAdapter, type OllamaAdapterConfig, type OllamaModelInfo, OllamaProvider, type OllamaProviderEntry, type OnToolConfirmCallback, OpenAIAdapter, OpenRouterAdapter, type OpenRouterOptions, PageError, type Participant, type Plan, type PlanStep, Planner, type PromptMessage, ProviderAdapter, type ProviderConfig, ProviderError, type ProviderInfo, type ProviderModelInfo, type ProviderOptions, type PruneResult, RateLimitError, type RequestToolDefinition, type Role, RuleLoader, type RuntimeConfigStatus, SDKError, SQLiteConversationStore, type SQLiteConversationStoreConfig, type SearchHistoryEntry, type SearchOptions, type SearchResult, type Skill, type SkillSection, type SkillToolsOptions, type SkillValidationMode, type SlmModelEntry, type StoredMessage, SummarizationError, type SummarizationOptions, type SummarizationResult, TOOLPACK_DIR_NAME, TOOL_SEARCH_NAME, type TextPart, TimeoutError, type ToolActor, type ToolAnnotations, type ToolCall, type ToolCallFunction, type ToolCallMessage, type ToolCallRequest, type ToolCallResult, type ToolCategory, type ToolConfirmation, type ToolConfirmationRequestedEvent, type ToolConfirmationResolvedEvent, type ToolContext, type ToolDefinition, ToolDiscoveryCache, type ToolLogEvent, type ToolParameterProperty, type ToolParameters, type ToolProgressEvent, type ToolProject, type ToolProjectDependencies, type ToolProjectManifest, ToolRegistry, type ToolResult, ToolRouter, type ToolSchema, type ToolSearchConfig, Toolpack, type ToolpackConfig, type ToolpackCredentials, type ToolpackInitConfig, type ToolpackInterceptor, type ToolpackMcpServerConfig, type ToolpackNextFunction, type ToolsConfig, type Usage, VertexAIAdapter, type VertexAIConfig, type WorkflowConfig, type WorkflowEvents, WorkflowExecutor, type WorkflowProgress, type WorkflowResult, addBypassRule, buildSummarizedHistory, cloudDeployTool, cloudListTool, cloudStatusTool, cloudToolsProject, codingExtractFunctionTool, codingFindReferencesTool, codingFindSymbolTool, codingGetCallHierarchyTool, codingGetDiagnosticsTool, codingGetExportsTool, codingGetImportsTool, codingGetOutlineTool, codingGetSymbolsTool, codingGoToDefinitionTool, codingMultiFileEditTool, codingRefactorRenameTool, codingToolsProject, countTokens, createContextWindowStateManager, createMcpToolProject, createMode, createSkillTools, createSummarizationReport, createSummarySystemMessage, createToolProject, dbCountTool, dbDeleteTool, dbInsertTool, dbQueryTool, dbSchemaTool, dbTablesTool, dbToolsProject, dbUpdateTool, diffApplyTool, diffCreateTool, diffPreviewTool, diffToolsProject, disconnectMcpToolProject, ensureGlobalConfigDir, ensureLocalConfigDir, estimateSummaryTokens, estimateTokenCount, execKillTool, execListProcessesTool, execReadOutputTool, execRunBackgroundTool, execRunBlockingTool, execRunShellTool, execRunTool, execTailOutputTool, execToolsProject, extractConversationKeypoints, fetchUrlAsBase64, fsAppendFileTool, fsBatchReadTool, fsBatchWriteTool, fsCopyTool, fsCreateDirTool, fsDeleteDirTool, fsDeleteFileTool, fsExistsTool, fsGlobTool, fsListDirTool, fsMoveTool, fsReadFileRangeTool, fsReadFileTool, fsReplaceInFileTool, fsSearchTool, fsStatTool, fsToolsProject, fsTreeTool, fsWriteFileTool, generateSummarizationPrompt, generateToolCategoriesPrompt, getContextWindowPercentage, getDefaultSlmModel, getGlobalConfigDir, getGlobalConfigPath, getGlobalToolpackDir, getLocalConfigDir, getLocalConfigPath, getLocalToolpackDir, getMessageStats, getMimeType, getOllamaBaseUrl, getOllamaProviderEntries, getRegisteredSlmModels, getRuntimeConfigStatus, getSafeOutputReserve, getToolSearchSchema, getToolpackConfig, getUserHomeDir, gitAddTool, gitBlameTool, gitBranchCreateTool, gitBranchListTool, gitCheckoutTool, gitCloneTool, gitCommitTool, gitDiffTool, gitLogTool, gitStatusTool, gitToolsProject, githubContentsGetTextTool, githubGraphqlExecuteTool, githubIssuesCommentsCreateTool, githubPrDiffGetTool, githubPrFilesListTool, githubPrReviewCommentsReplyTool, githubPrReviewThreadsListTool, githubPrReviewThreadsResolveTool, githubPrReviewsSubmitTool, githubToolsProject, groupMessagesByRole, handleContextWindowError, httpDeleteTool, httpDownloadTool, httpGetTool, httpPostTool, httpPutTool, httpToolsProject, initializeGlobalConfigIfFirstRun, isContextWindowError, isDataUri, isRegisteredSlm, isToolSearchTool, k8sApplyManifestTool, k8sDeleteResourceTool, k8sDescribeTool, k8sGetConfigMapTool, k8sGetLogsTool, k8sGetNamespacesTool, k8sListDeploymentsTool, k8sListPodsTool, k8sListServicesTool, k8sSwitchContextTool, k8sToolsProject, k8sWaitForDeploymentTool, loadFullConfig, loadRuntimeConfig, loadToolsConfig, mergeSummarizationResults, normalizeImagePart, ollamaRequest, ollamaStream, parseDataUri, parseFileEnvelope, parseSkillFile, parseSummarizationResponse, prepareSummarizationRequest, pruneMessages, raceAbort, readFileAsBase64, reloadToolpackConfig, removeBypassRule, saveToolsConfig, slackAuthTestTool, slackChatPostEphemeralTool, slackChatPostMessageTool, slackConversationsHistoryTool, slackConversationsRepliesTool, slackReactionsAddTool, slackToolsProject, systemCwdTool, systemDiskUsageTool, systemEnvTool, systemInfoTool, systemSetEnvTool, systemToolsProject, toDataUri, toolSearchDefinition, truncateMessage, untilAborted, validateSummarizationResult, webExtractLinksTool, webFeedTool, webFetchTool, webMapTool, webMetadataTool, webScrapeTool, webScreenshotTool, webSearchTool, webSitemapTool, webToolsProject, wouldExceedContextWindow };
4115
+ export { AGENT_MODE, AGENT_PLANNING_PROMPT, AGENT_WORKFLOW, AIClient, type AIClientConfig, AbortedError, type AddBypassRuleOptions, AnthropicAdapter, AnthropicVertexAdapter, type AnthropicVertexConfig, type AssembledPrompt, type AssemblerOptions, AuthenticationError, BM25Engine, BM25SearchEngine, type BM25SearchResult, BUILT_IN_MODES, type BypassRuleType, CHAT_MODE, CHAT_WORKFLOW, CODING_MODE, CODING_PLANNING_PROMPT, CODING_WORKFLOW, CONFIG_DIR_NAME, CONFIG_FILE_NAME, type CompletionChunk, type CompletionOptions, type CompletionRequest, type CompletionResponse, type ConfirmationDecision, type ConfirmationLevel$1 as ConfirmationLevel, ConnectionError, type ContextPrunedEvent, type ContextWindowConfig, ContextWindowConfigError, ContextWindowExceededError, type ContextWindowExceededEvent, type ContextWindowState, ContextWindowStateManager, type ContextWindowStrategy, type ContextWindowWarningEvent, ConversationNotFoundError, type ConversationScope, type ConversationSearchOptions, type ConversationStore, type ConversationSummarizedEvent, DEFAULT_MODE_NAME, DEFAULT_TOOLS_CONFIG, DEFAULT_TOOL_SEARCH_CONFIG, DEFAULT_WORKFLOW, DEFAULT_WORKFLOW_CONFIG, type EmbeddingRequest, type EmbeddingResponse, FILE_LIMITS, type FileEnvelope, type FilePart, type FileUploadRequest, type FileUploadResponse, GeminiAdapter, type GetOptions, type HitlConfig, type ImageDataPart, type ImageFilePart, type ImagePart, type ImageUrlPart, InMemoryConversationStore, type InMemoryConversationStoreConfig, InsufficientContextError, type InterceptedToolCall, InvalidRequestError, type JsonRpcRequest, type JsonRpcResponse, type KnowledgeInstance, type McpAgentDefinition, type McpAuthConfig, McpClient, type McpClientConfig, McpConnectionError, type McpCustomAuthConfig, type McpJwtAuthConfig, type McpServerCapabilities, type McpServerConfig, type McpServerExposeConfig, type McpServerHandle, type McpStaticAuthConfig, McpTimeoutError, type McpTool, McpToolManager, type McpToolsConfig, type McpTransport, type MediaOptions, type MediaUploadStrategy, type Message, type MessageContent, type ModeBlockedHint, type ModeConfig, ModeRegistry, OllamaAdapter, type OllamaAdapterConfig, type OllamaModelInfo, OllamaProvider, type OllamaProviderEntry, type OnToolConfirmCallback, OpenAIAdapter, OpenRouterAdapter, type OpenRouterOptions, PageError, type Participant, type Plan, type PlanStep, Planner, type PromptMessage, ProviderAdapter, type ProviderConfig, ProviderError, type ProviderInfo, type ProviderModelInfo, type ProviderOptions, type PruneResult, RateLimitError, type RequestToolDefinition, type Role, RuleLoader, type RuntimeConfigStatus, SDKError, SQLiteConversationStore, type SQLiteConversationStoreConfig, type SearchHistoryEntry, type SearchOptions, type SearchResult, type Skill, type SkillSection, type SkillToolsOptions, type SkillValidationMode, type SlmModelEntry, type StoredMessage, SummarizationError, type SummarizationOptions, type SummarizationResult, TOOLPACK_DIR_NAME, TOOL_SEARCH_NAME, type TextPart, TimeoutError, type ToolActor, type ToolAnnotations, type ToolCall, type ToolCallFunction, type ToolCallMessage, type ToolCallRequest, type ToolCallResult, type ToolCategory, type ToolConfirmation, type ToolConfirmationRequestedEvent, type ToolConfirmationResolvedEvent, type ToolContext, type ToolDefinition, ToolDiscoveryCache, type ToolInterceptor, type ToolLogEvent, type ToolParameterProperty, type ToolParameters, type ToolProgressEvent, type ToolProject, type ToolProjectDependencies, type ToolProjectManifest, ToolRegistry, type ToolResult, ToolRouter, type ToolSchema, type ToolSearchConfig, Toolpack, type ToolpackConfig, type ToolpackCredentials, type ToolpackInitConfig, type ToolpackInterceptor, type ToolpackMcpServerConfig, type ToolpackNextFunction, type ToolsConfig, type Usage, VertexAIAdapter, type VertexAIConfig, type WorkflowConfig, type WorkflowEvents, WorkflowExecutor, type WorkflowProgress, type WorkflowResult, addBypassRule, buildSummarizedHistory, cloudDeployTool, cloudListTool, cloudStatusTool, cloudToolsProject, codingExtractFunctionTool, codingFindReferencesTool, codingFindSymbolTool, codingGetCallHierarchyTool, codingGetDiagnosticsTool, codingGetExportsTool, codingGetImportsTool, codingGetOutlineTool, codingGetSymbolsTool, codingGoToDefinitionTool, codingMultiFileEditTool, codingRefactorRenameTool, codingToolsProject, countTokens, createContextWindowStateManager, createMcpToolProject, createMode, createSkillTools, createSummarizationReport, createSummarySystemMessage, createToolProject, dbCountTool, dbDeleteTool, dbInsertTool, dbQueryTool, dbSchemaTool, dbTablesTool, dbToolsProject, dbUpdateTool, diffApplyTool, diffCreateTool, diffPreviewTool, diffToolsProject, disconnectMcpToolProject, ensureGlobalConfigDir, ensureLocalConfigDir, estimateSummaryTokens, estimateTokenCount, execKillTool, execListProcessesTool, execReadOutputTool, execRunBackgroundTool, execRunBlockingTool, execRunShellTool, execRunTool, execTailOutputTool, execToolsProject, extractConversationKeypoints, fetchUrlAsBase64, fsAppendFileTool, fsBatchReadTool, fsBatchWriteTool, fsCopyTool, fsCreateDirTool, fsDeleteDirTool, fsDeleteFileTool, fsExistsTool, fsGlobTool, fsListDirTool, fsMoveTool, fsReadFileRangeTool, fsReadFileTool, fsReplaceInFileTool, fsSearchTool, fsStatTool, fsToolsProject, fsTreeTool, fsWriteFileTool, generateSummarizationPrompt, generateToolCategoriesPrompt, getContextWindowPercentage, getDefaultSlmModel, getGlobalConfigDir, getGlobalConfigPath, getGlobalToolpackDir, getLocalConfigDir, getLocalConfigPath, getLocalToolpackDir, getMessageStats, getMimeType, getOllamaBaseUrl, getOllamaProviderEntries, getRegisteredSlmModels, getRuntimeConfigStatus, getSafeOutputReserve, getToolSearchSchema, getToolpackConfig, getUserHomeDir, gitAddTool, gitBlameTool, gitBranchCreateTool, gitBranchListTool, gitCheckoutTool, gitCloneTool, gitCommitTool, gitDiffTool, gitLogTool, gitStatusTool, gitToolsProject, githubContentsGetTextTool, githubGraphqlExecuteTool, githubIssuesCommentsCreateTool, githubPrDiffGetTool, githubPrFilesListTool, githubPrReviewCommentsReplyTool, githubPrReviewThreadsListTool, githubPrReviewThreadsResolveTool, githubPrReviewsSubmitTool, githubToolsProject, groupMessagesByRole, handleContextWindowError, httpDeleteTool, httpDownloadTool, httpGetTool, httpPostTool, httpPutTool, httpToolsProject, initializeGlobalConfigIfFirstRun, isContextWindowError, isDataUri, isRegisteredSlm, isToolSearchTool, k8sApplyManifestTool, k8sDeleteResourceTool, k8sDescribeTool, k8sGetConfigMapTool, k8sGetLogsTool, k8sGetNamespacesTool, k8sListDeploymentsTool, k8sListPodsTool, k8sListServicesTool, k8sSwitchContextTool, k8sToolsProject, k8sWaitForDeploymentTool, loadFullConfig, loadRuntimeConfig, loadToolsConfig, mergeSummarizationResults, normalizeImagePart, ollamaRequest, ollamaStream, parseDataUri, parseFileEnvelope, parseSkillFile, parseSummarizationResponse, prepareSummarizationRequest, pruneMessages, raceAbort, readFileAsBase64, reloadToolpackConfig, removeBypassRule, saveToolsConfig, slackAuthTestTool, slackChatPostEphemeralTool, slackChatPostMessageTool, slackConversationsHistoryTool, slackConversationsRepliesTool, slackReactionsAddTool, slackToolsProject, systemCwdTool, systemDiskUsageTool, systemEnvTool, systemInfoTool, systemSetEnvTool, systemToolsProject, toDataUri, toolSearchDefinition, truncateMessage, untilAborted, validateSummarizationResult, webExtractLinksTool, webFeedTool, webFetchTool, webMapTool, webMetadataTool, webScrapeTool, webScreenshotTool, webSearchTool, webSitemapTool, webToolsProject, wouldExceedContextWindow };
package/dist/index.d.ts CHANGED
@@ -654,6 +654,19 @@ interface ToolCallRequest {
654
654
  type: 'function';
655
655
  function: ToolCallFunction;
656
656
  }
657
+ /** One tool call, as a {@link ToolInterceptor} sees it. */
658
+ interface InterceptedToolCall {
659
+ toolName: string;
660
+ args: Record<string, any>;
661
+ /** The tool round of the request this call belongs to (1 for the first). Parallel calls of one round share it. */
662
+ round: number;
663
+ }
664
+ /**
665
+ * Wraps every tool call of one request. Call `run()` to run the tool (and use or change its result), or return text
666
+ * without calling it to stop the call: the model then sees that text as the tool's result. The tool's started, completed
667
+ * and log events are sent only when `run()` is called.
668
+ */
669
+ type ToolInterceptor = (call: InterceptedToolCall, run: () => Promise<string>) => Promise<string> | string;
657
670
  interface RequestToolDefinition {
658
671
  name: string;
659
672
  displayName: string;
@@ -699,6 +712,11 @@ interface CompletionRequest<T = unknown> {
699
712
  stream?: boolean;
700
713
  tools?: ToolCallRequest[];
701
714
  requestTools?: RequestToolDefinition[];
715
+ /**
716
+ * Wraps every tool call of this request, whatever the tool (request, mode or registry tool, and `tool.search`).
717
+ * It can stop a call or change its result. See {@link ToolInterceptor}. Not sent to the provider.
718
+ */
719
+ interceptTool?: ToolInterceptor;
702
720
  tool_choice?: 'auto' | 'none' | 'required';
703
721
  /** AbortSignal to cancel the request */
704
722
  signal?: AbortSignal;
@@ -1588,6 +1606,7 @@ declare class AIClient extends EventEmitter {
1588
1606
  * Emits 'tool:started', 'tool:completed', and 'tool:failed' events.
1589
1607
  */
1590
1608
  private executeTool;
1609
+ private runTool;
1591
1610
  /**
1592
1611
  * Find similar tool name to detect hallucinations.
1593
1612
  * Detects common patterns like underscore vs dot (fs_delete_file vs fs.delete_file).
@@ -4093,4 +4112,4 @@ declare class RuleLoader {
4093
4112
  private readFile;
4094
4113
  }
4095
4114
 
4096
- export { AGENT_MODE, AGENT_PLANNING_PROMPT, AGENT_WORKFLOW, AIClient, type AIClientConfig, AbortedError, type AddBypassRuleOptions, AnthropicAdapter, AnthropicVertexAdapter, type AnthropicVertexConfig, type AssembledPrompt, type AssemblerOptions, AuthenticationError, BM25Engine, BM25SearchEngine, type BM25SearchResult, BUILT_IN_MODES, type BypassRuleType, CHAT_MODE, CHAT_WORKFLOW, CODING_MODE, CODING_PLANNING_PROMPT, CODING_WORKFLOW, CONFIG_DIR_NAME, CONFIG_FILE_NAME, type CompletionChunk, type CompletionOptions, type CompletionRequest, type CompletionResponse, type ConfirmationDecision, type ConfirmationLevel$1 as ConfirmationLevel, ConnectionError, type ContextPrunedEvent, type ContextWindowConfig, ContextWindowConfigError, ContextWindowExceededError, type ContextWindowExceededEvent, type ContextWindowState, ContextWindowStateManager, type ContextWindowStrategy, type ContextWindowWarningEvent, ConversationNotFoundError, type ConversationScope, type ConversationSearchOptions, type ConversationStore, type ConversationSummarizedEvent, DEFAULT_MODE_NAME, DEFAULT_TOOLS_CONFIG, DEFAULT_TOOL_SEARCH_CONFIG, DEFAULT_WORKFLOW, DEFAULT_WORKFLOW_CONFIG, type EmbeddingRequest, type EmbeddingResponse, FILE_LIMITS, type FileEnvelope, type FilePart, type FileUploadRequest, type FileUploadResponse, GeminiAdapter, type GetOptions, type HitlConfig, type ImageDataPart, type ImageFilePart, type ImagePart, type ImageUrlPart, InMemoryConversationStore, type InMemoryConversationStoreConfig, InsufficientContextError, InvalidRequestError, type JsonRpcRequest, type JsonRpcResponse, type KnowledgeInstance, type McpAgentDefinition, type McpAuthConfig, McpClient, type McpClientConfig, McpConnectionError, type McpCustomAuthConfig, type McpJwtAuthConfig, type McpServerCapabilities, type McpServerConfig, type McpServerExposeConfig, type McpServerHandle, type McpStaticAuthConfig, McpTimeoutError, type McpTool, McpToolManager, type McpToolsConfig, type McpTransport, type MediaOptions, type MediaUploadStrategy, type Message, type MessageContent, type ModeBlockedHint, type ModeConfig, ModeRegistry, OllamaAdapter, type OllamaAdapterConfig, type OllamaModelInfo, OllamaProvider, type OllamaProviderEntry, type OnToolConfirmCallback, OpenAIAdapter, OpenRouterAdapter, type OpenRouterOptions, PageError, type Participant, type Plan, type PlanStep, Planner, type PromptMessage, ProviderAdapter, type ProviderConfig, ProviderError, type ProviderInfo, type ProviderModelInfo, type ProviderOptions, type PruneResult, RateLimitError, type RequestToolDefinition, type Role, RuleLoader, type RuntimeConfigStatus, SDKError, SQLiteConversationStore, type SQLiteConversationStoreConfig, type SearchHistoryEntry, type SearchOptions, type SearchResult, type Skill, type SkillSection, type SkillToolsOptions, type SkillValidationMode, type SlmModelEntry, type StoredMessage, SummarizationError, type SummarizationOptions, type SummarizationResult, TOOLPACK_DIR_NAME, TOOL_SEARCH_NAME, type TextPart, TimeoutError, type ToolActor, type ToolAnnotations, type ToolCall, type ToolCallFunction, type ToolCallMessage, type ToolCallRequest, type ToolCallResult, type ToolCategory, type ToolConfirmation, type ToolConfirmationRequestedEvent, type ToolConfirmationResolvedEvent, type ToolContext, type ToolDefinition, ToolDiscoveryCache, type ToolLogEvent, type ToolParameterProperty, type ToolParameters, type ToolProgressEvent, type ToolProject, type ToolProjectDependencies, type ToolProjectManifest, ToolRegistry, type ToolResult, ToolRouter, type ToolSchema, type ToolSearchConfig, Toolpack, type ToolpackConfig, type ToolpackCredentials, type ToolpackInitConfig, type ToolpackInterceptor, type ToolpackMcpServerConfig, type ToolpackNextFunction, type ToolsConfig, type Usage, VertexAIAdapter, type VertexAIConfig, type WorkflowConfig, type WorkflowEvents, WorkflowExecutor, type WorkflowProgress, type WorkflowResult, addBypassRule, buildSummarizedHistory, cloudDeployTool, cloudListTool, cloudStatusTool, cloudToolsProject, codingExtractFunctionTool, codingFindReferencesTool, codingFindSymbolTool, codingGetCallHierarchyTool, codingGetDiagnosticsTool, codingGetExportsTool, codingGetImportsTool, codingGetOutlineTool, codingGetSymbolsTool, codingGoToDefinitionTool, codingMultiFileEditTool, codingRefactorRenameTool, codingToolsProject, countTokens, createContextWindowStateManager, createMcpToolProject, createMode, createSkillTools, createSummarizationReport, createSummarySystemMessage, createToolProject, dbCountTool, dbDeleteTool, dbInsertTool, dbQueryTool, dbSchemaTool, dbTablesTool, dbToolsProject, dbUpdateTool, diffApplyTool, diffCreateTool, diffPreviewTool, diffToolsProject, disconnectMcpToolProject, ensureGlobalConfigDir, ensureLocalConfigDir, estimateSummaryTokens, estimateTokenCount, execKillTool, execListProcessesTool, execReadOutputTool, execRunBackgroundTool, execRunBlockingTool, execRunShellTool, execRunTool, execTailOutputTool, execToolsProject, extractConversationKeypoints, fetchUrlAsBase64, fsAppendFileTool, fsBatchReadTool, fsBatchWriteTool, fsCopyTool, fsCreateDirTool, fsDeleteDirTool, fsDeleteFileTool, fsExistsTool, fsGlobTool, fsListDirTool, fsMoveTool, fsReadFileRangeTool, fsReadFileTool, fsReplaceInFileTool, fsSearchTool, fsStatTool, fsToolsProject, fsTreeTool, fsWriteFileTool, generateSummarizationPrompt, generateToolCategoriesPrompt, getContextWindowPercentage, getDefaultSlmModel, getGlobalConfigDir, getGlobalConfigPath, getGlobalToolpackDir, getLocalConfigDir, getLocalConfigPath, getLocalToolpackDir, getMessageStats, getMimeType, getOllamaBaseUrl, getOllamaProviderEntries, getRegisteredSlmModels, getRuntimeConfigStatus, getSafeOutputReserve, getToolSearchSchema, getToolpackConfig, getUserHomeDir, gitAddTool, gitBlameTool, gitBranchCreateTool, gitBranchListTool, gitCheckoutTool, gitCloneTool, gitCommitTool, gitDiffTool, gitLogTool, gitStatusTool, gitToolsProject, githubContentsGetTextTool, githubGraphqlExecuteTool, githubIssuesCommentsCreateTool, githubPrDiffGetTool, githubPrFilesListTool, githubPrReviewCommentsReplyTool, githubPrReviewThreadsListTool, githubPrReviewThreadsResolveTool, githubPrReviewsSubmitTool, githubToolsProject, groupMessagesByRole, handleContextWindowError, httpDeleteTool, httpDownloadTool, httpGetTool, httpPostTool, httpPutTool, httpToolsProject, initializeGlobalConfigIfFirstRun, isContextWindowError, isDataUri, isRegisteredSlm, isToolSearchTool, k8sApplyManifestTool, k8sDeleteResourceTool, k8sDescribeTool, k8sGetConfigMapTool, k8sGetLogsTool, k8sGetNamespacesTool, k8sListDeploymentsTool, k8sListPodsTool, k8sListServicesTool, k8sSwitchContextTool, k8sToolsProject, k8sWaitForDeploymentTool, loadFullConfig, loadRuntimeConfig, loadToolsConfig, mergeSummarizationResults, normalizeImagePart, ollamaRequest, ollamaStream, parseDataUri, parseFileEnvelope, parseSkillFile, parseSummarizationResponse, prepareSummarizationRequest, pruneMessages, raceAbort, readFileAsBase64, reloadToolpackConfig, removeBypassRule, saveToolsConfig, slackAuthTestTool, slackChatPostEphemeralTool, slackChatPostMessageTool, slackConversationsHistoryTool, slackConversationsRepliesTool, slackReactionsAddTool, slackToolsProject, systemCwdTool, systemDiskUsageTool, systemEnvTool, systemInfoTool, systemSetEnvTool, systemToolsProject, toDataUri, toolSearchDefinition, truncateMessage, untilAborted, validateSummarizationResult, webExtractLinksTool, webFeedTool, webFetchTool, webMapTool, webMetadataTool, webScrapeTool, webScreenshotTool, webSearchTool, webSitemapTool, webToolsProject, wouldExceedContextWindow };
4115
+ export { AGENT_MODE, AGENT_PLANNING_PROMPT, AGENT_WORKFLOW, AIClient, type AIClientConfig, AbortedError, type AddBypassRuleOptions, AnthropicAdapter, AnthropicVertexAdapter, type AnthropicVertexConfig, type AssembledPrompt, type AssemblerOptions, AuthenticationError, BM25Engine, BM25SearchEngine, type BM25SearchResult, BUILT_IN_MODES, type BypassRuleType, CHAT_MODE, CHAT_WORKFLOW, CODING_MODE, CODING_PLANNING_PROMPT, CODING_WORKFLOW, CONFIG_DIR_NAME, CONFIG_FILE_NAME, type CompletionChunk, type CompletionOptions, type CompletionRequest, type CompletionResponse, type ConfirmationDecision, type ConfirmationLevel$1 as ConfirmationLevel, ConnectionError, type ContextPrunedEvent, type ContextWindowConfig, ContextWindowConfigError, ContextWindowExceededError, type ContextWindowExceededEvent, type ContextWindowState, ContextWindowStateManager, type ContextWindowStrategy, type ContextWindowWarningEvent, ConversationNotFoundError, type ConversationScope, type ConversationSearchOptions, type ConversationStore, type ConversationSummarizedEvent, DEFAULT_MODE_NAME, DEFAULT_TOOLS_CONFIG, DEFAULT_TOOL_SEARCH_CONFIG, DEFAULT_WORKFLOW, DEFAULT_WORKFLOW_CONFIG, type EmbeddingRequest, type EmbeddingResponse, FILE_LIMITS, type FileEnvelope, type FilePart, type FileUploadRequest, type FileUploadResponse, GeminiAdapter, type GetOptions, type HitlConfig, type ImageDataPart, type ImageFilePart, type ImagePart, type ImageUrlPart, InMemoryConversationStore, type InMemoryConversationStoreConfig, InsufficientContextError, type InterceptedToolCall, InvalidRequestError, type JsonRpcRequest, type JsonRpcResponse, type KnowledgeInstance, type McpAgentDefinition, type McpAuthConfig, McpClient, type McpClientConfig, McpConnectionError, type McpCustomAuthConfig, type McpJwtAuthConfig, type McpServerCapabilities, type McpServerConfig, type McpServerExposeConfig, type McpServerHandle, type McpStaticAuthConfig, McpTimeoutError, type McpTool, McpToolManager, type McpToolsConfig, type McpTransport, type MediaOptions, type MediaUploadStrategy, type Message, type MessageContent, type ModeBlockedHint, type ModeConfig, ModeRegistry, OllamaAdapter, type OllamaAdapterConfig, type OllamaModelInfo, OllamaProvider, type OllamaProviderEntry, type OnToolConfirmCallback, OpenAIAdapter, OpenRouterAdapter, type OpenRouterOptions, PageError, type Participant, type Plan, type PlanStep, Planner, type PromptMessage, ProviderAdapter, type ProviderConfig, ProviderError, type ProviderInfo, type ProviderModelInfo, type ProviderOptions, type PruneResult, RateLimitError, type RequestToolDefinition, type Role, RuleLoader, type RuntimeConfigStatus, SDKError, SQLiteConversationStore, type SQLiteConversationStoreConfig, type SearchHistoryEntry, type SearchOptions, type SearchResult, type Skill, type SkillSection, type SkillToolsOptions, type SkillValidationMode, type SlmModelEntry, type StoredMessage, SummarizationError, type SummarizationOptions, type SummarizationResult, TOOLPACK_DIR_NAME, TOOL_SEARCH_NAME, type TextPart, TimeoutError, type ToolActor, type ToolAnnotations, type ToolCall, type ToolCallFunction, type ToolCallMessage, type ToolCallRequest, type ToolCallResult, type ToolCategory, type ToolConfirmation, type ToolConfirmationRequestedEvent, type ToolConfirmationResolvedEvent, type ToolContext, type ToolDefinition, ToolDiscoveryCache, type ToolInterceptor, type ToolLogEvent, type ToolParameterProperty, type ToolParameters, type ToolProgressEvent, type ToolProject, type ToolProjectDependencies, type ToolProjectManifest, ToolRegistry, type ToolResult, ToolRouter, type ToolSchema, type ToolSearchConfig, Toolpack, type ToolpackConfig, type ToolpackCredentials, type ToolpackInitConfig, type ToolpackInterceptor, type ToolpackMcpServerConfig, type ToolpackNextFunction, type ToolsConfig, type Usage, VertexAIAdapter, type VertexAIConfig, type WorkflowConfig, type WorkflowEvents, WorkflowExecutor, type WorkflowProgress, type WorkflowResult, addBypassRule, buildSummarizedHistory, cloudDeployTool, cloudListTool, cloudStatusTool, cloudToolsProject, codingExtractFunctionTool, codingFindReferencesTool, codingFindSymbolTool, codingGetCallHierarchyTool, codingGetDiagnosticsTool, codingGetExportsTool, codingGetImportsTool, codingGetOutlineTool, codingGetSymbolsTool, codingGoToDefinitionTool, codingMultiFileEditTool, codingRefactorRenameTool, codingToolsProject, countTokens, createContextWindowStateManager, createMcpToolProject, createMode, createSkillTools, createSummarizationReport, createSummarySystemMessage, createToolProject, dbCountTool, dbDeleteTool, dbInsertTool, dbQueryTool, dbSchemaTool, dbTablesTool, dbToolsProject, dbUpdateTool, diffApplyTool, diffCreateTool, diffPreviewTool, diffToolsProject, disconnectMcpToolProject, ensureGlobalConfigDir, ensureLocalConfigDir, estimateSummaryTokens, estimateTokenCount, execKillTool, execListProcessesTool, execReadOutputTool, execRunBackgroundTool, execRunBlockingTool, execRunShellTool, execRunTool, execTailOutputTool, execToolsProject, extractConversationKeypoints, fetchUrlAsBase64, fsAppendFileTool, fsBatchReadTool, fsBatchWriteTool, fsCopyTool, fsCreateDirTool, fsDeleteDirTool, fsDeleteFileTool, fsExistsTool, fsGlobTool, fsListDirTool, fsMoveTool, fsReadFileRangeTool, fsReadFileTool, fsReplaceInFileTool, fsSearchTool, fsStatTool, fsToolsProject, fsTreeTool, fsWriteFileTool, generateSummarizationPrompt, generateToolCategoriesPrompt, getContextWindowPercentage, getDefaultSlmModel, getGlobalConfigDir, getGlobalConfigPath, getGlobalToolpackDir, getLocalConfigDir, getLocalConfigPath, getLocalToolpackDir, getMessageStats, getMimeType, getOllamaBaseUrl, getOllamaProviderEntries, getRegisteredSlmModels, getRuntimeConfigStatus, getSafeOutputReserve, getToolSearchSchema, getToolpackConfig, getUserHomeDir, gitAddTool, gitBlameTool, gitBranchCreateTool, gitBranchListTool, gitCheckoutTool, gitCloneTool, gitCommitTool, gitDiffTool, gitLogTool, gitStatusTool, gitToolsProject, githubContentsGetTextTool, githubGraphqlExecuteTool, githubIssuesCommentsCreateTool, githubPrDiffGetTool, githubPrFilesListTool, githubPrReviewCommentsReplyTool, githubPrReviewThreadsListTool, githubPrReviewThreadsResolveTool, githubPrReviewsSubmitTool, githubToolsProject, groupMessagesByRole, handleContextWindowError, httpDeleteTool, httpDownloadTool, httpGetTool, httpPostTool, httpPutTool, httpToolsProject, initializeGlobalConfigIfFirstRun, isContextWindowError, isDataUri, isRegisteredSlm, isToolSearchTool, k8sApplyManifestTool, k8sDeleteResourceTool, k8sDescribeTool, k8sGetConfigMapTool, k8sGetLogsTool, k8sGetNamespacesTool, k8sListDeploymentsTool, k8sListPodsTool, k8sListServicesTool, k8sSwitchContextTool, k8sToolsProject, k8sWaitForDeploymentTool, loadFullConfig, loadRuntimeConfig, loadToolsConfig, mergeSummarizationResults, normalizeImagePart, ollamaRequest, ollamaStream, parseDataUri, parseFileEnvelope, parseSkillFile, parseSummarizationResponse, prepareSummarizationRequest, pruneMessages, raceAbort, readFileAsBase64, reloadToolpackConfig, removeBypassRule, saveToolsConfig, slackAuthTestTool, slackChatPostEphemeralTool, slackChatPostMessageTool, slackConversationsHistoryTool, slackConversationsRepliesTool, slackReactionsAddTool, slackToolsProject, systemCwdTool, systemDiskUsageTool, systemEnvTool, systemInfoTool, systemSetEnvTool, systemToolsProject, toDataUri, toolSearchDefinition, truncateMessage, untilAborted, validateSummarizationResult, webExtractLinksTool, webFeedTool, webFetchTool, webMapTool, webMetadataTool, webScrapeTool, webScreenshotTool, webSearchTool, webSitemapTool, webToolsProject, wouldExceedContextWindow };
package/dist/index.js CHANGED
@@ -410,17 +410,17 @@ When the user asks you to do something, be proactive:
410
410
  ${l.join(`
411
411
 
412
412
  `)}
413
- </rules>`;return this.modeCache.set(n,{value:p,cachedAt:Date.now()}),p}clearCache(){this.modeCache.clear()}async collectFromFolder(e,t){let o=lw(e);try{await this.collectRecursive(o,t)}catch{}}async collectRecursive(e,t){let o=await aw(e,{withFileTypes:!0});for(let n of o){let s=es(e,n.name);n.isDirectory()?await this.collectRecursive(s,t):n.isFile()&&cw(n.name)===".md"&&t.add(s)}}async readFile(e,t){if(t.has(e))return t.get(e);try{let o=await iw(e,"utf-8");return t.set(e,o),o}catch{return""}}};function Rn(r,e){lt("debug")&&(b(`[AIClient][${r}] Messages (${e.length}):`),e.forEach((t,o)=>{let n=t,s=typeof n.content=="string"?n.content:M(n.content,1e4);b(`[AIClient][${r}] #${o} role=${n.role} content=${s}`)}))}function Oa(r){let e=it(r).toLowerCase();return e?[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/,/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b.*\b(file|folder|directory)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl|map)\b/,/https?:\/\//].some(o=>o.test(e)):!1}function Ia(r){let e=it(r).toLowerCase();if(!e)return!1;let t=[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/],o=[/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl)\b/];return t.some(n=>n.test(e))&&!o.some(n=>n.test(e))}var $n=class extends dw{providers;defaultProvider;toolRegistry;toolsConfig;toolRouter;bm25Engine;queryClassifier;toolOrchestrator;activeMode=null;overrideSystemPrompt;disableBaseContext;disableToolGuidance;toolResultMaxChars;hitlConfig;onToolConfirm;conversationId;contextWindowConfig;actor;contextWindowStateManager;providerModelCache=new Map;ruleLoader;requestSeq=0;constructor(e){super(),this.providers=new Map(Object.entries(e.providers)),this.defaultProvider=e.defaultProvider,this.toolRegistry=e.toolRegistry,this.toolsConfig=e.toolsConfig||ae,this.toolRouter=new Ht,this.bm25Engine=new Bt,this.queryClassifier=new St,this.toolOrchestrator=new _n,this.overrideSystemPrompt=e.systemPrompt,this.disableBaseContext=e.disableBaseContext||!1,this.disableToolGuidance=e.disableToolGuidance||!1;let t=this.toolsConfig.resultMaxChars??ae.resultMaxChars??2e4;this.toolResultMaxChars=Number.isFinite(t)&&t>0?t:2e4,this.hitlConfig=e.hitlConfig,this.onToolConfirm=e.onToolConfirm,this.conversationId=e.conversationId,this.contextWindowConfig=e.contextWindowConfig,this.actor=e.actor,this.providerModelCache=new Map,this.ruleLoader=new Pt,this.contextWindowConfig&&this.contextWindowConfig.enabled!==!1&&(this.contextWindowStateManager=ka(this.contextWindowConfig)),this.toolRegistry&&this.bm25Engine.index(this.toolRegistry.getAll())}getConversationId(){return this.conversationId||"global"}async getModelInfo(e,t){let o=e.name||e.constructor.name,n=this.providerModelCache.get(o);if(!n){try{n=await e.getModels()}catch{n=[]}this.providerModelCache.set(o,n)}return n.find(s=>s.id===t||s.displayName===t)}async countRequestTokens(e,t,o){let n=await t.countTokens(e.messages,o);return typeof n=="number"&&Number.isFinite(n)?n:ba(e.messages,o,t.getDisplayName().toLowerCase())}async pruneConversation(e,t,o){let n=this.contextWindowConfig?.retainSystemMessages??!0,s=e;for(let i=0;i<3;i+=1){let a=await this.countRequestTokens(s,t,s.model);if(a<=o)return s;let l=a-o,p=wa(s.messages,l,n),d=new Set(p.pruneInfo.removedMessages),m=s.messages.filter(y=>!d.has(y)),u={...s,messages:m};if(this.contextWindowStateManager&&this.contextWindowStateManager.recordPruneOperation(this.getConversationId(),p.tokensReclaimed),await this.countRequestTokens(u,t,u.model)<=o||m.length===s.messages.length)return u;s=u}return e}async pruneToMaxMessageHistory(e){let t=this.contextWindowConfig?.maxMessageHistoryLength;if(!t||e.messages.length<=t)return e;let o=this.contextWindowConfig?.retainSystemMessages??!0,n=[];e.messages.forEach((l,p)=>{o&&l.role==="system"||l.role!=="tool"&&n.push(p)});let s=Math.max(0,e.messages.length-t);if(s===0)return e;let i=new Set(n.slice(0,s)),a=e.messages.filter((l,p)=>!i.has(p));return{...e,messages:a}}async summarizeConversation(e,t){let o=e.messages,n=o.filter(C=>C.role==="system"),s=o.filter(C=>C.role!=="system");if(s.length<4)return e;let i=s.slice(-4),a=s.slice(0,-4);if(a.length<2)return e;let l=this.contextWindowConfig?.summarizerModel||e.model,p=va(a,{model:l,maxSummaryTokens:500}),d=await Be(t.generate({model:l,messages:p,max_tokens:500,temperature:0,response_format:"text",signal:e.signal}),e.signal);if(!d.content)throw new Gt("Summarization provider returned no summary",this.getConversationId(),a.length,"invalid_response");let m=await this.countRequestTokens({...e,messages:a},t,l),u=Ca(d.content,a,m),T=xa(u);if(!T.valid)throw new Gt(`Summarization result is invalid: ${T.issues.join("; ")}`,this.getConversationId(),a.length,"invalid_quality",d.content);let y=Jr(u.summary,a.length),w=[...n,y,...i];return this.contextWindowStateManager&&this.contextWindowStateManager.recordSummarization(this.getConversationId(),u.tokensSaved),{...e,messages:w}}async enforceContextWindow(e,t){if(!this.contextWindowConfig||this.contextWindowConfig.enabled===!1)return e;let o=await this.pruneToMaxMessageHistory(e),n=await this.getModelInfo(t,o.model),s=n?.contextWindow??1e5,i=o.max_tokens??n?.maxOutputTokens??1024,a=this.contextWindowConfig.outputTokenBuffer??1.15,l=Ta(i,a),p=Math.max(0,s-l),d=Math.floor(s*((this.contextWindowConfig.pruneThreshold??85)/100)),m=Math.min(p,d),u=await this.countRequestTokens(o,t,o.model);if(this.contextWindowStateManager&&(this.contextWindowStateManager.updateTokenCount(this.getConversationId(),u),u>m&&this.contextWindowStateManager.recordWarning(this.getConversationId())),u<=m)return o;let T=this.contextWindowConfig.strategy??"prune";if(T==="fail"&&u>p)throw new Ut("Context window exceeded by request messages",this.getConversationId(),u,p,T);if(T==="summarize")try{let w=await this.summarizeConversation(o,t);if(await this.countRequestTokens(w,t,w.model)<=p)return w;o=await this.pruneConversation(w,t,p)}catch(w){if(w instanceof A)throw w;o=await this.pruneConversation(o,t,p)}else o=await this.pruneConversation(o,t,p);let y=await this.countRequestTokens(o,t,o.model);if(y>p&&T==="fail")throw new Ut("Context window exceeded after attempted cleanup",this.getConversationId(),y,p,T);return o}isBypassed(e){let t=this.hitlConfig;if(!t||t.enabled===!1)return!0;let o=t.confirmationMode??"all";if(o==="off"||o==="high-only"&&e.confirmation?.level==="medium")return!0;let n=t.bypass??{};return!!(n.tools?.includes(e.name)||n.categories?.includes(e.category)||e.confirmation&&n.levels?.includes(e.confirmation.level))}registerProvider(e,t){this.providers.set(e,t)}getProvider(e){let t=e||this.defaultProvider;if(!t)throw new N("No provider specified and no default provider configured","NO_PROVIDER_CONFIGURED",400);let o=this.providers.get(t);if(!o)throw new N(`Provider '${t}' not found`,"PROVIDER_NOT_FOUND",404);return o}updateHitlConfig(e){this.hitlConfig=e}getHitlConfig(){return this.hitlConfig}setDefaultProvider(e){if(!this.providers.has(e))throw new N(`Provider '${e}' not found`,"PROVIDER_NOT_FOUND",404);this.defaultProvider=e}getToolRegistry(){return this.toolRegistry}getProviders(){return new Map(this.providers)}setToolRegistry(e){this.toolRegistry=e}setToolsConfig(e){this.toolsConfig=e}setSystemPrompt(e){this.overrideSystemPrompt=e}setMode(e){this.activeMode=e,k(`[AIClient] Mode set to: ${e?e.displayName:"none (cleared)"}`)}getMode(){return this.activeMode}getQueryClassifier(){return this.queryClassifier}reindexTools(){this.toolRegistry&&(this.bm25Engine.index(this.toolRegistry.getAll()),k(`[AIClient] Re-indexed ${this.bm25Engine.getIndexedCount()} tools for BM25 search`))}clearToolDiscoveryCache(){this.toolRouter.clearDiscoveryCache()}async generate(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=this.resolveRequestMode(e),a=i?.toolsConfig?{...this.toolsConfig,...i.toolsConfig}:this.toolsConfig,l=this.injectBaseAgentContext(e,i);l=this.injectOverrideSystemPrompt(l),l=this.injectModeSystemPrompt(l,i),l=await this.injectModeRules(l,i);let p=t||this.defaultProvider,d=await this.enrichRequestWithTools(l,i),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let T=a.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",y=(m.tools?.length||0)>0,w=m.tool_choice!=null,C=Oa(m.messages),S=Ia(m.messages);!w&&y&&(T==="required"||T==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",P=i?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,...P?{response_format:P}:{}};k(`[AIClient][${s}] generate() start provider=${p} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${T} needsTools=${C} autoExecute=${a.enabled&&a.autoExecute}`),Zr(s,m.tools),Rn(s,m.messages);let j=oe=>Be(ha(()=>n.generate(oe),{signal:e.signal,onRetry:(H,Z)=>k(`[AIClient][${s}] Rate limited \u2014 retrying in ${Z/1e3}s (attempt ${H}/3)`)}),e.signal),R=await j(E);if(b(`[AIClient][${s}] generate() initial response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`),a.autoExecute&&(this.toolRegistry||u.size>0||(i?.customTools?.length??0)>0)){let oe=it(m.messages),H=this.queryClassifier.classify(oe),Z=a.maxToolRounds,xe=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(H,Z);m.maxToolRounds!==void 0?b(`[AIClient][${s}] maxToolRounds overridden per-request: ${xe} (classifier bypassed)`):xe!==Z?k(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), adjusted maxToolRounds: ${Z} \u2192 ${xe}`):b(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), keeping maxToolRounds: ${xe}`);let ce=0,Q=[...m.messages];for(R.tool_calls&&R.tool_calls.length>0&&k(`[AIClient] Received ${R.tool_calls.length} tool call(s): ${R.tool_calls.map(G=>G.name).join(", ")}`);R.tool_calls&&R.tool_calls.length>0&&ce<xe;){if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal`),new A;ce++,k(`[AIClient][${s}] generate() tool round ${ce}/${xe} tool_calls=${R.tool_calls.length}`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(B=>({id:B.id,type:"function",function:{name:B.name,arguments:JSON.stringify(B.arguments)}}))});let G=this.toolOrchestrator.shouldUseParallelExecution(R.tool_calls),K=3,De=R.tool_calls,We=R.tool_calls.filter(B=>B.name==="web.fetch");if(We.length>K){k(`[AIClient][${s}] Limiting web.fetch calls from ${We.length} \u2192 ${K} to prevent context overflow`);let B=We.slice(0,K);De=[...R.tool_calls.filter(ye=>ye.name!=="web.fetch"),...B];let J=We.slice(K);for(let ye of J)Q.push({role:"tool",tool_call_id:ye.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let pe=5e4,he=0;if(G){k(`[AIClient][${s}] Using parallel execution for ${De.length} tools`);let B;try{B=await Be(this.toolOrchestrator.executeWithDependencies(De,D=>this.executeTool(D,u,i,ce,e.signal),5),e.signal)}catch(D){if(D instanceof A)throw D;fe(`[AIClient][${s}] Parallel tool execution failed: ${D.message}`),B=new Map(De.map(J=>[J.id,JSON.stringify({error:D.message??"Tool execution failed"})]))}for(let D of De){let J=B.get(D.id)??JSON.stringify({error:"Tool execution result missing"}),ye=typeof J=="string"?J:JSON.stringify(J),xt=pe-he,ne=ye.startsWith("data:image/"),re;ne?re=ye:he+ye.length>pe?(O(`[AIClient][${s}] Tool output budget exceeded (${pe} chars)`),re=this.budgetTruncate(ye,xt)):typeof J=="string"&&J.length>this.toolResultMaxChars?re=`${J.slice(0,this.toolResultMaxChars)}
414
- [TRUNCATED tool result: ${J.length} chars]`:re=ye;let $=typeof re=="string"?re:JSON.stringify(re);ne||(he+=$.length),Q.push({role:"tool",tool_call_id:D.id,content:re})}b(`[AIClient][${s}] Round tool output size: ${he} chars (budget: ${pe})`)}else{k(`[AIClient][${s}] Using sequential execution for ${De.length} tools`);for(let B of De){let D;try{D=await this.executeTool(B,u,i,ce,e.signal)}catch($){if($ instanceof A)throw $;D=JSON.stringify({error:$.message??"Tool execution failed"})}let J=typeof D=="string"?D:JSON.stringify(D),ye=pe-he,xt=J.startsWith("data:image/"),ne;xt?ne=J:he+J.length>pe?(O(`[AIClient][${s}] Tool output budget exceeded (${pe} chars)`),ne=this.budgetTruncate(J,ye)):typeof D=="string"&&D.length>this.toolResultMaxChars?ne=`${D.slice(0,this.toolResultMaxChars)}
415
- [TRUNCATED tool result: ${D.length} chars]`:ne=J;let re=typeof ne=="string"?ne:JSON.stringify(ne);xt||(he+=re.length),Q.push({role:"tool",tool_call_id:B.id,content:ne})}b(`[AIClient][${s}] Round tool output size: ${he} chars (budget: ${pe})`)}if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal during tool execution`),new A;let Le={...m,messages:Q,__toolpack_request_id:s,...P?{response_format:P}:{}},Ue=o?.getLatestRequestTools?.()??[];if(Ue.length>0){let B=new Map((m.requestTools??[]).map(D=>[D.name,D]));for(let D of Ue)B.set(D.name,D);Le.requestTools=Array.from(B.values());for(let D of Ue)u.set(D.name,D)}let Pe=this.stripRequestTools((await this.enrichRequestWithTools(Le,i)).request);Pe=await this.enforceContextWindow(Pe,n),Pe.tool_choice==="required"&&(Pe.tool_choice=S?"none":"auto",k(`[AIClient][${s}] generate() followup tool_choice override required->${Pe.tool_choice}`)),lt("debug")&&(b(`[AIClient][${s}] generate() followup request messages=${Q.length}`),Rn(s,Q)),R=await j(Pe),b(`[AIClient][${s}] generate() followup response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`)}if(ce>=xe&&!e.signal?.aborted&&R.tool_calls&&R.tool_calls.length>0){k(`[AIClient][${s}] Tool-round cap (${xe}) hit with pending tool calls; requesting graceful conclusion`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(K=>({id:K.id,type:"function",function:{name:K.name,arguments:JSON.stringify(K.arguments)}}))});for(let K of R.tool_calls)Q.push({role:"tool",tool_call_id:K.id,content:"[Tool call skipped: maximum tool rounds reached]"});Q.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let G={...m,messages:Q,__toolpack_request_id:s,tools:[],requestTools:[],tool_choice:void 0};try{R=await j(await this.enforceContextWindow(G,n)),k(`[AIClient][${s}] Graceful conclusion received content_length=${R.content?.length??0}`)}catch(K){if(K instanceof A)throw K;O(`[AIClient][${s}] Graceful conclusion call failed: ${K?.message??K}; returning last response`)}}}return R.data===void 0&&R.content&&e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format&&(R.data=e.response_format.parse(JSON.parse(R.content))),R}catch(s){throw this.wrapError(s)}}async*stream(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=t||this.defaultProvider,a=this.resolveRequestMode(e),l=a?.toolsConfig?{...this.toolsConfig,...a.toolsConfig}:this.toolsConfig,p=this.injectBaseAgentContext(e,a);p=this.injectOverrideSystemPrompt(p),p=this.injectModeSystemPrompt(p,a),p=await this.injectModeRules(p,a);let d=await this.enrichRequestWithTools(p,a),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let T=l.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",y=(m.tools?.length||0)>0,w=m.tool_choice!=null,C=Oa(m.messages),S=Ia(m.messages);!w&&y&&(T==="required"||T==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",P=a?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,...P?{response_format:P}:{}};if(k(`[AIClient][${s}] stream() start provider=${i} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${T} needsTools=${C} autoExecute=${l.enabled&&l.autoExecute}`),Zr(s,m.tools),Rn(s,m.messages),!l.autoExecute||!this.toolRegistry&&u.size===0&&(a?.customTools?.length??0)===0){if(yield*Pn(n.stream(E),e.signal),e.signal?.aborted)throw new A;return}let j=[...m.messages],R=0,oe=!1,H=it(m.messages),Z=this.queryClassifier.classify(H),xe=l.maxToolRounds,ce=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(Z,xe);for(m.maxToolRounds!==void 0?b(`[AIClient][${s}] stream() maxToolRounds overridden per-request: ${ce} (classifier bypassed)`):ce!==xe&&k(`[AIClient][${s}] stream() Query classified as ${Z.type} (confidence: ${Z.confidence.toFixed(2)}), adjusted maxToolRounds: ${xe} \u2192 ${ce}`);R<=ce;){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal`),new A;let Q="",G=[];R++,k(`[AIClient][${s}] stream() round_start ${R}/${ce}`);let K=null,De={...m,messages:j,...P?{response_format:P}:{}},We=o?.getLatestRequestTools?.()??[];if(We.length>0){let $=new Map((m.requestTools??[]).map(q=>[q.name,q]));for(let q of We)$.set(q.name,q);De.requestTools=Array.from($.values());for(let q of We)u.set(q.name,q)}let pe=this.stripRequestTools((await this.enrichRequestWithTools(De,a)).request);pe=await this.enforceContextWindow(pe,n),R>1&&pe.tool_choice==="required"&&(pe.tool_choice=S?"none":"auto",k(`[AIClient][${s}] stream() round_${R} tool_choice override required->${pe.tool_choice}`));for await(let $ of Pn(n.stream(pe),e.signal)){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during chunk processing`),new A;$.tool_calls&&$.tool_calls.length>0&&(G.push(...$.tool_calls),b(`[AIClient][${s}] stream() tool_calls_chunk count=${$.tool_calls.length} names=${$.tool_calls.map(q=>q.name).join(", ")}`),yield $),$.delta&&(Q+=$.delta,yield $),$.finish_reason&&(K=$.finish_reason),$.finish_reason==="stop"&&(yield $)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal while waiting for the provider`),new A;if(b(`[AIClient][${s}] stream() round_end finish_reason=${K??"unknown"} accumulated_len=${Q.length} tool_calls_total=${G.length} content=${Q}`),G.length===0)break;k(`[AIClient][${s}] stream() received ${G.length} tool call(s): ${G.map($=>$.name).join(", ")}`),k(`[AIClient][${s}] stream() tool round ${R}/${ce}`),j.push({role:"assistant",content:Q||"",tool_calls:G.map($=>({id:$.id,type:"function",function:{name:$.name,arguments:JSON.stringify($.arguments)}}))});let he=3,Le=G,Ue=G.filter($=>$.name==="web.fetch");if(Ue.length>he){k(`[AIClient][${s}] Limiting web.fetch calls from ${Ue.length} \u2192 ${he} to prevent context overflow`);let $=Ue.slice(0,he);Le=[...G.filter(Wt=>Wt.name!=="web.fetch"),...$];let _e=Ue.slice(he);for(let Wt of _e)j.push({role:"tool",tool_call_id:Wt.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let Pe=5e4,B=0,D=[],J=!1,ye=setInterval(()=>{J||D.push({delta:""})},500),xt=Date.now(),ne,re;try{if(Le.length>=2)k(`[AIClient][${s}] stream() using parallel execution for ${Le.length} tools`),re=new Map,ne=await Be(this.toolOrchestrator.executeWithDependencies(Le,async $=>{let q=Date.now(),_e=await this.executeTool($,u,a,R,e.signal);return re.set($.id,Date.now()-q),_e},5),e.signal);else{k(`[AIClient][${s}] stream() executing single tool sequentially`),re=new Map,ne=new Map;for(let $ of Le){let q=Date.now(),_e=await this.executeTool($,u,a,R,e.signal);re.set($.id,Date.now()-q),ne.set($.id,_e)}}}finally{J=!0,clearInterval(ye)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during tool execution`),new A;for(;D.length>0;)yield D.shift();await new Promise($=>setTimeout($,0)),b(`[AIClient][${s}] stream() tool batch completed in ${Date.now()-xt}ms`);for(let $ of Le){let q=ne.get($.id),_e=typeof q=="string"?q:JSON.stringify(q),Wt=Pe-B,LT=re.get($.id)??0,pa=_e.startsWith("data:image/"),Ge;pa?Ge=_e:B+_e.length>Pe?(O(`[AIClient][${s}] Tool output budget exceeded (${Pe} chars)`),Ge=this.budgetTruncate(_e,Wt)):typeof q=="string"&&q.length>this.toolResultMaxChars?Ge=`${q.slice(0,this.toolResultMaxChars)}
416
- [TRUNCATED tool result: ${q.length} chars]`:Ge=_e;let ma=typeof Ge=="string"?Ge:JSON.stringify(Ge);pa||(B+=ma.length),j.push({role:"tool",tool_call_id:$.id,content:Ge}),yield{delta:"",tool_calls:[{...$,result:ma,duration:LT}]}}b(`[AIClient][${s}] Round tool output size: ${B} chars (budget: ${Pe})`),lt("debug")&&(b(`[AIClient][${s}] stream() after_tools messages=${j.length}`),Rn(s,j)),R>ce&&(oe=!0)}if(oe&&!e.signal?.aborted){k(`[AIClient][${s}] Tool-round cap (${ce}) hit; requesting graceful conclusion`),j.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let Q={...m,messages:j,tools:[],requestTools:[],tool_choice:void 0};try{let G=await this.enforceContextWindow(Q,n);for await(let K of Pn(n.stream(G),e.signal))yield K;if(e.signal?.aborted)throw new A;k(`[AIClient][${s}] Graceful conclusion stream complete`)}catch(G){if(G instanceof A)throw G;O(`[AIClient][${s}] Graceful conclusion stream failed: ${G?.message??G}`)}}}catch(s){if(s instanceof A){yield{delta:"",finish_reason:"aborted"};return}throw this.wrapError(s)}}async embed(e,t){let o=this.getProvider(t);try{return await o.embed(e)}catch(n){throw this.wrapError(n)}}async enrichRequestWithTools(e,t){if(t?.blockAllTools)return k(`[AIClient] Mode "${t.displayName}" blocks all tools`),{request:e,requestToolMap:new Map};let o=this.buildRequestToolMap(e.requestTools),n=Array.from(o.values()).map(y=>this.requestToolToSchema(y)),s=o.size>0,i=t?.toolsConfig?{...this.toolsConfig,...t.toolsConfig}:this.toolsConfig,a=this.toolDefinitionsToSchemas(t?.customTools??[]),l=this.mergeSchemas(a,n);if(!i.enabled&&!s&&a.length===0)return b("[AIClient] Tools disabled and no request-scoped or mode tools"),{request:e,requestToolMap:o};let p=i;if(t?.toolSearch&&i.toolSearch&&(p={...i,toolSearch:{...i.toolSearch,...t.toolSearch.enabled!==void 0?{enabled:t.toolSearch.enabled}:{},...t.toolSearch.alwaysLoadedTools?{alwaysLoadedTools:t.toolSearch.alwaysLoadedTools}:{},...t.toolSearch.alwaysLoadedCategories?{alwaysLoadedCategories:t.toolSearch.alwaysLoadedCategories}:{}}},b(`[AIClient] Merged mode toolSearch config: enabled=${p.toolSearch?.enabled}, alwaysLoadedTools=${p.toolSearch?.alwaysLoadedTools?.length||0}`)),e.tools&&e.tools.length>0){if(!p.toolSearch?.enabled||!this.toolRegistry){b(`[AIClient] Request already has ${e.tools.length} tools`);let x=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=x===e.tools?e:{...e,tools:x};return{request:this.injectRequestToolGuidance(v,x),requestToolMap:o}}let y=await this.toolRouter.resolve(e.messages,this.toolRegistry,p);if(b(`[AIClient] Resolved ${y.length} tools to send: ${y.map(x=>x.name).join(", ")||"none"}`),t&&y.length>0){let x=y.length;y=this.filterSchemasByMode(y,t);let v=x-y.length;v>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${v} tools`)}let w=new Set(e.tools.map(x=>x.function.name)),C=y.filter(x=>!w.has(x.name)).map(x=>({type:"function",function:{name:x.name,description:x.description,parameters:x.parameters}}));if(C.length===0){b(`[AIClient] Request already has ${e.tools.length} tools (no new discoveries)`);let x=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=x===e.tools?e:{...e,tools:x};return{request:this.injectRequestToolGuidance(v,x),requestToolMap:o}}let S={...e,tools:this.mergeToolCallRequests([...e.tools,...C],this.schemasToToolCallRequests(l))};return p.toolSearch?.enabled&&this.toolRegistry&&(S=this.injectToolSearchPrompt(S)),{request:this.injectRequestToolGuidance(S,S.tools),requestToolMap:o}}if(!this.toolRegistry){b("[AIClient] Tool registry not configured, skipping tool resolution");let y=this.schemasToToolCallRequests(l),w=y.length>0?{...e,tools:y}:e;return{request:this.injectRequestToolGuidance(w,y),requestToolMap:o}}let d=this.toolRegistry,m=await this.toolRouter.resolve(e.messages,d,p);if(b(`[AIClient] Resolved ${m.length} tools to send: ${m.map(y=>y.name).join(", ")||"none"}`),t&&m.length>0){let y=m.length;m=this.filterSchemasByMode(m,t);let w=y-m.length;w>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${w} tools`)}let u=this.schemasToToolCallRequests(this.mergeSchemas(m,l));if(u.length===0)return{request:e,requestToolMap:o};let T={...e,tools:u};return i.toolSearch?.enabled&&d&&(T=this.injectToolSearchPrompt(T)),{request:this.injectRequestToolGuidance(T,u),requestToolMap:o}}toolDefinitionsToSchemas(e){return e.map(t=>({name:t.name,displayName:t.displayName,description:t.description,parameters:t.parameters,category:t.category,...t.cacheable!==void 0&&{cacheable:t.cacheable},...t.annotations!==void 0&&{annotations:t.annotations}}))}buildRequestToolMap(e){let t=new Map;for(let o of e||[])t.set(o.name,o);return t}requestToolToSchema(e){return{name:e.name,displayName:e.displayName,description:e.description,parameters:e.parameters,category:e.category,cacheable:e.cacheable}}mergeSchemas(e,t){let o=new Map;for(let n of e)o.set(n.name,n);for(let n of t)o.set(n.name,n);return Array.from(o.values())}schemasToToolCallRequests(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.parameters}}))}mergeToolCallRequests(e,t){if(t.length===0)return e;let o=new Map;for(let n of e)o.set(n.function.name,n);for(let n of t)o.set(n.function.name,n);return Array.from(o.values())}injectRequestToolGuidance(e,t){if(this.disableToolGuidance)return e;let o=new Set((t||e.tools||[]).map(p=>p.function.name));if(o.size===0)return e;let n="<!-- TOOLPACK_REQUEST_TOOL_GUIDANCE -->",s=[],i=o.has("mind_believe");if(o.has("knowledge_search")||o.has("knowledge_add")){let p=["Knowledge Base:"];if(o.has("knowledge_search")&&p.push("- Use `knowledge_search` proactively whenever the user asks about anything that could have been stored, including personal facts about the user, their preferences, names, past decisions, domain-specific information or anything that could have been stored in the memory. Search before concluding you do not know something."),o.has("knowledge_add")){let d=i?"- Use `knowledge_add` for factual domain knowledge: documents, research, technical references, or organizational information shared across agents. Do NOT use it for personal user facts or preferences \u2014 use `mind_believe` for those.":"- Use `knowledge_add` when you encounter a durable fact, user preference, or decision that future conversations should know. Do not add confidential information, routine task outputs, or context that is specific to this conversation only.";p.push(d)}s.push(p.join(`
413
+ </rules>`;return this.modeCache.set(n,{value:p,cachedAt:Date.now()}),p}clearCache(){this.modeCache.clear()}async collectFromFolder(e,t){let o=lw(e);try{await this.collectRecursive(o,t)}catch{}}async collectRecursive(e,t){let o=await aw(e,{withFileTypes:!0});for(let n of o){let s=es(e,n.name);n.isDirectory()?await this.collectRecursive(s,t):n.isFile()&&cw(n.name)===".md"&&t.add(s)}}async readFile(e,t){if(t.has(e))return t.get(e);try{let o=await iw(e,"utf-8");return t.set(e,o),o}catch{return""}}};function Rn(r,e){lt("debug")&&(b(`[AIClient][${r}] Messages (${e.length}):`),e.forEach((t,o)=>{let n=t,s=typeof n.content=="string"?n.content:M(n.content,1e4);b(`[AIClient][${r}] #${o} role=${n.role} content=${s}`)}))}function Oa(r){let e=it(r).toLowerCase();return e?[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/,/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b.*\b(file|folder|directory)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl|map)\b/,/https?:\/\//].some(o=>o.test(e)):!1}function Ia(r){let e=it(r).toLowerCase();if(!e)return!1;let t=[/\b(list|show|print|display)\b.*\b(files|folders|directory|dir)\b/,/\b(current|this)\b.*\b(directory|folder|repo|repository)\b/,/\b(read|open|view)\b.*\b(file|log|config|json|yaml|env)\b/],o=[/\b(write|create|update|modify|edit|patch|delete|remove|rename|move|copy)\b/,/\b(run|execute)\b.*\b(command|shell|script|tests?)\b/,/\b(http|get|post|put|delete|download|fetch|curl)\b/,/\b(web|search|scrape|crawl)\b/];return t.some(n=>n.test(e))&&!o.some(n=>n.test(e))}var $n=class extends dw{providers;defaultProvider;toolRegistry;toolsConfig;toolRouter;bm25Engine;queryClassifier;toolOrchestrator;activeMode=null;overrideSystemPrompt;disableBaseContext;disableToolGuidance;toolResultMaxChars;hitlConfig;onToolConfirm;conversationId;contextWindowConfig;actor;contextWindowStateManager;providerModelCache=new Map;ruleLoader;requestSeq=0;constructor(e){super(),this.providers=new Map(Object.entries(e.providers)),this.defaultProvider=e.defaultProvider,this.toolRegistry=e.toolRegistry,this.toolsConfig=e.toolsConfig||ae,this.toolRouter=new Ht,this.bm25Engine=new Bt,this.queryClassifier=new St,this.toolOrchestrator=new _n,this.overrideSystemPrompt=e.systemPrompt,this.disableBaseContext=e.disableBaseContext||!1,this.disableToolGuidance=e.disableToolGuidance||!1;let t=this.toolsConfig.resultMaxChars??ae.resultMaxChars??2e4;this.toolResultMaxChars=Number.isFinite(t)&&t>0?t:2e4,this.hitlConfig=e.hitlConfig,this.onToolConfirm=e.onToolConfirm,this.conversationId=e.conversationId,this.contextWindowConfig=e.contextWindowConfig,this.actor=e.actor,this.providerModelCache=new Map,this.ruleLoader=new Pt,this.contextWindowConfig&&this.contextWindowConfig.enabled!==!1&&(this.contextWindowStateManager=ka(this.contextWindowConfig)),this.toolRegistry&&this.bm25Engine.index(this.toolRegistry.getAll())}getConversationId(){return this.conversationId||"global"}async getModelInfo(e,t){let o=e.name||e.constructor.name,n=this.providerModelCache.get(o);if(!n){try{n=await e.getModels()}catch{n=[]}this.providerModelCache.set(o,n)}return n.find(s=>s.id===t||s.displayName===t)}async countRequestTokens(e,t,o){let n=await t.countTokens(e.messages,o);return typeof n=="number"&&Number.isFinite(n)?n:ba(e.messages,o,t.getDisplayName().toLowerCase())}async pruneConversation(e,t,o){let n=this.contextWindowConfig?.retainSystemMessages??!0,s=e;for(let i=0;i<3;i+=1){let a=await this.countRequestTokens(s,t,s.model);if(a<=o)return s;let l=a-o,p=wa(s.messages,l,n),d=new Set(p.pruneInfo.removedMessages),m=s.messages.filter(y=>!d.has(y)),u={...s,messages:m};if(this.contextWindowStateManager&&this.contextWindowStateManager.recordPruneOperation(this.getConversationId(),p.tokensReclaimed),await this.countRequestTokens(u,t,u.model)<=o||m.length===s.messages.length)return u;s=u}return e}async pruneToMaxMessageHistory(e){let t=this.contextWindowConfig?.maxMessageHistoryLength;if(!t||e.messages.length<=t)return e;let o=this.contextWindowConfig?.retainSystemMessages??!0,n=[];e.messages.forEach((l,p)=>{o&&l.role==="system"||l.role!=="tool"&&n.push(p)});let s=Math.max(0,e.messages.length-t);if(s===0)return e;let i=new Set(n.slice(0,s)),a=e.messages.filter((l,p)=>!i.has(p));return{...e,messages:a}}async summarizeConversation(e,t){let o=e.messages,n=o.filter(C=>C.role==="system"),s=o.filter(C=>C.role!=="system");if(s.length<4)return e;let i=s.slice(-4),a=s.slice(0,-4);if(a.length<2)return e;let l=this.contextWindowConfig?.summarizerModel||e.model,p=va(a,{model:l,maxSummaryTokens:500}),d=await Be(t.generate({model:l,messages:p,max_tokens:500,temperature:0,response_format:"text",signal:e.signal}),e.signal);if(!d.content)throw new Gt("Summarization provider returned no summary",this.getConversationId(),a.length,"invalid_response");let m=await this.countRequestTokens({...e,messages:a},t,l),u=Ca(d.content,a,m),T=xa(u);if(!T.valid)throw new Gt(`Summarization result is invalid: ${T.issues.join("; ")}`,this.getConversationId(),a.length,"invalid_quality",d.content);let y=Jr(u.summary,a.length),w=[...n,y,...i];return this.contextWindowStateManager&&this.contextWindowStateManager.recordSummarization(this.getConversationId(),u.tokensSaved),{...e,messages:w}}async enforceContextWindow(e,t){if(!this.contextWindowConfig||this.contextWindowConfig.enabled===!1)return e;let o=await this.pruneToMaxMessageHistory(e),n=await this.getModelInfo(t,o.model),s=n?.contextWindow??1e5,i=o.max_tokens??n?.maxOutputTokens??1024,a=this.contextWindowConfig.outputTokenBuffer??1.15,l=Ta(i,a),p=Math.max(0,s-l),d=Math.floor(s*((this.contextWindowConfig.pruneThreshold??85)/100)),m=Math.min(p,d),u=await this.countRequestTokens(o,t,o.model);if(this.contextWindowStateManager&&(this.contextWindowStateManager.updateTokenCount(this.getConversationId(),u),u>m&&this.contextWindowStateManager.recordWarning(this.getConversationId())),u<=m)return o;let T=this.contextWindowConfig.strategy??"prune";if(T==="fail"&&u>p)throw new Ut("Context window exceeded by request messages",this.getConversationId(),u,p,T);if(T==="summarize")try{let w=await this.summarizeConversation(o,t);if(await this.countRequestTokens(w,t,w.model)<=p)return w;o=await this.pruneConversation(w,t,p)}catch(w){if(w instanceof A)throw w;o=await this.pruneConversation(o,t,p)}else o=await this.pruneConversation(o,t,p);let y=await this.countRequestTokens(o,t,o.model);if(y>p&&T==="fail")throw new Ut("Context window exceeded after attempted cleanup",this.getConversationId(),y,p,T);return o}isBypassed(e){let t=this.hitlConfig;if(!t||t.enabled===!1)return!0;let o=t.confirmationMode??"all";if(o==="off"||o==="high-only"&&e.confirmation?.level==="medium")return!0;let n=t.bypass??{};return!!(n.tools?.includes(e.name)||n.categories?.includes(e.category)||e.confirmation&&n.levels?.includes(e.confirmation.level))}registerProvider(e,t){this.providers.set(e,t)}getProvider(e){let t=e||this.defaultProvider;if(!t)throw new N("No provider specified and no default provider configured","NO_PROVIDER_CONFIGURED",400);let o=this.providers.get(t);if(!o)throw new N(`Provider '${t}' not found`,"PROVIDER_NOT_FOUND",404);return o}updateHitlConfig(e){this.hitlConfig=e}getHitlConfig(){return this.hitlConfig}setDefaultProvider(e){if(!this.providers.has(e))throw new N(`Provider '${e}' not found`,"PROVIDER_NOT_FOUND",404);this.defaultProvider=e}getToolRegistry(){return this.toolRegistry}getProviders(){return new Map(this.providers)}setToolRegistry(e){this.toolRegistry=e}setToolsConfig(e){this.toolsConfig=e}setSystemPrompt(e){this.overrideSystemPrompt=e}setMode(e){this.activeMode=e,k(`[AIClient] Mode set to: ${e?e.displayName:"none (cleared)"}`)}getMode(){return this.activeMode}getQueryClassifier(){return this.queryClassifier}reindexTools(){this.toolRegistry&&(this.bm25Engine.index(this.toolRegistry.getAll()),k(`[AIClient] Re-indexed ${this.bm25Engine.getIndexedCount()} tools for BM25 search`))}clearToolDiscoveryCache(){this.toolRouter.clearDiscoveryCache()}async generate(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=this.resolveRequestMode(e),a=i?.toolsConfig?{...this.toolsConfig,...i.toolsConfig}:this.toolsConfig,l=this.injectBaseAgentContext(e,i);l=this.injectOverrideSystemPrompt(l),l=this.injectModeSystemPrompt(l,i),l=await this.injectModeRules(l,i);let p=t||this.defaultProvider,d=await this.enrichRequestWithTools(l,i),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let T=a.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",y=(m.tools?.length||0)>0,w=m.tool_choice!=null,C=Oa(m.messages),S=Ia(m.messages);!w&&y&&(T==="required"||T==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",P=i?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,...P?{response_format:P}:{}};k(`[AIClient][${s}] generate() start provider=${p} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${T} needsTools=${C} autoExecute=${a.enabled&&a.autoExecute}`),Zr(s,m.tools),Rn(s,m.messages);let j=oe=>Be(ha(()=>n.generate(oe),{signal:e.signal,onRetry:(H,Z)=>k(`[AIClient][${s}] Rate limited \u2014 retrying in ${Z/1e3}s (attempt ${H}/3)`)}),e.signal),R=await j(E);if(b(`[AIClient][${s}] generate() initial response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`),a.autoExecute&&(this.toolRegistry||u.size>0||(i?.customTools?.length??0)>0)){let oe=it(m.messages),H=this.queryClassifier.classify(oe),Z=a.maxToolRounds,xe=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(H,Z);m.maxToolRounds!==void 0?b(`[AIClient][${s}] maxToolRounds overridden per-request: ${xe} (classifier bypassed)`):xe!==Z?k(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), adjusted maxToolRounds: ${Z} \u2192 ${xe}`):b(`[AIClient][${s}] Query classified as ${H.type} (confidence: ${H.confidence.toFixed(2)}), keeping maxToolRounds: ${xe}`);let ce=0,Q=[...m.messages];for(R.tool_calls&&R.tool_calls.length>0&&k(`[AIClient] Received ${R.tool_calls.length} tool call(s): ${R.tool_calls.map(G=>G.name).join(", ")}`);R.tool_calls&&R.tool_calls.length>0&&ce<xe;){if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal`),new A;ce++,k(`[AIClient][${s}] generate() tool round ${ce}/${xe} tool_calls=${R.tool_calls.length}`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(B=>({id:B.id,type:"function",function:{name:B.name,arguments:JSON.stringify(B.arguments)}}))});let G=this.toolOrchestrator.shouldUseParallelExecution(R.tool_calls),K=3,De=R.tool_calls,We=R.tool_calls.filter(B=>B.name==="web.fetch");if(We.length>K){k(`[AIClient][${s}] Limiting web.fetch calls from ${We.length} \u2192 ${K} to prevent context overflow`);let B=We.slice(0,K);De=[...R.tool_calls.filter(ye=>ye.name!=="web.fetch"),...B];let J=We.slice(K);for(let ye of J)Q.push({role:"tool",tool_call_id:ye.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let pe=5e4,he=0;if(G){k(`[AIClient][${s}] Using parallel execution for ${De.length} tools`);let B;try{B=await Be(this.toolOrchestrator.executeWithDependencies(De,D=>this.executeTool(D,u,i,ce,e.signal,e.interceptTool),5),e.signal)}catch(D){if(D instanceof A)throw D;fe(`[AIClient][${s}] Parallel tool execution failed: ${D.message}`),B=new Map(De.map(J=>[J.id,JSON.stringify({error:D.message??"Tool execution failed"})]))}for(let D of De){let J=B.get(D.id)??JSON.stringify({error:"Tool execution result missing"}),ye=typeof J=="string"?J:JSON.stringify(J),xt=pe-he,ne=ye.startsWith("data:image/"),re;ne?re=ye:he+ye.length>pe?(O(`[AIClient][${s}] Tool output budget exceeded (${pe} chars)`),re=this.budgetTruncate(ye,xt)):typeof J=="string"&&J.length>this.toolResultMaxChars?re=`${J.slice(0,this.toolResultMaxChars)}
414
+ [TRUNCATED tool result: ${J.length} chars]`:re=ye;let $=typeof re=="string"?re:JSON.stringify(re);ne||(he+=$.length),Q.push({role:"tool",tool_call_id:D.id,content:re})}b(`[AIClient][${s}] Round tool output size: ${he} chars (budget: ${pe})`)}else{k(`[AIClient][${s}] Using sequential execution for ${De.length} tools`);for(let B of De){let D;try{D=await this.executeTool(B,u,i,ce,e.signal,e.interceptTool)}catch($){if($ instanceof A)throw $;D=JSON.stringify({error:$.message??"Tool execution failed"})}let J=typeof D=="string"?D:JSON.stringify(D),ye=pe-he,xt=J.startsWith("data:image/"),ne;xt?ne=J:he+J.length>pe?(O(`[AIClient][${s}] Tool output budget exceeded (${pe} chars)`),ne=this.budgetTruncate(J,ye)):typeof D=="string"&&D.length>this.toolResultMaxChars?ne=`${D.slice(0,this.toolResultMaxChars)}
415
+ [TRUNCATED tool result: ${D.length} chars]`:ne=J;let re=typeof ne=="string"?ne:JSON.stringify(ne);xt||(he+=re.length),Q.push({role:"tool",tool_call_id:B.id,content:ne})}b(`[AIClient][${s}] Round tool output size: ${he} chars (budget: ${pe})`)}if(e.signal?.aborted)throw k(`[AIClient][${s}] generate() aborted by signal during tool execution`),new A;let Le={...m,messages:Q,__toolpack_request_id:s,...P?{response_format:P}:{}},Ue=o?.getLatestRequestTools?.()??[];if(Ue.length>0){let B=new Map((m.requestTools??[]).map(D=>[D.name,D]));for(let D of Ue)B.set(D.name,D);Le.requestTools=Array.from(B.values());for(let D of Ue)u.set(D.name,D)}let Pe=this.stripRequestTools((await this.enrichRequestWithTools(Le,i)).request);Pe=await this.enforceContextWindow(Pe,n),Pe.tool_choice==="required"&&(Pe.tool_choice=S?"none":"auto",k(`[AIClient][${s}] generate() followup tool_choice override required->${Pe.tool_choice}`)),lt("debug")&&(b(`[AIClient][${s}] generate() followup request messages=${Q.length}`),Rn(s,Q)),R=await j(Pe),b(`[AIClient][${s}] generate() followup response finish_reason=${R.finish_reason??"unknown"} tool_calls=${R.tool_calls?.length||0} content=${R.content||""}`)}if(ce>=xe&&!e.signal?.aborted&&R.tool_calls&&R.tool_calls.length>0){k(`[AIClient][${s}] Tool-round cap (${xe}) hit with pending tool calls; requesting graceful conclusion`),Q.push({role:"assistant",content:R.content||"",tool_calls:R.tool_calls.map(K=>({id:K.id,type:"function",function:{name:K.name,arguments:JSON.stringify(K.arguments)}}))});for(let K of R.tool_calls)Q.push({role:"tool",tool_call_id:K.id,content:"[Tool call skipped: maximum tool rounds reached]"});Q.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let G={...m,messages:Q,__toolpack_request_id:s,tools:[],requestTools:[],interceptTool:void 0,tool_choice:void 0};try{R=await j(await this.enforceContextWindow(G,n)),k(`[AIClient][${s}] Graceful conclusion received content_length=${R.content?.length??0}`)}catch(K){if(K instanceof A)throw K;O(`[AIClient][${s}] Graceful conclusion call failed: ${K?.message??K}; returning last response`)}}}return R.data===void 0&&R.content&&e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format&&(R.data=e.response_format.parse(JSON.parse(R.content))),R}catch(s){throw this.wrapError(s)}}async*stream(e,t,o){let n=this.getProvider(t);try{let s=this.newRequestId(),i=t||this.defaultProvider,a=this.resolveRequestMode(e),l=a?.toolsConfig?{...this.toolsConfig,...a.toolsConfig}:this.toolsConfig,p=this.injectBaseAgentContext(e,a);p=this.injectOverrideSystemPrompt(p),p=this.injectModeSystemPrompt(p,a),p=await this.injectModeRules(p,a);let d=await this.enrichRequestWithTools(p,a),m=d.request,u=d.requestToolMap;m=await this.enforceContextWindow(m,n);let T=l.toolChoicePolicy||process.env.TOOLPACK_SDK_TOOL_CHOICE_POLICY||"auto",y=(m.tools?.length||0)>0,w=m.tool_choice!=null,C=Oa(m.messages),S=Ia(m.messages);!w&&y&&(T==="required"||T==="required_for_actions"&&C)&&(m.tool_choice="required");let v=n?.constructor?.name||"UnknownProvider",P=a?.response_format,E={...this.stripRequestTools(m),__toolpack_request_id:s,...P?{response_format:P}:{}};if(k(`[AIClient][${s}] stream() start provider=${i} class=${v} model=${m.model} messages=${m.messages.length} tools=${m.tools?.length||0} tool_choice=${m.tool_choice??"unset"} policy=${T} needsTools=${C} autoExecute=${l.enabled&&l.autoExecute}`),Zr(s,m.tools),Rn(s,m.messages),!l.autoExecute||!this.toolRegistry&&u.size===0&&(a?.customTools?.length??0)===0){if(yield*Pn(n.stream(E),e.signal),e.signal?.aborted)throw new A;return}let j=[...m.messages],R=0,oe=!1,H=it(m.messages),Z=this.queryClassifier.classify(H),xe=l.maxToolRounds,ce=m.maxToolRounds!==void 0?m.maxToolRounds:this.queryClassifier.getToolRoundsAdjustment(Z,xe);for(m.maxToolRounds!==void 0?b(`[AIClient][${s}] stream() maxToolRounds overridden per-request: ${ce} (classifier bypassed)`):ce!==xe&&k(`[AIClient][${s}] stream() Query classified as ${Z.type} (confidence: ${Z.confidence.toFixed(2)}), adjusted maxToolRounds: ${xe} \u2192 ${ce}`);R<=ce;){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal`),new A;let Q="",G=[];R++,k(`[AIClient][${s}] stream() round_start ${R}/${ce}`);let K=null,De={...m,messages:j,...P?{response_format:P}:{}},We=o?.getLatestRequestTools?.()??[];if(We.length>0){let $=new Map((m.requestTools??[]).map(q=>[q.name,q]));for(let q of We)$.set(q.name,q);De.requestTools=Array.from($.values());for(let q of We)u.set(q.name,q)}let pe=this.stripRequestTools((await this.enrichRequestWithTools(De,a)).request);pe=await this.enforceContextWindow(pe,n),R>1&&pe.tool_choice==="required"&&(pe.tool_choice=S?"none":"auto",k(`[AIClient][${s}] stream() round_${R} tool_choice override required->${pe.tool_choice}`));for await(let $ of Pn(n.stream(pe),e.signal)){if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during chunk processing`),new A;$.tool_calls&&$.tool_calls.length>0&&(G.push(...$.tool_calls),b(`[AIClient][${s}] stream() tool_calls_chunk count=${$.tool_calls.length} names=${$.tool_calls.map(q=>q.name).join(", ")}`),yield $),$.delta&&(Q+=$.delta,yield $),$.finish_reason&&(K=$.finish_reason),$.finish_reason==="stop"&&(yield $)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal while waiting for the provider`),new A;if(b(`[AIClient][${s}] stream() round_end finish_reason=${K??"unknown"} accumulated_len=${Q.length} tool_calls_total=${G.length} content=${Q}`),G.length===0)break;k(`[AIClient][${s}] stream() received ${G.length} tool call(s): ${G.map($=>$.name).join(", ")}`),k(`[AIClient][${s}] stream() tool round ${R}/${ce}`),j.push({role:"assistant",content:Q||"",tool_calls:G.map($=>({id:$.id,type:"function",function:{name:$.name,arguments:JSON.stringify($.arguments)}}))});let he=3,Le=G,Ue=G.filter($=>$.name==="web.fetch");if(Ue.length>he){k(`[AIClient][${s}] Limiting web.fetch calls from ${Ue.length} \u2192 ${he} to prevent context overflow`);let $=Ue.slice(0,he);Le=[...G.filter(Wt=>Wt.name!=="web.fetch"),...$];let _e=Ue.slice(he);for(let Wt of _e)j.push({role:"tool",tool_call_id:Wt.id,content:"[Skipped: web.fetch fan-out limit exceeded]"})}let Pe=5e4,B=0,D=[],J=!1,ye=setInterval(()=>{J||D.push({delta:""})},500),xt=Date.now(),ne,re;try{if(Le.length>=2)k(`[AIClient][${s}] stream() using parallel execution for ${Le.length} tools`),re=new Map,ne=await Be(this.toolOrchestrator.executeWithDependencies(Le,async $=>{let q=Date.now(),_e=await this.executeTool($,u,a,R,e.signal,e.interceptTool);return re.set($.id,Date.now()-q),_e},5),e.signal);else{k(`[AIClient][${s}] stream() executing single tool sequentially`),re=new Map,ne=new Map;for(let $ of Le){let q=Date.now(),_e=await this.executeTool($,u,a,R,e.signal,e.interceptTool);re.set($.id,Date.now()-q),ne.set($.id,_e)}}}finally{J=!0,clearInterval(ye)}if(e.signal?.aborted)throw k(`[AIClient][${s}] stream() aborted by signal during tool execution`),new A;for(;D.length>0;)yield D.shift();await new Promise($=>setTimeout($,0)),b(`[AIClient][${s}] stream() tool batch completed in ${Date.now()-xt}ms`);for(let $ of Le){let q=ne.get($.id),_e=typeof q=="string"?q:JSON.stringify(q),Wt=Pe-B,LT=re.get($.id)??0,pa=_e.startsWith("data:image/"),Ge;pa?Ge=_e:B+_e.length>Pe?(O(`[AIClient][${s}] Tool output budget exceeded (${Pe} chars)`),Ge=this.budgetTruncate(_e,Wt)):typeof q=="string"&&q.length>this.toolResultMaxChars?Ge=`${q.slice(0,this.toolResultMaxChars)}
416
+ [TRUNCATED tool result: ${q.length} chars]`:Ge=_e;let ma=typeof Ge=="string"?Ge:JSON.stringify(Ge);pa||(B+=ma.length),j.push({role:"tool",tool_call_id:$.id,content:Ge}),yield{delta:"",tool_calls:[{...$,result:ma,duration:LT}]}}b(`[AIClient][${s}] Round tool output size: ${B} chars (budget: ${Pe})`),lt("debug")&&(b(`[AIClient][${s}] stream() after_tools messages=${j.length}`),Rn(s,j)),R>ce&&(oe=!0)}if(oe&&!e.signal?.aborted){k(`[AIClient][${s}] Tool-round cap (${ce}) hit; requesting graceful conclusion`),j.push({role:"user",content:"You have reached the maximum number of tool calls allowed. Do not call any more tools. Based on what you have gathered so far, either complete the task or clearly explain what you were unable to accomplish and why."});let Q={...m,messages:j,tools:[],requestTools:[],interceptTool:void 0,tool_choice:void 0};try{let G=await this.enforceContextWindow(Q,n);for await(let K of Pn(n.stream(G),e.signal))yield K;if(e.signal?.aborted)throw new A;k(`[AIClient][${s}] Graceful conclusion stream complete`)}catch(G){if(G instanceof A)throw G;O(`[AIClient][${s}] Graceful conclusion stream failed: ${G?.message??G}`)}}}catch(s){if(s instanceof A){yield{delta:"",finish_reason:"aborted"};return}throw this.wrapError(s)}}async embed(e,t){let o=this.getProvider(t);try{return await o.embed(e)}catch(n){throw this.wrapError(n)}}async enrichRequestWithTools(e,t){if(t?.blockAllTools)return k(`[AIClient] Mode "${t.displayName}" blocks all tools`),{request:e,requestToolMap:new Map};let o=this.buildRequestToolMap(e.requestTools),n=Array.from(o.values()).map(y=>this.requestToolToSchema(y)),s=o.size>0,i=t?.toolsConfig?{...this.toolsConfig,...t.toolsConfig}:this.toolsConfig,a=this.toolDefinitionsToSchemas(t?.customTools??[]),l=this.mergeSchemas(a,n);if(!i.enabled&&!s&&a.length===0)return b("[AIClient] Tools disabled and no request-scoped or mode tools"),{request:e,requestToolMap:o};let p=i;if(t?.toolSearch&&i.toolSearch&&(p={...i,toolSearch:{...i.toolSearch,...t.toolSearch.enabled!==void 0?{enabled:t.toolSearch.enabled}:{},...t.toolSearch.alwaysLoadedTools?{alwaysLoadedTools:t.toolSearch.alwaysLoadedTools}:{},...t.toolSearch.alwaysLoadedCategories?{alwaysLoadedCategories:t.toolSearch.alwaysLoadedCategories}:{}}},b(`[AIClient] Merged mode toolSearch config: enabled=${p.toolSearch?.enabled}, alwaysLoadedTools=${p.toolSearch?.alwaysLoadedTools?.length||0}`)),e.tools&&e.tools.length>0){if(!p.toolSearch?.enabled||!this.toolRegistry){b(`[AIClient] Request already has ${e.tools.length} tools`);let x=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=x===e.tools?e:{...e,tools:x};return{request:this.injectRequestToolGuidance(v,x),requestToolMap:o}}let y=await this.toolRouter.resolve(e.messages,this.toolRegistry,p);if(b(`[AIClient] Resolved ${y.length} tools to send: ${y.map(x=>x.name).join(", ")||"none"}`),t&&y.length>0){let x=y.length;y=this.filterSchemasByMode(y,t);let v=x-y.length;v>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${v} tools`)}let w=new Set(e.tools.map(x=>x.function.name)),C=y.filter(x=>!w.has(x.name)).map(x=>({type:"function",function:{name:x.name,description:x.description,parameters:x.parameters}}));if(C.length===0){b(`[AIClient] Request already has ${e.tools.length} tools (no new discoveries)`);let x=this.mergeToolCallRequests(e.tools,this.schemasToToolCallRequests(l)),v=x===e.tools?e:{...e,tools:x};return{request:this.injectRequestToolGuidance(v,x),requestToolMap:o}}let S={...e,tools:this.mergeToolCallRequests([...e.tools,...C],this.schemasToToolCallRequests(l))};return p.toolSearch?.enabled&&this.toolRegistry&&(S=this.injectToolSearchPrompt(S)),{request:this.injectRequestToolGuidance(S,S.tools),requestToolMap:o}}if(!this.toolRegistry){b("[AIClient] Tool registry not configured, skipping tool resolution");let y=this.schemasToToolCallRequests(l),w=y.length>0?{...e,tools:y}:e;return{request:this.injectRequestToolGuidance(w,y),requestToolMap:o}}let d=this.toolRegistry,m=await this.toolRouter.resolve(e.messages,d,p);if(b(`[AIClient] Resolved ${m.length} tools to send: ${m.map(y=>y.name).join(", ")||"none"}`),t&&m.length>0){let y=m.length;m=this.filterSchemasByMode(m,t);let w=y-m.length;w>0&&k(`[AIClient] Mode "${t.displayName}" filtered out ${w} tools`)}let u=this.schemasToToolCallRequests(this.mergeSchemas(m,l));if(u.length===0)return{request:e,requestToolMap:o};let T={...e,tools:u};return i.toolSearch?.enabled&&d&&(T=this.injectToolSearchPrompt(T)),{request:this.injectRequestToolGuidance(T,u),requestToolMap:o}}toolDefinitionsToSchemas(e){return e.map(t=>({name:t.name,displayName:t.displayName,description:t.description,parameters:t.parameters,category:t.category,...t.cacheable!==void 0&&{cacheable:t.cacheable},...t.annotations!==void 0&&{annotations:t.annotations}}))}buildRequestToolMap(e){let t=new Map;for(let o of e||[])t.set(o.name,o);return t}requestToolToSchema(e){return{name:e.name,displayName:e.displayName,description:e.description,parameters:e.parameters,category:e.category,cacheable:e.cacheable}}mergeSchemas(e,t){let o=new Map;for(let n of e)o.set(n.name,n);for(let n of t)o.set(n.name,n);return Array.from(o.values())}schemasToToolCallRequests(e){return e.map(t=>({type:"function",function:{name:t.name,description:t.description,parameters:t.parameters}}))}mergeToolCallRequests(e,t){if(t.length===0)return e;let o=new Map;for(let n of e)o.set(n.function.name,n);for(let n of t)o.set(n.function.name,n);return Array.from(o.values())}injectRequestToolGuidance(e,t){if(this.disableToolGuidance)return e;let o=new Set((t||e.tools||[]).map(p=>p.function.name));if(o.size===0)return e;let n="<!-- TOOLPACK_REQUEST_TOOL_GUIDANCE -->",s=[],i=o.has("mind_believe");if(o.has("knowledge_search")||o.has("knowledge_add")){let p=["Knowledge Base:"];if(o.has("knowledge_search")&&p.push("- Use `knowledge_search` proactively whenever the user asks about anything that could have been stored, including personal facts about the user, their preferences, names, past decisions, domain-specific information or anything that could have been stored in the memory. Search before concluding you do not know something."),o.has("knowledge_add")){let d=i?"- Use `knowledge_add` for factual domain knowledge: documents, research, technical references, or organizational information shared across agents. Do NOT use it for personal user facts or preferences \u2014 use `mind_believe` for those.":"- Use `knowledge_add` when you encounter a durable fact, user preference, or decision that future conversations should know. Do not add confidential information, routine task outputs, or context that is specific to this conversation only.";p.push(d)}s.push(p.join(`
417
417
  `))}if(i||o.has("mind_reflect")||o.has("mind_recall")){let p=["Agent Memory (Mind):"];i&&p.push("- Use `mind_believe` to record what you have personally learned about this user: their preferences, habits, stated personal facts (names, family, job, decisions), or anything you should remember about them across future conversations. Call it at the end of your response when you learn something personal. Always prefer `mind_believe` over `knowledge_add` for personal user facts."),o.has("mind_reflect")&&p.push("- Use `mind_reflect` to record a lesson learned, standing rule, or observation from this interaction that should influence future behaviour."),o.has("mind_recall")&&p.push("- Use `mind_recall` to search your personal memory before answering questions about the user or recalling past decisions."),s.push(p.join(`
418
418
  `))}if(o.has("conversation_search")&&s.push("Conversation History:\n- Only recent messages may be present in context.\n- Use `conversation_search` to find relevant details from earlier in this conversation when needed."),s.length===0)return e;let a=`${n}
419
419
  ${s.join(`
420
420
 
421
421
  `)}`,l=e.messages.findIndex(p=>p.role==="system");if(l>=0){let p=e.messages.map((d,m)=>{if(m!==l)return d;let u=typeof d.content=="string"?d.content:"";return u.includes(n)?d:{...d,content:`${u}
422
422
 
423
- ${a}`.trim()}});return{...e,messages:p}}return{...e,messages:[{role:"system",content:a},...e.messages]}}stripRequestTools(e){let{requestTools:t,mode:o,...n}=e;return n}newRequestId(){return`${Date.now()}-${++this.requestSeq}`}resolveRequestMode(e){return e.mode===void 0?this.activeMode:e.mode===null?null:typeof e.mode=="string"?(O(`[AIClient] Unresolved mode name "${e.mode}" on request \u2014 falling back to active mode. Pass requests through Toolpack.generate()/stream() to resolve mode names.`),this.activeMode):e.mode}filterSchemasByMode(e,t){return e.filter(o=>{if(t.blockedTools.includes(o.name)||t.blockedToolCategories.includes(o.category))return!1;if(kt(o.name)){let i=t.toolSearch?.enabled;if(i!==void 0?i:this.toolsConfig.toolSearch?.enabled??!1)return!0}let n=t.allowedTools.length>0,s=t.allowedToolCategories.length>0;if(n||s){let i=n&&t.allowedTools.includes(o.name),a=s&&t.allowedToolCategories.includes(o.category);return i||a}return!0})}injectModeSystemPrompt(e,t){if(!t||!t.systemPrompt)return b(`[AIClient] injectModeSystemPrompt: No active mode or empty systemPrompt. mode=${t?.name}, systemPrompt=${t?.systemPrompt?.substring(0,50)}`),e;let o=t.systemPrompt;if(b(`[AIClient] injectModeSystemPrompt: Injecting mode prompt for ${t.name}, length=${o.length}`),e.messages.some(s=>s.role==="system")){let s=e.messages.map(i=>{if(i.role==="system"){let a=typeof i.content=="string"?i.content:"";return{...i,content:`${o}
423
+ ${a}`.trim()}});return{...e,messages:p}}return{...e,messages:[{role:"system",content:a},...e.messages]}}stripRequestTools(e){let{requestTools:t,mode:o,interceptTool:n,...s}=e;return s}newRequestId(){return`${Date.now()}-${++this.requestSeq}`}resolveRequestMode(e){return e.mode===void 0?this.activeMode:e.mode===null?null:typeof e.mode=="string"?(O(`[AIClient] Unresolved mode name "${e.mode}" on request \u2014 falling back to active mode. Pass requests through Toolpack.generate()/stream() to resolve mode names.`),this.activeMode):e.mode}filterSchemasByMode(e,t){return e.filter(o=>{if(t.blockedTools.includes(o.name)||t.blockedToolCategories.includes(o.category))return!1;if(kt(o.name)){let i=t.toolSearch?.enabled;if(i!==void 0?i:this.toolsConfig.toolSearch?.enabled??!1)return!0}let n=t.allowedTools.length>0,s=t.allowedToolCategories.length>0;if(n||s){let i=n&&t.allowedTools.includes(o.name),a=s&&t.allowedToolCategories.includes(o.category);return i||a}return!0})}injectModeSystemPrompt(e,t){if(!t||!t.systemPrompt)return b(`[AIClient] injectModeSystemPrompt: No active mode or empty systemPrompt. mode=${t?.name}, systemPrompt=${t?.systemPrompt?.substring(0,50)}`),e;let o=t.systemPrompt;if(b(`[AIClient] injectModeSystemPrompt: Injecting mode prompt for ${t.name}, length=${o.length}`),e.messages.some(s=>s.role==="system")){let s=e.messages.map(i=>{if(i.role==="system"){let a=typeof i.content=="string"?i.content:"";return{...i,content:`${o}
424
424
 
425
425
  ${a}`}}return i});return{...e,messages:s}}else return{...e,messages:[{role:"system",content:o},...e.messages]}}async injectModeRules(e,t){if(!t)return e;let o=await this.ruleLoader.loadForMode(t.name,t.rulesDir);if(!o)return e;if(b(`[AIClient] injectModeRules: Injecting rules for mode "${t.name}", length=${o.length}`),e.messages.some(s=>s.role==="system")){let s=e.messages.map(i=>{if(i.role==="system"){let a=typeof i.content=="string"?i.content:"";return{...i,content:`${a}
426
426
 
@@ -449,7 +449,7 @@ When you need a tool:
449
449
  NEVER guess or hallucinate tool names. ALWAYS use tool.search to discover tools you don't have.
450
450
  `.trim();if(t){let i=e.messages.map(a=>{if(a.role==="system"){let l=typeof a.content=="string"?a.content:"";return{...a,content:`${l}
451
451
 
452
- ${s}`}}return a});return{...e,messages:i}}else return{...e,messages:[{role:"system",content:s},...e.messages]}}async executeTool(e,t,o,n=0,s){if(s?.aborted)throw new A;let i=Date.now();this.emit("tool:started",{toolName:e.name,toolCallId:e.id,status:"started",args:e.arguments}),k(`[AIClient] Executing tool: ${e.name} with args: ${M(e.arguments,500)}`);let a=t.get(e.name),l=a?void 0:o?.customTools?.find(m=>m.name===e.name),p=a||l?void 0:this.toolRegistry?.get(e.name);if(!a&&!l&&!this.toolRegistry){let m="No tool registry configured";return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:m,duration:Date.now()-i}),JSON.stringify({error:m})}if(kt(e.name)){let m=this.executeToolSearch(e.arguments,o),u=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof m=="string"?m.substring(0,200):JSON.stringify(m).substring(0,200),duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:m,duration:u,status:"success",timestamp:Date.now()}),m}let d=a||l||p;if(!d){O(`[AIClient] Tool '${e.name}' not found in registry or mode`);let m=this.findSimilarToolName(e.name),u=m?`Tool '${e.name}' not found. Did you mean '${m}'? Use tool.search to discover available tools.`:`Tool '${e.name}' not found. Use tool.search to discover available tools.`;return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:u,duration:Date.now()-i}),JSON.stringify({error:u})}try{let m=e.arguments,u=l??p;if(u?.confirmation&&this.onToolConfirm&&!this.isBypassed(u)){this.emit("tool:confirmation_requested",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason});let x=await Be(this.onToolConfirm(u,m,{roundNumber:n,conversationId:this.conversationId}),s);if(this.emit("tool:confirmation_resolved",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason,decision:x}),x.action==="deny"){let v=`[Execution denied by user${x.reason?": "+x.reason:""}]`,P=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:v,duration:P}),this.emit("tool:log",{id:e.id,name:e.name,arguments:m,result:v,duration:P,status:"success",timestamp:Date.now()}),v}x.action==="modify"&&(m=x.args)}let T=o?.toolsConfig?.additionalConfigurations?{...this.toolsConfig?.additionalConfigurations,...o.toolsConfig.additionalConfigurations}:this.toolsConfig?.additionalConfigurations??{},y={workspaceRoot:process.cwd(),actor:(typeof this.actor=="function"?this.actor():this.actor)??void 0,config:T,log:x=>k(`[Tool] ${x}`),processRegistry:this.toolRegistry?.runtimeContext?.processRegistry,githubTokenStore:this.toolRegistry?.runtimeContext?.githubTokenStore,signal:s},w=await Be(Promise.resolve(d.execute(m,y)),s),C=Date.now()-i;this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof w=="string"?w.startsWith("data:image/")?w:w.substring(0,200):JSON.stringify(w).substring(0,200),duration:C}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:w,duration:C,status:"success",timestamp:Date.now()});let S=typeof w=="string"?w.length:JSON.stringify(w).length;return k(`[AIClient] Tool ${e.name} executed successfully in ${C}ms result_len=${S}`),lt("debug")&&b(`[AIClient] Tool ${e.name} result_preview=${M(w,400)}`),typeof w=="string"?w:JSON.stringify(w)}catch(m){let u=Date.now()-i,T=m.message||"Tool execution failed";if(this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:T,duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:JSON.stringify({error:T}),duration:u,status:"error",timestamp:Date.now()}),fe(`[AIClient] Tool ${e.name} failed: ${M(T,300)}`),m instanceof A)throw m;return JSON.stringify({error:T})}}findSimilarToolName(e){if(!this.toolRegistry)return null;let t=this.toolRegistry.getAll(),o=e.replace(/_/g,".");if(t.some(l=>l.name===o))return o;let n=e.replace(/\./g,"_");if(t.some(l=>l.name===n))return n;let s=e.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase().replace(/_/g,".");if(t.some(l=>l.name===s))return s;let i=null,a=1/0;for(let l of t){let p=this.levenshteinDistance(e.toLowerCase(),l.name.toLowerCase());p<=2&&p<a&&(a=p,i=l.name)}return i}levenshteinDistance(e,t){let o=[];for(let n=0;n<=t.length;n++)o[n]=[n];for(let n=0;n<=e.length;n++)o[0][n]=n;for(let n=1;n<=t.length;n++)for(let s=1;s<=e.length;s++)t.charAt(n-1)===e.charAt(s-1)?o[n][s]=o[n-1][s-1]:o[n][s]=Math.min(o[n-1][s-1]+1,o[n][s-1]+1,o[n-1][s]+1);return o[t.length][e.length]}executeToolSearch(e,t){let{query:o,category:n}=e,s=this.toolsConfig.toolSearch?.searchResultLimit??5,i=typeof n=="string"&&n.length>0?n:void 0,a=t===void 0?this.activeMode:t;if(a&&!(this.filterSchemasByMode([st()],a).length>0))return O("[AIClient] tool.search blocked by active mode"),JSON.stringify({query:o,found:0,tools:[],hint:"tool.search is not allowed in the current mode."});k(`[AIClient] Executing tool.search: query="${o}" category=${i||"all"} limit=${s}`);let l=a?Math.max(s*4,s):s,p=this.bm25Engine.search(o,{limit:l,category:i});if(i&&p.length===0&&(k(`[AIClient] tool.search category="${i}" returned 0 results; retrying without category filter`),p=this.bm25Engine.search(o,{limit:l})),a&&p.length>0){let m=this.filterSchemasByMode(p.map(w=>w.tool),a),u=new Set(m.map(w=>w.name)),T=p.length;p=p.filter(w=>u.has(w.toolName));let y=T-p.length;y>0&&b(`[AIClient] tool.search filtered out ${y} disallowed results for mode "${a.displayName}"`)}p.length>s&&(p=p.slice(0,s));let d=p.map(m=>m.toolName);return this.toolRouter.getDiscoveryCache().recordDiscovery(o,d),b(`[AIClient] tool.search found ${p.length} tools: ${d.join(", ")||"none"}`),JSON.stringify({query:o,found:p.length,tools:p.map(m=>({name:m.tool.name,displayName:m.tool.displayName,description:m.tool.description,category:m.tool.category,parameters:m.tool.parameters,relevanceScore:Math.round(m.score*100)/100})),hint:p.length>0?`Found ${p.length} tools. You can now call any of these tools directly.`:`No tools found for "${o}". Try a different search term.`})}wrapError(e){return e instanceof A||e instanceof N?e:new F(e.message||"Unknown provider error","UNKNOWN_PROVIDER_ERROR",500,e)}budgetTruncate(e,t){let o=`
452
+ ${s}`}}return a});return{...e,messages:i}}else return{...e,messages:[{role:"system",content:s},...e.messages]}}async executeTool(e,t,o,n=0,s,i){if(!i)return this.runTool(e,t,o,n,s);if(s?.aborted)throw new A;return i({toolName:e.name,args:e.arguments,round:n},()=>this.runTool(e,t,o,n,s))}async runTool(e,t,o,n=0,s){if(s?.aborted)throw new A;let i=Date.now();this.emit("tool:started",{toolName:e.name,toolCallId:e.id,status:"started",args:e.arguments}),k(`[AIClient] Executing tool: ${e.name} with args: ${M(e.arguments,500)}`);let a=t.get(e.name),l=a?void 0:o?.customTools?.find(m=>m.name===e.name),p=a||l?void 0:this.toolRegistry?.get(e.name);if(!a&&!l&&!this.toolRegistry){let m="No tool registry configured";return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:m,duration:Date.now()-i}),JSON.stringify({error:m})}if(kt(e.name)){let m=this.executeToolSearch(e.arguments,o),u=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof m=="string"?m.substring(0,200):JSON.stringify(m).substring(0,200),duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:m,duration:u,status:"success",timestamp:Date.now()}),m}let d=a||l||p;if(!d){O(`[AIClient] Tool '${e.name}' not found in registry or mode`);let m=this.findSimilarToolName(e.name),u=m?`Tool '${e.name}' not found. Did you mean '${m}'? Use tool.search to discover available tools.`:`Tool '${e.name}' not found. Use tool.search to discover available tools.`;return this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:u,duration:Date.now()-i}),JSON.stringify({error:u})}try{let m=e.arguments,u=l??p;if(u?.confirmation&&this.onToolConfirm&&!this.isBypassed(u)){this.emit("tool:confirmation_requested",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason});let x=await Be(this.onToolConfirm(u,m,{roundNumber:n,conversationId:this.conversationId}),s);if(this.emit("tool:confirmation_resolved",{tool:u,args:m,level:u.confirmation.level,reason:u.confirmation.reason,decision:x}),x.action==="deny"){let v=`[Execution denied by user${x.reason?": "+x.reason:""}]`,P=Date.now()-i;return this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:v,duration:P}),this.emit("tool:log",{id:e.id,name:e.name,arguments:m,result:v,duration:P,status:"success",timestamp:Date.now()}),v}x.action==="modify"&&(m=x.args)}let T=o?.toolsConfig?.additionalConfigurations?{...this.toolsConfig?.additionalConfigurations,...o.toolsConfig.additionalConfigurations}:this.toolsConfig?.additionalConfigurations??{},y={workspaceRoot:process.cwd(),actor:(typeof this.actor=="function"?this.actor():this.actor)??void 0,config:T,log:x=>k(`[Tool] ${x}`),processRegistry:this.toolRegistry?.runtimeContext?.processRegistry,githubTokenStore:this.toolRegistry?.runtimeContext?.githubTokenStore,signal:s},w=await Be(Promise.resolve(d.execute(m,y)),s),C=Date.now()-i;this.emit("tool:completed",{toolName:e.name,toolCallId:e.id,status:"completed",result:typeof w=="string"?w.startsWith("data:image/")?w:w.substring(0,200):JSON.stringify(w).substring(0,200),duration:C}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:w,duration:C,status:"success",timestamp:Date.now()});let S=typeof w=="string"?w.length:JSON.stringify(w).length;return k(`[AIClient] Tool ${e.name} executed successfully in ${C}ms result_len=${S}`),lt("debug")&&b(`[AIClient] Tool ${e.name} result_preview=${M(w,400)}`),typeof w=="string"?w:JSON.stringify(w)}catch(m){let u=Date.now()-i,T=m.message||"Tool execution failed";if(this.emit("tool:failed",{toolName:e.name,toolCallId:e.id,status:"failed",error:T,duration:u}),this.emit("tool:log",{id:e.id,name:e.name,arguments:e.arguments,result:JSON.stringify({error:T}),duration:u,status:"error",timestamp:Date.now()}),fe(`[AIClient] Tool ${e.name} failed: ${M(T,300)}`),m instanceof A)throw m;return JSON.stringify({error:T})}}findSimilarToolName(e){if(!this.toolRegistry)return null;let t=this.toolRegistry.getAll(),o=e.replace(/_/g,".");if(t.some(l=>l.name===o))return o;let n=e.replace(/\./g,"_");if(t.some(l=>l.name===n))return n;let s=e.replace(/([a-z])([A-Z])/g,"$1_$2").toLowerCase().replace(/_/g,".");if(t.some(l=>l.name===s))return s;let i=null,a=1/0;for(let l of t){let p=this.levenshteinDistance(e.toLowerCase(),l.name.toLowerCase());p<=2&&p<a&&(a=p,i=l.name)}return i}levenshteinDistance(e,t){let o=[];for(let n=0;n<=t.length;n++)o[n]=[n];for(let n=0;n<=e.length;n++)o[0][n]=n;for(let n=1;n<=t.length;n++)for(let s=1;s<=e.length;s++)t.charAt(n-1)===e.charAt(s-1)?o[n][s]=o[n-1][s-1]:o[n][s]=Math.min(o[n-1][s-1]+1,o[n][s-1]+1,o[n-1][s]+1);return o[t.length][e.length]}executeToolSearch(e,t){let{query:o,category:n}=e,s=this.toolsConfig.toolSearch?.searchResultLimit??5,i=typeof n=="string"&&n.length>0?n:void 0,a=t===void 0?this.activeMode:t;if(a&&!(this.filterSchemasByMode([st()],a).length>0))return O("[AIClient] tool.search blocked by active mode"),JSON.stringify({query:o,found:0,tools:[],hint:"tool.search is not allowed in the current mode."});k(`[AIClient] Executing tool.search: query="${o}" category=${i||"all"} limit=${s}`);let l=a?Math.max(s*4,s):s,p=this.bm25Engine.search(o,{limit:l,category:i});if(i&&p.length===0&&(k(`[AIClient] tool.search category="${i}" returned 0 results; retrying without category filter`),p=this.bm25Engine.search(o,{limit:l})),a&&p.length>0){let m=this.filterSchemasByMode(p.map(w=>w.tool),a),u=new Set(m.map(w=>w.name)),T=p.length;p=p.filter(w=>u.has(w.toolName));let y=T-p.length;y>0&&b(`[AIClient] tool.search filtered out ${y} disallowed results for mode "${a.displayName}"`)}p.length>s&&(p=p.slice(0,s));let d=p.map(m=>m.toolName);return this.toolRouter.getDiscoveryCache().recordDiscovery(o,d),b(`[AIClient] tool.search found ${p.length} tools: ${d.join(", ")||"none"}`),JSON.stringify({query:o,found:p.length,tools:p.map(m=>({name:m.tool.name,displayName:m.tool.displayName,description:m.tool.description,category:m.tool.category,parameters:m.tool.parameters,relevanceScore:Math.round(m.score*100)/100})),hint:p.length>0?`Found ${p.length} tools. You can now call any of these tools directly.`:`No tools found for "${o}". Try a different search term.`})}wrapError(e){return e instanceof A||e instanceof N?e:new F(e.message||"Unknown provider error","UNKNOWN_PROVIDER_ERROR",500,e)}budgetTruncate(e,t){let o=`
453
453
  [Output truncated \u2014 round budget reached. Call the tool again with a narrower query to retrieve more.]`,s=t-o.length;return s>=100?e.slice(0,s)+o:"[Tool output omitted \u2014 round budget exhausted. Call the tool again with a narrower query.]"}};c();c();import Ba from"@anthropic-ai/sdk";import{zodOutputFormat as hw}from"@anthropic-ai/sdk/helpers/zod";c();ie();var te=class{name;async getModels(){return[]}getDisplayName(){return this.name||this.constructor.name.replace(/Adapter$/,"")}supportsFileUpload(){return!1}async uploadFile(e){throw new I(`File upload API is not supported by ${this.getDisplayName()}`)}async deleteFile(e){throw new I(`File deletion API is not supported by ${this.getDisplayName()}`)}async countTokens(e,t){return null}};ie();_();Ae();var En=class extends te{client;constructor(e,t){super(),this.client=new Ba({apiKey:e,baseURL:t})}supportsFileUpload(){return!0}async uploadFile(e){try{let t=await import("fs");if(!e.filePath)throw new I("Anthropic uploadFile requires a filePath.");return{id:(await this.client.files.create({file:t.createReadStream(e.filePath),purpose:e.purpose||"vision"})).id}}catch(t){throw this.handleError(t)}}async deleteFile(e){try{await this.client.files.delete(e)}catch(t){throw this.handleError(t)}}getDisplayName(){return"Anthropic"}async getModels(){return[{id:"claude-haiku-4-5-20251001",displayName:"Claude Haiku 4.5",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:64e3},{id:"claude-sonnet-4-5-20250929",displayName:"Claude Sonnet 4.5",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-sonnet-4-6",displayName:"Claude Sonnet 4.6",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-opus-4-5",displayName:"Claude Opus 4.5",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-opus-4-6",displayName:"Claude Opus 4.6",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0,fileUpload:!0},contextWindow:2e5,maxOutputTokens:16384}]}sanitizeToolName(e){return e.replace(/\./g,"_")}restoreToolName(e,t){return t?.find(n=>this.sanitizeToolName(n.function.name)===e)?.function.name||e.replace(/_/g,".")}async generate(e){try{let t=e.__toolpack_request_id||`gen-${Date.now()}`,o=await this.toAnthropicMessages(e.messages,e.mediaOptions),n=o.system,s=o.userMessages,i={model:e.model,messages:s,system:n,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p,stream:!1};e.tools&&e.tools.length>0?(i.tools=e.tools.map(T=>({name:this.sanitizeToolName(T.function.name),description:T.function.description,input_schema:T.function.parameters})),e.tool_choice==="required"?i.tool_choice={type:"any"}:e.tool_choice==="none"?delete i.tools:i.tool_choice={type:"auto"},b(`[Anthropic][${t}] Sending ${i.tools?.length||0} tools with tool_choice: ${i.tool_choice?.type||"unset"}`),i.tools&&i.tools.length>0&&b(`[Anthropic][${t}] First tool: ${M(i.tools[0],800)}`)):b(`[Anthropic][${t}] NO TOOLS in request`),b(`[Anthropic][${t}] generate() request: model=${i.model}, messages=${i.messages.length}, tools=${i.tools?.length||0}, tool_choice=${i.tool_choice?.type??"unset"}`),ee(t,"Anthropic",i.messages);let a=e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format;a&&(i.output_config={format:hw(e.response_format)});let p=a?await this.client.messages.parse(i,e.signal?{signal:e.signal}:void 0):await this.client.messages.create(i,e.signal?{signal:e.signal}:void 0),d=[],m=[];for(let T of p.content)T.type==="text"?d.push(T.text):T.type==="tool_use"&&m.push({id:T.id,name:this.restoreToolName(T.name,e.tools),arguments:T.input});b(`[Anthropic][${t}] Response finish_reason=${p.stop_reason} tool_calls=${m.length} content_preview=${M(d.join(""),200)}`);let u={content:d.length>0?d.join(""):null,usage:{prompt_tokens:p.usage.input_tokens,completion_tokens:p.usage.output_tokens,total_tokens:p.usage.input_tokens+p.usage.output_tokens},finish_reason:this.mapFinishReason(p.stop_reason),tool_calls:m.length>0?m:void 0,raw:p};return a&&p.parsed_output!==void 0&&(u.data=p.parsed_output),u}catch(t){throw this.handleError(t)}}async*stream(e){try{let t=e.__toolpack_request_id||`str-${Date.now()}`,o=await this.toAnthropicMessages(e.messages,e.mediaOptions),n={model:e.model,messages:o.userMessages,system:o.system,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p,stream:!0};e.tools&&e.tools.length>0?(n.tools=e.tools.map(d=>({name:this.sanitizeToolName(d.function.name),description:d.function.description,input_schema:d.function.parameters})),e.tool_choice==="required"?n.tool_choice={type:"any"}:e.tool_choice==="none"?delete n.tools:n.tool_choice={type:"auto"},b(`[Anthropic][${t}] Sending ${n.tools?.length||0} tools with tool_choice: ${n.tool_choice?.type||"unset"}`),n.tools&&n.tools.length>0&&b(`[Anthropic][${t}] First tool: ${M(n.tools[0],800)}`)):b(`[Anthropic][${t}] NO TOOLS in request`),b(`[Anthropic][${t}] Stream request: model=${n.model}, messages=${n.messages.length}, tools=${n.tools?.length||0}, tool_choice=${n.tool_choice?.type??"unset"}`),ee(t,"Anthropic",n.messages);let s=await this.client.messages.create(n,e.signal?{signal:e.signal}:void 0),i="",a="",l="",p=!1;for await(let d of s)d.type==="content_block_start"&&d.content_block?.type==="tool_use"&&(p=!0,i=d.content_block.id,a=d.content_block.name,l=""),d.type==="content_block_delta"&&(d.delta.type==="text_delta"?yield{delta:d.delta.text}:d.delta.type==="input_json_delta"&&p&&(l+=d.delta.partial_json)),d.type==="content_block_stop"&&p&&(b(`[Anthropic][${t}] Stream finish_reason=tool_calls accumulated_call=${a}`),yield{delta:"",finish_reason:"tool_calls",tool_calls:[{id:i,name:this.restoreToolName(a,e.tools),arguments:JSON.parse(l||"{}")}]},p=!1),d.type==="message_stop"&&(Ke(`[Anthropic][${t}] Stream chunk finish_reason=stop`),yield{delta:"",finish_reason:"stop"})}catch(t){throw this.handleError(t)}}async embed(e){throw new I("Embeddings are not strictly supported by the Anthropic API currently.")}async toAnthropicMessages(e,t={}){let o,n=[],{normalizeImagePart:s}=await Promise.resolve().then(()=>(Ae(),_t));for(let i of e)if(i.role==="system"){if(typeof i.content=="string")o=i.content;else if(i.content!==null){let a=i.content.filter(l=>typeof l=="object"&&l.type==="text").map(l=>l.text).join(`
454
454
  `);a&&(o=a)}}else if(i.role==="tool"&&i.tool_call_id){let a=typeof i.content=="string"?i.content:JSON.stringify(i.content),l=a.match(/^data:([\w/+.-]+);base64,(.+)$/s),p=l?null:ct(a),d=l?l[1].startsWith("image/")?[{type:"image",source:{type:"base64",media_type:l[1],data:l[2]}}]:[{type:"document",source:{type:"base64",media_type:l[1],data:l[2]}}]:p?p.mimeType.startsWith("image/")?[{type:"image",source:{type:"url",url:p.url}}]:[{type:"document",source:{type:"url",url:p.url}}]:a;n.push({role:"user",content:[{type:"tool_result",tool_use_id:i.tool_call_id,content:d}]})}else if(i.role==="assistant"&&i.tool_calls&&i.tool_calls.length>0){let a=[];if(typeof i.content=="string"&&i.content)a.push({type:"text",text:i.content});else if(Array.isArray(i.content)){let l=i.content.filter(p=>typeof p=="object"&&p.type==="text").map(p=>p.text).join(`
455
455
  `);l&&a.push({type:"text",text:l})}for(let l of i.tool_calls)a.push({type:"tool_use",id:l.id,name:this.sanitizeToolName(l.function.name),input:typeof l.function.arguments=="string"?JSON.parse(l.function.arguments||"{}"):l.function.arguments});n.push({role:"assistant",content:a})}else{let a=[];typeof i.content=="string"?a=i.content:i.content!==null&&(a=(await Promise.all(i.content.map(async l=>{if(l.type==="text")return{type:"text",text:l.text};if(l.type==="image_url"){let p=l.image_url.url;if(p.startsWith("data:")){let d=p.match(/^data:(image\/\w+);base64,(.+)$/);if(d)return{type:"image",source:{type:"base64",media_type:d[1],data:d[2]}}}return{type:"image",source:{type:"url",url:p}}}if(l.type==="image_data"||l.type==="image_file"){let{data:p,mimeType:d}=await s(l);return{type:"image",source:{type:"base64",media_type:d,data:p}}}if(l.type==="file"){let{url:p,mimeType:d}=l.file,m=p.match(/^data:([\w/+.-]+);base64,(.+)$/s);if(m){let[,u,T]=m;return u.startsWith("image/")?{type:"image",source:{type:"base64",media_type:u,data:T}}:{type:"document",source:{type:"base64",media_type:u,data:T}}}return d.startsWith("image/")?{type:"image",source:{type:"url",url:p}}:{type:"document",source:{type:"url",url:p}}}return null}))).filter(Boolean)),n.push({role:i.role==="user"?"user":"assistant",content:a})}return{system:o,userMessages:n}}mapFinishReason(e){return e==="end_turn"?"stop":e==="max_tokens"?"length":e==="stop_sequence"?"stop":e}handleError(e){if(e instanceof Ba.APIError){let t=e.message;return e.status===401?new be(t,e):e.status===429?new me(t,void 0,e):e.status&&e.status>=400&&e.status<500?new I(t,e):new F(t,"ANTHROPIC_ERROR",e.status||500,e)}return new F("Unknown Anthropic error","UNKNOWN",500,e)}};c();import yw from"@anthropic-ai/vertex-sdk";ie();_();var Dn=class extends te{client;constructor(e={}){super(),this.name="anthropic-vertex";let t=e.projectId??process.env.ANTHROPIC_VERTEX_PROJECT_ID??process.env.GOOGLE_CLOUD_PROJECT,o=e.region??process.env.ANTHROPIC_VERTEX_REGION??"us-east5";this.client=new yw({projectId:t,region:o})}getDisplayName(){return"Anthropic (Vertex AI)"}async getModels(){return[{id:"claude-sonnet-4-5@20250929",displayName:"Claude Sonnet 4.5 (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-haiku-4-5@20251001",displayName:"Claude Haiku 4.5 (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:16384},{id:"claude-3-5-sonnet-v2@20241022",displayName:"Claude 3.5 Sonnet v2 (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:8192},{id:"claude-3-5-haiku@20241022",displayName:"Claude 3.5 Haiku (Vertex AI)",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2e5,maxOutputTokens:8192}]}async generate(e){try{let t=e.__toolpack_request_id||`anv-${Date.now()}`,{system:o,userMessages:n}=await this.toAnthropicMessages(e.messages),s={model:e.model,messages:n,system:o,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p};e.tools&&e.tools.length>0&&(s.tools=e.tools.map(p=>({name:this.sanitizeToolName(p.function.name),description:p.function.description,input_schema:p.function.parameters})),e.tool_choice==="required"?s.tool_choice={type:"any"}:e.tool_choice==="none"?delete s.tools:s.tool_choice={type:"auto"}),b(`[AnthropicVertex][${t}] generate() model=${s.model} messages=${s.messages.length} tools=${s.tools?.length??0}`),ee(t,"AnthropicVertex",s.messages);let i=await this.client.messages.create(s,e.signal?{signal:e.signal}:void 0),a=[],l=[];for(let p of i.content)p.type==="text"&&a.push(p.text),p.type==="tool_use"&&l.push({id:p.id,name:this.restoreToolName(p.name,e.tools),arguments:p.input});return b(`[AnthropicVertex][${t}] Response finish_reason=${i.stop_reason} tool_calls=${l.length} content_preview=${M(a.join(""),200)}`),{content:a.length>0?a.join(""):null,usage:{prompt_tokens:i.usage.input_tokens,completion_tokens:i.usage.output_tokens,total_tokens:i.usage.input_tokens+i.usage.output_tokens},finish_reason:this.mapFinishReason(i.stop_reason),tool_calls:l.length>0?l:void 0,raw:i}}catch(t){throw this.handleError(t)}}async*stream(e){try{let t=e.__toolpack_request_id||`anv-str-${Date.now()}`,{system:o,userMessages:n}=await this.toAnthropicMessages(e.messages),s={model:e.model,messages:n,system:o,max_tokens:e.max_tokens||4096,temperature:e.temperature,top_p:e.top_p,stream:!0};e.tools&&e.tools.length>0&&(s.tools=e.tools.map(m=>({name:this.sanitizeToolName(m.function.name),description:m.function.description,input_schema:m.function.parameters})),e.tool_choice==="required"?s.tool_choice={type:"any"}:e.tool_choice==="none"?delete s.tools:s.tool_choice={type:"auto"}),b(`[AnthropicVertex][${t}] stream() model=${s.model} messages=${s.messages.length} tools=${s.tools?.length??0}`);let i=await this.client.messages.create(s,e.signal?{signal:e.signal}:void 0),a="",l="",p="",d=!1;for await(let m of i)m.type==="content_block_start"&&m.content_block?.type==="tool_use"&&(d=!0,a=m.content_block.id,l=m.content_block.name,p=""),m.type==="content_block_delta"&&(m.delta.type==="text_delta"?yield{delta:m.delta.text}:m.delta.type==="input_json_delta"&&d&&(p+=m.delta.partial_json)),m.type==="content_block_stop"&&d&&(yield{delta:"",finish_reason:"tool_calls",tool_calls:[{id:a,name:this.restoreToolName(l,e.tools),arguments:JSON.parse(p||"{}")}]},d=!1),m.type==="message_stop"&&(yield{delta:"",finish_reason:"stop"})}catch(t){throw this.handleError(t)}}async embed(e){throw new I("Embeddings are not supported by the Anthropic API.")}sanitizeToolName(e){return e.replace(/\./g,"_")}restoreToolName(e,t){return t?.find(n=>this.sanitizeToolName(n.function.name)===e)?.function.name??e.replace(/_/g,".")}async toAnthropicMessages(e){let t,o=[];for(let n of e)if(n.role==="system")t=typeof n.content=="string"?n.content:"";else if(n.role==="tool"&&n.tool_call_id){let s=typeof n.content=="string"?n.content:JSON.stringify(n.content),i=s.match(/^data:([\w/+.-]+);base64,(.+)$/s),a=i?i[1].startsWith("image/")?[{type:"image",source:{type:"base64",media_type:i[1],data:i[2]}}]:[{type:"document",source:{type:"base64",media_type:i[1],data:i[2]}}]:s;o.push({role:"user",content:[{type:"tool_result",tool_use_id:n.tool_call_id,content:a}]})}else if(n.role==="assistant"&&n.tool_calls&&n.tool_calls.length>0){let s=[];typeof n.content=="string"&&n.content&&s.push({type:"text",text:n.content});for(let i of n.tool_calls)s.push({type:"tool_use",id:i.id,name:this.sanitizeToolName(i.function.name),input:typeof i.function.arguments=="string"?JSON.parse(i.function.arguments||"{}"):i.function.arguments});o.push({role:"assistant",content:s})}else{let s;typeof n.content=="string"||n.content===null?s=n.content??"":s=(await Promise.all(n.content.map(async i=>{if(i.type==="text")return{type:"text",text:i.text};if(i.type==="image_url"){let a=i.image_url.url;if(a.startsWith("data:")){let l=a.match(/^data:(image\/\w+);base64,(.+)$/);if(l)return{type:"image",source:{type:"base64",media_type:l[1],data:l[2]}}}return{type:"image",source:{type:"url",url:a}}}if(i.type==="image_data"||i.type==="image_file"){let{normalizeImagePart:a}=await Promise.resolve().then(()=>(Ae(),_t)),{data:l,mimeType:p}=await a(i);return{type:"image",source:{type:"base64",media_type:p,data:l}}}if(i.type==="file"){let{url:a,mimeType:l}=i.file,p=a.match(/^data:([\w/+.-]+);base64,(.+)$/s);if(p){let[,d,m]=p;return d.startsWith("image/")?{type:"image",source:{type:"base64",media_type:d,data:m}}:{type:"document",source:{type:"base64",media_type:d,data:m}}}return l.startsWith("image/")?{type:"image",source:{type:"url",url:a}}:{type:"document",source:{type:"url",url:a}}}return null}))).filter(Boolean),o.push({role:n.role==="user"?"user":"assistant",content:s})}return{system:t,userMessages:o}}mapFinishReason(e){return e==="end_turn"?"stop":e==="max_tokens"?"length":"stop"}handleError(e){let t=e?.message??String(e);return e?.status===401||e?.status===403?new be(t,e):e?.status===429?new me(t,void 0,e):e?.status>=400&&e?.status<500?new I(t,e):new F(t||"Anthropic Vertex error","ANTHROPIC_VERTEX_ERROR",e?.status??500,e)}};c();import{GoogleGenAI as bw}from"@google/genai";import{zodToJsonSchema as Tw}from"zod-to-json-schema";ie();_();Ae();var An=class r extends te{ai;location;thinkingBudget;rawContentCache=new Map;static RAW_CONTENT_CACHE_MAX=500;constructor(e={}){super(),this.name="vertexai";let t=e.projectId??process.env.TOOLPACK_VERTEXAI_PROJECT??process.env.VERTEX_AI_PROJECT??process.env.GOOGLE_CLOUD_PROJECT;if(!t)throw new be("Vertex AI requires a GCP project ID. Pass projectId in config or set TOOLPACK_VERTEXAI_PROJECT / VERTEX_AI_PROJECT / GOOGLE_CLOUD_PROJECT.");this.location=e.location??process.env.TOOLPACK_VERTEXAI_LOCATION??process.env.VERTEX_AI_LOCATION??"us-central1",this.ai=new bw({vertexai:!0,project:t,location:this.location,...e.googleAuthOptions?{googleAuthOptions:e.googleAuthOptions}:{}}),this.thinkingBudget=e.thinkingBudget}getDisplayName(){return"Google Vertex AI"}async getModels(){return[{id:"gemini-3.5-flash",displayName:"Gemini 3.5 Flash",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-3.1-pro-preview",displayName:"Gemini 3.1 Pro Preview",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-2.5-pro-preview-05-06",displayName:"Gemini 2.5 Pro Preview",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-2.5-flash-preview-04-17",displayName:"Gemini 2.5 Flash Preview",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:65536},{id:"gemini-2.0-flash-001",displayName:"Gemini 2.0 Flash",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:8192},{id:"gemini-1.5-pro-002",displayName:"Gemini 1.5 Pro",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:2097152,maxOutputTokens:8192},{id:"gemini-1.5-flash-002",displayName:"Gemini 1.5 Flash",capabilities:{chat:!0,streaming:!0,toolCalling:!0,embeddings:!1,vision:!0},contextWindow:1048576,maxOutputTokens:8192}]}async generate(e){try{let t=e.__toolpack_request_id||`vtx-${Date.now()}`;b(`[VertexAI][${t}] generate() model=${e.model} messages=${e.messages.length} tools=${e.tools?.length??0}`),ee(t,"VertexAI",e.messages);let{model:o,config:n}=this.buildRequestParams(e),{history:s,lastUserMessage:i}=this.formatHistory(e.messages),a=i!==null?[...s,{role:"user",parts:typeof i=="string"?[{text:i}]:i}]:s;for(let u of a){let T=u.parts;if(Array.isArray(T))for(let y=0;y<T.length;y++){let w=T[y];w?.inlineData!==void 0&&!w.inlineData?.data&&T.splice(y--,1)}}e.signal&&(n.abortSignal=e.signal);let l=await this.ai.models.generateContent({model:o,contents:a,config:n}),{content:p,toolCalls:d,rawContent:m}=this.parseResponse(l,e.tools);if(d.length>0&&m){let u=d.map(T=>T.id).join("|");this.rawContentCache.size>=r.RAW_CONTENT_CACHE_MAX&&this.rawContentCache.delete(this.rawContentCache.keys().next().value),this.rawContentCache.set(u,m)}return b(`[VertexAI][${t}] Response finish_reason=${d.length>0?"tool_calls":"stop"} tool_calls=${d.length} content_preview=${M(p,200)}`),{content:p||null,usage:{prompt_tokens:l.usageMetadata?.promptTokenCount??0,completion_tokens:l.usageMetadata?.candidatesTokenCount??0,total_tokens:l.usageMetadata?.totalTokenCount??0},finish_reason:d.length>0?"tool_calls":"stop",tool_calls:d.length>0?d:void 0,raw:l}}catch(t){throw this.handleError(t)}}async*stream(e){try{let t=e.__toolpack_request_id||`vtx-str-${Date.now()}`;b(`[VertexAI][${t}] stream() model=${e.model} messages=${e.messages.length} tools=${e.tools?.length??0}`),ee(t,"VertexAI",e.messages);let{model:o,config:n}=this.buildRequestParams(e),{history:s,lastUserMessage:i}=this.formatHistory(e.messages),a=i!==null?[...s,{role:"user",parts:typeof i=="string"?[{text:i}]:i}]:s;for(let m of a){let u=m.parts;if(Array.isArray(u))for(let T=0;T<u.length;T++){let y=u[T];y?.inlineData!==void 0&&!y.inlineData?.data&&u.splice(T--,1)}}e.signal&&(n.abortSignal=e.signal);let l=await this.ai.models.generateContentStream({model:o,contents:a,config:n}),p=[],d=[];for await(let m of l)for(let u of m.candidates??[])for(let T of u.content?.parts??[])if(d.push(T),T.functionCall){let y=T.functionCall;b(`[VertexAI][${t}] stream tool_call name=${y.name}`);let w=`vtx_${Date.now()}_${Math.random().toString(36).slice(2,8)}`;p.push(w),yield{delta:"",finish_reason:"tool_calls",tool_calls:[{id:w,name:this.restoreToolName(y.name,e.tools),arguments:y.args??{}}]}}else T.text&&(yield{delta:T.text});if(p.length>0&&d.length>0){let m=p.join("|"),u={role:"model",parts:d};this.rawContentCache.size>=r.RAW_CONTENT_CACHE_MAX&&this.rawContentCache.delete(this.rawContentCache.keys().next().value),this.rawContentCache.set(m,u)}}catch(t){throw this.handleError(t)}}async embed(e){throw new I("Vertex AI embeddings are not supported by this adapter. Use the Gemini adapter (gemini provider) with text-embedding-004 instead.")}buildRequestParams(e){let t=e.response_format&&typeof e.response_format=="object"&&"parse"in e.response_format,o={systemInstruction:this.extractSystemInstruction(e.messages),maxOutputTokens:e.max_tokens,temperature:e.temperature,topP:e.top_p,responseMimeType:(e.response_format==="json_object"||t)&&!e.tools?.length?"application/json":"text/plain",...t&&!e.tools?.length?{responseSchema:this.sanitizeSchema(Tw(e.response_format))}:{}};return e.tools&&e.tools.length>0&&(o.tools=[{functionDeclarations:e.tools.map(n=>({name:this.sanitizeToolName(n.function.name),description:n.function.description,parameters:this.sanitizeSchema(n.function.parameters)}))}]),this.thinkingBudget!==void 0&&this.thinkingBudget!==0&&(o.thinkingConfig={thinkingBudget:this.thinkingBudget}),{model:e.model,config:o}}formatHistory(e){let t=e.filter(l=>l.role!=="system");if(t.length===0)return{history:[],lastUserMessage:""};let o=t[t.length-1],n=o.role==="tool"&&!!o.tool_call_id,i=(n?t:t.slice(0,-1)).map(l=>{if(l.role==="tool"&&l.tool_call_id){let p=this.sanitizeToolName(l.name??l.tool_call_id),d=typeof l.content=="string"?l.content:JSON.stringify(l.content),m=d.match(/^data:([\w/+.-]+);base64,(.+)$/s),u=m?null:ct(d),T=[{functionResponse:{name:p,response:{name:p,content:m||u?"File data attached as sibling part.":d}}}];return m&&T.push({inlineData:{mimeType:m[1],data:m[2]}}),u&&T.push({fileData:{mimeType:u.mimeType,fileUri:u.url}}),{role:"function",parts:T}}if(l.role==="assistant"&&l.tool_calls&&l.tool_calls.length>0){let p=l.tool_calls.map(u=>u.id).join("|"),d=this.rawContentCache.get(p);if(d)return d;let m=[];typeof l.content=="string"&&l.content&&m.push({text:l.content});for(let u of l.tool_calls)m.push({functionCall:{name:this.sanitizeToolName(u.function.name),args:typeof u.function.arguments=="string"?JSON.parse(u.function.arguments||"{}"):u.function.arguments}});return{role:"model",parts:m}}return{role:l.role==="user"?"user":"model",parts:this.contentToParts(l.content)}}),a=[];for(let l of i){let p=a[a.length-1];l.role==="function"&&p?.role==="function"?p.parts.push(...l.parts):a.push(l)}return{history:a,lastUserMessage:n?null:this.contentToParts(o.content)}}contentToParts(e){return typeof e=="string"?[{text:e}]:e?e.map(t=>{if(t.type==="text")return{text:t.text};if(t.type==="image_data"){let{data:o,mimeType:n}=t.image_data??{};return o?{inlineData:{mimeType:n??"image/jpeg",data:o}}:null}if(t.type==="image_url"){let o=t.image_url?.url??"";return o?{fileData:{mimeType:"image/jpeg",fileUri:o}}:null}if(t.type==="file"){let o=t.file.url.match(/^data:([\w/+.-]+);base64,(.+)$/s);return o?o[2]?{inlineData:{mimeType:o[1],data:o[2]}}:null:t.file.url?{fileData:{mimeType:t.file.mimeType,fileUri:t.file.url}}:null}return null}).filter(t=>t!==null):[]}parseResponse(e,t){let o=[],n="",s=null;for(let i of e.candidates??[]){i.content&&(s=i.content);for(let a of i.content?.parts??[])if(a.text&&!a.thought&&(n+=a.text),a.functionCall){let l=a.functionCall;o.push({id:`vtx_${Date.now()}_${Math.random().toString(36).slice(2,8)}`,name:this.restoreToolName(l.name,t),arguments:l.args??{}})}}return{content:n,toolCalls:o,rawContent:s}}extractSystemInstruction(e){let t=e.filter(o=>o.role==="system");if(t.length!==0)return t.map(o=>typeof o.content=="string"?o.content:"").join(`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "toolpack-sdk",
3
- "version": "3.5.0",
3
+ "version": "3.6.0",
4
4
  "description": "TypeScript SDK for production AI agents — 110+ built-in tools across 14 categories, multi-provider support (OpenAI, Anthropic, Gemini, Ollama), workflow engine, and mode system",
5
5
  "engines": {
6
6
  "node": ">=20"