@stacksjs/ai 0.70.44 → 0.70.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ # MIT License
2
+
3
+ Copyright (c) 2023 Open Web Foundation
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -5,7 +5,8 @@ import type { AIDriver, AIDriverConfig, AIMessage, AIResult, ChatCompletionOptio
5
5
  export declare function configure(config: AnthropicDriverConfig): void;
6
6
  export declare function createAnthropicDriver(config: AnthropicDriverConfig): AIDriver;
7
7
  /**
8
- * Chat completion with full options
8
+ * Chat completion with full options. Supports tools + structured
9
+ * output via `responseFormat` (stacksjs/stacks#1878 A-1).
9
10
  */
10
11
  export declare function chat(messages: AIMessage[], options?: ChatCompletionOptions & { system?: string }): Promise<AIResult>;
11
12
  /**
@@ -1,3 +1,6 @@
1
+ export type { RetryConfig } from './utils/retry';
2
+ export type { UsageRecord, UsageReporter } from './utils/usage';
3
+ export type { SanitizeResult } from './utils/tokens';
1
4
  // Types
2
5
  export * from './types';
3
6
  // Drivers
@@ -19,4 +22,18 @@ export * from './mcp';
19
22
  // AWS Bedrock utilities
20
23
  export * from './utils/client-bedrock';
21
24
  export * from './utils/client-bedrock-runtime';
25
+ // Cross-driver vision helpers (stacksjs/stacks#1878 A-3).
26
+ // `buildMessageWithImages(command, images)` constructs portable
27
+ // content arrays; `normalizeMessagesForProvider(messages, 'openai' | 'anthropic')`
28
+ // translates between the OpenAI image_url and Anthropic image
29
+ // source formats so apps can switch providers without rewriting.
30
+ export { buildMessageWithImages, normalizeMessagesForProvider } from './utils/vision';
31
+ // HTTP retry helper for 429/5xx (stacksjs/stacks#1878 A-5).
32
+ export { fetchWithRetry } from './utils/retry';
33
+ // Usage tracking (stacksjs/stacks#1878 A-6). Apps install reporters
34
+ // via `onUsage(fn)`; drivers fire `recordUsage(...)` per completion.
35
+ // Default with no reporters is a no-op.
36
+ export { clearUsageReporters, listUsageReporters, onUsage, recordUsage } from './utils/usage';
37
+ // Token estimation + prompt-injection heuristics (stacksjs/stacks#1878 A-7).
38
+ export { estimateMessageTokens, estimateTokens, sanitizePrompt } from './utils/tokens';
22
39
  export * from './utils/model-access';
package/dist/src/index.js CHANGED
@@ -1,44 +1,44 @@
1
1
  // @bun
2
- var F=import.meta.require;var t=null;function zQ(Q){t=Q}function o(Q){let X={...t,...Q};if(!X.apiKey)X.apiKey=process.env.ANTHROPIC_API_KEY||"";return X}function S(Q){let{apiKey:X,model:Y="claude-sonnet-4-20250514",maxTokens:Z=4096,anthropicVersion:H="2023-06-01"}=Q;return{name:"Claude API",async process(W,J,V){if(!X)throw Error("Anthropic API key not set. Configure your API key in settings.");let G=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":X,"anthropic-version":H},body:JSON.stringify({model:Y,max_tokens:Z,system:J,messages:[...V,{role:"user",content:W}]})});if(!G.ok){let j=await G.text();throw Error(`Claude API error: ${j}`)}let U=await G.json();if(!U.content||U.content.length===0)throw Error("Claude API returned empty content");return U.content[0].text},async*stream(W,J,V){if(!X)throw Error("Anthropic API key not set. Configure your API key in settings.");let G=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":X,"anthropic-version":H},body:JSON.stringify({model:Y,max_tokens:Z,system:J,stream:!0,messages:[...V,{role:"user",content:W}]})});if(!G.ok){let q=await G.text();throw Error(`Claude API error: ${q}`)}let U=G.body?.getReader();if(!U)throw Error("No response body");let j=new TextDecoder,$="";while(!0){let{done:q,value:L}=await U.read();if(q)break;$+=j.decode(L,{stream:!0});let A=$.split(`
3
- `);$=A.pop()||"";for(let B of A)if(B.startsWith("data: ")){let z=B.slice(6);if(z==="[DONE]")continue;try{let E=JSON.parse(z);if(E.type==="content_block_delta"&&E.delta?.text)yield E.delta.text}catch{}}}if($.startsWith("data: ")){let q=$.slice(6);if(q!=="[DONE]")try{let L=JSON.parse(q);if(L.type==="content_block_delta"&&L.delta?.text)yield L.delta.text}catch{}}}}}async function e(Q,X={}){let Y=o(),{model:Z="claude-sonnet-4-20250514",maxTokens:H=4096,temperature:W,topP:J,stop:V,system:G}=X,U=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Y.apiKey,"anthropic-version":Y.anthropicVersion||"2023-06-01"},body:JSON.stringify({model:Z,max_tokens:H,temperature:W,top_p:J,stop_sequences:V?Array.isArray(V)?V:[V]:void 0,system:G,messages:Q})});if(!U.ok){let $=await U.text();throw Error(`Claude API error: ${$}`)}let j=await U.json();if(!j.content||j.content.length===0)throw Error("Claude API returned empty content");return{content:j.content[0].text,model:j.model,usage:{promptTokens:j.usage?.input_tokens||0,completionTokens:j.usage?.output_tokens||0,totalTokens:(j.usage?.input_tokens||0)+(j.usage?.output_tokens||0)},finishReason:j.stop_reason}}async function*BQ(Q,X={}){let Y=o(),{model:Z="claude-sonnet-4-20250514",maxTokens:H=4096,temperature:W,topP:J,stop:V,system:G}=X,U=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Y.apiKey,"anthropic-version":Y.anthropicVersion||"2023-06-01"},body:JSON.stringify({model:Z,max_tokens:H,temperature:W,top_p:J,stop_sequences:V?Array.isArray(V)?V:[V]:void 0,system:G,stream:!0,messages:Q})});if(!U.ok){let L=await U.text();throw Error(`Claude API error: ${L}`)}let j=U.body?.getReader();if(!j)throw Error("No response body");let $=new TextDecoder,q="";while(!0){let{done:L,value:A}=await j.read();if(L)break;q+=$.decode(A,{stream:!0});let B=q.split(`
4
- `);q=B.pop()||"";for(let z of B)if(z.startsWith("data: ")){let E=z.slice(6);if(E==="[DONE]")continue;try{let O=JSON.parse(E);if(O.type==="content_block_delta"&&O.delta?.text)yield O.delta.text}catch{}}}}async function EQ(Q,X={}){return(await e([{role:"user",content:Q}],X)).content}function QQ(Q){return Math.ceil(Q.length/4)}var LQ={create:S},AQ={configure:zQ,chat:e,streamChat:BQ,prompt:EQ,estimateTokens:QQ,createDriver:S};var XQ=null;function OQ(Q){XQ=Q}function D(Q){let X={...XQ,...Q};if(!X.apiKey)X.apiKey=process.env.OPENAI_API_KEY||"";return X}function P(Q){let{apiKey:X,model:Y="gpt-4o",maxTokens:Z=4096,baseUrl:H="https://api.openai.com/v1",embeddingModel:W="text-embedding-3-small"}=Q;return{name:"OpenAI",async process(J,V,G){if(!X)throw Error("OpenAI API key not set. Configure your API key in settings.");let U=await fetch(`${H}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify({model:Y,max_tokens:Z,messages:[{role:"system",content:V},...G,{role:"user",content:J}]})});if(!U.ok){let $=await U.text();throw Error(`OpenAI API error: ${$}`)}let j=await U.json();if(!j.choices||j.choices.length===0)throw Error("OpenAI API returned empty choices");return j.choices[0].message.content},async*stream(J,V,G){if(!X)throw Error("OpenAI API key not set. Configure your API key in settings.");let U=await fetch(`${H}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify({model:Y,max_tokens:Z,stream:!0,messages:[{role:"system",content:V},...G,{role:"user",content:J}]})});if(!U.ok){let L=await U.text();throw Error(`OpenAI API error: ${L}`)}let j=U.body?.getReader();if(!j)throw Error("No response body");let $=new TextDecoder,q="";while(!0){let{done:L,value:A}=await j.read();if(L)break;q+=$.decode(A,{stream:!0});let B=q.split(`
5
- `);q=B.pop()||"";for(let z of B)if(z.startsWith("data: ")){let E=z.slice(6);if(E==="[DONE]")continue;try{let _=JSON.parse(E).choices[0]?.delta?.content;if(_)yield _}catch{}}}if(q.startsWith("data: ")){let L=q.slice(6);if(L!=="[DONE]")try{let B=JSON.parse(L).choices[0]?.delta?.content;if(B)yield B}catch{}}},async embed(J){if(!X)throw Error("OpenAI API key not set. Configure your API key in settings.");let V=await fetch(`${H}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify({model:W,input:J})});if(!V.ok){let U=await V.text();throw Error(`OpenAI Embeddings API error: ${U}`)}let G=await V.json();if(Array.isArray(J))return G.data.map((U)=>U.embedding);return G.data[0].embedding}}}async function _Q(Q,X={}){let Y=D(),{model:Z="gpt-4o",maxTokens:H=4096,temperature:W,topP:J,stop:V}=X,G=await fetch(`${Y.baseUrl||"https://api.openai.com/v1"}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:Z,max_tokens:H,temperature:W,top_p:J,stop:V,messages:Q})});if(!G.ok){let j=await G.text();throw Error(`OpenAI API error: ${j}`)}let U=await G.json();if(!U.choices||U.choices.length===0)throw Error("OpenAI API returned empty choices");return{content:U.choices[0].message.content,model:U.model,usage:{promptTokens:U.usage?.prompt_tokens||0,completionTokens:U.usage?.completion_tokens||0,totalTokens:U.usage?.total_tokens||0},finishReason:U.choices[0].finish_reason}}async function*RQ(Q,X={}){let Y=D(),{model:Z="gpt-4o",maxTokens:H=4096,temperature:W,topP:J,stop:V}=X,G=await fetch(`${Y.baseUrl||"https://api.openai.com/v1"}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:Z,max_tokens:H,temperature:W,top_p:J,stop:V,stream:!0,messages:Q})});if(!G.ok){let q=await G.text();throw Error(`OpenAI API error: ${q}`)}let U=G.body?.getReader();if(!U)throw Error("No response body");let j=new TextDecoder,$="";while(!0){let{done:q,value:L}=await U.read();if(q)break;$+=j.decode(L,{stream:!0});let A=$.split(`
6
- `);$=A.pop()||"";for(let B of A)if(B.startsWith("data: ")){let z=B.slice(6);if(z==="[DONE]")continue;try{let O=JSON.parse(z).choices[0]?.delta?.content;if(O)yield O}catch{}}}}async function FQ(Q,X="text-embedding-3-small"){let Y=D(),Z=await fetch(`${Y.baseUrl||"https://api.openai.com/v1"}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:X,input:Q})});if(!Z.ok){let W=await Z.text();throw Error(`OpenAI Embeddings API error: ${W}`)}let H=await Z.json();if(Array.isArray(Q))return H.data.map((W)=>W.embedding);return H.data[0].embedding}async function NQ(Q,X={}){let Y=D(),{model:Z="dall-e-3",size:H="1024x1024",quality:W="standard",n:J=1,responseFormat:V="url"}=X,G=await fetch(`${Y.baseUrl||"https://api.openai.com/v1"}/images/generations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:Z,prompt:Q,size:H,quality:W,n:J,response_format:V})});if(!G.ok){let j=await G.text();throw Error(`OpenAI Image API error: ${j}`)}return(await G.json()).data}async function wQ(Q,X={}){let Y=D(),Z=new FormData;if(Z.append("file",Q),Z.append("model",X.model||"whisper-1"),X.language)Z.append("language",X.language);if(X.prompt)Z.append("prompt",X.prompt);if(X.responseFormat)Z.append("response_format",X.responseFormat);if(X.temperature!==void 0)Z.append("temperature",String(X.temperature));let H=await fetch(`${Y.baseUrl||"https://api.openai.com/v1"}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${Y.apiKey}`},body:Z});if(!H.ok){let W=await H.text();throw Error(`OpenAI Whisper API error: ${W}`)}return H.json()}async function MQ(Q,X={}){let Y=D(),{model:Z="tts-1",voice:H="alloy",responseFormat:W="mp3",speed:J=1}=X,V=await fetch(`${Y.baseUrl||"https://api.openai.com/v1"}/audio/speech`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:Z,input:Q,voice:H,response_format:W,speed:J})});if(!V.ok){let G=await V.text();throw Error(`OpenAI TTS API error: ${G}`)}return V.arrayBuffer()}var KQ={create:P},TQ={configure:OQ,chat:_Q,streamChat:RQ,embed:FQ,generateImage:NQ,transcribe:wQ,textToSpeech:MQ,createDriver:P};var v={};function DQ(Q){v={...v,...Q}}function M(Q){return{host:Q?.host||v.host||process.env.OLLAMA_HOST||"http://localhost:11434",model:Q?.model||v.model||process.env.OLLAMA_MODEL||"llama3.2",embeddingModel:Q?.embeddingModel||v.embeddingModel||"nomic-embed-text"}}function b(Q={}){let{host:X=process.env.OLLAMA_HOST||"http://localhost:11434",model:Y=process.env.OLLAMA_MODEL||"llama3.2",embeddingModel:Z="nomic-embed-text"}=Q;return{name:"Ollama",async process(H,W,J){let V=await fetch(`${X}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Y,messages:[{role:"system",content:W},...J,{role:"user",content:H}],stream:!1})});if(!V.ok){let U=await V.text();throw Error(`Ollama API error: ${U}`)}return(await V.json()).message.content},async*stream(H,W,J){let V=await fetch(`${X}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Y,messages:[{role:"system",content:W},...J,{role:"user",content:H}],stream:!0})});if(!V.ok){let $=await V.text();throw Error(`Ollama API error: ${$}`)}let G=V.body?.getReader();if(!G)throw Error("No response body");let U=new TextDecoder,j="";while(!0){let{done:$,value:q}=await G.read();if($)break;j+=U.decode(q,{stream:!0});let L=j.split(`
7
- `);j=L.pop()||"";for(let A of L){if(!A.trim())continue;try{let B=JSON.parse(A);if(B.message?.content)yield B.message.content}catch{}}}},async embed(H){let W=Array.isArray(H)?H:[H],J=[];for(let V of W){let G=await fetch(`${X}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z,prompt:V})});if(!G.ok){let j=await G.text();throw Error(`Ollama Embeddings API error: ${j}`)}let U=await G.json();J.push(U.embedding)}return Array.isArray(H)?J:J[0]}}}async function IQ(Q,X={}){let Y=M(),{model:Z=Y.model,temperature:H,topP:W,stop:J}=X,V=await fetch(`${Y.host}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z,messages:Q,stream:!1,options:{temperature:H,top_p:W,stop:J}})});if(!V.ok){let U=await V.text();throw Error(`Ollama API error: ${U}`)}let G=await V.json();return{content:G.message.content,model:G.model,usage:{promptTokens:G.prompt_eval_count||0,completionTokens:G.eval_count||0,totalTokens:(G.prompt_eval_count||0)+(G.eval_count||0)},finishReason:G.done_reason||"stop"}}async function*xQ(Q,X={}){let Y=M(),{model:Z=Y.model,temperature:H,topP:W,stop:J}=X,V=await fetch(`${Y.host}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z,messages:Q,stream:!0,options:{temperature:H,top_p:W,stop:J}})});if(!V.ok){let $=await V.text();throw Error(`Ollama API error: ${$}`)}let G=V.body?.getReader();if(!G)throw Error("No response body");let U=new TextDecoder,j="";while(!0){let{done:$,value:q}=await G.read();if($)break;j+=U.decode(q,{stream:!0});let L=j.split(`
8
- `);j=L.pop()||"";for(let A of L){if(!A.trim())continue;try{let B=JSON.parse(A);if(B.message?.content)yield B.message.content}catch{}}}}async function kQ(Q,X={}){let Y=M(),Z=await fetch(`${Y.host}/api/generate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:X.model||Y.model,prompt:Q,system:X.system,template:X.template,context:X.context,raw:X.raw,format:X.format,images:X.images,stream:!1})});if(!Z.ok){let W=await Z.text();throw Error(`Ollama API error: ${W}`)}let H=await Z.json();return{content:H.response,model:H.model,usage:{promptTokens:H.prompt_eval_count||0,completionTokens:H.eval_count||0,totalTokens:(H.prompt_eval_count||0)+(H.eval_count||0)}}}async function CQ(Q,X){let Y=M(),Z=X||Y.embeddingModel,H=Array.isArray(Q)?Q:[Q],W=[];for(let J of H){let V=await fetch(`${Y.host}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z,prompt:J})});if(!V.ok){let U=await V.text();throw Error(`Ollama Embeddings API error: ${U}`)}let G=await V.json();W.push(G.embedding)}return Array.isArray(Q)?W:W[0]}async function SQ(){let Q=M(),X=await fetch(`${Q.host}/api/tags`,{method:"GET"});if(!X.ok){let Z=await X.text();throw Error(`Ollama API error: ${Z}`)}return(await X.json()).models}async function PQ(Q,X){let Y=M(),Z=await fetch(`${Y.host}/api/pull`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Q,stream:!0})});if(!Z.ok){let V=await Z.text();throw Error(`Ollama API error: ${V}`)}let H=Z.body?.getReader();if(!H)return;let W=new TextDecoder,J="";while(!0){let{done:V,value:G}=await H.read();if(V)break;J+=W.decode(G,{stream:!0});let U=J.split(`
9
- `);J=U.pop()||"";for(let j of U){if(!j.trim())continue;try{let $=JSON.parse(j);if(X)X($.status,$.completed,$.total)}catch{}}}}async function vQ(Q){let X=M(),Y=await fetch(`${X.host}/api/delete`,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Q})});if(!Y.ok){let Z=await Y.text();throw Error(`Ollama API error: ${Z}`)}}async function bQ(Q){let X=M(),Y=await fetch(`${X.host}/api/show`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Q})});if(!Y.ok){let Z=await Y.text();throw Error(`Ollama API error: ${Z}`)}return Y.json()}async function hQ(){let Q=M();try{return(await fetch(`${Q.host}/api/tags`,{method:"GET"})).ok}catch{return!1}}var yQ={create:b},fQ={configure:DQ,chat:IQ,streamChat:xQ,generate:kQ,embed:CQ,listModels:SQ,pullModel:PQ,deleteModel:vQ,showModel:bQ,isRunning:hQ,createDriver:b};var p=null;async function u(){if(!p)try{p=await import("@anthropic-ai/claude-agent-sdk")}catch{throw Error("Claude Agent SDK not installed. Run: bun add @anthropic-ai/claude-agent-sdk")}return p}var N={lastSessionId:void 0},I={maxTurns:25,allowedTools:["Read","Write","Edit","Bash","Glob","Grep"],permissionMode:"bypassPermissions"};function c(Q={}){let{maxTurns:X=I.maxTurns,cwd:Y,allowedTools:Z=I.allowedTools,disallowedTools:H,permissionMode:W=I.permissionMode,customSystemPrompt:J,appendSystemPrompt:V,resumeSessionId:G}=Q;return{name:"Claude Agent SDK",async process(U,j,$){let q=await u(),{query:L}=q,A=j?`${j}
10
-
11
- User request: ${U}`:U,B={allowedTools:Z,permissionMode:W,maxTurns:X};if(H)B.disallowedTools=H;if(J)B.customSystemPrompt=J;if(V)B.appendSystemPrompt=V;if(Y)B.cwd=Y;if(G||N.lastSessionId)B.resume=G||N.lastSessionId;let z="";try{for await(let E of L({prompt:A,options:B})){if(E.type==="system"&&E.subtype==="init")N.lastSessionId=E.session_id;if("result"in E&&typeof E.result==="string")z=E.result}return z||"No response from Claude Agent SDK"}catch(E){let O=E;if(O.message.includes("ANTHROPIC_API_KEY"))throw Error("Claude Agent SDK requires ANTHROPIC_API_KEY environment variable or Claude Code authentication.");throw Error(`Claude Agent SDK error: ${O.message}`)}},async*stream(U,j,$){let q=await u(),{query:L}=q,A=j?`${j}
12
-
13
- User request: ${U}`:U,B={allowedTools:Z,permissionMode:W,maxTurns:X};if(H)B.disallowedTools=H;if(J)B.customSystemPrompt=J;if(V)B.appendSystemPrompt=V;if(Y)B.cwd=Y;if(G||N.lastSessionId)B.resume=G||N.lastSessionId;try{for await(let z of L({prompt:A,options:B})){if(z.type==="system"&&z.subtype==="init")N.lastSessionId=z.session_id;if(z.type==="assistant"){let E=z;if(E.message?.content){for(let O of E.message.content)if(O.type==="text"&&O.text)yield O.text}}if("result"in z&&typeof z.result==="string")yield z.result}}catch(z){let E=z;if(E.message.includes("ANTHROPIC_API_KEY"))throw Error("Claude Agent SDK requires ANTHROPIC_API_KEY environment variable or Claude Code authentication.");throw Error(`Claude Agent SDK error: ${E.message}`)}}}}async function gQ(Q,X,Y={}){let Z=await u(),{query:H}=Z,{maxTurns:W=I.maxTurns,allowedTools:J=I.allowedTools,disallowedTools:V,permissionMode:G=I.permissionMode,customSystemPrompt:U,appendSystemPrompt:j,resumeSessionId:$}=Y,q={allowedTools:J,permissionMode:G,maxTurns:W};if(V)q.disallowedTools=V;if(U)q.customSystemPrompt=U;if(j)q.appendSystemPrompt=j;if(X)q.cwd=X;if($||N.lastSessionId)q.resume=$||N.lastSessionId;let L=new TextEncoder,A="",B,z=new Promise((O)=>{B=O});return{stream:new ReadableStream({async start(O){try{for await(let _ of H({prompt:Q,options:q})){if(_.type==="system"&&_.subtype==="init")N.lastSessionId=_.session_id;if(_.type==="assistant"){let C=_;if(C.message?.content){for(let g of C.message.content)if(g.type==="text"&&g.text)A+=g.text,O.enqueue(L.encode(g.text))}}if("result"in _&&typeof _.result==="string"){if(!A)A=_.result,O.enqueue(L.encode(_.result))}}B(A),O.close()}catch(_){B(A),O.error(_)}}}),fullResponse:z}}async function uQ(Q,X){let Y=await u(),{query:Z}=Y,H="";for await(let W of Z({prompt:X,options:{resume:Q,permissionMode:"bypassPermissions"}}))if("result"in W&&typeof W.result==="string")H=W.result;return H||"No response from resumed session"}function YQ(){return N.lastSessionId}function ZQ(){N.lastSessionId=void 0}var cQ={createDriver:c,processStreaming:gQ,resumeSession:uQ,getLastSessionId:YQ,clearSession:ZQ};var HQ=0;function lQ(Q,X){switch(Q){case"Read":{let Y=X.file_path||"";return`
2
+ var M=import.meta.require;var IQ={maxRetries:3,baseDelayMs:500,maxDelayMs:30000};async function S(Q,Z,Y={}){let H={...IQ,...Y},X;for(let G=0;G<=H.maxRetries;G++){if(X=await fetch(Q,Z),X.ok)return X;if(X.status<500&&X.status!==429)return X;if(G===H.maxRetries)return X;let V=TQ(X.headers.get("Retry-After"))??DQ(G,H),$=Math.min(V,H.maxDelayMs);try{await X.text().catch(()=>{})}catch{}await new Promise((W)=>setTimeout(W,$))}return X}function TQ(Q){if(!Q)return null;let Z=Number.parseInt(Q,10);if(Number.isFinite(Z)&&String(Z)===Q.trim())return Math.max(0,Z*1000);let Y=Date.parse(Q);if(Number.isFinite(Y))return Math.max(0,Y-Date.now());return null}function DQ(Q,Z){let Y=Math.min(Z.baseDelayMs*2**Q,Z.maxDelayMs);return Math.random()*Y}var P=[];function CQ(Q){return P.push(Q),()=>{let Z=P.indexOf(Q);if(Z>=0)P.splice(Z,1)}}function xQ(){P.length=0}function h(Q){for(let Z of P)try{let Y=Z(Q);if(Y&&typeof Y.then==="function")Y.catch((H)=>{console.error("[ai/usage] reporter rejected:",H)})}catch(Y){console.error("[ai/usage] reporter threw:",Y)}}function SQ(){return P}function PQ(Q){if(Q.type==="text")return{type:"text",text:Q.text??""};if(Q.type==="image_url")return{type:"image_url",image_url:Q.image_url};if(Q.type==="image"&&Q.source){if(Q.source.type==="base64")return{type:"image_url",image_url:{url:`data:${Q.source.media_type};base64,${Q.source.data}`}}}return Q}function kQ(Q){if(Q.type==="text")return{type:"text",text:Q.text??""};if(Q.type==="image"&&Q.source)return{type:"image",source:Q.source};if(Q.type==="image_url"&&Q.image_url){let Z=Q.image_url.url,Y=Z.match(/^data:([^;]+);base64,(.+)$/);if(Y)return{type:"image",source:{type:"base64",media_type:Y[1],data:Y[2]}};return{type:"image",source:{type:"url",url:Z}}}return Q}function I(Q,Z){return Q.map((Y)=>{if(typeof Y.content==="string")return Y;let H=Z==="openai"?PQ:kQ;return{role:Y.role,content:Y.content.map(H)}})}function vQ(Q,Z){let Y=[];for(let H of Z)if(H.dataBase64&&H.mediaType)Y.push({type:"image",source:{type:"base64",media_type:H.mediaType,data:H.dataBase64}});else if(H.url)Y.push({type:"image_url",image_url:{url:H.url,detail:H.detail}});return Y.push({type:"text",text:Q}),Y}var o="claude-sonnet-4-20250514",t=4096,e="2023-06-01",p="https://api.anthropic.com/v1",WQ=null;function yQ(Q){WQ=Q}function qQ(Q){let Z={...WQ,...Q};if(!Z.apiKey)Z.apiKey=process.env.ANTHROPIC_API_KEY||"";return Z}function f(Q){let{apiKey:Z,model:Y=o,maxTokens:H=t,anthropicVersion:X=e}=Q;return{name:"Claude API",async process(G,J,V){if(!Z)throw Error("Anthropic API key not set. Configure your API key in settings.");let $=await S(`${p}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Z,"anthropic-version":X},body:JSON.stringify({model:Y,max_tokens:H,system:J,messages:[...V,{role:"user",content:G}]})});if(!$.ok){let q=await $.text();throw Error(`Claude API error: ${q}`)}let W=await $.json();if(!W.content||W.content.length===0)throw Error("Claude API returned empty content");return W.content[0].text},async*stream(G,J,V){if(!Z)throw Error("Anthropic API key not set. Configure your API key in settings.");let $=await fetch(`${p}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Z,"anthropic-version":X},body:JSON.stringify({model:Y,max_tokens:H,system:J,stream:!0,messages:[...V,{role:"user",content:G}]})});if(!$.ok){let w=await $.text();throw Error(`Claude API error: ${w}`)}let W=$.body?.getReader();if(!W)throw Error("No response body");let q=new TextDecoder,z="",B=function*(w){if(w==="[DONE]")return;let O;try{O=JSON.parse(w)}catch{return}if(O.type==="error"){let U=O.error?.message??JSON.stringify(O.error??O);throw Error(`[anthropic/stream] mid-stream error: ${U}`)}if(O.type==="content_block_delta"&&O.delta?.text)yield O.delta.text};while(!0){let{done:w,value:O}=await W.read();if(w)break;z+=q.decode(O,{stream:!0});let U=z.split(`
3
+ `);z=U.pop()||"";for(let j of U)if(j.startsWith("data: "))yield*B(j.slice(6))}if(z.startsWith("data: "))yield*B(z.slice(6))}}}async function zQ(Q,Z={}){let Y=qQ(),{model:H=o,maxTokens:X=t,temperature:G,topP:J,stop:V,system:$,tools:W,toolChoice:q,responseFormat:z}=Z,B=I(Q,"anthropic"),w=Date.now(),O={model:H,max_tokens:X,temperature:G,top_p:J,stop_sequences:V?Array.isArray(V)?V:[V]:void 0,system:$,messages:B};if(W&&W.length>0){if(O.tools=W.map((R)=>({name:R.name,description:R.description,input_schema:R.parameters??{type:"object",properties:{}}})),q!==void 0)O.tool_choice=bQ(q)}if(z&&z.type!=="text"){let R=hQ(z),x=Array.isArray(O.tools)?O.tools:[];if(O.tools=[...x,R],q===void 0)O.tool_choice={type:"tool",name:R.name}}let U=await fetch(`${p}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Y.apiKey,"anthropic-version":Y.anthropicVersion||e},body:JSON.stringify(O)});if(!U.ok){let R=await U.text();throw Error(`Claude API error: ${R}`)}let j=await U.json();if(!j.content||j.content.length===0)throw Error("Claude API returned empty content");let K=j.content.find((R)=>R.type==="tool_use")??j.content.find((R)=>R.type==="text")??j.content[0],L={content:K?.type==="tool_use"?JSON.stringify(K.input):K?.text??"",model:j.model,usage:{promptTokens:j.usage?.input_tokens||0,completionTokens:j.usage?.output_tokens||0,totalTokens:(j.usage?.input_tokens||0)+(j.usage?.output_tokens||0)},finishReason:j.stop_reason};return h({provider:"anthropic",model:j.model,promptTokens:L.usage.promptTokens,completionTokens:L.usage.completionTokens,totalTokens:L.usage.totalTokens,durationMs:Date.now()-w,timestamp:Date.now()}),L}function bQ(Q){if(Q==="auto")return{type:"auto"};if(Q==="required")return{type:"any"};if(Q==="none")return{type:"auto",disable_parallel_tool_use:!0};return{type:"tool",name:Q.name}}function hQ(Q){if(Q.type==="json_schema")return{name:Q.json_schema.name,description:`Returns the result as JSON matching the '${Q.json_schema.name}' schema.`,input_schema:Q.json_schema.schema};return{name:"structured_output",description:"Returns the result as a JSON object.",input_schema:{type:"object",additionalProperties:!0}}}async function*fQ(Q,Z={}){let Y=qQ(),{model:H=o,maxTokens:X=t,temperature:G,topP:J,stop:V,system:$}=Z,W=await fetch(`${p}/messages`,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Y.apiKey,"anthropic-version":Y.anthropicVersion||e},body:JSON.stringify({model:H,max_tokens:X,temperature:G,top_p:J,stop_sequences:V?Array.isArray(V)?V:[V]:void 0,system:$,stream:!0,messages:I(Q,"anthropic")})});if(!W.ok){let w=await W.text();throw Error(`Claude API error: ${w}`)}let q=W.body?.getReader();if(!q)throw Error("No response body");let z=new TextDecoder,B="";while(!0){let{done:w,value:O}=await q.read();if(w)break;B+=z.decode(O,{stream:!0});let U=B.split(`
4
+ `);B=U.pop()||"";for(let j of U)if(j.startsWith("data: ")){let K=j.slice(6);if(K==="[DONE]")continue;try{let N=JSON.parse(K);if(N.type==="content_block_delta"&&N.delta?.text)yield N.delta.text}catch{}}}}async function gQ(Q,Z={}){return(await zQ([{role:"user",content:Q}],Z)).content}function jQ(Q){return Math.ceil(Q.length/4)}var uQ={create:f},cQ={configure:yQ,chat:zQ,streamChat:fQ,prompt:gQ,estimateTokens:jQ,createDriver:f};var QQ="gpt-4o",ZQ=4096,BQ="text-embedding-3-small",T="https://api.openai.com/v1",OQ=null;function dQ(Q){OQ=Q}function k(Q){let Z={...OQ,...Q};if(!Z.apiKey)Z.apiKey=process.env.OPENAI_API_KEY||"";return Z}function g(Q){let{apiKey:Z,model:Y=QQ,maxTokens:H=ZQ,baseUrl:X=T,embeddingModel:G=BQ}=Q;return{name:"OpenAI",async process(J,V,$){if(!Z)throw Error("OpenAI API key not set. Configure your API key in settings.");let W=await S(`${X}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Z}`},body:JSON.stringify({model:Y,max_tokens:H,messages:[{role:"system",content:V},...$,{role:"user",content:J}]})});if(!W.ok){let z=await W.text();throw Error(`OpenAI API error: ${z}`)}let q=await W.json();if(!q.choices||q.choices.length===0)throw Error("OpenAI API returned empty choices");return q.choices[0].message.content},async*stream(J,V,$){if(!Z)throw Error("OpenAI API key not set. Configure your API key in settings.");let W=await fetch(`${X}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Z}`},body:JSON.stringify({model:Y,max_tokens:H,stream:!0,messages:[{role:"system",content:V},...$,{role:"user",content:J}]})});if(!W.ok){let O=await W.text();throw Error(`OpenAI API error: ${O}`)}let q=W.body?.getReader();if(!q)throw Error("No response body");let z=new TextDecoder,B="",w=function*(O){if(O==="[DONE]")return;let U;try{U=JSON.parse(O)}catch{return}if(U?.error){let K=U.error.message||JSON.stringify(U.error);throw Error(`[openai/stream] mid-stream error: ${K}`)}let j=U.choices?.[0]?.delta?.content;if(j)yield j};while(!0){let{done:O,value:U}=await q.read();if(O)break;B+=z.decode(U,{stream:!0});let j=B.split(`
5
+ `);B=j.pop()||"";for(let K of j)if(K.startsWith("data: "))yield*w(K.slice(6))}if(B.startsWith("data: "))yield*w(B.slice(6))},async embed(J){if(!Z)throw Error("OpenAI API key not set. Configure your API key in settings.");let V=await fetch(`${X}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Z}`},body:JSON.stringify({model:G,input:J})});if(!V.ok){let W=await V.text();throw Error(`OpenAI Embeddings API error: ${W}`)}let $=await V.json();if(Array.isArray(J))return $.data.map((W)=>W.embedding);return $.data[0].embedding}}}async function lQ(Q,Z={}){let Y=k(),{model:H=QQ,maxTokens:X=ZQ,temperature:G,topP:J,stop:V}=Z,$=I(Q,"openai"),W=Date.now(),q=await S(`${Y.baseUrl||T}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:H,max_tokens:X,temperature:G,top_p:J,stop:V,messages:$})});if(!q.ok){let w=await q.text();throw Error(`OpenAI API error: ${w}`)}let z=await q.json();if(!z.choices||z.choices.length===0)throw Error("OpenAI API returned empty choices");let B={content:z.choices[0].message.content,model:z.model,usage:{promptTokens:z.usage?.prompt_tokens||0,completionTokens:z.usage?.completion_tokens||0,totalTokens:z.usage?.total_tokens||0},finishReason:z.choices[0].finish_reason};return h({provider:"openai",model:z.model,promptTokens:B.usage.promptTokens,completionTokens:B.usage.completionTokens,totalTokens:B.usage.totalTokens,durationMs:Date.now()-W,timestamp:Date.now()}),B}async function*mQ(Q,Z={}){let Y=k(),{model:H=QQ,maxTokens:X=ZQ,temperature:G,topP:J,stop:V}=Z,$=await fetch(`${Y.baseUrl||T}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:H,max_tokens:X,temperature:G,top_p:J,stop:V,stream:!0,messages:I(Q,"openai")})});if(!$.ok){let B=await $.text();throw Error(`OpenAI API error: ${B}`)}let W=$.body?.getReader();if(!W)throw Error("No response body");let q=new TextDecoder,z="";while(!0){let{done:B,value:w}=await W.read();if(B)break;z+=q.decode(w,{stream:!0});let O=z.split(`
6
+ `);z=O.pop()||"";for(let U of O)if(U.startsWith("data: ")){let j=U.slice(6);if(j==="[DONE]")continue;try{let N=JSON.parse(j).choices[0]?.delta?.content;if(N)yield N}catch{}}}}async function pQ(Q,Z=BQ){let Y=k(),H=await fetch(`${Y.baseUrl||T}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:Z,input:Q})});if(!H.ok){let G=await H.text();throw Error(`OpenAI Embeddings API error: ${G}`)}let X=await H.json();if(Array.isArray(Q))return X.data.map((G)=>G.embedding);return X.data[0].embedding}async function iQ(Q,Z={}){let Y=k(),{model:H="dall-e-3",size:X="1024x1024",quality:G="standard",n:J=1,responseFormat:V="url"}=Z,$=await fetch(`${Y.baseUrl||T}/images/generations`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:H,prompt:Q,size:X,quality:G,n:J,response_format:V})});if(!$.ok){let q=await $.text();throw Error(`OpenAI Image API error: ${q}`)}return(await $.json()).data}async function aQ(Q,Z={}){let Y=k(),H=new FormData;if(H.append("file",Q),H.append("model",Z.model||"whisper-1"),Z.language)H.append("language",Z.language);if(Z.prompt)H.append("prompt",Z.prompt);if(Z.responseFormat)H.append("response_format",Z.responseFormat);if(Z.temperature!==void 0)H.append("temperature",String(Z.temperature));let X=await fetch(`${Y.baseUrl||T}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${Y.apiKey}`},body:H});if(!X.ok){let G=await X.text();throw Error(`OpenAI Whisper API error: ${G}`)}return X.json()}async function nQ(Q,Z={}){let Y=k(),{model:H="tts-1",voice:X="alloy",responseFormat:G="mp3",speed:J=1}=Z,V=await fetch(`${Y.baseUrl||T}/audio/speech`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y.apiKey}`},body:JSON.stringify({model:H,input:Q,voice:X,response_format:G,speed:J})});if(!V.ok){let $=await V.text();throw Error(`OpenAI TTS API error: ${$}`)}return V.arrayBuffer()}var rQ={create:g},sQ={configure:dQ,chat:lQ,streamChat:mQ,embed:pQ,generateImage:iQ,transcribe:aQ,textToSpeech:nQ,createDriver:g};var u={};function oQ(Q){u={...u,...Q}}function E(Q){return{host:Q?.host||u.host||process.env.OLLAMA_HOST||"http://localhost:11434",model:Q?.model||u.model||process.env.OLLAMA_MODEL||"llama3.2",embeddingModel:Q?.embeddingModel||u.embeddingModel||"nomic-embed-text"}}function c(Q={}){let{host:Z=process.env.OLLAMA_HOST||"http://localhost:11434",model:Y=process.env.OLLAMA_MODEL||"llama3.2",embeddingModel:H="nomic-embed-text"}=Q;return{name:"Ollama",async process(X,G,J){let V=await fetch(`${Z}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Y,messages:[{role:"system",content:G},...J,{role:"user",content:X}],stream:!1})});if(!V.ok){let W=await V.text();throw Error(`Ollama API error: ${W}`)}return(await V.json()).message.content},async*stream(X,G,J){let V=await fetch(`${Z}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Y,messages:[{role:"system",content:G},...J,{role:"user",content:X}],stream:!0})});if(!V.ok){let z=await V.text();throw Error(`Ollama API error: ${z}`)}let $=V.body?.getReader();if(!$)throw Error("No response body");let W=new TextDecoder,q="";while(!0){let{done:z,value:B}=await $.read();if(z)break;q+=W.decode(B,{stream:!0});let w=q.split(`
7
+ `);q=w.pop()||"";for(let O of w){if(!O.trim())continue;try{let U=JSON.parse(O);if(U.message?.content)yield U.message.content}catch{}}}},async embed(X){let G=Array.isArray(X)?X:[X],J=[];for(let V of G){let $=await fetch(`${Z}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:H,prompt:V})});if(!$.ok){let q=await $.text();throw Error(`Ollama Embeddings API error: ${q}`)}let W=await $.json();J.push(W.embedding)}return Array.isArray(X)?J:J[0]}}}async function tQ(Q,Z={}){let Y=E(),{model:H=Y.model,temperature:X,topP:G,stop:J}=Z,V=await fetch(`${Y.host}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:H,messages:Q,stream:!1,options:{temperature:X,top_p:G,stop:J}})});if(!V.ok){let W=await V.text();throw Error(`Ollama API error: ${W}`)}let $=await V.json();return{content:$.message.content,model:$.model,usage:{promptTokens:$.prompt_eval_count||0,completionTokens:$.eval_count||0,totalTokens:($.prompt_eval_count||0)+($.eval_count||0)},finishReason:$.done_reason||"stop"}}async function*eQ(Q,Z={}){let Y=E(),{model:H=Y.model,temperature:X,topP:G,stop:J}=Z,V=await fetch(`${Y.host}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:H,messages:Q,stream:!0,options:{temperature:X,top_p:G,stop:J}})});if(!V.ok){let z=await V.text();throw Error(`Ollama API error: ${z}`)}let $=V.body?.getReader();if(!$)throw Error("No response body");let W=new TextDecoder,q="";while(!0){let{done:z,value:B}=await $.read();if(z)break;q+=W.decode(B,{stream:!0});let w=q.split(`
8
+ `);q=w.pop()||"";for(let O of w){if(!O.trim())continue;try{let U=JSON.parse(O);if(U.message?.content)yield U.message.content}catch{}}}}async function QZ(Q,Z={}){let Y=E(),H=await fetch(`${Y.host}/api/generate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z.model||Y.model,prompt:Q,system:Z.system,template:Z.template,context:Z.context,raw:Z.raw,format:Z.format,images:Z.images,stream:!1})});if(!H.ok){let G=await H.text();throw Error(`Ollama API error: ${G}`)}let X=await H.json();return{content:X.response,model:X.model,usage:{promptTokens:X.prompt_eval_count||0,completionTokens:X.eval_count||0,totalTokens:(X.prompt_eval_count||0)+(X.eval_count||0)}}}async function ZZ(Q,Z){let Y=E(),H=Z||Y.embeddingModel,X=Array.isArray(Q)?Q:[Q],G=[];for(let J of X){let V=await fetch(`${Y.host}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:H,prompt:J})});if(!V.ok){let W=await V.text();throw Error(`Ollama Embeddings API error: ${W}`)}let $=await V.json();G.push($.embedding)}return Array.isArray(Q)?G:G[0]}async function YZ(){let Q=E(),Z=await fetch(`${Q.host}/api/tags`,{method:"GET"});if(!Z.ok){let H=await Z.text();throw Error(`Ollama API error: ${H}`)}return(await Z.json()).models}async function HZ(Q,Z){let Y=E(),H=await fetch(`${Y.host}/api/pull`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Q,stream:!0})});if(!H.ok){let V=await H.text();throw Error(`Ollama API error: ${V}`)}let X=H.body?.getReader();if(!X)return;let G=new TextDecoder,J="";while(!0){let{done:V,value:$}=await X.read();if(V)break;J+=G.decode($,{stream:!0});let W=J.split(`
9
+ `);J=W.pop()||"";for(let q of W){if(!q.trim())continue;try{let z=JSON.parse(q);if(Z)Z(z.status,z.completed,z.total)}catch{}}}}async function XZ(Q){let Z=E(),Y=await fetch(`${Z.host}/api/delete`,{method:"DELETE",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Q})});if(!Y.ok){let H=await Y.text();throw Error(`Ollama API error: ${H}`)}}async function JZ(Q){let Z=E(),Y=await fetch(`${Z.host}/api/show`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({name:Q})});if(!Y.ok){let H=await Y.text();throw Error(`Ollama API error: ${H}`)}return Y.json()}async function VZ(){let Q=E();try{return(await fetch(`${Q.host}/api/tags`,{method:"GET"})).ok}catch{return!1}}var GZ={create:c},$Z={configure:oQ,chat:tQ,streamChat:eQ,generate:QZ,embed:ZZ,listModels:YZ,pullModel:HZ,deleteModel:XZ,showModel:JZ,isRunning:VZ,createDriver:c};var YQ=null;async function i(){if(!YQ)try{YQ=await import("@anthropic-ai/claude-agent-sdk")}catch{throw Error("Claude Agent SDK not installed. Run: bun add @anthropic-ai/claude-agent-sdk")}return YQ}var A={lastSessionId:void 0},v={maxTurns:25,allowedTools:["Read","Write","Edit","Bash","Glob","Grep"],permissionMode:"bypassPermissions"};function a(Q={}){let{maxTurns:Z=v.maxTurns,cwd:Y,allowedTools:H=v.allowedTools,disallowedTools:X,permissionMode:G=v.permissionMode,customSystemPrompt:J,appendSystemPrompt:V,resumeSessionId:$}=Q;return{name:"Claude Agent SDK",async process(W,q,z){let B=await i(),{query:w}=B,O=q?`${q}
10
+
11
+ User request: ${W}`:W,U={allowedTools:H,permissionMode:G,maxTurns:Z};if(X)U.disallowedTools=X;if(J)U.customSystemPrompt=J;if(V)U.appendSystemPrompt=V;if(Y)U.cwd=Y;if($||A.lastSessionId)U.resume=$||A.lastSessionId;let j="";try{for await(let K of w({prompt:O,options:U})){if(K.type==="system"&&K.subtype==="init")A.lastSessionId=K.session_id;if("result"in K&&typeof K.result==="string")j=K.result}return j||"No response from Claude Agent SDK"}catch(K){let N=K;if(N.message.includes("ANTHROPIC_API_KEY"))throw Error("Claude Agent SDK requires ANTHROPIC_API_KEY environment variable or Claude Code authentication.");throw Error(`Claude Agent SDK error: ${N.message}`)}},async*stream(W,q,z){let B=await i(),{query:w}=B,O=q?`${q}
12
+
13
+ User request: ${W}`:W,U={allowedTools:H,permissionMode:G,maxTurns:Z};if(X)U.disallowedTools=X;if(J)U.customSystemPrompt=J;if(V)U.appendSystemPrompt=V;if(Y)U.cwd=Y;if($||A.lastSessionId)U.resume=$||A.lastSessionId;try{for await(let j of w({prompt:O,options:U})){if(j.type==="system"&&j.subtype==="init")A.lastSessionId=j.session_id;if(j.type==="assistant"){let K=j;if(K.message?.content){for(let N of K.message.content)if(N.type==="text"&&N.text)yield N.text}}if("result"in j&&typeof j.result==="string")yield j.result}}catch(j){let K=j;if(K.message.includes("ANTHROPIC_API_KEY"))throw Error("Claude Agent SDK requires ANTHROPIC_API_KEY environment variable or Claude Code authentication.");throw Error(`Claude Agent SDK error: ${K.message}`)}}}}async function WZ(Q,Z,Y={}){let H=await i(),{query:X}=H,{maxTurns:G=v.maxTurns,allowedTools:J=v.allowedTools,disallowedTools:V,permissionMode:$=v.permissionMode,customSystemPrompt:W,appendSystemPrompt:q,resumeSessionId:z}=Y,B={allowedTools:J,permissionMode:$,maxTurns:G};if(V)B.disallowedTools=V;if(W)B.customSystemPrompt=W;if(q)B.appendSystemPrompt=q;if(Z)B.cwd=Z;if(z||A.lastSessionId)B.resume=z||A.lastSessionId;let w=new TextEncoder,O="",U,j=new Promise((N)=>{U=N});return{stream:new ReadableStream({async start(N){try{for await(let L of X({prompt:Q,options:B})){if(L.type==="system"&&L.subtype==="init")A.lastSessionId=L.session_id;if(L.type==="assistant"){let R=L;if(R.message?.content){for(let x of R.message.content)if(x.type==="text"&&x.text)O+=x.text,N.enqueue(w.encode(x.text))}}if("result"in L&&typeof L.result==="string"){if(!O)O=L.result,N.enqueue(w.encode(L.result))}}U(O),N.close()}catch(L){U(O),N.error(L)}}}),fullResponse:j}}async function qZ(Q,Z){let Y=await i(),{query:H}=Y,X="";for await(let G of H({prompt:Z,options:{resume:Q,permissionMode:"bypassPermissions"}}))if("result"in G&&typeof G.result==="string")X=G.result;return X||"No response from resumed session"}function UQ(){return A.lastSessionId}function KQ(){A.lastSessionId=void 0}var zZ={createDriver:a,processStreaming:WZ,resumeSession:qZ,getLastSessionId:UQ,clearSession:KQ};var wQ=0;function jZ(Q,Z){switch(Q){case"Read":{let Y=Z.file_path||"";return`
14
14
  \uD83D\uDCD6 Reading: ${Y.split("/").pop()||Y}
15
15
  `}case"Glob":return`
16
- \uD83D\uDD0D Searching files: ${X.pattern||""}
16
+ \uD83D\uDD0D Searching files: ${Z.pattern||""}
17
17
  `;case"Grep":return`
18
- \uD83D\uDD0E Searching for: "${X.pattern||""}"
19
- `;case"Edit":{let Y=X.file_path||"";return`
18
+ \uD83D\uDD0E Searching for: "${Z.pattern||""}"
19
+ `;case"Edit":{let Y=Z.file_path||"";return`
20
20
  \u270F\uFE0F Editing: ${Y.split("/").pop()||Y}
21
- `}case"Write":{let Y=X.file_path||"";return`
21
+ `}case"Write":{let Y=Z.file_path||"";return`
22
22
  \uD83D\uDCDD Writing: ${Y.split("/").pop()||Y}
23
- `}case"Bash":{let Y=(X.command||"").substring(0,50);return`
23
+ `}case"Bash":{let Y=(Z.command||"").substring(0,50);return`
24
24
  \uD83D\uDCBB Running: ${Y}${Y.length>=50?"...":""}
25
25
  `}case"Task":return`
26
- \uD83D\uDE80 Launching agent: ${X.description||"task"}
26
+ \uD83D\uDE80 Launching agent: ${Z.description||"task"}
27
27
  `;default:return`
28
28
  \uD83D\uDD27 Using: ${Q}
29
- `}}function dQ(Q={}){return{name:"Claude CLI (Local)",async process(X,Y,Z){let{$:H}=awaitPromise.resolve(globalThis.Bun);if((await H`which claude`.quiet().nothrow()).exitCode!==0)throw Error("Claude CLI not found. Install it with: npm install -g @anthropic-ai/claude-code");let J=Y?`Context:
29
+ `}}function BZ(Q={}){return{name:"Claude CLI (Local)",async process(Z,Y,H){let{$:X}=awaitPromise.resolve(globalThis.Bun);if((await X`which claude`.quiet().nothrow()).exitCode!==0)throw Error("Claude CLI not found. Install it with: npm install -g @anthropic-ai/claude-code");let J=Y?`Context:
30
30
  ${Y}
31
31
 
32
- User request: ${X}`:X,V=Q.cwd||process.cwd();try{return(await H`cd ${V} && claude --print --dangerously-skip-permissions ${J}`.quiet()).text().trim()}catch{try{return(await H`cd ${V} && claude --print --allowedTools "Write,Edit,Bash" ${J}`.quiet()).text().trim()}catch(G){throw Error(`Claude CLI error: ${G.message}`)}}}}}function mQ(Q){let{ec2Host:X=process.env.BUDDY_EC2_HOST,ec2User:Y=process.env.BUDDY_EC2_USER||"ubuntu",ec2Key:Z=process.env.BUDDY_EC2_KEY}=Q;return{name:"Claude CLI (EC2)",async process(H,W,J){let{$:V}=awaitPromise.resolve(globalThis.Bun);if(!X)throw Error("BUDDY_EC2_HOST environment variable not set. Set it to your EC2 instance IP/hostname.");let U=(W?`Context:
33
- ${W}
32
+ User request: ${Z}`:Z,V=Q.cwd||process.cwd();try{return(await X`cd ${V} && claude --print --dangerously-skip-permissions ${J}`.quiet()).text().trim()}catch{try{return(await X`cd ${V} && claude --print --allowedTools "Write,Edit,Bash" ${J}`.quiet()).text().trim()}catch($){throw Error(`Claude CLI error: ${$.message}`)}}}}}function OZ(Q){let{ec2Host:Z=process.env.BUDDY_EC2_HOST,ec2User:Y=process.env.BUDDY_EC2_USER||"ubuntu",ec2Key:H=process.env.BUDDY_EC2_KEY}=Q;return{name:"Claude CLI (EC2)",async process(X,G,J){let{$:V}=awaitPromise.resolve(globalThis.Bun);if(!Z)throw Error("BUDDY_EC2_HOST environment variable not set. Set it to your EC2 instance IP/hostname.");let W=(G?`Context:
33
+ ${G}
34
34
 
35
- User request: ${H}`:H).replace(/'/g,"'\\''"),j=Z?`-i ${Z}`:"",$=`${Y}@${X}`;try{return(await V`ssh ${j} ${$} "claude --print '${U}'"`.quiet()).text().trim()}catch(q){throw Error(`EC2 Claude CLI error: ${q.message}. Make sure SSH is configured and claude CLI is installed on EC2.`)}}}}async function pQ(Q,X){let{spawn:Y}=awaitPromise.resolve(globalThis.Bun),Z=Y(["claude","--print","--verbose","--output-format","stream-json","--dangerously-skip-permissions",Q],{cwd:X,stdout:"pipe",stderr:"pipe"}),H="",W=new TextDecoder,J=new TextEncoder,V=new ReadableStream({async start(U){try{let j=Z.stdout.getReader(),$="",q="",L=await j.read();while(!L.done){$+=W.decode(L.value,{stream:!0});let A=$.split(`
36
- `);$=A.pop()||"";for(let B of A){if(!B.trim())continue;try{let z=JSON.parse(B),E="";if(z.type==="system"&&z.subtype==="init")HQ++;else if(z.type==="content_block_start"&&z.content_block?.text)E=z.content_block.text;else if(z.type==="content_block_delta"&&z.delta?.text)E=z.delta.text;else if(z.type==="assistant"&&z.message?.content){for(let O of z.message.content)if(O.type==="text"&&O.text)E+=O.text;else if(O.type==="tool_use"&&O.name)E+=lQ(O.name,O.input||{})}else if(z.type==="user"&&z.message?.content){for(let O of z.message.content)if(O.type==="tool_result")E+=` \u2713 done
37
- `}else if(z.type==="result"&&z.result){H=z.result;let O=z.result.substring(0,Math.min(50,z.result.length));if(!q.includes(O))E=z.result}if(E){if(z.type==="content_block_delta")q+=E,U.enqueue(J.encode(E));else if(!q.endsWith(E))q+=E,U.enqueue(J.encode(E))}}catch{if(!q.includes(B))q+=B,H+=B,U.enqueue(J.encode(B))}}L=await j.read()}if($.trim())try{let A=JSON.parse($);if(A.result&&!H)H=A.result}catch{if(!q.includes($))H+=$,U.enqueue(J.encode($))}await Z.exited,U.close()}catch(j){U.error(j)}}}),G=(async()=>{return await Z.exited,H.trim()})();return{stream:V,fullResponse:G}}function iQ(){HQ=0}var l={createLocal:dQ,createEC2:mQ,processStreaming:pQ,resetPromptCount:iQ};import{existsSync as T,mkdirSync as VQ,readFileSync as JQ,writeFileSync as aQ}from"fs";import{homedir as WQ}from"os";import{dirname as rQ,join as x}from"path";var k={workDir:x(WQ(),"Code",".buddy-repos"),commitMessage:"chore: wip",ollamaHost:process.env.OLLAMA_HOST||"http://localhost:11434",ollamaModel:process.env.OLLAMA_MODEL||"llama3.2"},K={anthropic:process.env.ANTHROPIC_API_KEY,openai:process.env.OPENAI_API_KEY,claudeCliHost:process.env.BUDDY_EC2_HOST},w={repo:null,conversationHistory:[],currentDriver:"claude-cli-local",github:null};if(!T(k.workDir))VQ(k.workDir,{recursive:!0});var R={getState:()=>w,setRepo:(Q)=>{w.repo=Q},setCurrentDriver:(Q)=>{w.currentDriver=Q},setGitHub:(Q)=>{w.github=Q},addToHistory:(Q)=>{w.conversationHistory.push(Q)},clearHistory:()=>{w.conversationHistory=[]}};function nQ(Q){return`You are Buddy, an AI code assistant that helps users modify codebases through voice commands.
35
+ User request: ${X}`:X).replace(/'/g,"'\\''"),q=H?`-i ${H}`:"",z=`${Y}@${Z}`;try{return(await V`ssh ${q} ${z} "claude --print '${W}'"`.quiet()).text().trim()}catch(B){throw Error(`EC2 Claude CLI error: ${B.message}. Make sure SSH is configured and claude CLI is installed on EC2.`)}}}}async function UZ(Q,Z){let{spawn:Y}=awaitPromise.resolve(globalThis.Bun),H=Y(["claude","--print","--verbose","--output-format","stream-json","--dangerously-skip-permissions",Q],{cwd:Z,stdout:"pipe",stderr:"pipe"}),X="",G=new TextDecoder,J=new TextEncoder,V=new ReadableStream({async start(W){try{let q=H.stdout.getReader(),z="",B="",w=await q.read();while(!w.done){z+=G.decode(w.value,{stream:!0});let O=z.split(`
36
+ `);z=O.pop()||"";for(let U of O){if(!U.trim())continue;try{let j=JSON.parse(U),K="";if(j.type==="system"&&j.subtype==="init")wQ++;else if(j.type==="content_block_start"&&j.content_block?.text)K=j.content_block.text;else if(j.type==="content_block_delta"&&j.delta?.text)K=j.delta.text;else if(j.type==="assistant"&&j.message?.content){for(let N of j.message.content)if(N.type==="text"&&N.text)K+=N.text;else if(N.type==="tool_use"&&N.name)K+=jZ(N.name,N.input||{})}else if(j.type==="user"&&j.message?.content){for(let N of j.message.content)if(N.type==="tool_result")K+=` \u2713 done
37
+ `}else if(j.type==="result"&&j.result){X=j.result;let N=j.result.substring(0,Math.min(50,j.result.length));if(!B.includes(N))K=j.result}if(K){if(j.type==="content_block_delta")B+=K,W.enqueue(J.encode(K));else if(!B.endsWith(K))B+=K,W.enqueue(J.encode(K))}}catch{if(!B.includes(U))B+=U,X+=U,W.enqueue(J.encode(U))}}w=await q.read()}if(z.trim())try{let O=JSON.parse(z);if(O.result&&!X)X=O.result}catch{if(!B.includes(z))X+=z,W.enqueue(J.encode(z))}await H.exited,W.close()}catch(q){W.error(q)}}}),$=(async()=>{return await H.exited,X.trim()})();return{stream:V,fullResponse:$}}function KZ(){wQ=0}var n={createLocal:BZ,createEC2:OZ,processStreaming:UZ,resetPromptCount:KZ};import{existsSync as C,mkdirSync as LQ,readFileSync as NQ,writeFileSync as wZ}from"fs";import{homedir as RQ}from"os";import{dirname as NZ,join as y}from"path";var b={workDir:y(RQ(),"Code",".buddy-repos"),commitMessage:"chore: wip",ollamaHost:process.env.OLLAMA_HOST||"http://localhost:11434",ollamaModel:process.env.OLLAMA_MODEL||"llama3.2"},D={anthropic:process.env.ANTHROPIC_API_KEY,openai:process.env.OPENAI_API_KEY,claudeCliHost:process.env.BUDDY_EC2_HOST},_={repo:null,conversationHistory:[],currentDriver:"claude-cli-local",github:null};if(!C(b.workDir))LQ(b.workDir,{recursive:!0});var F={getState:()=>_,setRepo:(Q)=>{_.repo=Q},setCurrentDriver:(Q)=>{_.currentDriver=Q},setGitHub:(Q)=>{_.github=Q},addToHistory:(Q)=>{_.conversationHistory.push(Q)},clearHistory:()=>{_.conversationHistory=[]}};function LZ(Q){return`You are Buddy, an AI code assistant that helps users modify codebases through voice commands.
38
38
 
39
- ${w.repo?`You are working on the repository: ${w.repo.name}
40
- Branch: ${w.repo.branch}
41
- Path: ${w.repo.path}
39
+ ${_.repo?`You are working on the repository: ${_.repo.name}
40
+ Branch: ${_.repo.branch}
41
+ Path: ${_.repo.path}
42
42
 
43
43
  ${Q}`:"No repository is currently open."}
44
44
 
@@ -57,7 +57,7 @@ FILE: path/to/file.ts
57
57
  // Full file content
58
58
  \`\`\`
59
59
 
60
- Be concise but thorough. The user will review and commit your changes.`}function sQ(){return{name:"Mock",async process(Q){await new Promise((Y)=>setTimeout(Y,1000));let X=Q.toLowerCase();if(X.includes("readme")||X.includes("documentation"))return`I'll update the README.md file for you.
60
+ Be concise but thorough. The user will review and commit your changes.`}function RZ(){return{name:"Mock",async process(Q){await new Promise((Y)=>setTimeout(Y,1000));let Z=Q.toLowerCase();if(Z.includes("readme")||Z.includes("documentation"))return`I'll update the README.md file for you.
61
61
 
62
62
  Analyzing the repository structure...
63
63
 
@@ -81,7 +81,7 @@ npm run start
81
81
  \`\`\`
82
82
 
83
83
  File modified: README.md
84
- Lines added: 12`;if(X.includes("fix")||X.includes("bug"))return`I'll analyze and fix the issue.
84
+ Lines added: 12`;if(Z.includes("fix")||Z.includes("bug"))return`I'll analyze and fix the issue.
85
85
 
86
86
  Scanning for potential bugs...
87
87
 
@@ -105,44 +105,44 @@ export function main() {
105
105
  }
106
106
  \`\`\`
107
107
 
108
- Files modified: 1`}}}function tQ(Q){let X=R.getState();switch(Q){case"claude-cli-local":return l.createLocal({cwd:X.repo?.path});case"claude-cli-ec2":return l.createEC2({cwd:X.repo?.path,ec2Host:K.claudeCliHost});case"claude":case"anthropic":if(!K.anthropic)throw Error("Anthropic API key not set. Configure your API key in settings.");return S({apiKey:K.anthropic});case"openai":if(!K.openai)throw Error("OpenAI API key not set. Configure your API key in settings.");return P({apiKey:K.openai});case"ollama":return b({host:k.ollamaHost,model:k.ollamaModel});case"claude-sdk":case"claude-agent-sdk":return c({cwd:X.repo?.path,maxTurns:25,permissionMode:"bypassPermissions"});case"mock":return sQ();default:throw Error(`Unknown driver: ${Q}. Available: claude-cli-local, claude-cli-ec2, claude, claude-sdk, openai, ollama, mock`)}}function tX(){return["claude-cli-local","claude-cli-ec2","claude","claude-sdk","openai","ollama","mock"]}async function oQ(Q){let{$:X}=awaitPromise.resolve(globalThis.Bun),Z=(await X`cd ${Q} && find . -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -not -name "*.lock" | head -50`.quiet()).text().trim(),H="",W=x(Q,"README.md");if(T(W))H=JQ(W,"utf-8").slice(0,2000);let J="",V=x(Q,"package.json");if(T(V))J=JQ(V,"utf-8");return`
108
+ Files modified: 1`}}}function FZ(Q){let Z=F.getState();switch(Q){case"claude-cli-local":return n.createLocal({cwd:Z.repo?.path});case"claude-cli-ec2":return n.createEC2({cwd:Z.repo?.path,ec2Host:D.claudeCliHost});case"claude":case"anthropic":if(!D.anthropic)throw Error("Anthropic API key not set. Configure your API key in settings.");return f({apiKey:D.anthropic});case"openai":if(!D.openai)throw Error("OpenAI API key not set. Configure your API key in settings.");return g({apiKey:D.openai});case"ollama":return c({host:b.ollamaHost,model:b.ollamaModel});case"claude-sdk":case"claude-agent-sdk":return a({cwd:Z.repo?.path,maxTurns:25,permissionMode:"bypassPermissions"});case"mock":return RZ();default:throw Error(`Unknown driver: ${Q}. Available: claude-cli-local, claude-cli-ec2, claude, claude-sdk, openai, ollama, mock`)}}function v6(){return["claude-cli-local","claude-cli-ec2","claude","claude-sdk","openai","ollama","mock"]}async function MZ(Q){let{$:Z}=awaitPromise.resolve(globalThis.Bun),H=(await Z`cd ${Q} && find . -type f -not -path "*/node_modules/*" -not -path "*/.git/*" -not -name "*.lock" | head -50`.quiet()).text().trim(),X="",G=y(Q,"README.md");if(C(G))X=NQ(G,"utf-8").slice(0,2000);let J="",V=y(Q,"package.json");if(C(V))J=NQ(V,"utf-8");return`
109
109
  Repository Structure:
110
- ${Z}
111
-
112
- ${H?`README.md (excerpt):
113
110
  ${H}
111
+
112
+ ${X?`README.md (excerpt):
113
+ ${X}
114
114
  `:""}
115
115
  ${J?`package.json:
116
116
  ${J}
117
117
  `:""}
118
- `.trim()}async function oX(Q){let{$:X}=awaitPromise.resolve(globalThis.Bun),Y,Z;if(Q.includes("github.com")||Q.startsWith("git@"))if(Z=Q.split("/").pop()?.replace(".git","")||"repo",Y=x(k.workDir,Z),T(Y))await X`cd ${Y} && git pull --rebase`.quiet();else await X`git clone ${Q} ${Y}`.quiet();else{if(Y=Q.startsWith("~")?Q.replace("~",WQ()):Q,!T(Y))throw Error(`Local path does not exist: ${Y}`);if(!T(x(Y,".git")))throw Error(`Not a git repository: ${Y}`);Z=Y.split("/").pop()||"repo"}let W=(await X`cd ${Y} && git branch --show-current`.quiet()).text().trim(),V=(await X`cd ${Y} && git status --porcelain`.quiet()).text().trim().length>0,U=(await X`cd ${Y} && git log -1 --format="%h %s"`.quiet()).text().trim(),j={path:Y,name:Z,branch:W,hasChanges:V,lastCommit:U};return R.setRepo(j),R.clearHistory(),j}async function eX(Q){let X=R.getState();if(!X.repo)throw Error("No repository opened");let Y=[],Z=/FILE:\s*([^\n]+)\n```\w*\n([\s\S]*?)```/g;for(let H of Q.matchAll(Z)){let W=H[1].trim(),J=H[2],V=x(X.repo.path,W),G=rQ(V);if(!T(G))VQ(G,{recursive:!0});aQ(V,J),Y.push(W)}if(Y.length>0&&X.repo)X.repo.hasChanges=!0;return Y}async function eQ(){let Q=R.getState();if(!Q.repo||!Q.github)return;let{$:X}=awaitPromise.resolve(globalThis.Bun),{name:Y,email:Z}=Q.github;await X`cd ${Q.repo.path} && git config user.name ${Y}`.quiet(),await X`cd ${Q.repo.path} && git config user.email ${Z}`.quiet()}async function QY(){let Q=R.getState();if(!Q.repo)throw Error("No repository opened");let{$:X}=awaitPromise.resolve(globalThis.Bun);if(Q.github)await eQ();await X`cd ${Q.repo.path} && git add -A`.quiet(),await X`cd ${Q.repo.path} && git commit -m ${k.commitMessage}`.quiet();let Z=(await X`cd ${Q.repo.path} && git rev-parse --short HEAD`.quiet()).text().trim();return Q.repo.hasChanges=!1,Q.repo.lastCommit=Z,Z}async function XY(){let Q=R.getState();if(!Q.repo)throw Error("No repository opened");let{$:X}=awaitPromise.resolve(globalThis.Bun);await X`cd ${Q.repo.path} && git push`.quiet()}async function YY(Q,X){let Y=R.getState();if(!Y.repo)throw Error("No repository opened");let Z=X||Y.currentDriver,H=tQ(Z);if(X)R.setCurrentDriver(X);let W=await oQ(Y.repo.path),J=nQ(W),V=await H.process(Q,J,Y.conversationHistory);return R.addToHistory({role:"user",content:Q}),R.addToHistory({role:"assistant",content:V}),V}async function ZY(Q,X,Y){let Z=R.getState();if(!Z.repo)throw Error("No repository opened");let H=X||Z.currentDriver,W=["claude-cli-local","claude-sdk"];if(!W.includes(H))throw Error(`Streaming only supported for ${W.join(", ")} drivers. Current: ${H}`);if(X)R.setCurrentDriver(X);let J=Q;if(Y&&Y.length>0){let G=`## Previous Conversation
118
+ `.trim()}async function y6(Q){let{$:Z}=awaitPromise.resolve(globalThis.Bun),Y,H;if(Q.includes("github.com")||Q.startsWith("git@"))if(H=Q.split("/").pop()?.replace(".git","")||"repo",Y=y(b.workDir,H),C(Y))await Z`cd ${Y} && git pull --rebase`.quiet();else await Z`git clone ${Q} ${Y}`.quiet();else{if(Y=Q.startsWith("~")?Q.replace("~",RQ()):Q,!C(Y))throw Error(`Local path does not exist: ${Y}`);if(!C(y(Y,".git")))throw Error(`Not a git repository: ${Y}`);H=Y.split("/").pop()||"repo"}let G=(await Z`cd ${Y} && git branch --show-current`.quiet()).text().trim(),V=(await Z`cd ${Y} && git status --porcelain`.quiet()).text().trim().length>0,W=(await Z`cd ${Y} && git log -1 --format="%h %s"`.quiet()).text().trim(),q={path:Y,name:H,branch:G,hasChanges:V,lastCommit:W};return F.setRepo(q),F.clearHistory(),q}async function b6(Q){let Z=F.getState();if(!Z.repo)throw Error("No repository opened");let Y=[],H=/FILE:\s*([^\n]+)\n```\w*\n([\s\S]*?)```/g;for(let X of Q.matchAll(H)){let G=X[1].trim(),J=X[2],V=y(Z.repo.path,G),$=NZ(V);if(!C($))LQ($,{recursive:!0});wZ(V,J),Y.push(G)}if(Y.length>0&&Z.repo)Z.repo.hasChanges=!0;return Y}async function AZ(){let Q=F.getState();if(!Q.repo||!Q.github)return;let{$:Z}=awaitPromise.resolve(globalThis.Bun),{name:Y,email:H}=Q.github;await Z`cd ${Q.repo.path} && git config user.name ${Y}`.quiet(),await Z`cd ${Q.repo.path} && git config user.email ${H}`.quiet()}async function h6(){let Q=F.getState();if(!Q.repo)throw Error("No repository opened");let{$:Z}=awaitPromise.resolve(globalThis.Bun);if(Q.github)await AZ();await Z`cd ${Q.repo.path} && git add -A`.quiet(),await Z`cd ${Q.repo.path} && git commit -m ${b.commitMessage}`.quiet();let H=(await Z`cd ${Q.repo.path} && git rev-parse --short HEAD`.quiet()).text().trim();return Q.repo.hasChanges=!1,Q.repo.lastCommit=H,H}async function f6(){let Q=F.getState();if(!Q.repo)throw Error("No repository opened");let{$:Z}=awaitPromise.resolve(globalThis.Bun);await Z`cd ${Q.repo.path} && git push`.quiet()}async function g6(Q,Z){let Y=F.getState();if(!Y.repo)throw Error("No repository opened");let H=Z||Y.currentDriver,X=FZ(H);if(Z)F.setCurrentDriver(Z);let G=await MZ(Y.repo.path),J=LZ(G),V=await X.process(Q,J,Y.conversationHistory);return F.addToHistory({role:"user",content:Q}),F.addToHistory({role:"assistant",content:V}),V}async function u6(Q,Z,Y){let H=F.getState();if(!H.repo)throw Error("No repository opened");let X=Z||H.currentDriver,G=["claude-cli-local","claude-sdk"];if(!G.includes(X))throw Error(`Streaming only supported for ${G.join(", ")} drivers. Current: ${X}`);if(Z)F.setCurrentDriver(Z);let J=Q;if(Y&&Y.length>0){let $=`## Previous Conversation
119
119
  Here is our conversation so far:
120
120
 
121
- `;for(let U of Y){let j=U.role==="user"?"User":"Assistant";G+=`**${j}:** ${U.content}
121
+ `;for(let W of Y){let q=W.role==="user"?"User":"Assistant";$+=`**${q}:** ${W.content}
122
122
 
123
- `}G+=`---
123
+ `}$+=`---
124
124
 
125
125
  ## Current Request
126
- `,J=G+Q}let V=await l.processStreaming(J,Z.repo.path);return V.fullResponse.then((G)=>{R.addToHistory({role:"user",content:Q}),R.addToHistory({role:"assistant",content:G})}),V}async function HY(Q,X){if(!K.anthropic)throw Error("Anthropic API key not set. Configure your API key in settings.");let Y=[];if(X&&X.length>0)for(let U of X)Y.push({role:U.role,content:U.content});Y.push({role:"user",content:Q});let Z=`You are a helpful AI assistant. Answer questions naturally and conversationally.
126
+ `,J=$+Q}let V=await n.processStreaming(J,H.repo.path);return V.fullResponse.then(($)=>{F.addToHistory({role:"user",content:Q}),F.addToHistory({role:"assistant",content:$})}),V}async function c6(Q,Z){if(!D.anthropic)throw Error("Anthropic API key not set. Configure your API key in settings.");let Y=[];if(Z&&Z.length>0)for(let W of Z)Y.push({role:W.role,content:W.content});Y.push({role:"user",content:Q});let H=`You are a helpful AI assistant. Answer questions naturally and conversationally.
127
127
  You can discuss any topic - technology, science, philosophy, everyday questions, or anything else the user asks about.
128
- Be concise but thorough. If the user asks about coding or their project specifically, help with that too.`,H=new TextEncoder,W="",J,V=new Promise((U)=>{J=U});return{stream:new ReadableStream({async start(U){try{let j=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":K.anthropic,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:"claude-sonnet-4-20250514",max_tokens:4096,system:Z,stream:!0,messages:Y})});if(!j.ok){let A=await j.text();throw Error(`Claude API error: ${A}`)}let $=j.body?.getReader();if(!$)throw Error("No response body");let q=new TextDecoder,L="";while(!0){let{done:A,value:B}=await $.read();if(A)break;L+=q.decode(B,{stream:!0});let z=L.split(`
129
- `);L=z.pop()||"";for(let E of z)if(E.startsWith("data: ")){let O=E.slice(6);if(O==="[DONE]")continue;try{let _=JSON.parse(O);if(_.type==="content_block_delta"&&_.delta?.text){let C=_.delta.text;W+=C,U.enqueue(H.encode(C))}}catch{}}}R.addToHistory({role:"user",content:Q}),R.addToHistory({role:"assistant",content:W}),J(W),U.close()}catch(j){J(W),U.error(j)}}}),fullResponse:V}}import QX from"process";var d=null;async function GQ(){if(d)return d;let Q=await import("@stacksjs/ts-cloud/aws");if(!Q?.BedrockRuntimeClient)throw Error("@stacksjs/ts-cloud/aws does not export BedrockRuntimeClient \u2014 rebuild ts-cloud or remove the AI dependency.");return d=new Q.BedrockRuntimeClient(QX.env.REGION||"us-east-1"),d}async function i(Q){return(await GQ()).invokeModel(Q)}async function WY(Q){return(await GQ()).invokeModelWithResponseStream(Q)}var XX="amazon.titan-text-express-v1";function UQ(Q){if(Q)return Q;return globalThis.config?.ai?.bedrock?.model||process.env.BEDROCK_MODEL_ID||XX}async function jY(Q,X={}){let{maxTokenCount:Y=512,temperature:Z=0,topP:H=0.9,modelId:W}=X;try{let J=await i({modelId:UQ(W),contentType:"application/json",accept:"*/*",body:JSON.stringify({inputText:`Summarize the following text: ${Q}`,textGenerationConfig:{maxTokenCount:Y,stopSequences:[],temperature:Z,topP:H}})});return JSON.parse(new TextDecoder().decode(J.body)).results[0].outputText}catch(J){throw Error(`Error summarizing text: ${J.message}`)}}async function $Y(Q,X={}){let{maxTokenCount:Y=512,temperature:Z=0,topP:H=0.9,modelId:W}=X;try{let J=await i({modelId:UQ(W),contentType:"application/json",accept:"*/*",body:JSON.stringify({inputText:Q,textGenerationConfig:{maxTokenCount:Y,stopSequences:[],temperature:Z,topP:H}})});return JSON.parse(new TextDecoder().decode(J.body)).results[0].outputText}catch(J){throw Error(`Error asking question: ${J.message}`)}}async function YX(Q,X={}){let{provider:Y="openai",model:Z="dall-e-3",size:H="1024x1024",quality:W="standard",n:J=1,responseFormat:V="url",style:G="vivid"}=X;if(Y==="openai")return ZX(Q,{model:Z,size:H,quality:W,n:J,responseFormat:V,style:G});throw Error(`Image generation not supported for provider: ${Y}. Use 'openai'.`)}async function ZX(Q,X){let Y=process.env.OPENAI_API_KEY;if(!Y)throw Error("OPENAI_API_KEY environment variable is required for image generation.");let Z=await fetch("https://api.openai.com/v1/images/generations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y}`},body:JSON.stringify({model:X.model,prompt:Q,size:X.size,quality:X.quality,n:X.n,response_format:X.responseFormat,style:X.style})});if(!Z.ok){let W=await Z.text();throw Error(`OpenAI Image API error: ${W}`)}return{images:(await Z.json()).data.map((W)=>({url:W.url,b64_json:W.b64_json,revisedPrompt:W.revised_prompt})),provider:"openai",model:X.model}}async function HX(Q,X,Y={}){let Z=process.env.OPENAI_API_KEY;if(!Z)throw Error("OPENAI_API_KEY environment variable is required for image editing.");let H=new FormData;if(H.append("image",Q),H.append("prompt",X),H.append("model",Y.model||"dall-e-2"),Y.mask)H.append("mask",Y.mask);if(Y.n)H.append("n",String(Y.n));if(Y.size)H.append("size",Y.size);if(Y.responseFormat)H.append("response_format",Y.responseFormat);let W=await fetch("https://api.openai.com/v1/images/edits",{method:"POST",headers:{Authorization:`Bearer ${Z}`},body:H});if(!W.ok){let V=await W.text();throw Error(`OpenAI Image Edit API error: ${V}`)}return{images:(await W.json()).data.map((V)=>({url:V.url,b64_json:V.b64_json})),provider:"openai",model:Y.model||"dall-e-2"}}async function JX(Q,X={}){let Y=process.env.OPENAI_API_KEY;if(!Y)throw Error("OPENAI_API_KEY environment variable is required for image variations.");let Z=new FormData;if(Z.append("image",Q),Z.append("model",X.model||"dall-e-2"),X.n)Z.append("n",String(X.n));if(X.size)Z.append("size",X.size);if(X.responseFormat)Z.append("response_format",X.responseFormat);let H=await fetch("https://api.openai.com/v1/images/variations",{method:"POST",headers:{Authorization:`Bearer ${Y}`},body:Z});if(!H.ok){let J=await H.text();throw Error(`OpenAI Image Variations API error: ${J}`)}return{images:(await H.json()).data.map((J)=>({url:J.url,b64_json:J.b64_json})),provider:"openai",model:X.model||"dall-e-2"}}async function VX(Q,X,Y={}){let{provider:Z="anthropic"}=Y;switch(Z){case"anthropic":return WX(Q,X,Y);case"openai":return GX(Q,X,Y);case"ollama":return UX(Q,X,Y);default:throw Error(`Vision not supported for provider: ${Z}`)}}async function h(Q){if(Q.type==="base64")return{data:Q.data,mediaType:Q.mediaType};if(Q.type==="url"){let X=await fetch(Q.url);if(!X.ok)throw Error(`Failed to fetch image from URL: ${Q.url}`);let Y=await X.arrayBuffer(),Z=Buffer.from(Y).toString("base64"),H=X.headers.get("content-type")||"image/png";return{data:Z,mediaType:H}}if(Q.type==="file"){let{readFile:X}=await import("fs/promises"),Z=(await X(Q.path)).toString("base64"),H=Q.path.split(".").pop()?.toLowerCase()||"png";return{data:Z,mediaType:{png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp"}[H]||"image/png"}}throw Error("Invalid image input type")}async function WX(Q,X,Y){let Z=process.env.ANTHROPIC_API_KEY;if(!Z)throw Error("ANTHROPIC_API_KEY environment variable is required for Claude vision.");let{data:H,mediaType:W}=await h(Q),J=Y.model||"claude-sonnet-4-20250514",V=Y.maxTokens||4096,G=[{role:"user",content:[{type:"image",source:{type:"base64",media_type:W,data:H}},{type:"text",text:X}]}],U=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":Z,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:J,max_tokens:V,temperature:Y.temperature,messages:G})});if(!U.ok){let $=await U.text();throw Error(`Claude Vision API error: ${$}`)}let j=await U.json();return{content:j.content[0].text,model:j.model,provider:"anthropic",usage:{promptTokens:j.usage?.input_tokens||0,completionTokens:j.usage?.output_tokens||0,totalTokens:(j.usage?.input_tokens||0)+(j.usage?.output_tokens||0)},finishReason:j.stop_reason}}async function GX(Q,X,Y){let Z=process.env.OPENAI_API_KEY;if(!Z)throw Error("OPENAI_API_KEY environment variable is required for GPT-4 vision.");let H=Y.model||"gpt-4o",W=Y.maxTokens||4096,J=Y.detail||"auto",V;if(Q.type==="url")V={type:"image_url",image_url:{url:Q.url,detail:J}};else{let{data:j,mediaType:$}=await h(Q);V={type:"image_url",image_url:{url:`data:${$};base64,${j}`,detail:J}}}let G=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Z}`},body:JSON.stringify({model:H,max_tokens:W,temperature:Y.temperature,messages:[{role:"user",content:[V,{type:"text",text:X}]}]})});if(!G.ok){let j=await G.text();throw Error(`OpenAI Vision API error: ${j}`)}let U=await G.json();return{content:U.choices[0].message.content,model:U.model,provider:"openai",usage:{promptTokens:U.usage?.prompt_tokens||0,completionTokens:U.usage?.completion_tokens||0,totalTokens:U.usage?.total_tokens||0},finishReason:U.choices[0].finish_reason}}async function UX(Q,X,Y){let Z=process.env.OLLAMA_HOST||"http://localhost:11434",H=Y.model||"llava",{data:W}=await h(Q),J=await fetch(`${Z}/api/generate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:H,prompt:X,images:[W],stream:!1})});if(!J.ok){let G=await J.text();throw Error(`Ollama Vision API error: ${G}`)}let V=await J.json();return{content:V.response,model:V.model,provider:"ollama",usage:{promptTokens:V.prompt_eval_count||0,completionTokens:V.eval_count||0,totalTokens:(V.prompt_eval_count||0)+(V.eval_count||0)}}}async function jX(Q,X,Y={}){let{provider:Z="anthropic"}=Y;if(Z==="anthropic"){let H=process.env.ANTHROPIC_API_KEY;if(!H)throw Error("ANTHROPIC_API_KEY required for multi-image analysis.");let W=Y.model||"claude-sonnet-4-20250514",J=[];for(let U of Q){let{data:j,mediaType:$}=await h(U);J.push({type:"image",source:{type:"base64",media_type:$,data:j}})}J.push({type:"text",text:X});let V=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":H,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:W,max_tokens:Y.maxTokens||4096,temperature:Y.temperature,messages:[{role:"user",content:J}]})});if(!V.ok){let U=await V.text();throw Error(`Claude Vision API error: ${U}`)}let G=await V.json();return{content:G.content[0].text,model:G.model,provider:"anthropic",usage:{promptTokens:G.usage?.input_tokens||0,completionTokens:G.usage?.output_tokens||0,totalTokens:(G.usage?.input_tokens||0)+(G.usage?.output_tokens||0)},finishReason:G.stop_reason}}if(Z==="openai"){let H=process.env.OPENAI_API_KEY;if(!H)throw Error("OPENAI_API_KEY required for multi-image analysis.");let W=Y.model||"gpt-4o",J=Y.detail||"auto",V=[];for(let j of Q)if(j.type==="url")V.push({type:"image_url",image_url:{url:j.url,detail:J}});else{let{data:$,mediaType:q}=await h(j);V.push({type:"image_url",image_url:{url:`data:${q};base64,${$}`,detail:J}})}V.push({type:"text",text:X});let G=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${H}`},body:JSON.stringify({model:W,max_tokens:Y.maxTokens||4096,temperature:Y.temperature,messages:[{role:"user",content:V}]})});if(!G.ok){let j=await G.text();throw Error(`OpenAI Vision API error: ${j}`)}let U=await G.json();return{content:U.choices[0].message.content,model:U.model,provider:"openai",usage:{promptTokens:U.usage?.prompt_tokens||0,completionTokens:U.usage?.completion_tokens||0,totalTokens:U.usage?.total_tokens||0},finishReason:U.choices[0].finish_reason}}throw Error(`Multi-image analysis not supported for provider: ${Z}`)}var zY={generate:YX,edit:HX,variation:JX,analyze:VX,analyzeMultiple:jX};async function a(Q,X={}){let{provider:Y="openai"}=X;if(Y==="openai")return $X(Q,X.model||"text-embedding-3-small");if(Y==="ollama")return qX(Q,X.model||"nomic-embed-text");throw Error(`Embedding provider not supported: ${Y}`)}async function $X(Q,X){let Y=process.env.OPENAI_API_KEY;if(!Y)throw Error("OPENAI_API_KEY environment variable is required for embeddings.");let Z=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y}`},body:JSON.stringify({model:X,input:Q})});if(!Z.ok){let W=await Z.text();throw Error(`OpenAI Embeddings API error: ${W}`)}let H=await Z.json();if(Array.isArray(Q))return H.data.map((W)=>W.embedding);return H.data[0].embedding}async function qX(Q,X){let Y=process.env.OLLAMA_HOST||"http://localhost:11434",Z=Array.isArray(Q)?Q:[Q],H=[];for(let W of Z){let J=await fetch(`${Y}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:X,prompt:W})});if(!J.ok){let G=await J.text();throw Error(`Ollama Embeddings API error: ${G}`)}let V=await J.json();H.push(V.embedding)}return Array.isArray(Q)?H:H[0]}function jQ(Q,X){if(Q.length!==X.length)throw Error(`Vector dimensions must match: ${Q.length} vs ${X.length}`);let Y=0,Z=0,H=0;for(let J=0;J<Q.length;J++)Y+=Q[J]*X[J],Z+=Q[J]*Q[J],H+=X[J]*X[J];let W=Math.sqrt(Z)*Math.sqrt(H);if(W===0)return 0;return Y/W}function zX(Q,X){if(Q.length!==X.length)throw Error(`Vector dimensions must match: ${Q.length} vs ${X.length}`);let Y=0;for(let Z=0;Z<Q.length;Z++)Y+=Q[Z]*X[Z];return Y}function BX(Q,X){if(Q.length!==X.length)throw Error(`Vector dimensions must match: ${Q.length} vs ${X.length}`);let Y=0;for(let Z=0;Z<Q.length;Z++){let H=Q[Z]-X[Z];Y+=H*H}return Math.sqrt(Y)}class r{documents=[];embeddingOptions;constructor(Q={}){this.embeddingOptions=Q}async add(Q){if(Q.length===0)return;let X=Q.map((H)=>H.content),Y=await a(X,this.embeddingOptions),Z=X.length===1?[Y]:Y;for(let H=0;H<Q.length;H++)this.documents.push({...Q[H],embedding:Z[H]})}addWithEmbedding(Q,X){this.documents.push({...Q,embedding:X})}async search(Q,X=5){if(this.documents.length===0)return[];let Y=await a(Q,this.embeddingOptions);return this.searchByVector(Y,X)}searchByVector(Q,X=5){if(this.documents.length===0)return[];let Y=this.documents.map((Z)=>({document:{id:Z.id,content:Z.content,metadata:Z.metadata},score:jQ(Q,Z.embedding)}));return Y.sort((Z,H)=>H.score-Z.score),Y.slice(0,X).map((Z,H)=>({...Z,rank:H+1}))}remove(Q){let X=this.documents.length;return this.documents=this.documents.filter((Y)=>Y.id!==Q),this.documents.length<X}clear(){this.documents=[]}get size(){return this.documents.length}get ids(){return this.documents.map((Q)=>Q.id)}}async function EX(Q,X,Y={}){let{provider:Z="anthropic",topK:H=5,maxTokens:W=4096,temperature:J,systemPrompt:V}=Y,G=await X.search(Q,H),U=G.map((q,L)=>`[Source ${L+1}] (score: ${q.score.toFixed(3)})
130
- ${q.document.content}`).join(`
128
+ Be concise but thorough. If the user asks about coding or their project specifically, help with that too.`,X=new TextEncoder,G="",J,V=new Promise((W)=>{J=W});return{stream:new ReadableStream({async start(W){try{let q=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":D.anthropic,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:"claude-sonnet-4-20250514",max_tokens:4096,system:H,stream:!0,messages:Y})});if(!q.ok){let O=await q.text();throw Error(`Claude API error: ${O}`)}let z=q.body?.getReader();if(!z)throw Error("No response body");let B=new TextDecoder,w="";while(!0){let{done:O,value:U}=await z.read();if(O)break;w+=B.decode(U,{stream:!0});let j=w.split(`
129
+ `);w=j.pop()||"";for(let K of j)if(K.startsWith("data: ")){let N=K.slice(6);if(N==="[DONE]")continue;try{let L=JSON.parse(N);if(L.type==="content_block_delta"&&L.delta?.text){let R=L.delta.text;G+=R,W.enqueue(X.encode(R))}}catch{}}}F.addToHistory({role:"user",content:Q}),F.addToHistory({role:"assistant",content:G}),J(G),W.close()}catch(q){J(G),W.error(q)}}}),fullResponse:V}}import _Z from"process";var r=null;async function FQ(){if(r)return r;let Q=await import("@stacksjs/ts-cloud/aws");if(!Q?.BedrockRuntimeClient)throw Error("@stacksjs/ts-cloud/aws does not export BedrockRuntimeClient \u2014 rebuild ts-cloud or remove the AI dependency.");return r=new Q.BedrockRuntimeClient(_Z.env.REGION||"us-east-1"),r}async function HQ(Q){return(await FQ()).invokeModel(Q)}async function m6(Q){return(await FQ()).invokeModelWithResponseStream(Q)}var EZ="amazon.titan-text-express-v1";function MQ(Q){if(Q)return Q;return globalThis.config?.ai?.bedrock?.model||process.env.BEDROCK_MODEL_ID||EZ}async function a6(Q,Z={}){let{maxTokenCount:Y=512,temperature:H=0,topP:X=0.9,modelId:G}=Z;try{let J=await HQ({modelId:MQ(G),contentType:"application/json",accept:"*/*",body:JSON.stringify({inputText:`Summarize the following text: ${Q}`,textGenerationConfig:{maxTokenCount:Y,stopSequences:[],temperature:H,topP:X}})});return JSON.parse(new TextDecoder().decode(J.body)).results[0].outputText}catch(J){throw Error(`Error summarizing text: ${J.message}`)}}async function n6(Q,Z={}){let{maxTokenCount:Y=512,temperature:H=0,topP:X=0.9,modelId:G}=Z;try{let J=await HQ({modelId:MQ(G),contentType:"application/json",accept:"*/*",body:JSON.stringify({inputText:Q,textGenerationConfig:{maxTokenCount:Y,stopSequences:[],temperature:H,topP:X}})});return JSON.parse(new TextDecoder().decode(J.body)).results[0].outputText}catch(J){throw Error(`Error asking question: ${J.message}`)}}async function IZ(Q,Z={}){let{provider:Y="openai",model:H="dall-e-3",size:X="1024x1024",quality:G="standard",n:J=1,responseFormat:V="url",style:$="vivid"}=Z;if(Y==="openai")return TZ(Q,{model:H,size:X,quality:G,n:J,responseFormat:V,style:$});throw Error(`Image generation not supported for provider: ${Y}. Use 'openai'.`)}async function TZ(Q,Z){let Y=process.env.OPENAI_API_KEY;if(!Y)throw Error("OPENAI_API_KEY environment variable is required for image generation.");let H=await fetch("https://api.openai.com/v1/images/generations",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y}`},body:JSON.stringify({model:Z.model,prompt:Q,size:Z.size,quality:Z.quality,n:Z.n,response_format:Z.responseFormat,style:Z.style})});if(!H.ok){let G=await H.text();throw Error(`OpenAI Image API error: ${G}`)}return{images:(await H.json()).data.map((G)=>({url:G.url,b64_json:G.b64_json,revisedPrompt:G.revised_prompt})),provider:"openai",model:Z.model}}async function DZ(Q,Z,Y={}){let H=process.env.OPENAI_API_KEY;if(!H)throw Error("OPENAI_API_KEY environment variable is required for image editing.");let X=new FormData;if(X.append("image",Q),X.append("prompt",Z),X.append("model",Y.model||"dall-e-2"),Y.mask)X.append("mask",Y.mask);if(Y.n)X.append("n",String(Y.n));if(Y.size)X.append("size",Y.size);if(Y.responseFormat)X.append("response_format",Y.responseFormat);let G=await fetch("https://api.openai.com/v1/images/edits",{method:"POST",headers:{Authorization:`Bearer ${H}`},body:X});if(!G.ok){let V=await G.text();throw Error(`OpenAI Image Edit API error: ${V}`)}return{images:(await G.json()).data.map((V)=>({url:V.url,b64_json:V.b64_json})),provider:"openai",model:Y.model||"dall-e-2"}}async function CZ(Q,Z={}){let Y=process.env.OPENAI_API_KEY;if(!Y)throw Error("OPENAI_API_KEY environment variable is required for image variations.");let H=new FormData;if(H.append("image",Q),H.append("model",Z.model||"dall-e-2"),Z.n)H.append("n",String(Z.n));if(Z.size)H.append("size",Z.size);if(Z.responseFormat)H.append("response_format",Z.responseFormat);let X=await fetch("https://api.openai.com/v1/images/variations",{method:"POST",headers:{Authorization:`Bearer ${Y}`},body:H});if(!X.ok){let J=await X.text();throw Error(`OpenAI Image Variations API error: ${J}`)}return{images:(await X.json()).data.map((J)=>({url:J.url,b64_json:J.b64_json})),provider:"openai",model:Z.model||"dall-e-2"}}async function xZ(Q,Z,Y={}){let{provider:H="anthropic"}=Y;switch(H){case"anthropic":return SZ(Q,Z,Y);case"openai":return PZ(Q,Z,Y);case"ollama":return kZ(Q,Z,Y);default:throw Error(`Vision not supported for provider: ${H}`)}}async function d(Q){if(Q.type==="base64")return{data:Q.data,mediaType:Q.mediaType};if(Q.type==="url"){let Z=await fetch(Q.url);if(!Z.ok)throw Error(`Failed to fetch image from URL: ${Q.url}`);let Y=await Z.arrayBuffer(),H=Buffer.from(Y).toString("base64"),X=Z.headers.get("content-type")||"image/png";return{data:H,mediaType:X}}if(Q.type==="file"){let{readFile:Z}=await import("fs/promises"),H=(await Z(Q.path)).toString("base64"),X=Q.path.split(".").pop()?.toLowerCase()||"png";return{data:H,mediaType:{png:"image/png",jpg:"image/jpeg",jpeg:"image/jpeg",gif:"image/gif",webp:"image/webp"}[X]||"image/png"}}throw Error("Invalid image input type")}async function SZ(Q,Z,Y){let H=process.env.ANTHROPIC_API_KEY;if(!H)throw Error("ANTHROPIC_API_KEY environment variable is required for Claude vision.");let{data:X,mediaType:G}=await d(Q),J=Y.model||"claude-sonnet-4-20250514",V=Y.maxTokens||4096,$=[{role:"user",content:[{type:"image",source:{type:"base64",media_type:G,data:X}},{type:"text",text:Z}]}],W=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":H,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:J,max_tokens:V,temperature:Y.temperature,messages:$})});if(!W.ok){let z=await W.text();throw Error(`Claude Vision API error: ${z}`)}let q=await W.json();return{content:q.content[0].text,model:q.model,provider:"anthropic",usage:{promptTokens:q.usage?.input_tokens||0,completionTokens:q.usage?.output_tokens||0,totalTokens:(q.usage?.input_tokens||0)+(q.usage?.output_tokens||0)},finishReason:q.stop_reason}}async function PZ(Q,Z,Y){let H=process.env.OPENAI_API_KEY;if(!H)throw Error("OPENAI_API_KEY environment variable is required for GPT-4 vision.");let X=Y.model||"gpt-4o",G=Y.maxTokens||4096,J=Y.detail||"auto",V;if(Q.type==="url")V={type:"image_url",image_url:{url:Q.url,detail:J}};else{let{data:q,mediaType:z}=await d(Q);V={type:"image_url",image_url:{url:`data:${z};base64,${q}`,detail:J}}}let $=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${H}`},body:JSON.stringify({model:X,max_tokens:G,temperature:Y.temperature,messages:[{role:"user",content:[V,{type:"text",text:Z}]}]})});if(!$.ok){let q=await $.text();throw Error(`OpenAI Vision API error: ${q}`)}let W=await $.json();return{content:W.choices[0].message.content,model:W.model,provider:"openai",usage:{promptTokens:W.usage?.prompt_tokens||0,completionTokens:W.usage?.completion_tokens||0,totalTokens:W.usage?.total_tokens||0},finishReason:W.choices[0].finish_reason}}async function kZ(Q,Z,Y){let H=process.env.OLLAMA_HOST||"http://localhost:11434",X=Y.model||"llava",{data:G}=await d(Q),J=await fetch(`${H}/api/generate`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:X,prompt:Z,images:[G],stream:!1})});if(!J.ok){let $=await J.text();throw Error(`Ollama Vision API error: ${$}`)}let V=await J.json();return{content:V.response,model:V.model,provider:"ollama",usage:{promptTokens:V.prompt_eval_count||0,completionTokens:V.eval_count||0,totalTokens:(V.prompt_eval_count||0)+(V.eval_count||0)}}}async function vZ(Q,Z,Y={}){let{provider:H="anthropic"}=Y;if(H==="anthropic"){let X=process.env.ANTHROPIC_API_KEY;if(!X)throw Error("ANTHROPIC_API_KEY required for multi-image analysis.");let G=Y.model||"claude-sonnet-4-20250514",J=[];for(let W of Q){let{data:q,mediaType:z}=await d(W);J.push({type:"image",source:{type:"base64",media_type:z,data:q}})}J.push({type:"text",text:Z});let V=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":X,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:G,max_tokens:Y.maxTokens||4096,temperature:Y.temperature,messages:[{role:"user",content:J}]})});if(!V.ok){let W=await V.text();throw Error(`Claude Vision API error: ${W}`)}let $=await V.json();return{content:$.content[0].text,model:$.model,provider:"anthropic",usage:{promptTokens:$.usage?.input_tokens||0,completionTokens:$.usage?.output_tokens||0,totalTokens:($.usage?.input_tokens||0)+($.usage?.output_tokens||0)},finishReason:$.stop_reason}}if(H==="openai"){let X=process.env.OPENAI_API_KEY;if(!X)throw Error("OPENAI_API_KEY required for multi-image analysis.");let G=Y.model||"gpt-4o",J=Y.detail||"auto",V=[];for(let q of Q)if(q.type==="url")V.push({type:"image_url",image_url:{url:q.url,detail:J}});else{let{data:z,mediaType:B}=await d(q);V.push({type:"image_url",image_url:{url:`data:${B};base64,${z}`,detail:J}})}V.push({type:"text",text:Z});let $=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify({model:G,max_tokens:Y.maxTokens||4096,temperature:Y.temperature,messages:[{role:"user",content:V}]})});if(!$.ok){let q=await $.text();throw Error(`OpenAI Vision API error: ${q}`)}let W=await $.json();return{content:W.choices[0].message.content,model:W.model,provider:"openai",usage:{promptTokens:W.usage?.prompt_tokens||0,completionTokens:W.usage?.completion_tokens||0,totalTokens:W.usage?.total_tokens||0},finishReason:W.choices[0].finish_reason}}throw Error(`Multi-image analysis not supported for provider: ${H}`)}var s6={generate:IZ,edit:DZ,variation:CZ,analyze:xZ,analyzeMultiple:vZ};async function XQ(Q,Z={}){let{provider:Y="openai"}=Z;if(Y==="openai")return yZ(Q,Z.model||"text-embedding-3-small");if(Y==="ollama")return bZ(Q,Z.model||"nomic-embed-text");throw Error(`Embedding provider not supported: ${Y}`)}async function yZ(Q,Z){let Y=process.env.OPENAI_API_KEY;if(!Y)throw Error("OPENAI_API_KEY environment variable is required for embeddings.");let H=await fetch("https://api.openai.com/v1/embeddings",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${Y}`},body:JSON.stringify({model:Z,input:Q})});if(!H.ok){let G=await H.text();throw Error(`OpenAI Embeddings API error: ${G}`)}let X=await H.json();if(Array.isArray(Q))return X.data.map((G)=>G.embedding);return X.data[0].embedding}async function bZ(Q,Z){let Y=process.env.OLLAMA_HOST||"http://localhost:11434",H=Array.isArray(Q)?Q:[Q],X=[];for(let G of H){let J=await fetch(`${Y}/api/embeddings`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z,prompt:G})});if(!J.ok){let $=await J.text();throw Error(`Ollama Embeddings API error: ${$}`)}let V=await J.json();X.push(V.embedding)}return Array.isArray(Q)?X:X[0]}function AQ(Q,Z){if(Q.length!==Z.length)throw Error(`Vector dimensions must match: ${Q.length} vs ${Z.length}`);let Y=0,H=0,X=0;for(let J=0;J<Q.length;J++)Y+=Q[J]*Z[J],H+=Q[J]*Q[J],X+=Z[J]*Z[J];let G=Math.sqrt(H)*Math.sqrt(X);if(G===0)return 0;return Y/G}function hZ(Q,Z){if(Q.length!==Z.length)throw Error(`Vector dimensions must match: ${Q.length} vs ${Z.length}`);let Y=0;for(let H=0;H<Q.length;H++)Y+=Q[H]*Z[H];return Y}function fZ(Q,Z){if(Q.length!==Z.length)throw Error(`Vector dimensions must match: ${Q.length} vs ${Z.length}`);let Y=0;for(let H=0;H<Q.length;H++){let X=Q[H]-Z[H];Y+=X*X}return Math.sqrt(Y)}class JQ{documents=[];embeddingOptions;constructor(Q={}){this.embeddingOptions=Q}async add(Q){if(Q.length===0)return;let Z=Q.map((X)=>X.content),Y=await XQ(Z,this.embeddingOptions),H=Z.length===1?[Y]:Y;for(let X=0;X<Q.length;X++)this.documents.push({...Q[X],embedding:H[X]})}addWithEmbedding(Q,Z){this.documents.push({...Q,embedding:Z})}async search(Q,Z=5){if(this.documents.length===0)return[];let Y=await XQ(Q,this.embeddingOptions);return this.searchByVector(Y,Z)}searchByVector(Q,Z=5){if(this.documents.length===0)return[];let Y=this.documents.map((H)=>({document:{id:H.id,content:H.content,metadata:H.metadata},score:AQ(Q,H.embedding)}));return Y.sort((H,X)=>X.score-H.score),Y.slice(0,Z).map((H,X)=>({...H,rank:X+1}))}remove(Q){let Z=this.documents.length;return this.documents=this.documents.filter((Y)=>Y.id!==Q),this.documents.length<Z}clear(){this.documents=[]}get size(){return this.documents.length}get ids(){return this.documents.map((Q)=>Q.id)}}async function gZ(Q,Z,Y={}){let{provider:H="anthropic",topK:X=5,maxTokens:G=4096,temperature:J,systemPrompt:V}=Y,$=await Z.search(Q,X),W=$.map((B,w)=>`[Source ${w+1}] (score: ${B.score.toFixed(3)})
130
+ ${B.document.content}`).join(`
131
131
 
132
132
  ---
133
133
 
134
- `),j=V||"You are a helpful assistant. Answer the user's question based on the provided context. If the context doesn't contain relevant information, say so. Always cite your sources by referencing [Source N].",$=`Context:
135
- ${U}
134
+ `),q=V||"You are a helpful assistant. Answer the user's question based on the provided context. If the context doesn't contain relevant information, say so. Always cite your sources by referencing [Source N].",z=`Context:
135
+ ${W}
136
136
 
137
- Question: ${Q}`;if(Z==="anthropic")return LX($,j,G,{maxTokens:W,temperature:J,model:Y.model});if(Z==="openai")return AX($,j,G,{maxTokens:W,temperature:J,model:Y.model});if(Z==="ollama")return OX($,j,G,{maxTokens:W,temperature:J,model:Y.model});throw Error(`RAG provider not supported: ${Z}`)}async function LX(Q,X,Y,Z){let H=process.env.ANTHROPIC_API_KEY;if(!H)throw Error("ANTHROPIC_API_KEY required for RAG with Anthropic.");let W=Z.model||"claude-sonnet-4-20250514",J=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":H,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:W,max_tokens:Z.maxTokens||4096,temperature:Z.temperature,system:X,messages:[{role:"user",content:Q}]})});if(!J.ok){let G=await J.text();throw Error(`Claude API error: ${G}`)}let V=await J.json();return{content:V.content[0].text,model:V.model,usage:{promptTokens:V.usage?.input_tokens||0,completionTokens:V.usage?.output_tokens||0,totalTokens:(V.usage?.input_tokens||0)+(V.usage?.output_tokens||0)},finishReason:V.stop_reason,sources:Y}}async function AX(Q,X,Y,Z){let H=process.env.OPENAI_API_KEY;if(!H)throw Error("OPENAI_API_KEY required for RAG with OpenAI.");let W=Z.model||"gpt-4o",J=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${H}`},body:JSON.stringify({model:W,max_tokens:Z.maxTokens||4096,temperature:Z.temperature,messages:[{role:"system",content:X},{role:"user",content:Q}]})});if(!J.ok){let G=await J.text();throw Error(`OpenAI API error: ${G}`)}let V=await J.json();return{content:V.choices[0].message.content,model:V.model,usage:{promptTokens:V.usage?.prompt_tokens||0,completionTokens:V.usage?.completion_tokens||0,totalTokens:V.usage?.total_tokens||0},finishReason:V.choices[0].finish_reason,sources:Y}}async function OX(Q,X,Y,Z){let H=process.env.OLLAMA_HOST||"http://localhost:11434",W=Z.model||"llama3.2",J=await fetch(`${H}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:W,messages:[{role:"system",content:X},{role:"user",content:Q}],stream:!1,options:{temperature:Z.temperature}})});if(!J.ok){let G=await J.text();throw Error(`Ollama API error: ${G}`)}let V=await J.json();return{content:V.message.content,model:V.model,usage:{promptTokens:V.prompt_eval_count||0,completionTokens:V.eval_count||0,totalTokens:(V.prompt_eval_count||0)+(V.eval_count||0)},finishReason:V.done_reason||"stop",sources:Y}}function $Q(Q,X={}){let{chunkSize:Y=1000,chunkOverlap:Z=200,separator:H=`
138
- `}=X,W=Q.split(H),J=[],V="";for(let G of W)if(V.length+G.length+1>Y&&V.length>0)if(J.push(V.trim()),Z>0){let U=Math.max(0,V.length-Z);V=V.slice(U)+H+G}else V=G;else V+=(V?H:"")+G;if(V.trim())J.push(V.trim());return J}async function _X(Q,X={}){let Y=$Q(Q,X),Z=new r(X),H=Y.map((W,J)=>({id:`${X.idPrefix||"chunk"}-${J}`,content:W,metadata:{chunkIndex:J,totalChunks:Y.length}}));return await Z.add(H),Z}var EY={createEmbedding:a,cosineSimilarity:jQ,dotProduct:zX,euclideanDistance:BX,VectorIndex:r,rag:EX,chunkText:$Q,indexText:_X};async function RX(Q,X={}){let{provider:Y="anthropic",aspects:Z}=X,H=Z?`
139
- Also analyze sentiment for these specific aspects: ${Z.join(", ")}`:"",W=`You are a sentiment analysis expert. Analyze the sentiment of the given text and respond with ONLY valid JSON in this exact format:
137
+ Question: ${Q}`;if(H==="anthropic")return uZ(z,q,$,{maxTokens:G,temperature:J,model:Y.model});if(H==="openai")return cZ(z,q,$,{maxTokens:G,temperature:J,model:Y.model});if(H==="ollama")return dZ(z,q,$,{maxTokens:G,temperature:J,model:Y.model});throw Error(`RAG provider not supported: ${H}`)}async function uZ(Q,Z,Y,H){let X=process.env.ANTHROPIC_API_KEY;if(!X)throw Error("ANTHROPIC_API_KEY required for RAG with Anthropic.");let G=H.model||"claude-sonnet-4-20250514",J=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":X,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:G,max_tokens:H.maxTokens||4096,temperature:H.temperature,system:Z,messages:[{role:"user",content:Q}]})});if(!J.ok){let $=await J.text();throw Error(`Claude API error: ${$}`)}let V=await J.json();return{content:V.content[0].text,model:V.model,usage:{promptTokens:V.usage?.input_tokens||0,completionTokens:V.usage?.output_tokens||0,totalTokens:(V.usage?.input_tokens||0)+(V.usage?.output_tokens||0)},finishReason:V.stop_reason,sources:Y}}async function cZ(Q,Z,Y,H){let X=process.env.OPENAI_API_KEY;if(!X)throw Error("OPENAI_API_KEY required for RAG with OpenAI.");let G=H.model||"gpt-4o",J=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify({model:G,max_tokens:H.maxTokens||4096,temperature:H.temperature,messages:[{role:"system",content:Z},{role:"user",content:Q}]})});if(!J.ok){let $=await J.text();throw Error(`OpenAI API error: ${$}`)}let V=await J.json();return{content:V.choices[0].message.content,model:V.model,usage:{promptTokens:V.usage?.prompt_tokens||0,completionTokens:V.usage?.completion_tokens||0,totalTokens:V.usage?.total_tokens||0},finishReason:V.choices[0].finish_reason,sources:Y}}async function dZ(Q,Z,Y,H){let X=process.env.OLLAMA_HOST||"http://localhost:11434",G=H.model||"llama3.2",J=await fetch(`${X}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:G,messages:[{role:"system",content:Z},{role:"user",content:Q}],stream:!1,options:{temperature:H.temperature}})});if(!J.ok){let $=await J.text();throw Error(`Ollama API error: ${$}`)}let V=await J.json();return{content:V.message.content,model:V.model,usage:{promptTokens:V.prompt_eval_count||0,completionTokens:V.eval_count||0,totalTokens:(V.prompt_eval_count||0)+(V.eval_count||0)},finishReason:V.done_reason||"stop",sources:Y}}function _Q(Q,Z={}){let{chunkSize:Y=1000,chunkOverlap:H=200,separator:X=`
138
+ `}=Z,G=Q.split(X),J=[],V="";for(let $ of G)if(V.length+$.length+1>Y&&V.length>0)if(J.push(V.trim()),H>0){let W=Math.max(0,V.length-H);V=V.slice(W)+X+$}else V=$;else V+=(V?X:"")+$;if(V.trim())J.push(V.trim());return J}async function lZ(Q,Z={}){let Y=_Q(Q,Z),H=new JQ(Z),X=Y.map((G,J)=>({id:`${Z.idPrefix||"chunk"}-${J}`,content:G,metadata:{chunkIndex:J,totalChunks:Y.length}}));return await H.add(X),H}var t6={createEmbedding:XQ,cosineSimilarity:AQ,dotProduct:hZ,euclideanDistance:fZ,VectorIndex:JQ,rag:gZ,chunkText:_Q,indexText:lZ};async function mZ(Q,Z={}){let{provider:Y="anthropic",aspects:H}=Z,X=H?`
139
+ Also analyze sentiment for these specific aspects: ${H.join(", ")}`:"",G=`You are a sentiment analysis expert. Analyze the sentiment of the given text and respond with ONLY valid JSON in this exact format:
140
140
  {
141
141
  "sentiment": "positive" | "negative" | "neutral" | "mixed",
142
142
  "score": <number from -1.0 to 1.0>,
143
- "confidence": <number from 0.0 to 1.0>${Z?`,
143
+ "confidence": <number from 0.0 to 1.0>${H?`,
144
144
  "aspects": [{"aspect": "<name>", "sentiment": "positive" | "negative" | "neutral", "score": <number>}]`:""}
145
- }${H}`,J=await y(Y,W,Q,X.model);try{return JSON.parse(J.content)}catch{let V=J.content.toLowerCase(),G=V.includes("positive"),U=V.includes("negative");return{sentiment:G&&U?"mixed":G?"positive":U?"negative":"neutral",score:G?0.5:U?-0.5:0,confidence:0.5}}}async function FX(Q,X,Y={}){let{provider:Z="anthropic",multiLabel:H=!1}=Y,W=`You are a text classification expert. Classify the given text into ${H?"one or more of":"exactly one of"} these categories: ${X.join(", ")}.
145
+ }${X}`,J=await l(Y,G,Q,Z.model);try{return JSON.parse(J.content)}catch{let V=J.content.toLowerCase(),$=V.includes("positive"),W=V.includes("negative");return{sentiment:$&&W?"mixed":$?"positive":W?"negative":"neutral",score:$?0.5:W?-0.5:0,confidence:0.5}}}async function pZ(Q,Z,Y={}){let{provider:H="anthropic",multiLabel:X=!1}=Y,G=`You are a text classification expert. Classify the given text into ${X?"one or more of":"exactly one of"} these categories: ${Z.join(", ")}.
146
146
 
147
147
  Respond with ONLY valid JSON in this exact format:
148
148
  {
@@ -151,9 +151,9 @@ Respond with ONLY valid JSON in this exact format:
151
151
  "allLabels": [{"label": "<label>", "confidence": <number>}]
152
152
  }
153
153
 
154
- Include ALL provided labels in allLabels with their confidence scores, sorted by confidence descending.`,J=await y(Z,W,Q,Y.model);try{return JSON.parse(J.content)}catch{return{label:X[0],confidence:0.5,allLabels:X.map((V)=>({label:V,confidence:1/X.length}))}}}async function NX(Q,X={}){let{provider:Y="anthropic",style:Z="concise",maxLength:H,language:W}=X,J;switch(Z){case"bullet-points":J="Use bullet points to organize the key points.";break;case"detailed":J="Provide a detailed summary covering all major points.";break;default:J="Be concise and focus on the most important points."}let V=H?` Keep the summary under ${H} words.`:"",G=W?` Write the summary in ${W}.`:"",U=`You are an expert summarizer. ${J}${V}${G}`;return y(Y,U,`Summarize the following text:
154
+ Include ALL provided labels in allLabels with their confidence scores, sorted by confidence descending.`,J=await l(H,G,Q,Y.model);try{return JSON.parse(J.content)}catch{return{label:Z[0],confidence:0.5,allLabels:Z.map((V)=>({label:V,confidence:1/Z.length}))}}}async function iZ(Q,Z={}){let{provider:Y="anthropic",style:H="concise",maxLength:X,language:G}=Z,J;switch(H){case"bullet-points":J="Use bullet points to organize the key points.";break;case"detailed":J="Provide a detailed summary covering all major points.";break;default:J="Be concise and focus on the most important points."}let V=X?` Keep the summary under ${X} words.`:"",$=G?` Write the summary in ${G}.`:"",W=`You are an expert summarizer. ${J}${V}${$}`;return l(Y,W,`Summarize the following text:
155
155
 
156
- ${Q}`,X.model)}async function wX(Q,X,Y={}){let{provider:Z="anthropic",limit:H=5}=Y,W=MX(Q),J=X.map((j)=>`ID: ${j.id} | Category: ${j.category||"none"} | Tags: ${j.tags?.join(", ")||"none"} | Content: ${j.content.slice(0,200)}`).join(`
156
+ ${Q}`,Z.model)}async function aZ(Q,Z,Y={}){let{provider:H="anthropic",limit:X=5}=Y,G=nZ(Q),J=Z.map((q)=>`ID: ${q.id} | Category: ${q.category||"none"} | Tags: ${q.tags?.join(", ")||"none"} | Content: ${q.content.slice(0,200)}`).join(`
157
157
  `),V=`You are a recommendation engine. Based on the user profile, recommend the most relevant items. Respond with ONLY valid JSON:
158
158
  {
159
159
  "recommendations": [
@@ -161,15 +161,15 @@ ${Q}`,X.model)}async function wX(Q,X,Y={}){let{provider:Z="anthropic",limit:H=5}
161
161
  ]
162
162
  }
163
163
 
164
- Return at most ${H} recommendations, sorted by relevance score descending.`,G=`User Profile:
165
- ${W}
164
+ Return at most ${X} recommendations, sorted by relevance score descending.`,$=`User Profile:
165
+ ${G}
166
166
 
167
167
  Available Items:
168
- ${J}`,U=await y(Z,V,G,Y.model);try{return{recommendations:JSON.parse(U.content).recommendations.slice(0,H),model:U.model,provider:Z}}catch{return{recommendations:[],model:U.model,provider:Z}}}function MX(Q){let X=Object.entries(Q.preferences).sort(([,Z],[,H])=>H-Z).slice(0,10).map(([Z,H])=>`${Z}: ${H.toFixed(2)}`).join(", "),Y=Q.interactions.sort((Z,H)=>H.timestamp-Z.timestamp).slice(0,10).map((Z)=>`${Z.type} on ${Z.itemId}`).join(", ");return`Segments: ${Q.segments.join(", ")}
169
- Top Preferences: ${X||"none"}
170
- Recent Interactions: ${Y||"none"}`}function KX(Q,X=[]){return{id:Q,preferences:{},interactions:[],segments:X}}function TX(Q,X){Q.interactions.push(X);let Z={view:0.1,click:0.3,like:0.5,share:0.6,bookmark:0.7,purchase:1,dislike:-0.5,custom:X.weight||0.3}[X.type]||0.1,H=X.itemId;return Q.preferences[H]=(Q.preferences[H]||0)+Z,Q}async function DX(Q,X,Y={}){let{provider:Z="anthropic"}=Y,H=new Set(Q.interactions.map((U)=>U.itemId)),W=X.filter((U)=>H.has(U.id));if(W.length===0)return Q.segments;let J=W.slice(0,20).map((U)=>U.content.slice(0,200)).join(`
168
+ ${J}`,W=await l(H,V,$,Y.model);try{return{recommendations:JSON.parse(W.content).recommendations.slice(0,X),model:W.model,provider:H}}catch{return{recommendations:[],model:W.model,provider:H}}}function nZ(Q){let Z=Object.entries(Q.preferences).sort(([,H],[,X])=>X-H).slice(0,10).map(([H,X])=>`${H}: ${X.toFixed(2)}`).join(", "),Y=Q.interactions.sort((H,X)=>X.timestamp-H.timestamp).slice(0,10).map((H)=>`${H.type} on ${H.itemId}`).join(", ");return`Segments: ${Q.segments.join(", ")}
169
+ Top Preferences: ${Z||"none"}
170
+ Recent Interactions: ${Y||"none"}`}function rZ(Q,Z=[]){return{id:Q,preferences:{},interactions:[],segments:Z}}function sZ(Q,Z){Q.interactions.push(Z);let H={view:0.1,click:0.3,like:0.5,share:0.6,bookmark:0.7,purchase:1,dislike:-0.5,custom:Z.weight||0.3}[Z.type]||0.1,X=Z.itemId;return Q.preferences[X]=(Q.preferences[X]||0)+H,Q}async function oZ(Q,Z,Y={}){let{provider:H="anthropic"}=Y,X=new Set(Q.interactions.map((W)=>W.itemId)),G=Z.filter((W)=>X.has(W.id));if(G.length===0)return Q.segments;let J=G.slice(0,20).map((W)=>W.content.slice(0,200)).join(`
171
171
  ---
172
- `),G=await y(Z,`Extract the main interests/topics from the user's interaction history. Return ONLY a JSON array of strings, e.g. ["technology", "cooking", "travel"]. Maximum 10 interests.`,J,Y.model);try{return JSON.parse(G.content)}catch{return Q.segments}}async function y(Q,X,Y,Z){if(Q==="anthropic"){let H=process.env.ANTHROPIC_API_KEY;if(!H)throw Error("ANTHROPIC_API_KEY required.");let W=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":H,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:Z||"claude-sonnet-4-20250514",max_tokens:4096,system:X,messages:[{role:"user",content:Y}]})});if(!W.ok){let V=await W.text();throw Error(`Claude API error: ${V}`)}let J=await W.json();return{content:J.content[0].text,model:J.model,usage:{promptTokens:J.usage?.input_tokens||0,completionTokens:J.usage?.output_tokens||0,totalTokens:(J.usage?.input_tokens||0)+(J.usage?.output_tokens||0)},finishReason:J.stop_reason}}if(Q==="openai"){let H=process.env.OPENAI_API_KEY;if(!H)throw Error("OPENAI_API_KEY required.");let W=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${H}`},body:JSON.stringify({model:Z||"gpt-4o",max_tokens:4096,messages:[{role:"system",content:X},{role:"user",content:Y}]})});if(!W.ok){let V=await W.text();throw Error(`OpenAI API error: ${V}`)}let J=await W.json();return{content:J.choices[0].message.content,model:J.model,usage:{promptTokens:J.usage?.prompt_tokens||0,completionTokens:J.usage?.completion_tokens||0,totalTokens:J.usage?.total_tokens||0},finishReason:J.choices[0].finish_reason}}if(Q==="ollama"){let H=process.env.OLLAMA_HOST||"http://localhost:11434",W=await fetch(`${H}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:Z||"llama3.2",messages:[{role:"system",content:X},{role:"user",content:Y}],stream:!1})});if(!W.ok){let V=await W.text();throw Error(`Ollama API error: ${V}`)}let J=await W.json();return{content:J.message.content,model:J.model,usage:{promptTokens:J.prompt_eval_count||0,completionTokens:J.eval_count||0,totalTokens:(J.prompt_eval_count||0)+(J.eval_count||0)},finishReason:J.done_reason||"stop"}}throw Error(`Provider not supported: ${Q}`)}var AY={analyzeSentiment:RX,classifyText:FX,summarize:NX,recommend:wX,createProfile:KX,recordInteraction:TX,extractUserInterests:DX};class f{config;process=null;requestId=0;pendingRequests=new Map;tools=[];resources=[];prompts=[];initialized=!1;buffer="";constructor(Q){this.config=Q}async connect(){if(this.config.transport.type==="stdio")await this.connectStdio();else if(this.config.transport.type==="sse"||this.config.transport.type==="streamable-http")await this.connectHTTP();else throw Error(`Unsupported transport type: ${this.config.transport.type}`);this.initialized=!0}async connectStdio(){let Q=this.config.transport,{spawn:X}=awaitPromise.resolve(globalThis.Bun);this.process=X([Q.command,...Q.args||[]],{stdin:"pipe",stdout:"pipe",stderr:"pipe",env:{...process.env,...Q.env}}),this.readStdout(),await this.sendRequest("initialize",{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"stacks-ai",version:"1.0.0"}}),await this.sendNotification("notifications/initialized",{}),await this.discoverCapabilities()}async connectHTTP(){let Q=this.config.transport,X=await fetch(Q.url,{method:"POST",headers:{"Content-Type":"application/json",...Q.headers},body:JSON.stringify({jsonrpc:"2.0",id:this.nextId(),method:"initialize",params:{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"stacks-ai",version:"1.0.0"}}})});if(!X.ok){let Y=await X.text();throw Error(`MCP HTTP connection error: ${Y}`)}await this.discoverCapabilities()}async readStdout(){if(!this.process)return;let Q=this.process.stdout?.getReader();if(!Q)return;let X=new TextDecoder;try{while(!0){let{done:Y,value:Z}=await Q.read();if(Y)break;this.buffer+=X.decode(Z,{stream:!0}),this.processBuffer()}}catch{}}processBuffer(){let Q=this.buffer.split(`
173
- `);this.buffer=Q.pop()||"";for(let X of Q){if(!X.trim())continue;try{let Y=JSON.parse(X);if(Y.id!==void 0&&this.pendingRequests.has(Y.id)){let Z=this.pendingRequests.get(Y.id);if(this.pendingRequests.delete(Y.id),Y.error)Z.reject(Error(Y.error.message||"MCP error"));else Z.resolve(Y.result)}}catch{}}}nextId(){return++this.requestId}async sendRequest(Q,X={}){let Y=this.nextId(),Z=JSON.stringify({jsonrpc:"2.0",id:Y,method:Q,params:X})+`
174
- `;if(this.config.transport.type==="stdio"&&this.process){let H=this.process.stdin?.getWriter();if(H)await H.write(new TextEncoder().encode(Z)),H.releaseLock();return new Promise((W,J)=>{let V=setTimeout(()=>{this.pendingRequests.delete(Y),J(Error(`MCP request timeout: ${Q}`))},30000);this.pendingRequests.set(Y,{resolve:(G)=>{clearTimeout(V),W(G)},reject:(G)=>{clearTimeout(V),J(G)}})})}if(this.config.transport.type==="sse"||this.config.transport.type==="streamable-http"){let H=this.config.transport,W=await fetch(H.url,{method:"POST",headers:{"Content-Type":"application/json",...H.headers},body:Z});if(!W.ok){let V=await W.text();throw Error(`MCP request error: ${V}`)}let J=await W.json();if(J.error)throw Error(J.error.message||"MCP error");return J.result}throw Error("No transport available")}async sendNotification(Q,X={}){let Y=JSON.stringify({jsonrpc:"2.0",method:Q,params:X})+`
175
- `;if(this.config.transport.type==="stdio"&&this.process){let Z=this.process.stdin?.getWriter();if(Z)await Z.write(new TextEncoder().encode(Y)),Z.releaseLock()}}async discoverCapabilities(){let Q=this.config.capabilities||{tools:!0,resources:!0,prompts:!0};if(Q.tools!==!1)try{let X=await this.sendRequest("tools/list");this.tools=X?.tools||[]}catch{this.tools=[]}if(Q.resources!==!1)try{let X=await this.sendRequest("resources/list");this.resources=X?.resources||[]}catch{this.resources=[]}if(Q.prompts!==!1)try{let X=await this.sendRequest("prompts/list");this.prompts=X?.prompts||[]}catch{this.prompts=[]}}listTools(){return this.tools}listResources(){return this.resources}listPrompts(){return this.prompts}async callTool(Q,X={}){if(!this.initialized)throw Error("MCP client not connected. Call connect() first.");return await this.sendRequest("tools/call",{name:Q,arguments:X})}async readResource(Q){if(!this.initialized)throw Error("MCP client not connected. Call connect() first.");let Y=(await this.sendRequest("resources/read",{uri:Q}))?.contents?.[0];return{uri:Y?.uri||Q,mimeType:Y?.mimeType,text:Y?.text,blob:Y?.blob}}async getPrompt(Q,X={}){if(!this.initialized)throw Error("MCP client not connected. Call connect() first.");return this.sendRequest("prompts/get",{name:Q,arguments:X})}toAnthropicTools(){return this.tools.map((Q)=>({name:Q.name,description:Q.description,input_schema:Q.inputSchema}))}toOpenAITools(){return this.tools.map((Q)=>({type:"function",function:{name:Q.name,description:Q.description,parameters:Q.inputSchema}}))}async disconnect(){if(this.process)this.process.kill(),this.process=null;for(let Q of this.pendingRequests.values())try{Q.reject(Error("MCP client disconnected"))}catch{}this.pendingRequests.clear(),this.initialized=!1,this.tools=[],this.resources=[],this.prompts=[]}get isConnected(){return this.initialized}get serverName(){return this.config.name}}class qQ{clients=new Map;async addServer(Q){if(this.clients.has(Q.name))throw Error(`MCP server already registered: ${Q.name}`);let X=new f(Q);return await X.connect(),this.clients.set(Q.name,X),X}async removeServer(Q){let X=this.clients.get(Q);if(X)await X.disconnect(),this.clients.delete(Q)}getServer(Q){return this.clients.get(Q)}listServers(){return Array.from(this.clients.keys())}getAllTools(){let Q=[];for(let[X,Y]of this.clients)for(let Z of Y.listTools())Q.push({...Z,serverName:X});return Q}async callTool(Q,X={}){if(Q.includes("/")){let[Y,Z]=Q.split("/",2),H=this.clients.get(Y);if(!H)throw Error(`MCP server not found: ${Y}`);return H.callTool(Z,X)}for(let[,Y]of this.clients)if(Y.listTools().some((H)=>H.name===Q))return Y.callTool(Q,X);throw Error(`MCP tool not found: ${Q}`)}toAnthropicTools(){let Q=[];for(let[X,Y]of this.clients)for(let Z of Y.listTools())Q.push({name:`${X}__${Z.name}`,description:`[${X}] ${Z.description}`,input_schema:Z.inputSchema});return Q}toOpenAITools(){let Q=[];for(let[X,Y]of this.clients)for(let Z of Y.listTools())Q.push({type:"function",function:{name:`${X}__${Z.name}`,description:`[${X}] ${Z.description}`,parameters:Z.inputSchema}});return Q}async disconnectAll(){let Q=Array.from(this.clients.values()).map((X)=>X.disconnect());await Promise.all(Q),this.clients.clear()}}async function IX(Q,X,Y,Z){let H=new f({name:Q,transport:{type:"stdio",command:X,args:Y,env:Z}});return await H.connect(),H}async function xX(Q,X,Y){let Z=new f({name:Q,transport:{type:"streamable-http",url:X,headers:Y}});return await Z.connect(),Z}var _Y={MCPClient:f,MCPManager:qQ,connectStdio:IX,connectHTTP:xX};import kX from"process";var m=null;async function n(){if(m)return m;let Q=await import("@stacksjs/ts-cloud/aws");if(!Q?.BedrockClient)throw Error("@stacksjs/ts-cloud/aws does not export BedrockClient \u2014 rebuild ts-cloud or remove the AI dependency.");return m=new Q.BedrockClient(kX.env.REGION||"us-east-1"),m}async function NY(Q){return(await n()).createModelCustomizationJob(Q)}async function wY(Q){return(await n()).getModelCustomizationJob(Q)}async function MY(Q){return(await n()).listFoundationModels(Q)}import{log as s}from"@stacksjs/cli";import{ai as CX}from"@stacksjs/config";async function SX(){let Q=await import("@stacksjs/ts-cloud/aws");if(!Q?.BedrockClient)throw Error("@stacksjs/ts-cloud/aws does not export BedrockClient \u2014 rebuild ts-cloud or remove the AI dependency.");return new Q.BedrockClient("us-east-1")}async function IY(){let Q=await SX(),X=CX.models;if(!X)throw Error("No AI models found. Please set ./config/ai.ts values.");for(let Y of X)try{s.info(`Requesting access to model ${Y}`);let Z=await Q.requestModelAccess({modelId:Y});s.info(`Response for model ${Y}:`,Z)}catch(Z){s.error(`Error requesting access to model ${Y}:`,Z)}}export{jY as summarize,EY as search,iQ as resetPromptCount,IY as requestModelAccess,TX as recordInteraction,wX as recommend,EX as rag,XY as pushChanges,pQ as processCommandStreaming,YY as processCommand,AY as personalization,KQ as openaiDriver,TQ as openai,oX as openRepository,yQ as ollamaDriver,fQ as ollama,_Y as mcp,MY as listFoundationModels,WY as invokeModelWithResponseStream,i as invokeModel,_X as indexText,zY as image,oQ as getRepoContext,wY as getModelCustomizationJob,YQ as getLastSessionId,tQ as getDriver,tX as getAvailableDrivers,YX as generateImage,DX as extractUserInterests,BX as euclideanDistance,QQ as estimateTokens,HX as editImage,zX as dotProduct,KX as createProfile,P as createOpenAIDriver,b as createOllamaDriver,NY as createModelCustomizationJob,JX as createImageVariation,a as createEmbedding,dQ as createClaudeLocalAgent,mQ as createClaudeEC2Agent,c as createClaudeAgentSDKDriver,S as createAnthropicDriver,jQ as cosineSimilarity,IX as connectStdio,xX as connectHTTP,eQ as configureGitUser,QY as commitChanges,ZQ as clearSession,cQ as claudeAgentSDK,l as claudeAgent,FX as classifyText,$Q as chunkText,nQ as buildSystemPrompt,HY as buddyStreamSimple,R as buddyState,ZY as buddyProcessStreaming,$Y as ask,eX as applyChanges,K as apiKeys,LQ as anthropicDriver,AQ as anthropic,RX as analyzeSentiment,jX as analyzeImages,VX as analyzeImage,r as VectorIndex,qQ as MCPManager,f as MCPClient,k as CONFIG};
172
+ `),$=await l(H,`Extract the main interests/topics from the user's interaction history. Return ONLY a JSON array of strings, e.g. ["technology", "cooking", "travel"]. Maximum 10 interests.`,J,Y.model);try{return JSON.parse($.content)}catch{return Q.segments}}async function l(Q,Z,Y,H){if(Q==="anthropic"){let X=process.env.ANTHROPIC_API_KEY;if(!X)throw Error("ANTHROPIC_API_KEY required.");let G=await fetch("https://api.anthropic.com/v1/messages",{method:"POST",headers:{"Content-Type":"application/json","x-api-key":X,"anthropic-version":"2023-06-01"},body:JSON.stringify({model:H||"claude-sonnet-4-20250514",max_tokens:4096,system:Z,messages:[{role:"user",content:Y}]})});if(!G.ok){let V=await G.text();throw Error(`Claude API error: ${V}`)}let J=await G.json();return{content:J.content[0].text,model:J.model,usage:{promptTokens:J.usage?.input_tokens||0,completionTokens:J.usage?.output_tokens||0,totalTokens:(J.usage?.input_tokens||0)+(J.usage?.output_tokens||0)},finishReason:J.stop_reason}}if(Q==="openai"){let X=process.env.OPENAI_API_KEY;if(!X)throw Error("OPENAI_API_KEY required.");let G=await fetch("https://api.openai.com/v1/chat/completions",{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${X}`},body:JSON.stringify({model:H||"gpt-4o",max_tokens:4096,messages:[{role:"system",content:Z},{role:"user",content:Y}]})});if(!G.ok){let V=await G.text();throw Error(`OpenAI API error: ${V}`)}let J=await G.json();return{content:J.choices[0].message.content,model:J.model,usage:{promptTokens:J.usage?.prompt_tokens||0,completionTokens:J.usage?.completion_tokens||0,totalTokens:J.usage?.total_tokens||0},finishReason:J.choices[0].finish_reason}}if(Q==="ollama"){let X=process.env.OLLAMA_HOST||"http://localhost:11434",G=await fetch(`${X}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:H||"llama3.2",messages:[{role:"system",content:Z},{role:"user",content:Y}],stream:!1})});if(!G.ok){let V=await G.text();throw Error(`Ollama API error: ${V}`)}let J=await G.json();return{content:J.message.content,model:J.model,usage:{promptTokens:J.prompt_eval_count||0,completionTokens:J.eval_count||0,totalTokens:(J.prompt_eval_count||0)+(J.eval_count||0)},finishReason:J.done_reason||"stop"}}throw Error(`Provider not supported: ${Q}`)}var Q9={analyzeSentiment:mZ,classifyText:pZ,summarize:iZ,recommend:aZ,createProfile:rZ,recordInteraction:sZ,extractUserInterests:oZ};class m{config;process=null;requestId=0;pendingRequests=new Map;tools=[];resources=[];prompts=[];initialized=!1;buffer="";constructor(Q){this.config=Q}async connect(){if(this.config.transport.type==="stdio")await this.connectStdio();else if(this.config.transport.type==="sse"||this.config.transport.type==="streamable-http")await this.connectHTTP();else throw Error(`Unsupported transport type: ${this.config.transport.type}`);this.initialized=!0}async connectStdio(){let Q=this.config.transport,{spawn:Z}=awaitPromise.resolve(globalThis.Bun);this.process=Z([Q.command,...Q.args||[]],{stdin:"pipe",stdout:"pipe",stderr:"pipe",env:{...process.env,...Q.env}}),this.readStdout(),await this.sendRequest("initialize",{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"stacks-ai",version:"1.0.0"}}),await this.sendNotification("notifications/initialized",{}),await this.discoverCapabilities()}async connectHTTP(){let Q=this.config.transport,Z=await fetch(Q.url,{method:"POST",headers:{"Content-Type":"application/json",...Q.headers},body:JSON.stringify({jsonrpc:"2.0",id:this.nextId(),method:"initialize",params:{protocolVersion:"2024-11-05",capabilities:{},clientInfo:{name:"stacks-ai",version:"1.0.0"}}})});if(!Z.ok){let Y=await Z.text();throw Error(`MCP HTTP connection error: ${Y}`)}await this.discoverCapabilities()}async readStdout(){if(!this.process)return;let Q=this.process.stdout?.getReader();if(!Q)return;let Z=new TextDecoder;try{while(!0){let{done:Y,value:H}=await Q.read();if(Y)break;this.buffer+=Z.decode(H,{stream:!0}),this.processBuffer()}}catch{}}processBuffer(){let Q=this.buffer.split(`
173
+ `);this.buffer=Q.pop()||"";for(let Z of Q){if(!Z.trim())continue;try{let Y=JSON.parse(Z);if(Y.id!==void 0&&this.pendingRequests.has(Y.id)){let H=this.pendingRequests.get(Y.id);if(this.pendingRequests.delete(Y.id),Y.error)H.reject(Error(Y.error.message||"MCP error"));else H.resolve(Y.result)}}catch{}}}nextId(){return++this.requestId}async sendRequest(Q,Z={}){let Y=this.nextId(),H=JSON.stringify({jsonrpc:"2.0",id:Y,method:Q,params:Z})+`
174
+ `;if(this.config.transport.type==="stdio"&&this.process){let X=this.process.stdin?.getWriter();if(X)await X.write(new TextEncoder().encode(H)),X.releaseLock();return new Promise((G,J)=>{let V=setTimeout(()=>{this.pendingRequests.delete(Y),J(Error(`MCP request timeout: ${Q}`))},30000);this.pendingRequests.set(Y,{resolve:($)=>{clearTimeout(V),G($)},reject:($)=>{clearTimeout(V),J($)}})})}if(this.config.transport.type==="sse"||this.config.transport.type==="streamable-http"){let X=this.config.transport,G=await fetch(X.url,{method:"POST",headers:{"Content-Type":"application/json",...X.headers},body:H});if(!G.ok){let V=await G.text();throw Error(`MCP request error: ${V}`)}let J=await G.json();if(J.error)throw Error(J.error.message||"MCP error");return J.result}throw Error("No transport available")}async sendNotification(Q,Z={}){let Y=JSON.stringify({jsonrpc:"2.0",method:Q,params:Z})+`
175
+ `;if(this.config.transport.type==="stdio"&&this.process){let H=this.process.stdin?.getWriter();if(H)await H.write(new TextEncoder().encode(Y)),H.releaseLock()}}async discoverCapabilities(){let Q=this.config.capabilities||{tools:!0,resources:!0,prompts:!0};if(Q.tools!==!1)try{let Z=await this.sendRequest("tools/list");this.tools=Z?.tools||[]}catch{this.tools=[]}if(Q.resources!==!1)try{let Z=await this.sendRequest("resources/list");this.resources=Z?.resources||[]}catch{this.resources=[]}if(Q.prompts!==!1)try{let Z=await this.sendRequest("prompts/list");this.prompts=Z?.prompts||[]}catch{this.prompts=[]}}listTools(){return this.tools}listResources(){return this.resources}listPrompts(){return this.prompts}async callTool(Q,Z={}){if(!this.initialized)throw Error("MCP client not connected. Call connect() first.");return await this.sendRequest("tools/call",{name:Q,arguments:Z})}async readResource(Q){if(!this.initialized)throw Error("MCP client not connected. Call connect() first.");let Y=(await this.sendRequest("resources/read",{uri:Q}))?.contents?.[0];return{uri:Y?.uri||Q,mimeType:Y?.mimeType,text:Y?.text,blob:Y?.blob}}async getPrompt(Q,Z={}){if(!this.initialized)throw Error("MCP client not connected. Call connect() first.");return this.sendRequest("prompts/get",{name:Q,arguments:Z})}toAnthropicTools(){return this.tools.map((Q)=>({name:Q.name,description:Q.description,input_schema:Q.inputSchema}))}toOpenAITools(){return this.tools.map((Q)=>({type:"function",function:{name:Q.name,description:Q.description,parameters:Q.inputSchema}}))}async disconnect(){if(this.process)this.process.kill(),this.process=null;for(let Q of this.pendingRequests.values())try{Q.reject(Error("MCP client disconnected"))}catch{}this.pendingRequests.clear(),this.initialized=!1,this.tools=[],this.resources=[],this.prompts=[]}get isConnected(){return this.initialized}get serverName(){return this.config.name}}class EQ{clients=new Map;async addServer(Q){if(this.clients.has(Q.name))throw Error(`MCP server already registered: ${Q.name}`);let Z=new m(Q);return await Z.connect(),this.clients.set(Q.name,Z),Z}async removeServer(Q){let Z=this.clients.get(Q);if(Z)await Z.disconnect(),this.clients.delete(Q)}getServer(Q){return this.clients.get(Q)}listServers(){return Array.from(this.clients.keys())}getAllTools(){let Q=[];for(let[Z,Y]of this.clients)for(let H of Y.listTools())Q.push({...H,serverName:Z});return Q}async callTool(Q,Z={}){if(Q.includes("/")){let[Y,H]=Q.split("/",2),X=this.clients.get(Y);if(!X)throw Error(`MCP server not found: ${Y}`);return X.callTool(H,Z)}for(let[,Y]of this.clients)if(Y.listTools().some((X)=>X.name===Q))return Y.callTool(Q,Z);throw Error(`MCP tool not found: ${Q}`)}toAnthropicTools(){let Q=[];for(let[Z,Y]of this.clients)for(let H of Y.listTools())Q.push({name:`${Z}__${H.name}`,description:`[${Z}] ${H.description}`,input_schema:H.inputSchema});return Q}toOpenAITools(){let Q=[];for(let[Z,Y]of this.clients)for(let H of Y.listTools())Q.push({type:"function",function:{name:`${Z}__${H.name}`,description:`[${Z}] ${H.description}`,parameters:H.inputSchema}});return Q}async disconnectAll(){let Q=Array.from(this.clients.values()).map((Z)=>Z.disconnect());await Promise.all(Q),this.clients.clear()}}async function tZ(Q,Z,Y,H){let X=new m({name:Q,transport:{type:"stdio",command:Z,args:Y,env:H}});return await X.connect(),X}async function eZ(Q,Z,Y){let H=new m({name:Q,transport:{type:"streamable-http",url:Z,headers:Y}});return await H.connect(),H}var Y9={MCPClient:m,MCPManager:EQ,connectStdio:tZ,connectHTTP:eZ};import Q6 from"process";var s=null;async function VQ(){if(s)return s;let Q=await import("@stacksjs/ts-cloud/aws");if(!Q?.BedrockClient)throw Error("@stacksjs/ts-cloud/aws does not export BedrockClient \u2014 rebuild ts-cloud or remove the AI dependency.");return s=new Q.BedrockClient(Q6.env.REGION||"us-east-1"),s}async function J9(Q){return(await VQ()).createModelCustomizationJob(Q)}async function V9(Q){return(await VQ()).getModelCustomizationJob(Q)}async function G9(Q){return(await VQ()).listFoundationModels(Q)}function Z6(Q){let Z=Q.toLowerCase();if(Z.startsWith("gpt-"))return 3.5;if(Z.startsWith("claude"))return 3.5;return 3.5}function GQ(Q,Z="gpt-4o"){if(!Q)return 0;let Y=Z6(Z);return Math.max(1,Math.ceil(Q.length/Y))}function Y6(Q,Z="gpt-4o"){let X=2;for(let G of Q)if(X+=4,typeof G.content==="string")X+=GQ(G.content,Z);else if(Array.isArray(G.content)){for(let J of G.content)if(J.type==="text"&&J.text)X+=GQ(J.text,Z);else if(J.type==="image"||J.type==="image_url")X+=100}return X}var H6=[/\bignore\s+(?:all\s+)?(?:previous|prior|above)\s+instructions?\b/i,/\bdisregard\s+(?:all\s+)?(?:previous|prior|above)\b/i,/\bforget\s+(?:everything|all)\s+(?:you|i)\b/i,/\byou\s+are\s+now\s+a\s+\w+/i,/\bnew\s+instructions?:\s*/i,/\bsystem\s*[:>]\s*/i,/\b(?:reveal|show|print|output|display)\s+(?:your|the)\s+(?:system\s+)?prompt\b/i,/<\s*\/?\s*system\s*>/i,/\[INST\]|\[\/INST\]/i,/^\s*###\s+(?:instruction|system)/im];function X6(Q){if(!Q)return{ok:!0,matched:[],cleaned:Q};let Z=[],Y=Q;for(let H of H6)if(H.test(Y))Z.push(H.toString()),Y=Y.replace(H,"[redacted]");return{ok:Z.length===0,matched:Z,cleaned:Y}}import{log as $Q}from"@stacksjs/cli";import{ai as J6}from"@stacksjs/config";async function V6(){let Q=await import("@stacksjs/ts-cloud/aws");if(!Q?.BedrockClient)throw Error("@stacksjs/ts-cloud/aws does not export BedrockClient \u2014 rebuild ts-cloud or remove the AI dependency.");return new Q.BedrockClient("us-east-1")}async function j9(){let Q=await V6(),Z=J6.models;if(!Z)throw Error("No AI models found. Please set ./config/ai.ts values.");for(let Y of Z)try{$Q.info(`Requesting access to model ${Y}`);let H=await Q.requestModelAccess({modelId:Y});$Q.info(`Response for model ${Y}:`,H)}catch(H){$Q.error(`Error requesting access to model ${Y}:`,H)}}export{a6 as summarize,t6 as search,X6 as sanitizePrompt,KZ as resetPromptCount,j9 as requestModelAccess,h as recordUsage,sZ as recordInteraction,aZ as recommend,gZ as rag,f6 as pushChanges,UZ as processCommandStreaming,g6 as processCommand,Q9 as personalization,rQ as openaiDriver,sQ as openai,y6 as openRepository,CQ as onUsage,GZ as ollamaDriver,$Z as ollama,I as normalizeMessagesForProvider,Y9 as mcp,SQ as listUsageReporters,G9 as listFoundationModels,m6 as invokeModelWithResponseStream,HQ as invokeModel,lZ as indexText,s6 as image,MZ as getRepoContext,V9 as getModelCustomizationJob,UQ as getLastSessionId,FZ as getDriver,v6 as getAvailableDrivers,IZ as generateImage,S as fetchWithRetry,oZ as extractUserInterests,fZ as euclideanDistance,GQ as estimateTokens,Y6 as estimateMessageTokens,DZ as editImage,hZ as dotProduct,rZ as createProfile,g as createOpenAIDriver,c as createOllamaDriver,J9 as createModelCustomizationJob,CZ as createImageVariation,XQ as createEmbedding,BZ as createClaudeLocalAgent,OZ as createClaudeEC2Agent,a as createClaudeAgentSDKDriver,f as createAnthropicDriver,AQ as cosineSimilarity,tZ as connectStdio,eZ as connectHTTP,AZ as configureGitUser,h6 as commitChanges,xQ as clearUsageReporters,KQ as clearSession,zZ as claudeAgentSDK,n as claudeAgent,pZ as classifyText,_Q as chunkText,LZ as buildSystemPrompt,vQ as buildMessageWithImages,c6 as buddyStreamSimple,F as buddyState,u6 as buddyProcessStreaming,n6 as ask,b6 as applyChanges,D as apiKeys,uQ as anthropicDriver,cQ as anthropic,mZ as analyzeSentiment,vZ as analyzeImages,xZ as analyzeImage,JQ as VectorIndex,EQ as MCPManager,m as MCPClient,b as CONFIG};
@@ -42,6 +42,16 @@ export declare interface EmbeddingsResponse {
42
42
  total_tokens: number
43
43
  }
44
44
  }
