@arcteninc/core 0.0.178 → 0.0.179

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,3 +1,3 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react"),ot=require("@ai-sdk/react"),Je=require("ai"),_=Symbol.for("@arcteninc/core:originalName");function rt(f,l){return f[_]=l,f}function nt(f,l,g,y){if(typeof f!="function")return null;const w=f[_];if(w){const E=l[w];if(E&&!g.has(E.name))return{fn:f,meta:E}}const d=f.name;let c;if(d&&(c=l[d],c&&!g.has(c.name)))return f[_]=c.name,{fn:f,meta:c};if(y&&y.length>0){for(const E of y)if(!g.has(E)&&(c=l[E],c))return f[_]=c.name,{fn:f,meta:c}}else if(c=Object.values(l).find(N=>!g.has(N.name)),c)return f[_]=c.name,{fn:f,meta:c};return null}function Pe(f,l){if(!l)return[];let g,y;if("functions"in l&&typeof l.functions=="object"){const d=l;g=d.functions,y=d.toolOrder}else g=l,y=void 0;const w=new Set;return f.map(d=>{const c=nt(d,g,w,y);if(!c){const E=d.name,R=d[_]||E||"unnamed";return typeof process<"u"&&(process.env.NODE_ENV==="development"||process.env.NODE_ENV!=="production")&&typeof console<"u"&&console.warn&&console.warn(`⚠️ [@arcteninc/core] No metadata found for tool "${R}". This tool will be excluded.
2
- To fix: Run "arcten-extract-types ." and ensure "${R}" is used in ArctenAgent/useAgent.`),null}return w.add(c.meta.name),{name:c.meta.name,description:c.meta.description,jsonSchema:c.meta.parameters}}).filter(d=>d!==null)}const M=process.env.NODE_ENV==="development";function re(f){if(typeof f=="string")try{const l=JSON.parse(f);return re(l)}catch{return f}if(Array.isArray(f))return f.map(re);if(f&&typeof f=="object"){const l={};for(const[g,y]of Object.entries(f))l[g]=re(y);return l}return f}function st(f){if(typeof f=="string"){try{const l=JSON.parse(f);if(l&&typeof l=="object"&&!Array.isArray(l))return re(l)}catch{}return{}}return f&&typeof f=="object"&&!Array.isArray(f)?re(f):{}}function at(f,l){if(!f||f.length===0)return l;const g=new Map;l.forEach(d=>{const c=d[_]||d.name;c&&g.set(c,d)});const y=new Map(f.map(d=>[d.name,d])),w=[];return f.forEach(d=>{const c=g.get(d.name);if(!c){M&&console.log(`[useAgent] Skipping server-only tool: ${d.name}`);return}if(!d.isEnabled&&!d.isOverridable){M&&console.log(`[useAgent] Blocking non-overridable disabled tool: ${d.name}`);return}if(!d.isEnabled&&d.isOverridable&&c){M&&console.log(`[useAgent] Allowing overridable disabled tool with local implementation: ${d.name}`),w.push(c);return}d.isEnabled&&c&&w.push(c)}),l.forEach(d=>{const c=d[_]||d.name;c&&!y.has(c)&&(M&&console.log(`[useAgent] Allowing client-only tool (forward compatible): ${c}`),w.push(d))}),w}function it({apiBaseUrl:f="https://api.arcten.com",tokenEndpoint:l="/api/arcten/token",clientToken:g,skipTokenFetch:y=!1,user:w,tools:d=[],safeTools:c=[],safeToolNames:E,toolMetadata:N,systemPrompt:R="",agentId:J,agentName:K,projectId:x,enableRemoteConfig:T,remoteConfigUrl:S,initialMessages:D=[],conversationId:Q,state:P,onToolCall:U,onFinish:q,sources:j,ragConfig:ne,ragFilters:z,planning:$=!1}={}){const X=s.useRef(P),b=f.replace(/\/+$/,""),[A,pe]=s.useState(null),[lt,ve]=s.useState(!1),[ut,Me]=s.useState(null),se=s.useMemo(()=>{const t=j||[],e=A?.config?.sources||[];return[...new Set([...t,...e])]},[j,A]),C=s.useMemo(()=>ne!==void 0?ne:z?{enabled:!0,filters:z}:se&&se.length>0?{enabled:!0,organizationId:se[0],autoExecute:!0,filters:void 0}:{enabled:!1},[se,ne,z]),je=s.useMemo(()=>T===!1?!1:!!x,[x,T]);s.useEffect(()=>{if(!je||!v.current)return;(async()=>{ve(!0),Me(null);try{const o=`${S||b.replace("/chat","").replace(/\/$/,"")}/convex/api/query`,r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${v.current}`},body:JSON.stringify({path:"agents:getConfigForClient",args:{projectId:x,agentName:K,agentId:J},format:"json"})});if(!r.ok){if(r.status===404){M&&console.warn("[useAgent] Remote config endpoint not found (404), using local tools only"),pe(null);return}const a=await r.text().catch(()=>"Unknown error");throw new Error(`Failed to fetch remote config: ${r.status} ${a}`)}const n=await r.json();pe(n?.value||null),M&&console.log("[useAgent] Remote config loaded successfully:",n?.value)}catch(e){console.error("[useAgent] Failed to fetch remote config:",e);const o=e instanceof Error?e:new Error(String(e));Me(o),pe(null)}finally{ve(!1)}})()},[je,x,K,J,b,S]);const[W,me]=s.useState(g||null),v=s.useRef(g||null);s.useEffect(()=>{X.current=P},[P]);const[qe,te]=s.useState(null),[Z,ge]=s.useState(null),F=s.useRef(null),[Oe,Ne]=s.useState([]),[ye,Re]=s.useState(Q||(typeof window<"u"?crypto.randomUUID():null)),[ze,ae]=s.useState(!1),[we,be]=s.useState(new Map),ie=s.useRef(new Set),ke=s.useRef(new Set),ce=s.useRef(new Set);s.useEffect(()=>{X.current=P},[P]);const[Se,We]=s.useState([]),le=s.useMemo(()=>$?async function(){return{todos:Se}}:null,[$,Se]),ue=s.useMemo(()=>$?async function(e){return We(e),{success:!0,todos:e}}:null,[$]),L=s.useMemo(()=>C?.enabled?async function(e,o=20,r){const n={...C.filters,...r};if(j&&j.length>1){const i=j.map(p=>fetch(`${b}/search`,{method:"POST",headers:{"Content-Type":"application/json",...v.current?{Authorization:`Bearer ${v.current}`}:{}},body:JSON.stringify({q:e,k:Math.min(o,100),organizationId:p,...Object.keys(n).length>0?{filters:n}:{}})}).then(m=>m.ok?m.json():null)),h=await Promise.all(i),u=[];for(const p of h)p?.candidates&&u.push(...p.candidates);u.sort((p,m)=>{const O=p.scores?.rerank||p.scores?.dense||0;return(m.scores?.rerank||m.scores?.dense||0)-O});const k=u.slice(0,o).map((p,m)=>{const O=p.citation||p.url;return{rank:m+1,doc_id:p.doc_id,block_id:p.block_id,url:p.url,citation:O,title:p.title||"Untitled",snippet:p.snippet,score:p.scores?.rerank||p.scores?.dense||0,metadata:{site:p.metadata?.site,lang:p.metadata?.lang,contentType:p.metadata?.content_type}}});return{success:!0,query:e,total:u.length,results:k,summary:`Found ${u.length} relevant results across ${j.length} source(s) for "${e}". Top result: ${k[0]?.title||"N/A"}`}}const a=C.organizationId&&C.organizationId!=="default"?C.organizationId:j&&j.length>0?j[0]:void 0;try{const i={q:e,k:Math.min(o,100)};a&&(i.organizationId=a),Object.keys(n).length>0&&(i.filters=n);const h={"Content-Type":"application/json"};v.current&&(h.Authorization=`Bearer ${v.current}`);const u=await fetch(`${b}/search`,{method:"POST",headers:h,body:JSON.stringify(i)});if(!u.ok){const m=await u.text();return{success:!1,error:`Search failed: ${u.status} ${m}`}}const k=await u.json(),p=k.candidates.map((m,O)=>{const he=m.citation||m.url;return{rank:O+1,doc_id:m.doc_id,block_id:m.block_id,url:m.url,citation:he,title:m.title||"Untitled",snippet:m.snippet,score:m.scores?.rerank||m.scores?.dense||0,metadata:{site:m.metadata?.site,lang:m.metadata?.lang,contentType:m.metadata?.content_type}}});return{success:!0,query:k.query,total:k.total,results:p,summary:`Found ${k.total} relevant results for "${e}". Top result: ${p[0]?.title||"N/A"}`}}catch(i){return{success:!1,error:i instanceof Error?i.message:"Unknown error occurred"}}}:null,[C,b,v]),G=s.useMemo(()=>C?.enabled?async function(e,o){const r=C.organizationId&&C.organizationId!=="default"?C.organizationId:j&&j.length>0?j[0]:void 0;try{const n={"Content-Type":"application/json"};v.current&&(n.Authorization=`Bearer ${v.current}`);const a=await fetch(`${b}/fetch`,{method:"POST",headers:n,body:JSON.stringify({doc_id:e,block_ids:o,...r?{organizationId:r}:{}})});if(!a.ok){const h=await a.text();return{success:!1,error:`Fetch failed: ${a.status} ${h}`}}const i=await a.json();return{success:!0,blocks:i.blocks||[],fullContent:i.fullContent||"",pageUrl:i.pageUrl||"",pageTitle:i.pageTitle||"",summary:`Fetched ${i.blocks?.length||0} blocks from ${i.pageTitle||e}`}}catch(n){return{success:!1,error:n instanceof Error?n.message:"Unknown error occurred"}}}:null,[C,b,v]),fe=s.useMemo(()=>{if(A&&A.config?.tools){const t=at(A.config.tools,d);return M&&console.log("[useAgent] Merged remote config:",{remoteToolCount:A.config.tools.length,localToolCount:d.length,mergedToolCount:t.length}),t}return d},[A,d]),I=A?.enableRagTools??C?.enabled??!1,_e=s.useMemo(()=>{const t=[...fe,...c];return I&&(L&&t.push(L),G&&t.push(G)),t},[fe,c,L,G,I]),xe=s.useMemo(()=>[...fe,...c],[fe,c]),H=s.useMemo(()=>Pe(xe,N),[xe,N]),oe=s.useMemo(()=>{const t=new Map,e=new Map(H.map(o=>[o.name,o]));return C?.enabled&&(L&&t.set("searchDocs",L),G&&t.set("fetchDocContent",G)),$&&(le&&t.set("todo_read",le),ue&&t.set("todo_write",ue)),_e.forEach(o=>{if(o===L||o===G||o===le||o===ue)return;const r=o[_];if(r){const a=e.get(r);if(a){t.set(a.name,o);return}}const n=H.find(a=>a.name===o.name);n&&t.set(n.name,o)}),t},[_e,H,L,G,C,$,le,ue]),De=s.useMemo(()=>new Set(H.map(t=>t.name)),[H]),Ue=s.useMemo(()=>{const t=[];I&&t.push({name:"searchDocs",description:"Search documentation using semantic search. Returns relevant results with snippets and scores. Use this first to find relevant documentation. Default returns 20 results - use higher k values (30-50) when you need to find many sources.",jsonSchema:{type:"object",properties:{query:{type:"string",description:"The search query (user's question or keywords)"},k:{type:"number",description:"Number of results to return (default: 20, max: 100). Use 20-30 for comprehensive searches, or higher (50-100) when you need to find all relevant sources.",default:20},filters:{type:"object",description:"Optional filters to scope the search",properties:{site:{type:"string"},lang:{type:"string"},tags:{type:"array",items:{type:"string"}},docIds:{type:"array",items:{type:"string"}},pageIds:{type:"array",items:{type:"string"}}}}},required:["query"]}},{name:"fetchDocContent",description:"Fetch full content of documentation blocks after searching. Use this AFTER searchDocs when you find relevant results (scores > 0.3) to get complete text. Automatically fetches nearby blocks (5 chunks before/after each requested block) for context. You can pass multiple block_ids to fetch comprehensive content from multiple blocks/pages.",jsonSchema:{type:"object",properties:{doc_id:{type:"string",description:"The doc_id from searchDocs results"},block_ids:{type:"array",items:{type:"string"},description:"Array of block_ids from searchDocs results. You can pass multiple block_ids to fetch comprehensive content."}},required:["doc_id","block_ids"]}});const e=[];A?.config?.workflows&&A.config.workflows.forEach(r=>{const n={},a=[];r.parameters&&r.parameters.forEach(i=>{n[i.name]={type:i.type||"string",description:i.description},i.required&&a.push(i.name)}),e.push({name:`workflow_${r.name.replace(/\s+/g,"_").toLowerCase()}`,description:r.description||`Execute the "${r.name}" workflow. ${r.contentPlaintext?.slice(0,200)||""}`,jsonSchema:{type:"object",properties:n,required:a},_workflow:r})});const o=[];return $&&o.push({name:"todo_read",description:"Read the current todo list. Returns all todo items with their status (pending, in_progress, completed).",jsonSchema:{type:"object",properties:{},required:[]}},{name:"todo_write",description:"Write/update the todo list. Pass the complete list of todos to replace the current list. Each todo must have id, content, and status (pending, in_progress, completed).",jsonSchema:{type:"object",properties:{todoList:{type:"array",description:"The complete list of todo items",items:{type:"object",properties:{id:{type:"string",description:"Unique identifier for the todo item"},content:{type:"string",description:"The content/description of the todo item"},status:{type:"string",enum:["pending","in_progress","completed"],description:"The current status of the todo item"}},required:["id","content","status"]}}},required:["todoList"]}}),[...H,...t,...e,...o]},[H,I,A,$]),ee=s.useMemo(()=>Ue.filter(t=>t.name==="searchDocs"||t.name==="fetchDocContent"?I:t.name.startsWith("workflow_")?!0:t.name==="todo_read"||t.name==="todo_write"?$:De.has(t.name)),[Ue,De,I,$]),de=s.useMemo(()=>{const t=new Set;return I&&C?.autoExecute!==!1&&(t.add("searchDocs"),t.add("fetchDocContent")),$&&(t.add("todo_read"),t.add("todo_write")),A?.config?.tools?A.config.tools.forEach(e=>{e.isEnabled&&!e.requiresApproval&&t.add(e.name)}):(c.forEach(e=>{for(const[o,r]of oe.entries())if(r===e){t.add(o);break}}),E&&Array.isArray(E)&&E.forEach(e=>{typeof e=="string"&&t.add(e)})),A?.config?.workflows&&A.config.workflows.forEach(e=>{const o=`workflow_${e.name.replace(/\s+/g,"_").toLowerCase()}`;e.requiresApproval||t.add(o)}),t},[A,c,E,oe,I,C,$]);s.useEffect(()=>{if(y||g)return;let t=!1,e=null;const o=async(r=1,n=3)=>{if(!t)try{const a=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!a.ok)throw new Error("Failed to fetch token");const i=await a.json();t||(me(i.clientToken),v.current=i.clientToken,ge(i.expiresAt),te(null))}catch(a){if(console.error(`[useAgent] Token fetch failed (attempt ${r}/${n}):`,a),r<n&&!t){const i=Math.pow(2,r-1)*1e3;e=setTimeout(()=>o(r+1,n),i)}else t||te(a instanceof Error?a.message:"Failed to fetch token")}};return o(),()=>{t=!0,e&&clearTimeout(e),F.current&&clearTimeout(F.current)}},[l,JSON.stringify(w),y,g]),s.useEffect(()=>{if(!Z||y||g)return;F.current&&clearTimeout(F.current);const t=async(a=1,i=3)=>{try{const h=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!h.ok)throw new Error("Failed to refresh token");const u=await h.json();me(u.clientToken),v.current=u.clientToken,ge(u.expiresAt),te(null)}catch(h){if(console.error(`[useAgent] Token refresh failed (attempt ${a}/${i}):`,h),a<i){const u=Math.pow(2,a-1)*1e3;setTimeout(()=>t(a+1,i),u)}else te(h instanceof Error?h.message:"Failed to refresh token")}},e=Math.floor(Date.now()/1e3),o=Z-e,n=Math.max(0,o-5);return F.current=setTimeout(()=>t(),n*1e3),()=>{F.current&&clearTimeout(F.current)}},[Z,l,JSON.stringify(w),y,g]),s.useEffect(()=>{if(y||g)return;const t=async()=>{if(document.visibilityState!=="visible")return;const e=Math.floor(Date.now()/1e3);if(!Z||Z<=e+5){M&&console.log("[useAgent] Tab visible, token expired - refreshing");try{const r=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(r.ok){const n=await r.json();me(n.clientToken),v.current=n.clientToken,ge(n.expiresAt),te(null)}}catch(r){console.error("[useAgent] Token refresh on visibility change failed:",r)}}};return document.addEventListener("visibilitychange",t),()=>document.removeEventListener("visibilitychange",t)},[l,JSON.stringify(w),Z,y,g]);const Fe=async(t,e={})=>{const o=e.headers?new Headers(e.headers):new Headers;return o.delete("user-agent"),o.delete("User-Agent"),fetch(t,{...e,headers:o})},Te=s.useRef(null),Le=`${b}/chat`,{messages:B,sendMessage:Ge,status:Ee,error:$e,stop:He,addToolResult:Ae,setMessages:Ce}=ot.useChat({id:ye||void 0,messages:D,transport:new Je.DefaultChatTransport({api:Le,fetch:Fe,headers:()=>{const t={};return v.current&&(t.Authorization=`Bearer ${v.current}`),t},body:()=>{const t=ee.map(o=>({name:o.name,description:o.description,inputSchema:o.jsonSchema})),e=X.current;return{tools:t,...J&&{agentId:J},...K&&{agentName:K},...z&&{ragFilters:z},...e&&{state:e}}}}),sendAutomaticallyWhen:t=>{const e=t.messages;if(e[e.length-1]?.role!=="assistant")return!1;const n=[...e].reverse().find(i=>i.role==="user")?.id;if(n&&Te.current===n)return!1;const a=Je.lastAssistantMessageIsCompleteWithToolCalls(t);return a&&n&&(Te.current=n),a}}),Ie=Ge,Ve=s.useCallback(t=>(Te.current=null,ce.current=new Set,Ie(t)),[Ie]),V=s.useCallback((t,e,o)=>{Ae({toolCallId:e,tool:t,output:o})},[Ae]);s.useEffect(()=>{B.forEach(t=>{t.role==="assistant"&&t.parts.forEach(e=>{if(!e.type?.startsWith("tool-")||e.state!=="input-available")return;const o=e.type.replace("tool-",""),r=e.toolCallId;if(ie.current.has(r)||ke.current.has(r)){M&&console.log(`[useAgent] Skipping ${o} (${r}) - already processing or completed`);return}M&&console.log(`[useAgent] Starting ${o} (${r})`),ie.current.add(r);const n=h=>{M&&console.log(`[useAgent] Completed ${o} (${h})`),ke.current.add(h),ie.current.delete(h)},a=st(e.input),i=`${o}:${JSON.stringify(a)}`;if(ce.current.has(i)){M&&console.log(`[useAgent] Skipping duplicate tool call: ${i}`),V(o,r,"This tool was already called successfully with the same arguments in this response. Using previous result."),n(r);return}if(o.startsWith("workflow_")&&de.has(o)){(async()=>{try{const u=ee.find(p=>p.name===o)?._workflow;if(!u)throw new Error(`Workflow metadata not found for ${o}`);let k;if(u.webhook?.url){let p=a;if(u.webhook.bodyTemplate){let O=u.webhook.bodyTemplate;Object.entries(a).forEach(([he,tt])=>{O=O.replace(new RegExp(`\\{\\{${he}\\}\\}`,"g"),String(tt))}),p=JSON.parse(O)}const m=await fetch(u.webhook.url,{method:u.webhook.method||"POST",headers:{"Content-Type":"application/json",...u.webhook.headers||{}},body:JSON.stringify(p)});if(m.ok)k={success:!0,data:await m.json().catch(()=>({success:!0}))};else{const O=await m.text();k={success:!1,error:`Webhook failed: ${m.status} ${O}`}}}else k={success:!0,message:`Workflow "${u.name}" acknowledged. Follow the workflow instructions to proceed.`,instructions:u.contentPlaintext};n(r),V(o,r,k),ce.current.add(i)}catch(h){console.error(`[useAgent] Error executing workflow ${o}:`,h),n(r),V(o,r,`Error: ${h}`)}})();return}if(de.has(o)){const h=oe.get(o);h?(async()=>{try{const u=ee.find(p=>p.name===o);let k;if(u&&u.jsonSchema?.properties){const m=Object.keys(u.jsonSchema.properties).map(O=>a[O]);k=await h(...m)}else k=await h(...Object.values(a));n(r),V(o,r,k),ce.current.add(i)}catch(u){console.error(`[useAgent] Error executing tool ${o}:`,u),n(r),V(o,r,`Error: ${u}`)}})():(M&&console.warn(`[useAgent] Tool ${o} not found in toolsMap`),V(o,r,`Error: Tool "${o}" not found. The tool may not be registered or available.`),n(r))}else if(o.startsWith("workflow_")&&U)U({toolCall:{toolCallId:r,toolName:o,args:a}});else if(U)U({toolCall:{toolCallId:r,toolName:o,args:a}});else{const h={toolCallId:r,toolName:o,args:a};be(u=>{const k=new Map(u);return k.set(r,h),k})}})})},[B,de,oe,U,V,ee]),s.useEffect(()=>{if(Ee==="ready"&&B.length>0&&q){const t=B[B.length-1];t&&t.role==="assistant"&&q({message:t,messages:B,isAbort:!1,isDisconnect:!1,isError:!!$e})}},[Ee,B,$e,q]);async function Ye(){if(!(!w?.id||!W)){ae(!0);try{const e=await(await fetch(`${b}/conversations`,{headers:{Authorization:`Bearer ${W}`}})).json();Ne(e.conversations||[])}catch(t){console.error("Failed to fetch conversations:",t)}finally{ae(!1)}}}s.useEffect(()=>{w?.id&&W&&Ye()},[JSON.stringify(w),W,b]);async function Ke(t){Re(t),ae(!0);try{const e=await fetch(`${b}/conversations/${t}/messages`,{headers:{Authorization:`Bearer ${v.current}`}});if(!e.ok)throw new Error(`Failed to fetch messages: ${e.statusText}`);const r=(await e.json()).messages||[];Ce(r)}catch(e){console.error("Failed to load conversation messages:",e)}finally{ae(!1)}}async function Qe(t){if(W)try{await fetch(`${b}/conversations/${t}`,{method:"DELETE",headers:{Authorization:`Bearer ${W}`}}),Ne(Oe.filter(e=>e._id!==t)),t===ye&&Be()}catch(e){console.error("Failed to delete conversation:",e)}}function Be(){const t=crypto.randomUUID();Re(t),Ce([]),ie.current=new Set,ke.current=new Set}function Y(t){const e=t.tool||"unknown-tool";Ae({toolCallId:t.toolCallId,tool:e,output:t.output})}async function Xe(t,e,o){if(!e.startsWith("workflow_"))throw new Error(`${e} is not a workflow tool`);try{const n=ee.find(i=>i.name===e)?._workflow;if(!n)throw new Error(`Workflow metadata not found for ${e}`);let a;if(n.webhook?.url){let i=o;if(n.webhook.bodyTemplate){let u=n.webhook.bodyTemplate;Object.entries(o).forEach(([k,p])=>{u=u.replace(new RegExp(`\\{\\{${k}\\}\\}`,"g"),String(p))}),i=JSON.parse(u)}const h=await fetch(n.webhook.url,{method:n.webhook.method||"POST",headers:{"Content-Type":"application/json",...n.webhook.headers||{}},body:JSON.stringify(i)});if(h.ok)a={success:!0,data:await h.json().catch(()=>({success:!0}))};else{const u=await h.text();a={success:!1,error:`Webhook failed: ${h.status} ${u}`}}}else a={success:!0,message:`Workflow "${n.name}" acknowledged. Follow the workflow instructions to proceed.`,instructions:n.contentPlaintext};return Y({toolCallId:t,tool:e,output:a}),a}catch(r){const n={success:!1,error:String(r)};throw Y({toolCallId:t,tool:e,output:n}),r}}async function Ze(t){const e=we.get(t);if(!e){M&&console.warn(`[useAgent] Tool call ${t} not found in pending approvals`);return}be(r=>{const n=new Map(r);return n.delete(t),n});const o=oe.get(e.toolName);if(o)try{const r=ee.find(a=>a.name===e.toolName);let n;if(r&&r.jsonSchema?.properties){const i=Object.keys(r.jsonSchema.properties).map(h=>e.args[h]);n=await o(...i)}else n=await o(...Object.values(e.args));Y({toolCallId:e.toolCallId,tool:e.toolName,output:n})}catch(r){console.error(`[useAgent] Error executing tool ${e.toolName}:`,r),Y({toolCallId:e.toolCallId,tool:e.toolName,output:`Error: ${r}`})}else M&&console.warn(`[useAgent] Tool ${e.toolName} not found in toolsMap`),Y({toolCallId:e.toolCallId,tool:e.toolName,output:`Error: Tool "${e.toolName}" not found`})}function et(t){const e=we.get(t);if(!e){M&&console.warn(`[useAgent] Tool call ${t} not found in pending approvals`);return}be(o=>{const r=new Map(o);return r.delete(t),r}),Y({toolCallId:e.toolCallId,tool:e.toolName,output:{denied:!0,message:"Tool execution was denied by user"}})}return{id:ye,messages:B,status:Ee,error:$e,sendMessage:Ve,stop:He,addToolOutput:Y,executeWorkflowTool:Xe,setMessages:Ce,conversations:Oe,loadConversation:Ke,deleteConversation:Qe,startNewConversation:Be,isLoadingConversations:ze,clientToken:W,tokenError:qe,pendingToolApprovals:Array.from(we.values()),approveToolCall:Ze,denyToolCall:et,safeToolNames:de,todos:Se}}function ct(f={}){const{apiBaseUrl:l="https://api.arcten.com",tokenEndpoint:g="/token",clientToken:y,skipTokenFetch:w=!1}=f,[d,c]=s.useState(!1),[E,N]=s.useState(null),R=s.useRef(y||null);s.useEffect(()=>{if(y){R.current=y;return}if(w)return;(async()=>{try{const T=await fetch(`${l}${g}`,{method:"POST",headers:{"Content-Type":"application/json"}});if(T.ok){const S=await T.json();R.current=S.token}}catch(T){console.error("[useGenerate] Failed to fetch token:",T)}})()},[l,g,y,w]);const J=s.useCallback(async x=>{c(!0),N(null);try{const T={"Content-Type":"application/json"};R.current&&(T.Authorization=`Bearer ${R.current}`);const S=await fetch(`${l}/generate`,{method:"POST",headers:T,body:JSON.stringify(x)});if(!S.ok){const Q=await S.json().catch(()=>({}));throw new Error(Q.error||`HTTP ${S.status}`)}return await S.json()}catch(T){const S=T instanceof Error?T.message:String(T);throw N(S),T}finally{c(!1)}},[l]),K=s.useCallback(async(x,T)=>{c(!0),N(null);try{const S={"Content-Type":"application/json"};R.current&&(S.Authorization=`Bearer ${R.current}`);const D=await fetch(`${l}/generate/stream`,{method:"POST",headers:S,body:JSON.stringify(x)});if(!D.ok){const q=await D.json().catch(()=>({}));throw new Error(q.error||`HTTP ${D.status}`)}const Q=D.body?.getReader();if(!Q)throw new Error("No response body");const P=new TextDecoder;let U=null;for(;;){const{done:q,value:j}=await Q.read();if(q)break;const z=P.decode(j,{stream:!0}).split(`
3
- `).filter($=>$.startsWith("data: "));for(const $ of z){const X=$.slice(6).trim();if(X)try{const b=JSON.parse(X);if(b.error)throw new Error(b.error);b.done&&b.object?U={object:b.object,usage:b.usage,finishReason:b.finishReason}:b.partial&&T&&T(b.partial)}catch{}}}if(!U)throw new Error("Stream ended without final result");return U}catch(S){const D=S instanceof Error?S.message:String(S);throw N(D),S}finally{c(!1)}},[l]);return{generate:J,streamGenerate:K,isLoading:d,error:E}}exports.ARCTEN_ORIGINAL_NAME=_;exports.extractToolsMetadata=Pe;exports.preserveToolName=rt;exports.useAgent=it;exports.useGenerate=ct;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const s=require("react"),ot=require("@ai-sdk/react"),Je=require("ai"),_=Symbol.for("@arcteninc/core:originalName");function rt(f,l){return f[_]=l,f}function nt(f,l,g,y){if(typeof f!="function")return null;const w=f[_];if(w){const $=l[w];if($&&!g.has($.name))return{fn:f,meta:$}}const d=f.name;let c;if(d&&(c=l[d],c&&!g.has(c.name)))return f[_]=c.name,{fn:f,meta:c};if(y&&y.length>0){for(const $ of y)if(!g.has($)&&(c=l[$],c))return f[_]=c.name,{fn:f,meta:c}}else if(c=Object.values(l).find(N=>!g.has(N.name)),c)return f[_]=c.name,{fn:f,meta:c};return null}function Pe(f,l){if(!l)return[];let g,y;if("functions"in l&&typeof l.functions=="object"){const d=l;g=d.functions,y=d.toolOrder}else g=l,y=void 0;const w=new Set;return f.map(d=>{const c=nt(d,g,w,y);if(!c){const $=d.name,R=d[_]||$||"unnamed";return typeof process<"u"&&(process.env.NODE_ENV==="development"||process.env.NODE_ENV!=="production")&&typeof console<"u"&&console.warn&&console.warn(`⚠️ [@arcteninc/core] No metadata found for tool "${R}". This tool will be excluded.
2
+ To fix: Run "arcten-extract-types ." and ensure "${R}" is used in ArctenAgent/useAgent.`),null}return w.add(c.meta.name),{name:c.meta.name,description:c.meta.description,jsonSchema:c.meta.parameters}}).filter(d=>d!==null)}const M=process.env.NODE_ENV==="development";function re(f){if(typeof f=="string")try{const l=JSON.parse(f);return re(l)}catch{return f}if(Array.isArray(f))return f.map(re);if(f&&typeof f=="object"){const l={};for(const[g,y]of Object.entries(f))l[g]=re(y);return l}return f}function st(f){if(typeof f=="string"){try{const l=JSON.parse(f);if(l&&typeof l=="object"&&!Array.isArray(l))return re(l)}catch{}return{}}return f&&typeof f=="object"&&!Array.isArray(f)?re(f):{}}function at(f,l){if(!f||f.length===0)return l;const g=new Map;l.forEach(d=>{const c=d[_]||d.name;c&&g.set(c,d)});const y=new Map(f.map(d=>[d.name,d])),w=[];return f.forEach(d=>{const c=g.get(d.name);if(!c){M&&console.log(`[useAgent] Skipping server-only tool: ${d.name}`);return}if(!d.isEnabled&&!d.isOverridable){M&&console.log(`[useAgent] Blocking non-overridable disabled tool: ${d.name}`);return}if(!d.isEnabled&&d.isOverridable&&c){M&&console.log(`[useAgent] Allowing overridable disabled tool with local implementation: ${d.name}`),w.push(c);return}d.isEnabled&&c&&w.push(c)}),l.forEach(d=>{const c=d[_]||d.name;c&&!y.has(c)&&(M&&console.log(`[useAgent] Allowing client-only tool (forward compatible): ${c}`),w.push(d))}),w}function it({apiBaseUrl:f="https://api.arcten.com",tokenEndpoint:l="/api/arcten/token",clientToken:g,skipTokenFetch:y=!1,user:w,tools:d=[],safeTools:c=[],safeToolNames:$,toolMetadata:N,systemPrompt:R="",agentId:J,agentName:K,projectId:x,enableRemoteConfig:T,remoteConfigUrl:S,initialMessages:D=[],conversationId:Q,state:P,onToolCall:U,onFinish:q,sources:j,ragConfig:ne,ragFilters:z,planning:E=!1}={}){const X=s.useRef(P),b=f.replace(/\/+$/,""),[A,pe]=s.useState(null),[lt,ve]=s.useState(!1),[ut,Me]=s.useState(null),se=s.useMemo(()=>{const t=j||[],e=A?.config?.sources||[];return[...new Set([...t,...e])]},[j,A]),C=s.useMemo(()=>ne!==void 0?ne:z?{enabled:!0,filters:z}:se&&se.length>0?{enabled:!0,organizationId:se[0],autoExecute:!0,filters:void 0}:{enabled:!1},[se,ne,z]),je=s.useMemo(()=>T===!1?!1:!!x,[x,T]);s.useEffect(()=>{if(!je||!v.current)return;(async()=>{ve(!0),Me(null);try{const o=`${S||b.replace("/chat","").replace(/\/$/,"")}/convex/api/query`,r=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${v.current}`},body:JSON.stringify({path:"agents:getConfigForClient",args:{projectId:x,agentName:K,agentId:J},format:"json"})});if(!r.ok){if(r.status===404){M&&console.warn("[useAgent] Remote config endpoint not found (404), using local tools only"),pe(null);return}const a=await r.text().catch(()=>"Unknown error");throw new Error(`Failed to fetch remote config: ${r.status} ${a}`)}const n=await r.json();pe(n?.value||null),M&&console.log("[useAgent] Remote config loaded successfully:",n?.value)}catch(e){console.error("[useAgent] Failed to fetch remote config:",e);const o=e instanceof Error?e:new Error(String(e));Me(o),pe(null)}finally{ve(!1)}})()},[je,x,K,J,b,S]);const[W,me]=s.useState(g||null),v=s.useRef(g||null);s.useEffect(()=>{X.current=P},[P]);const[qe,te]=s.useState(null),[Z,ge]=s.useState(null),F=s.useRef(null),[Oe,Ne]=s.useState([]),[ye,Re]=s.useState(Q||(typeof window<"u"?crypto.randomUUID():null)),[ze,ae]=s.useState(!1),[we,be]=s.useState(new Map),ie=s.useRef(new Set),ke=s.useRef(new Set),ce=s.useRef(new Set);s.useEffect(()=>{X.current=P},[P]);const[Se,We]=s.useState([]),le=s.useMemo(()=>E?async function(){return{todos:Se}}:null,[E,Se]),ue=s.useMemo(()=>E?async function(e){return We(e),{success:!0,todos:e}}:null,[E]),L=s.useMemo(()=>C?.enabled?async function(e,o=20,r){const n={...C.filters,...r};if(j&&j.length>1){const i=j.map(p=>fetch(`${b}/search`,{method:"POST",headers:{"Content-Type":"application/json",...v.current?{Authorization:`Bearer ${v.current}`}:{}},body:JSON.stringify({q:e,k:Math.min(o,100),organizationId:p,...Object.keys(n).length>0?{filters:n}:{}})}).then(m=>m.ok?m.json():null)),h=await Promise.all(i),u=[];for(const p of h)p?.candidates&&u.push(...p.candidates);u.sort((p,m)=>{const O=p.scores?.rerank||p.scores?.dense||0;return(m.scores?.rerank||m.scores?.dense||0)-O});const k=u.slice(0,o).map((p,m)=>{const O=p.citation||p.url;return{rank:m+1,doc_id:p.doc_id,block_id:p.block_id,url:p.url,citation:O,title:p.title||"Untitled",snippet:p.snippet,score:p.scores?.rerank||p.scores?.dense||0,metadata:{site:p.metadata?.site,lang:p.metadata?.lang,contentType:p.metadata?.content_type}}});return{success:!0,query:e,total:u.length,results:k,summary:`Found ${u.length} relevant results across ${j.length} source(s) for "${e}". Top result: ${k[0]?.title||"N/A"}`}}const a=C.organizationId&&C.organizationId!=="default"?C.organizationId:j&&j.length>0?j[0]:void 0;try{const i={q:e,k:Math.min(o,100)};a&&(i.organizationId=a),Object.keys(n).length>0&&(i.filters=n);const h={"Content-Type":"application/json"};v.current&&(h.Authorization=`Bearer ${v.current}`);const u=await fetch(`${b}/search`,{method:"POST",headers:h,body:JSON.stringify(i)});if(!u.ok){const m=await u.text();return{success:!1,error:`Search failed: ${u.status} ${m}`}}const k=await u.json(),p=k.candidates.map((m,O)=>{const he=m.citation||m.url;return{rank:O+1,doc_id:m.doc_id,block_id:m.block_id,url:m.url,citation:he,title:m.title||"Untitled",snippet:m.snippet,score:m.scores?.rerank||m.scores?.dense||0,metadata:{site:m.metadata?.site,lang:m.metadata?.lang,contentType:m.metadata?.content_type}}});return{success:!0,query:k.query,total:k.total,results:p,summary:`Found ${k.total} relevant results for "${e}". Top result: ${p[0]?.title||"N/A"}`}}catch(i){return{success:!1,error:i instanceof Error?i.message:"Unknown error occurred"}}}:null,[C,b,v]),G=s.useMemo(()=>C?.enabled?async function(e,o){const r=C.organizationId&&C.organizationId!=="default"?C.organizationId:j&&j.length>0?j[0]:void 0;try{const n={"Content-Type":"application/json"};v.current&&(n.Authorization=`Bearer ${v.current}`);const a=await fetch(`${b}/fetch`,{method:"POST",headers:n,body:JSON.stringify({doc_id:e,block_ids:o,...r?{organizationId:r}:{}})});if(!a.ok){const h=await a.text();return{success:!1,error:`Fetch failed: ${a.status} ${h}`}}const i=await a.json();return{success:!0,blocks:i.blocks||[],fullContent:i.fullContent||"",pageUrl:i.pageUrl||"",pageTitle:i.pageTitle||"",summary:`Fetched ${i.blocks?.length||0} blocks from ${i.pageTitle||e}`}}catch(n){return{success:!1,error:n instanceof Error?n.message:"Unknown error occurred"}}}:null,[C,b,v]),fe=s.useMemo(()=>{if(A&&A.config?.tools){const t=at(A.config.tools,d);return M&&console.log("[useAgent] Merged remote config:",{remoteToolCount:A.config.tools.length,localToolCount:d.length,mergedToolCount:t.length}),t}return d},[A,d]),I=A?.enableRagTools??C?.enabled??!1,_e=s.useMemo(()=>{const t=[...fe,...c];return I&&(L&&t.push(L),G&&t.push(G)),t},[fe,c,L,G,I]),xe=s.useMemo(()=>[...fe,...c],[fe,c]),H=s.useMemo(()=>Pe(xe,N),[xe,N]),oe=s.useMemo(()=>{const t=new Map,e=new Map(H.map(o=>[o.name,o]));return C?.enabled&&(L&&t.set("searchDocs",L),G&&t.set("fetchDocContent",G)),E&&(le&&t.set("todo_read",le),ue&&t.set("todo_write",ue)),_e.forEach(o=>{if(o===L||o===G||o===le||o===ue)return;const r=o[_];if(r){const a=e.get(r);if(a){t.set(a.name,o);return}}const n=H.find(a=>a.name===o.name);n&&t.set(n.name,o)}),t},[_e,H,L,G,C,E,le,ue]),De=s.useMemo(()=>new Set(H.map(t=>t.name)),[H]),Ue=s.useMemo(()=>{const t=[];I&&t.push({name:"searchDocs",description:"Search documentation using semantic search. Returns relevant results with snippets and scores. Use this first to find relevant documentation. Default returns 20 results - use higher k values (30-50) when you need to find many sources.",jsonSchema:{type:"object",properties:{query:{type:"string",description:"The search query (user's question or keywords)"},k:{type:"number",description:"Number of results to return (default: 20, max: 100). Use 20-30 for comprehensive searches, or higher (50-100) when you need to find all relevant sources.",default:20},filters:{type:"object",description:"Optional filters to scope the search",properties:{site:{type:"string"},lang:{type:"string"},tags:{type:"array",items:{type:"string"}},docIds:{type:"array",items:{type:"string"}},pageIds:{type:"array",items:{type:"string"}}}}},required:["query"]}},{name:"fetchDocContent",description:"Fetch full content of documentation blocks after searching. Use this AFTER searchDocs when you find relevant results (scores > 0.3) to get complete text. Automatically fetches nearby blocks (5 chunks before/after each requested block) for context. You can pass multiple block_ids to fetch comprehensive content from multiple blocks/pages.",jsonSchema:{type:"object",properties:{doc_id:{type:"string",description:"The doc_id from searchDocs results"},block_ids:{type:"array",items:{type:"string"},description:"Array of block_ids from searchDocs results. You can pass multiple block_ids to fetch comprehensive content."}},required:["doc_id","block_ids"]}});const e=[];A?.config?.workflows&&A.config.workflows.forEach(r=>{const n={},a=[];r.parameters&&r.parameters.forEach(i=>{n[i.name]={type:i.type||"string",description:i.description},i.required&&a.push(i.name)}),e.push({name:`workflow_${r.name.replace(/\s+/g,"_").toLowerCase()}`,description:r.description||`Execute the "${r.name}" workflow. ${r.contentPlaintext?.slice(0,200)||""}`,jsonSchema:{type:"object",properties:n,required:a},_workflow:r})});const o=[];return E&&o.push({name:"todo_read",description:"Read the current todo list. Returns all todo items with their status (pending, in_progress, completed).",jsonSchema:{type:"object",properties:{},required:[]}},{name:"todo_write",description:"Write/update the todo list. Pass the complete list of todos to replace the current list. Each todo must have id, content, and status (pending, in_progress, completed).",jsonSchema:{type:"object",properties:{todoList:{type:"array",description:"The complete list of todo items",items:{type:"object",properties:{id:{type:"string",description:"Unique identifier for the todo item"},content:{type:"string",description:"The content/description of the todo item"},status:{type:"string",enum:["pending","in_progress","completed"],description:"The current status of the todo item"}},required:["id","content","status"]}}},required:["todoList"]}}),[...H,...t,...e,...o]},[H,I,A,E]),ee=s.useMemo(()=>Ue.filter(t=>t.name==="searchDocs"||t.name==="fetchDocContent"?I:t.name.startsWith("workflow_")?!0:t.name==="todo_read"||t.name==="todo_write"?E:De.has(t.name)),[Ue,De,I,E]),de=s.useMemo(()=>{const t=new Set;return I&&C?.autoExecute!==!1&&(t.add("searchDocs"),t.add("fetchDocContent")),E&&(t.add("todo_read"),t.add("todo_write")),A?.config?.tools?A.config.tools.forEach(e=>{e.isEnabled&&!e.requiresApproval&&t.add(e.name)}):(c.forEach(e=>{for(const[o,r]of oe.entries())if(r===e){t.add(o);break}}),$&&Array.isArray($)&&$.forEach(e=>{typeof e=="string"&&t.add(e)})),A?.config?.workflows&&A.config.workflows.forEach(e=>{const o=`workflow_${e.name.replace(/\s+/g,"_").toLowerCase()}`;e.requiresApproval||t.add(o)}),t},[A,c,$,oe,I,C,E]);s.useEffect(()=>{if(y||g)return;let t=!1,e=null;const o=async(r=1,n=3)=>{if(!t)try{const a=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!a.ok)throw new Error("Failed to fetch token");const i=await a.json();t||(me(i.clientToken),v.current=i.clientToken,ge(i.expiresAt),te(null))}catch(a){if(console.error(`[useAgent] Token fetch failed (attempt ${r}/${n}):`,a),r<n&&!t){const i=Math.pow(2,r-1)*1e3;e=setTimeout(()=>o(r+1,n),i)}else t||te(a instanceof Error?a.message:"Failed to fetch token")}};return o(),()=>{t=!0,e&&clearTimeout(e),F.current&&clearTimeout(F.current)}},[l,JSON.stringify(w),y,g]),s.useEffect(()=>{if(!Z||y||g)return;F.current&&clearTimeout(F.current);const t=async(a=1,i=3)=>{try{const h=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(!h.ok)throw new Error("Failed to refresh token");const u=await h.json();me(u.clientToken),v.current=u.clientToken,ge(u.expiresAt),te(null)}catch(h){if(console.error(`[useAgent] Token refresh failed (attempt ${a}/${i}):`,h),a<i){const u=Math.pow(2,a-1)*1e3;setTimeout(()=>t(a+1,i),u)}else te(h instanceof Error?h.message:"Failed to refresh token")}},e=Math.floor(Date.now()/1e3),o=Z-e,n=Math.max(0,o-5);return F.current=setTimeout(()=>t(),n*1e3),()=>{F.current&&clearTimeout(F.current)}},[Z,l,JSON.stringify(w),y,g]),s.useEffect(()=>{if(y||g)return;const t=async()=>{if(document.visibilityState!=="visible")return;const e=Math.floor(Date.now()/1e3);if(!Z||Z<=e+5){M&&console.log("[useAgent] Tab visible, token expired - refreshing");try{const r=await fetch(l,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({user:w})});if(r.ok){const n=await r.json();me(n.clientToken),v.current=n.clientToken,ge(n.expiresAt),te(null)}}catch(r){console.error("[useAgent] Token refresh on visibility change failed:",r)}}};return document.addEventListener("visibilitychange",t),()=>document.removeEventListener("visibilitychange",t)},[l,JSON.stringify(w),Z,y,g]);const Fe=async(t,e={})=>{const o=e.headers?new Headers(e.headers):new Headers;return o.delete("user-agent"),o.delete("User-Agent"),fetch(t,{...e,headers:o})},Te=s.useRef(null),Le=`${b}/chat`,{messages:B,sendMessage:Ge,status:Ee,error:$e,stop:He,addToolResult:Ae,setMessages:Ce}=ot.useChat({id:ye||void 0,messages:D,transport:new Je.DefaultChatTransport({api:Le,fetch:Fe,headers:()=>{const t={};return v.current&&(t.Authorization=`Bearer ${v.current}`),t},body:()=>{const t=ee.map(o=>({name:o.name,description:o.description,inputSchema:o.jsonSchema})),e=X.current;return{tools:t,...J&&{agentId:J},...K&&{agentName:K},...z&&{ragFilters:z},...e&&{state:e},...E&&{planning:!0}}}}),sendAutomaticallyWhen:t=>{const e=t.messages;if(e[e.length-1]?.role!=="assistant")return!1;const n=[...e].reverse().find(i=>i.role==="user")?.id;if(n&&Te.current===n)return!1;const a=Je.lastAssistantMessageIsCompleteWithToolCalls(t);return a&&n&&(Te.current=n),a}}),Ie=Ge,Ve=s.useCallback(t=>(Te.current=null,ce.current=new Set,Ie(t)),[Ie]),V=s.useCallback((t,e,o)=>{Ae({toolCallId:e,tool:t,output:o})},[Ae]);s.useEffect(()=>{B.forEach(t=>{t.role==="assistant"&&t.parts.forEach(e=>{if(!e.type?.startsWith("tool-")||e.state!=="input-available")return;const o=e.type.replace("tool-",""),r=e.toolCallId;if(ie.current.has(r)||ke.current.has(r)){M&&console.log(`[useAgent] Skipping ${o} (${r}) - already processing or completed`);return}M&&console.log(`[useAgent] Starting ${o} (${r})`),ie.current.add(r);const n=h=>{M&&console.log(`[useAgent] Completed ${o} (${h})`),ke.current.add(h),ie.current.delete(h)},a=st(e.input),i=`${o}:${JSON.stringify(a)}`;if(ce.current.has(i)){M&&console.log(`[useAgent] Skipping duplicate tool call: ${i}`),V(o,r,"This tool was already called successfully with the same arguments in this response. Using previous result."),n(r);return}if(o.startsWith("workflow_")&&de.has(o)){(async()=>{try{const u=ee.find(p=>p.name===o)?._workflow;if(!u)throw new Error(`Workflow metadata not found for ${o}`);let k;if(u.webhook?.url){let p=a;if(u.webhook.bodyTemplate){let O=u.webhook.bodyTemplate;Object.entries(a).forEach(([he,tt])=>{O=O.replace(new RegExp(`\\{\\{${he}\\}\\}`,"g"),String(tt))}),p=JSON.parse(O)}const m=await fetch(u.webhook.url,{method:u.webhook.method||"POST",headers:{"Content-Type":"application/json",...u.webhook.headers||{}},body:JSON.stringify(p)});if(m.ok)k={success:!0,data:await m.json().catch(()=>({success:!0}))};else{const O=await m.text();k={success:!1,error:`Webhook failed: ${m.status} ${O}`}}}else k={success:!0,message:`Workflow "${u.name}" acknowledged. Follow the workflow instructions to proceed.`,instructions:u.contentPlaintext};n(r),V(o,r,k),ce.current.add(i)}catch(h){console.error(`[useAgent] Error executing workflow ${o}:`,h),n(r),V(o,r,`Error: ${h}`)}})();return}if(de.has(o)){const h=oe.get(o);h?(async()=>{try{const u=ee.find(p=>p.name===o);let k;if(u&&u.jsonSchema?.properties){const m=Object.keys(u.jsonSchema.properties).map(O=>a[O]);k=await h(...m)}else k=await h(...Object.values(a));n(r),V(o,r,k),ce.current.add(i)}catch(u){console.error(`[useAgent] Error executing tool ${o}:`,u),n(r),V(o,r,`Error: ${u}`)}})():(M&&console.warn(`[useAgent] Tool ${o} not found in toolsMap`),V(o,r,`Error: Tool "${o}" not found. The tool may not be registered or available.`),n(r))}else if(o.startsWith("workflow_")&&U)U({toolCall:{toolCallId:r,toolName:o,args:a}});else if(U)U({toolCall:{toolCallId:r,toolName:o,args:a}});else{const h={toolCallId:r,toolName:o,args:a};be(u=>{const k=new Map(u);return k.set(r,h),k})}})})},[B,de,oe,U,V,ee]),s.useEffect(()=>{if(Ee==="ready"&&B.length>0&&q){const t=B[B.length-1];t&&t.role==="assistant"&&q({message:t,messages:B,isAbort:!1,isDisconnect:!1,isError:!!$e})}},[Ee,B,$e,q]);async function Ye(){if(!(!w?.id||!W)){ae(!0);try{const e=await(await fetch(`${b}/conversations`,{headers:{Authorization:`Bearer ${W}`}})).json();Ne(e.conversations||[])}catch(t){console.error("Failed to fetch conversations:",t)}finally{ae(!1)}}}s.useEffect(()=>{w?.id&&W&&Ye()},[JSON.stringify(w),W,b]);async function Ke(t){Re(t),ae(!0);try{const e=await fetch(`${b}/conversations/${t}/messages`,{headers:{Authorization:`Bearer ${v.current}`}});if(!e.ok)throw new Error(`Failed to fetch messages: ${e.statusText}`);const r=(await e.json()).messages||[];Ce(r)}catch(e){console.error("Failed to load conversation messages:",e)}finally{ae(!1)}}async function Qe(t){if(W)try{await fetch(`${b}/conversations/${t}`,{method:"DELETE",headers:{Authorization:`Bearer ${W}`}}),Ne(Oe.filter(e=>e._id!==t)),t===ye&&Be()}catch(e){console.error("Failed to delete conversation:",e)}}function Be(){const t=crypto.randomUUID();Re(t),Ce([]),ie.current=new Set,ke.current=new Set}function Y(t){const e=t.tool||"unknown-tool";Ae({toolCallId:t.toolCallId,tool:e,output:t.output})}async function Xe(t,e,o){if(!e.startsWith("workflow_"))throw new Error(`${e} is not a workflow tool`);try{const n=ee.find(i=>i.name===e)?._workflow;if(!n)throw new Error(`Workflow metadata not found for ${e}`);let a;if(n.webhook?.url){let i=o;if(n.webhook.bodyTemplate){let u=n.webhook.bodyTemplate;Object.entries(o).forEach(([k,p])=>{u=u.replace(new RegExp(`\\{\\{${k}\\}\\}`,"g"),String(p))}),i=JSON.parse(u)}const h=await fetch(n.webhook.url,{method:n.webhook.method||"POST",headers:{"Content-Type":"application/json",...n.webhook.headers||{}},body:JSON.stringify(i)});if(h.ok)a={success:!0,data:await h.json().catch(()=>({success:!0}))};else{const u=await h.text();a={success:!1,error:`Webhook failed: ${h.status} ${u}`}}}else a={success:!0,message:`Workflow "${n.name}" acknowledged. Follow the workflow instructions to proceed.`,instructions:n.contentPlaintext};return Y({toolCallId:t,tool:e,output:a}),a}catch(r){const n={success:!1,error:String(r)};throw Y({toolCallId:t,tool:e,output:n}),r}}async function Ze(t){const e=we.get(t);if(!e){M&&console.warn(`[useAgent] Tool call ${t} not found in pending approvals`);return}be(r=>{const n=new Map(r);return n.delete(t),n});const o=oe.get(e.toolName);if(o)try{const r=ee.find(a=>a.name===e.toolName);let n;if(r&&r.jsonSchema?.properties){const i=Object.keys(r.jsonSchema.properties).map(h=>e.args[h]);n=await o(...i)}else n=await o(...Object.values(e.args));Y({toolCallId:e.toolCallId,tool:e.toolName,output:n})}catch(r){console.error(`[useAgent] Error executing tool ${e.toolName}:`,r),Y({toolCallId:e.toolCallId,tool:e.toolName,output:`Error: ${r}`})}else M&&console.warn(`[useAgent] Tool ${e.toolName} not found in toolsMap`),Y({toolCallId:e.toolCallId,tool:e.toolName,output:`Error: Tool "${e.toolName}" not found`})}function et(t){const e=we.get(t);if(!e){M&&console.warn(`[useAgent] Tool call ${t} not found in pending approvals`);return}be(o=>{const r=new Map(o);return r.delete(t),r}),Y({toolCallId:e.toolCallId,tool:e.toolName,output:{denied:!0,message:"Tool execution was denied by user"}})}return{id:ye,messages:B,status:Ee,error:$e,sendMessage:Ve,stop:He,addToolOutput:Y,executeWorkflowTool:Xe,setMessages:Ce,conversations:Oe,loadConversation:Ke,deleteConversation:Qe,startNewConversation:Be,isLoadingConversations:ze,clientToken:W,tokenError:qe,pendingToolApprovals:Array.from(we.values()),approveToolCall:Ze,denyToolCall:et,safeToolNames:de,todos:Se}}function ct(f={}){const{apiBaseUrl:l="https://api.arcten.com",tokenEndpoint:g="/token",clientToken:y,skipTokenFetch:w=!1}=f,[d,c]=s.useState(!1),[$,N]=s.useState(null),R=s.useRef(y||null);s.useEffect(()=>{if(y){R.current=y;return}if(w)return;(async()=>{try{const T=await fetch(`${l}${g}`,{method:"POST",headers:{"Content-Type":"application/json"}});if(T.ok){const S=await T.json();R.current=S.token}}catch(T){console.error("[useGenerate] Failed to fetch token:",T)}})()},[l,g,y,w]);const J=s.useCallback(async x=>{c(!0),N(null);try{const T={"Content-Type":"application/json"};R.current&&(T.Authorization=`Bearer ${R.current}`);const S=await fetch(`${l}/generate`,{method:"POST",headers:T,body:JSON.stringify(x)});if(!S.ok){const Q=await S.json().catch(()=>({}));throw new Error(Q.error||`HTTP ${S.status}`)}return await S.json()}catch(T){const S=T instanceof Error?T.message:String(T);throw N(S),T}finally{c(!1)}},[l]),K=s.useCallback(async(x,T)=>{c(!0),N(null);try{const S={"Content-Type":"application/json"};R.current&&(S.Authorization=`Bearer ${R.current}`);const D=await fetch(`${l}/generate/stream`,{method:"POST",headers:S,body:JSON.stringify(x)});if(!D.ok){const q=await D.json().catch(()=>({}));throw new Error(q.error||`HTTP ${D.status}`)}const Q=D.body?.getReader();if(!Q)throw new Error("No response body");const P=new TextDecoder;let U=null;for(;;){const{done:q,value:j}=await Q.read();if(q)break;const z=P.decode(j,{stream:!0}).split(`
3
+ `).filter(E=>E.startsWith("data: "));for(const E of z){const X=E.slice(6).trim();if(X)try{const b=JSON.parse(X);if(b.error)throw new Error(b.error);b.done&&b.object?U={object:b.object,usage:b.usage,finishReason:b.finishReason}:b.partial&&T&&T(b.partial)}catch{}}}if(!U)throw new Error("Stream ended without final result");return U}catch(S){const D=S instanceof Error?S.message:String(S);throw N(D),S}finally{c(!1)}},[l]);return{generate:J,streamGenerate:K,isLoading:d,error:$}}exports.ARCTEN_ORIGINAL_NAME=_;exports.extractToolsMetadata=Pe;exports.preserveToolName=rt;exports.useAgent=it;exports.useGenerate=ct;
package/dist/index.mjs CHANGED
@@ -9,17 +9,17 @@ function it(u, c, m, g) {
9
9
  if (typeof u != "function") return null;
10
10
  const y = u[B];
11
11
  if (y) {
12
- const $ = c[y];
13
- if ($ && !m.has($.name))
14
- return { fn: u, meta: $ };
12
+ const S = c[y];
13
+ if (S && !m.has(S.name))
14
+ return { fn: u, meta: S };
15
15
  }
16
16
  const f = u.name;
17
17
  let i;
18
18
  if (f && (i = c[f], i && !m.has(i.name)))
19
19
  return u[B] = i.name, { fn: u, meta: i };
20
20
  if (g && g.length > 0) {
21
- for (const $ of g)
22
- if (!m.has($) && (i = c[$], i))
21
+ for (const S of g)
22
+ if (!m.has(S) && (i = c[S], i))
23
23
  return u[B] = i.name, { fn: u, meta: i };
24
24
  } else if (i = Object.values(c).find(
25
25
  (x) => !m.has(x.name)
@@ -45,7 +45,7 @@ function ct(u, c) {
45
45
  g
46
46
  );
47
47
  if (!i) {
48
- const $ = f.name, M = f[B] || $ || "unnamed";
48
+ const S = f.name, M = f[B] || S || "unnamed";
49
49
  return typeof process < "u" && (process.env.NODE_ENV === "development" || process.env.NODE_ENV !== "production") && typeof console < "u" && console.warn && console.warn(
50
50
  `⚠️ [@arcteninc/core] No metadata found for tool "${M}". This tool will be excluded.
51
51
  To fix: Run "arcten-extract-types ." and ensure "${M}" is used in ArctenAgent/useAgent.`
@@ -133,7 +133,7 @@ function yt({
133
133
  user: y,
134
134
  tools: f = [],
135
135
  safeTools: i = [],
136
- safeToolNames: $,
136
+ safeToolNames: S,
137
137
  toolMetadata: x,
138
138
  // NOTE: systemPrompt is deprecated; prompts are managed server-side per project/agent.
139
139
  systemPrompt: M = "",
@@ -151,7 +151,7 @@ function yt({
151
151
  ragConfig: ie,
152
152
  ragFilters: L,
153
153
  // Deprecated: use ragConfig or sources instead
154
- planning: S = !1
154
+ planning: $ = !1
155
155
  } = {}) {
156
156
  const te = z(q), w = u.replace(/\/+$/, ""), [E, we] = _(null), [ft, _e] = _(!1), [dt, xe] = _(
157
157
  null
@@ -228,11 +228,11 @@ function yt({
228
228
  R(() => {
229
229
  te.current = q;
230
230
  }, [q]);
231
- const [Ae, Le] = _([]), de = v(() => S ? async function() {
231
+ const [Ae, Le] = _([]), de = v(() => $ ? async function() {
232
232
  return { todos: Ae };
233
- } : null, [S, Ae]), he = v(() => S ? async function(e) {
233
+ } : null, [$, Ae]), he = v(() => $ ? async function(e) {
234
234
  return Le(e), { success: !0, todos: e };
235
- } : null, [S]), V = v(() => A?.enabled ? async function(e, o = 20, r) {
235
+ } : null, [$]), V = v(() => A?.enabled ? async function(e, o = 20, r) {
236
236
  const n = {
237
237
  ...A.filters,
238
238
  ...r
@@ -406,7 +406,7 @@ function yt({
406
406
  [Be, x]
407
407
  ), se = v(() => {
408
408
  const t = /* @__PURE__ */ new Map(), e = new Map(K.map((o) => [o.name, o]));
409
- return A?.enabled && (V && t.set("searchDocs", V), Y && t.set("fetchDocContent", Y)), S && (de && t.set("todo_read", de), he && t.set("todo_write", he)), Ie.forEach((o) => {
409
+ return A?.enabled && (V && t.set("searchDocs", V), Y && t.set("fetchDocContent", Y)), $ && (de && t.set("todo_read", de), he && t.set("todo_write", he)), Ie.forEach((o) => {
410
410
  if (o === V || o === Y || o === de || o === he)
411
411
  return;
412
412
  const r = o[B];
@@ -426,7 +426,7 @@ function yt({
426
426
  V,
427
427
  Y,
428
428
  A,
429
- S,
429
+ $,
430
430
  de,
431
431
  he
432
432
  ]), Je = v(() => new Set(K.map((t) => t.name)), [K]), Pe = v(() => {
@@ -503,7 +503,7 @@ function yt({
503
503
  });
504
504
  });
505
505
  const o = [];
506
- return S && o.push(
506
+ return $ && o.push(
507
507
  {
508
508
  name: "todo_read",
509
509
  description: "Read the current todo list. Returns all todo items with their status (pending, in_progress, completed).",
@@ -547,9 +547,9 @@ function yt({
547
547
  }
548
548
  }
549
549
  ), [...K, ...t, ...e, ...o];
550
- }, [K, J, E, S]), re = v(() => Pe.filter((t) => t.name === "searchDocs" || t.name === "fetchDocContent" ? J : t.name.startsWith("workflow_") ? !0 : t.name === "todo_read" || t.name === "todo_write" ? S : Je.has(t.name)), [Pe, Je, J, S]), me = v(() => {
550
+ }, [K, J, E, $]), re = v(() => Pe.filter((t) => t.name === "searchDocs" || t.name === "fetchDocContent" ? J : t.name.startsWith("workflow_") ? !0 : t.name === "todo_read" || t.name === "todo_write" ? $ : Je.has(t.name)), [Pe, Je, J, $]), me = v(() => {
551
551
  const t = /* @__PURE__ */ new Set();
552
- return J && A?.autoExecute !== !1 && (t.add("searchDocs"), t.add("fetchDocContent")), S && (t.add("todo_read"), t.add("todo_write")), E?.config?.tools ? E.config.tools.forEach((e) => {
552
+ return J && A?.autoExecute !== !1 && (t.add("searchDocs"), t.add("fetchDocContent")), $ && (t.add("todo_read"), t.add("todo_write")), E?.config?.tools ? E.config.tools.forEach((e) => {
553
553
  e.isEnabled && !e.requiresApproval && t.add(e.name);
554
554
  }) : (i.forEach((e) => {
555
555
  for (const [o, r] of se.entries())
@@ -557,7 +557,7 @@ function yt({
557
557
  t.add(o);
558
558
  break;
559
559
  }
560
- }), $ && Array.isArray($) && $.forEach((e) => {
560
+ }), S && Array.isArray(S) && S.forEach((e) => {
561
561
  typeof e == "string" && t.add(e);
562
562
  })), E?.config?.workflows && E.config.workflows.forEach((e) => {
563
563
  const o = `workflow_${e.name.replace(/\s+/g, "_").toLowerCase()}`;
@@ -566,11 +566,11 @@ function yt({
566
566
  }, [
567
567
  E,
568
568
  i,
569
- $,
569
+ S,
570
570
  se,
571
571
  J,
572
572
  A,
573
- S
573
+ $
574
574
  ]);
575
575
  R(() => {
576
576
  if (g || m)
@@ -720,7 +720,8 @@ function yt({
720
720
  ...W && { agentId: W },
721
721
  ...Z && { agentName: Z },
722
722
  ...L && { ragFilters: L },
723
- ...e && { state: e }
723
+ ...e && { state: e },
724
+ ...$ && { planning: !0 }
724
725
  };
725
726
  }
726
727
  }),
@@ -1100,7 +1101,7 @@ function wt(u = {}) {
1100
1101
  tokenEndpoint: m = "/token",
1101
1102
  clientToken: g,
1102
1103
  skipTokenFetch: y = !1
1103
- } = u, [f, i] = _(!1), [$, x] = _(null), M = z(g || null);
1104
+ } = u, [f, i] = _(!1), [S, x] = _(null), M = z(g || null);
1104
1105
  R(() => {
1105
1106
  if (g) {
1106
1107
  M.current = g;
@@ -1174,9 +1175,9 @@ function wt(u = {}) {
1174
1175
  const { done: F, value: O } = await ee.read();
1175
1176
  if (F) break;
1176
1177
  const L = q.decode(O, { stream: !0 }).split(`
1177
- `).filter((S) => S.startsWith("data: "));
1178
- for (const S of L) {
1179
- const te = S.slice(6).trim();
1178
+ `).filter(($) => $.startsWith("data: "));
1179
+ for (const $ of L) {
1180
+ const te = $.slice(6).trim();
1180
1181
  if (te)
1181
1182
  try {
1182
1183
  const w = JSON.parse(te);
@@ -1207,7 +1208,7 @@ function wt(u = {}) {
1207
1208
  generate: W,
1208
1209
  streamGenerate: Z,
1209
1210
  isLoading: f,
1210
- error: $
1211
+ error: S
1211
1212
  };
1212
1213
  }
1213
1214
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"useAgent.d.ts","sourceRoot":"","sources":["../../src/lib/useAgent.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAKf,MAAM,oBAAoB,CAAC;AAgK5B,wBAAgB,QAAQ,CAAC,EACvB,UAAU,EAAE,aAAwC,EACpD,aAAmC,EACnC,WAAW,EAAE,aAAa,EAC1B,cAAsB,EACtB,IAAI,EACJ,KAAU,EACV,SAAc,EACd,aAAa,EAAE,iBAAiB,EAChC,YAAY,EAEZ,YAAiB,EACjB,OAAO,EACP,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,eAAoB,EACpB,cAAc,EAAE,qBAAqB,EACrC,KAAK,EACL,UAAU,EACV,QAAQ,EACR,OAAO,EACP,SAAS,EACT,UAAU,EAAE,+CAA+C;AAC3D,QAAgB,GACjB,GAAE,eAAoB,GAAG,cAAc,CA0mDvC"}
1
+ {"version":3,"file":"useAgent.d.ts","sourceRoot":"","sources":["../../src/lib/useAgent.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAKf,MAAM,oBAAoB,CAAC;AAgK5B,wBAAgB,QAAQ,CAAC,EACvB,UAAU,EAAE,aAAwC,EACpD,aAAmC,EACnC,WAAW,EAAE,aAAa,EAC1B,cAAsB,EACtB,IAAI,EACJ,KAAU,EACV,SAAc,EACd,aAAa,EAAE,iBAAiB,EAChC,YAAY,EAEZ,YAAiB,EACjB,OAAO,EACP,SAAS,EACT,SAAS,EACT,kBAAkB,EAClB,eAAe,EACf,eAAoB,EACpB,cAAc,EAAE,qBAAqB,EACrC,KAAK,EACL,UAAU,EACV,QAAQ,EACR,OAAO,EACP,SAAS,EACT,UAAU,EAAE,+CAA+C;AAC3D,QAAgB,GACjB,GAAE,eAAoB,GAAG,cAAc,CA2mDvC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcteninc/core",
3
- "version": "0.0.178",
3
+ "version": "0.0.179",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"