@arcteninc/core 0.0.178 → 0.0.180
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 +3 -3
- package/dist/index.mjs +26 -25
- package/dist/lib/useAgent.d.ts.map +1 -1
- package/package.json +6 -6
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
|
|
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(
|
|
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
|
|
13
|
-
if (
|
|
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
|
|
22
|
-
if (!m.has(
|
|
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
|
|
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:
|
|
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(() =>
|
|
231
|
+
const [Ae, Le] = _([]), de = v(() => $ ? async function() {
|
|
232
232
|
return { todos: Ae };
|
|
233
|
-
} : null, [
|
|
233
|
+
} : null, [$, Ae]), he = v(() => $ ? async function(e) {
|
|
234
234
|
return Le(e), { success: !0, todos: e };
|
|
235
|
-
} : null, [
|
|
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)),
|
|
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
|
-
|
|
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
|
|
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,
|
|
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")),
|
|
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
|
-
}),
|
|
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
|
-
|
|
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), [
|
|
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((
|
|
1178
|
-
for (const
|
|
1179
|
-
const te =
|
|
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,
|
|
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.
|
|
3
|
+
"version": "0.0.180",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
"test": "bun test"
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
|
-
"ai": "^6.0.0
|
|
41
|
-
"@ai-sdk/react": "^3.0.0
|
|
40
|
+
"ai": "^6.0.0",
|
|
41
|
+
"@ai-sdk/react": "^3.0.0",
|
|
42
42
|
"react": "^18.0.0 || ^19.0.0",
|
|
43
43
|
"react-dom": "^18.0.0 || ^19.0.0"
|
|
44
44
|
},
|
|
@@ -54,10 +54,10 @@
|
|
|
54
54
|
"vite-plugin-dts": "^4.5.4"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
|
-
"@ai-sdk/openai": "^3.0.0
|
|
58
|
-
"@ai-sdk/react": "^3.0.0
|
|
57
|
+
"@ai-sdk/openai": "^3.0.0",
|
|
58
|
+
"@ai-sdk/react": "^3.0.0",
|
|
59
59
|
"acorn": "^8.15.0",
|
|
60
|
-
"ai": "^6.0.0
|
|
60
|
+
"ai": "^6.0.0",
|
|
61
61
|
"glob": "^11.0.3",
|
|
62
62
|
"nanoid": "^5.1.6",
|
|
63
63
|
"ts-json-schema-generator": "^2.4.0",
|