45
+ /**
46
+ * Tool / function definition that the model can call back into.
47
+ * Cross-provider shape: OpenAI's `tools[]` and Anthropic's `tools[]`
48
+ * map to this same structure via the JSON Schema for parameters.
49
+ */
50
+ export declare interface AITool {
51
+ name: string
52
+ description?: string
53
+ parameters?: Record<string, unknown>
54
+ }
45
55
  export declare interface ChatCompletionOptions {
46
56
  model?: string
47
57
  maxTokens?: number
@@ -49,6 +59,9 @@ export declare interface ChatCompletionOptions {
49
59
  topP?: number
50
60
  stop?: string | string[]
51
61
  stream?: boolean
62
+ tools?: AITool[]
63
+ toolChoice?: 'auto' | 'required' | 'none' | { name: string }
64
+ responseFormat?: AIResponseFormat
52
65
  }
53
66
  export declare interface AIResult {
54
67
  content: string
@@ -155,3 +168,18 @@ export declare interface AIConfig {
155
168
  search?: SearchConfig
156
169
  mcp?: MCPConfig
157
170
  }
171
+ /**
172
+ * Structured-output / JSON-mode response format. Modeled after
173
+ * OpenAI's `response_format` but the Anthropic driver maps it to
174
+ * the tools-as-json pattern internally (stacksjs/stacks#1878 A-1).
175
+ */
176
+ export type AIResponseFormat = | { type: 'text' }
177
+ | { type: 'json_object' }
178
+ | {
179
+ type: 'json_schema'
180
+ json_schema: {
181
+ name: string
182
+ schema: Record<string, unknown>
183
+ strict?: boolean
184
+ }
185
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Fetch with automatic retry on 429 / 5xx. Returns the final
3
+ * `Response` — the caller checks `.ok` and parses the body as usual.
4
+ *
5
+ * Does NOT retry network-level errors (connection reset, DNS
6
+ * failure) — those throw synchronously and the caller's existing
7
+ * try/catch handles them.
8
+ */
9
+ export declare function fetchWithRetry(input: RequestInfo | URL, init?: RequestInit, config?: RetryConfig): Promise<Response>;
10
+ /**
11
+ * Retry helper for AI driver HTTP calls (stacksjs/stacks#1878 A-5).
12
+ *
13
+ * Background: OpenAI / Anthropic / etc. routinely return 429 (rate
14
+ * limit) and 5xx (capacity / overloaded) responses with a
15
+ * `Retry-After` header indicating when the caller should try again.
16
+ * The pre-fix AI drivers threw immediately on any non-2xx, surfacing
17
+ * transient capacity issues as hard user-facing failures.
18
+ *
19
+ * This helper wraps `fetch()` with:
20
+ * - Honor `Retry-After` (seconds or HTTP-date) for 429 + 503
21
+ * - Exponential backoff + jitter for other 5xx
22
+ * - Cap at `maxRetries` attempts (default 3)
23
+ * - Surface the final non-recoverable response to the caller
24
+ *
25
+ * No retry on 4xx other than 429 — those are caller bugs (bad API
26
+ * key, malformed request) that won't clear with more retries.
27
+ */
28
+ /**
29
+ * Configurable retry policy. Defaults are tuned for the typical
30
+ * "Anthropic returned 429, try again in 3s" case without being so
31
+ * aggressive that a permanent outage hangs the request loop for
32
+ * minutes.
33
+ */
34
+ export declare interface RetryConfig {
35
+ maxRetries?: number
36
+ baseDelayMs?: number
37
+ maxDelayMs?: number
38
+ }
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Estimate the number of tokens in `text` for the given model.
3
+ * Heuristic only — for exact counts, use the provider's tokenizer.
4
+ *
5
+ * @example
6
+ * ```ts
7
+ * if (estimateTokens(prompt, 'gpt-4o') > 100_000) {
8
+ * throw new Error('prompt too long; consider chunking')
9
+ * }
10
+ * ```
11
+ */
12
+ export declare function estimateTokens(text: string, model?: string): number;
13
+ /**
14
+ * Estimate total tokens for a chat-completion request: sum of
15
+ * every message's content plus a fixed per-message overhead
16
+ * (matches the rough "+4 per message + 2 for the conversation"
17
+ * heuristic OpenAI's docs publish).
18
+ */
19
+ export declare function estimateMessageTokens(messages: Array<{ role: string, content: string | unknown }>, model?: string): number;
20
+ /**
21
+ * Inspect `text` for common prompt-injection patterns. Returns
22
+ * `{ ok, matched, cleaned }`. Apps decide what to do with the
23
+ * result — reject the request (`if (!result.ok) throw...`), pass
24
+ * the cleaned text on (`useText(result.cleaned)`), or just log
25
+ * for audit while letting the original through.
26
+ *
27
+ * **Limits:** this is heuristic. Adversarial inputs can paraphrase
28
+ * around any specific pattern. Use as a cheap first filter; for
29
+ * real defense, isolate the user input from the system prompt
30
+ * structurally (different roles, JSON-mode for the system layer)
31
+ * and guard the output side too.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * const check = sanitizePrompt(userInput)
36
+ * if (!check.ok) {
37
+ * log.warn('possible injection attempt', { patterns: check.matched })
38
+ * // option A: reject
39
+ * throw new HttpError(400, 'invalid input')
40
+ * // option B: pass cleaned
41
+ * await chat([{ role: 'user', content: check.cleaned }])
42
+ * }
43
+ * ```
44
+ */
45
+ export declare function sanitizePrompt(text: string): SanitizeResult;
46
+ export declare interface SanitizeResult {
47
+ ok: boolean
48
+ matched: string[]
49
+ cleaned: string
50
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Register a usage reporter. Returns an `unregister` callback for
3
+ * apps that want to swap reporters at runtime (test setup/teardown,
4
+ * tenant isolation, etc.).
5
+ */
6
+ export declare function onUsage(reporter: UsageReporter): () => void;
7
+ /**
8
+ * Drop every registered reporter. Useful for tests.
9
+ */
10
+ export declare function clearUsageReporters(): void;
11
+ /**
12
+ * Emit a usage record to every registered reporter. Called by
13
+ * driver completion paths after the response lands. Reporter
14
+ * errors are caught + logged so a misbehaving sink doesn't
15
+ * propagate up to the caller.
16
+ */
17
+ export declare function recordUsage(record: UsageRecord): void;
18
+ /**
19
+ * Snapshot the currently-registered reporters. Useful for tests
20
+ * to assert behavior without exposing the internal array.
21
+ */
22
+ export declare function listUsageReporters(): readonly UsageReporter[];
23
+ /**
24
+ * AI usage tracking (stacksjs/stacks#1878 A-6).
25
+ *
26
+ * Background: `AIResult.usage` returns token counts per-call but
27
+ * nothing aggregates them. Apps that want "this user has spent
28
+ * $X this month" build the aggregation themselves — wiring a
29
+ * listener on every model invocation, persisting the running
30
+ * total, etc.
31
+ *
32
+ * This module ships a singleton recorder that drivers emit to on
33
+ * each completion. Apps install one or more `UsageReporter`
34
+ * functions that get called with `{ provider, model, prompt_tokens,
35
+ * completion_tokens, timestamp, durationMs }` and decide what to
36
+ * do (store to DB, push to Datadog, etc.). Default behavior with
37
+ * no reporter is a no-op — the framework doesn't impose a sink.
38
+ */
39
+ export declare interface UsageRecord {
40
+ provider: string
41
+ model: string
42
+ promptTokens: number
43
+ completionTokens: number
44
+ totalTokens: number
45
+ durationMs: number
46
+ timestamp: number
47
+ metadata?: Record<string, unknown>
48
+ }
49
+ /**
50
+ * A reporter is called once per recorded completion. Multiple
51
+ * reporters can be installed simultaneously; they fire in
52
+ * registration order. Reporters MUST NOT throw — errors are
53
+ * caught and logged but otherwise ignored so a flaky metrics
54
+ * sink doesn't break the user's completion call.
55
+ */
56
+ export type UsageReporter = (record: UsageRecord) => void | Promise<void>;
@@ -0,0 +1,22 @@
1
+ import type { AIMessage, AIMessageContent } from '../types';
2
+ /**
3
+ * Normalize an entire `messages` array for the requested provider.
4
+ * Messages whose `content` is a plain string pass through unchanged.
5
+ * Messages with a content array get each block translated.
6
+ */
7
+ export declare function normalizeMessagesForProvider(messages: AIMessage[], provider: 'openai' | 'anthropic'): AIMessage[];
8
+ /**
9
+ * Convenience: convert a single command + optional image inputs into
10
+ * an `AIMessage` content array suitable for `chat()` calls. Used by
11
+ * the higher-level `text()` / `chat()` helpers when a user passes
12
+ * `{ command, images }` together.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const content = buildMessageWithImages('What is in this image?', [
17
+ * { url: 'https://example.com/cat.jpg' },
18
+ * ])
19
+ * await chat([{ role: 'user', content }])
20
+ * ```
21
+ */
22
+ export declare function buildMessageWithImages(command: string, images: Array<{ url?: string, dataBase64?: string, mediaType?: string, detail?: 'auto' | 'low' | 'high' }>): AIMessageContent[];
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@stacksjs/ai",
3
3
  "type": "module",
4
- "version": "0.70.44",
4
+ "version": "0.70.53",
5
5
  "description": "Stacks Artificial Intelligence.",
6
6
  "author": "Chris Breuer",
7
7
  "contributors": [
@@ -55,7 +55,7 @@
55
55
  "prepublishOnly": "bun run build"
56
56
  },
57
57
  "dependencies": {
58
- "@stacksjs/ts-cloud": "^0.2.15"
58
+ "@stacksjs/ts-cloud": "^0.7.12"
59
59
  },
60
60
  "peerDependencies": {
61
61
  "@anthropic-ai/claude-agent-sdk": "^0.2.79"