research-agent-ui 0.1.26 → 0.1.27

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.
@@ -1,4 +1,11 @@
1
1
  import type { MessagesDeps } from "../types";
2
+ /**
3
+ * Flattens an error's `cause` chain into one string. Drizzle wraps driver
4
+ * errors (e.g. D1's "no such column" / constraint failures) in a generic
5
+ * "Failed query" error and puts the real one in `cause`, which structured
6
+ * log sinks drop unless serialized explicitly.
7
+ */
8
+ export declare function describeError(err: unknown): string;
2
9
  export declare function createMessagesHandler(deps: MessagesDeps): {
3
10
  POST: (req: Request) => Promise<Response>;
4
11
  };
package/dist/api.cjs CHANGED
@@ -17,6 +17,6 @@ User question: ${a}
17
17
 
18
18
  Please provide a helpful answer based on the article content above.`,_=await m.stream([{role:`system`,content:`You are a helpful AI assistant that answers questions about articles.
19
19
  Provide clear, concise, and accurate answers based on the article content provided.
20
- If the answer is not in the article, say so.`},{role:`user`,content:g}]),v=``;for await(let e of _)v+=e.content;return Response.json({content:v,success:!0})}catch(e){return console.error(`Error in article Q&A:`,e),Response.json({error:`An error occurred while generating the answer`,details:e instanceof Error?e.message:String(e)},{status:500})}}}function f(e){let{chats:t,messages:r}=e.schema;return{GET:async i=>{try{let i=e.getDB(),a=await e.requireUserId(),o=await i.select({id:t.id,title:t.title,createdAt:t.createdAt,focusMode:t.focusMode,userId:t.userId,files:t.files,messageCount:(0,n.count)(r.id)}).from(t).leftJoin(r,(0,n.and)((0,n.eq)(r.chatId,t.id),(0,n.eq)(r.role,`user`))).where((0,n.eq)(t.userId,a)).groupBy(t.id,t.title,t.createdAt,t.focusMode,t.userId,t.files).orderBy(n.sql`${t.createdAt} DESC`);return Response.json({chats:o},{status:200})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error in getting chats: `,e),Response.json({message:`An error has occurred.`},{status:500}))}},DELETE:async i=>{try{let i=e.getDB(),a=await e.requireUserId(),o=await i.query.chats.findMany({where:(0,n.eq)(t.userId,a),columns:{id:!0}});if(o.length>0){let e=o.map(e=>e.id);await i.delete(r).where((0,n.inArray)(r.chatId,e)),await i.delete(t).where((0,n.eq)(t.userId,a))}return Response.json({message:`All chats deleted`},{status:200})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error in deleting all chats: `,e),Response.json({message:`An error has occurred.`},{status:500}))}}}}function p(e){let{chats:t,messages:r}=e.schema;return{GET:async(i,{params:a})=>{try{let i=e.getDB(),{id:o}=await a,s;try{s=await e.requireUserId()}catch{s=void 0}let c=await i.query.chats.findFirst({where:(0,n.eq)(t.id,o)});if(!c)return Response.json({message:`Chat not found`},{status:404});if(!(c.userId===s||c.isPublic))return Response.json({message:`Unauthorized - this chat is private`},{status:403});let l=await i.query.messages.findMany({where:(0,n.eq)(r.chatId,o)});return Response.json({chat:c,messages:l},{status:200})}catch(e){return console.error(`Error in getting chat by id: `,e),Response.json({message:`An error has occurred.`},{status:500})}},DELETE:async(i,{params:a})=>{try{let i=e.getDB(),{id:o}=await a,s=await e.requireUserId();return await i.query.chats.findFirst({where:(0,n.and)((0,n.eq)(t.id,o),(0,n.eq)(t.userId,s))})?(await i.delete(t).where((0,n.eq)(t.id,o)).execute(),await i.delete(r).where((0,n.eq)(r.chatId,o)).execute(),Response.json({message:`Chat deleted successfully`},{status:200})):Response.json({message:`Chat not found`},{status:404})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error in deleting chat by id: `,e),Response.json({message:`An error has occurred.`},{status:500}))}}}}function m(e){let{chats:t,messages:r}=e.schema;return{GET:async i=>{try{let a=e.getDB(),o=await e.requireUserId(),{searchParams:s}=new URL(i.url),c=s.get(`q`);if(!c||c.trim().length===0)return Response.json({chats:[]},{status:200});let l=`%${c.trim()}%`,u=await a.select({id:t.id,title:t.title,createdAt:t.createdAt,focusMode:t.focusMode,userId:t.userId,files:t.files}).from(t).where((0,n.and)((0,n.eq)(t.userId,o),(0,n.like)(t.title,l))).orderBy(n.sql`${t.createdAt} DESC`),d=await a.selectDistinct({id:t.id,title:t.title,createdAt:t.createdAt,focusMode:t.focusMode,userId:t.userId,files:t.files}).from(r).innerJoin(t,(0,n.eq)(r.chatId,t.id)).where((0,n.and)((0,n.eq)(t.userId,o),(0,n.or)((0,n.like)(r.content,l)))).orderBy(n.sql`${t.createdAt} DESC`),f=[...u,...d],p=Array.from(new Map(f.map(e=>[e.id,e])).values()),m=p.map(e=>e.id),h=m.length?await a.select({chatId:r.chatId,count:n.sql`count(*)`}).from(r).where((0,n.and)(n.sql`${r.chatId} IN (${n.sql.join(m.map(e=>n.sql`${e}`),n.sql`, `)})`,(0,n.eq)(r.role,`user`))).groupBy(r.chatId):[],g=new Map(h.map(e=>[e.chatId,Number(e.count)])),_=p.map(e=>({...e,messageCount:g.get(e.id)||0}));return Response.json({chats:_},{status:200})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error searching chats:`,e),Response.json({message:`An error has occurred.`},{status:500}))}}}}function h(e){let{chats:t}=e.schema;return{POST:async r=>{try{let i=e.getDB(),{chatId:a}=await r.json();if(!a)return Response.json({success:!1,error:`Chat ID is required`},{status:400});let o=await e.requireUserId(),s=await i.query.chats.findFirst({where:(0,n.eq)(t.id,a)});if(!s)return Response.json({success:!1,error:`Chat not found`},{status:404});if(s.userId!==o)return Response.json({success:!1,error:`Unauthorized`},{status:403});await i.update(t).set({isPublic:1}).where((0,n.eq)(t.id,a)).execute();let c=`${new URL(r.url).origin}/c/${a}`;return Response.json({success:!0,data:{chatId:a,shareUrl:c}})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({success:!1,error:`Authentication required`},{status:401}):(console.error(`Error in making chat public: `,e),Response.json({success:!1,error:`An error has occurred.`},{status:500}))}}}}function g(e){return{POST:async t=>{try{let n=e.getDB(),r=await e.requireUserId(),{chatId:i,messageId:a,role:o,suggestions:s,content:c,sources:l}=await t.json();return!i||!a||!o?Response.json({message:`Missing required fields`},{status:400}):(await n.insert(e.messagesSchema).values({chatId:i,userId:r,messageId:a,role:o,content:c||``,suggestions:s||[],sources:l||[],createdAt:new Date().toISOString()}),Response.json({message:`Message saved successfully`},{status:200}))}catch(e){return console.error(`Error saving message:`,e),Response.json({message:`Failed to save message`},{status:500})}}}}function _(e){return{GET:async n=>{try{let r=new t.default,i=new URL(n.url).searchParams.get(`guest`),a=i===`true`;i===null&&(a=!await e.getSession());let o=(await r.getActiveProviders(a)).filter(e=>!e.chatModels.some(e=>e.key===`error`));return o.length===0?Response.json({providers:[],error:a?`No guest-safe AI providers available. Please sign in for more options.`:`No AI providers configured. Please add OPENROUTER_API_KEY to your environment variables or configure your own API keys in Settings.`},{status:200}):Response.json({providers:o,isGuest:a},{status:200})}catch(e){return console.error(`An error occurred while fetching providers`,e),Response.json({message:`An error has occurred.`},{status:500})}},POST:async e=>{try{let{type:n,config:r}=await e.json();if(!n||!r)return Response.json({message:`Missing required fields.`},{status:400});let i=await new t.default().addProvider(n,r);return Response.json({provider:i},{status:200})}catch(e){return console.error(`An error occurred while creating provider`,e),Response.json({message:`An error has occurred.`},{status:500})}}}}function v(){return{DELETE:async(e,{params:n})=>{try{let{id:e}=await n;return e?(await new t.default().removeProvider(e),Response.json({message:`Provider deleted successfully.`},{status:200})):Response.json({message:`Provider ID is required.`},{status:400})}catch(e){return console.error(`An error occurred while deleting provider`,e.message),Response.json({message:`An error has occurred.`},{status:500})}},PATCH:async(e,{params:n})=>{try{let{config:r}=await e.json(),{id:i}=await n;if(!i||!r)return Response.json({message:`Missing required fields.`},{status:400});let a=await new t.default().updateProvider(i,r);return Response.json({provider:a},{status:200})}catch(e){return console.error(`An error occurred while updating provider`,e.message),Response.json({message:`An error has occurred.`},{status:500})}}}}function y(){return{POST:async(e,{params:n})=>{try{let{id:r}=await n,i=await e.json();return!i.key||!i.name?Response.json({message:`Key and name must be provided`},{status:400}):(await new t.default().addProviderModel(r,i.type,i),Response.json({message:`Model added successfully`},{status:200}))}catch(e){return console.error(`An error occurred while adding provider model`,e),Response.json({message:`An error has occurred.`},{status:500})}},DELETE:async(e,{params:n})=>{try{let{id:r}=await n,i=await e.json();return i.key?(await new t.default().removeProviderModel(r,i.type,i.key),Response.json({message:`Model added successfully`},{status:200})):Response.json({message:`Key and name must be provided`},{status:400})}catch(e){return console.error(`An error occurred while deleting provider model`,e),Response.json({message:`An error has occurred.`},{status:500})}}}}function b(e){return{GET:async t=>{try{let t=e.getConfiguredMCPServers();return Response.json({servers:t},{status:200})}catch(e){return console.error(`An error occurred while fetching MCP servers`,e),Response.json({message:`An error has occurred.`},{status:500})}},POST:async t=>{try{let{type:n,name:r,config:i}=await t.json();if(!n||!r||!i)return Response.json({message:`Missing required fields.`},{status:400});let a=e.configManager.addMCPServer(n,r,i);return Response.json({server:a},{status:200})}catch(e){return console.error(`An error occurred while creating MCP server`,e),Response.json({message:`An error has occurred.`},{status:500})}}}}function x(e){return{DELETE:async(t,{params:n})=>{try{let{id:t}=await n;return t?(e.configManager.removeMCPServer(t),Response.json({message:`MCP server deleted successfully.`},{status:200})):Response.json({message:`MCP Server ID is required.`},{status:400})}catch(e){return console.error(`An error occurred while deleting MCP server`,e.message),Response.json({message:`An error has occurred.`},{status:500})}},PATCH:async(t,{params:n})=>{try{let{name:r,config:i}=await t.json(),{id:a}=await n;if(!a||!r||!i)return Response.json({message:`Missing required fields.`},{status:400});let o=await e.configManager.updateMCPServer(a,r,i);return Response.json({server:o},{status:200})}catch(e){return console.error(`An error occurred while updating MCP server`,e.message),Response.json({message:`An error has occurred.`},{status:500})}}}}function S(e){return{POST:async(t,{params:n})=>{try{let{enabled:r}=await t.json(),{id:i}=await n;if(!i||typeof r!=`boolean`)return Response.json({message:`Missing required fields.`},{status:400});let a=e.configManager.toggleMCPServer(i,r);return Response.json({server:a},{status:200})}catch(e){return console.error(`An error occurred while toggling MCP server`,e.message),Response.json({message:`An error has occurred.`},{status:500})}}}}var C={tech:{query:[`technology news`,`latest tech`,`AI`,`science and innovation`],links:[`techcrunch.com`,`wired.com`,`theverge.com`]},finance:{query:[`finance news`,`economy`,`stock market`,`investing`],links:[`bloomberg.com`,`cnbc.com`,`marketwatch.com`]},art:{query:[`art news`,`culture`,`modern art`,`cultural events`],links:[`artnews.com`,`hyperallergic.com`,`theartnewspaper.com`]},sports:{query:[`sports news`,`latest sports`,`cricket football tennis`],links:[`espn.com`,`bbc.com/sport`,`skysports.com`]},entertainment:{query:[`entertainment news`,`movies`,`TV shows`,`celebrities`],links:[`hollywoodreporter.com`,`variety.com`,`deadline.com`]}};function w(e={}){let t=e.searxngDomain??`https://search.qwksearch.com`;return{GET:async e=>{let n=new URL(e.url).searchParams,i=n.get(`q`),a=n.get(`cat`)||`general`,o=parseInt(n.get(`page`)||`1`,10),s=n.get(`lang`)||`en-US`,c=n.get(`safesearch`)===`true`,l=n.get(`recency`)||void 0,u=n.get(`publicInstances`)===`true`;if(!i)return Response.json({error:`Query parameter is required`},{status:400});let d=Date.now();try{let e=await(0,r.searchWeb)(i,{category:a,recency:l,safesearch:c,maxRetries:6,privateSearxng:!u&&t,proxy:``,lang:s,page:o});e&&(Array.isArray(e)?e.length>0:e.results&&e.results.length>0)||(e=await(0,r.searchWeb)(i,{category:a,recency:l,safesearch:c,maxRetries:6,privateSearxng:!1,proxy:``,lang:s,page:o}));let n=Date.now()-d;return e?Array.isArray(e)?Response.json({results:e,elapsedTime:n}):Response.json({...e,elapsedTime:n}):Response.json({results:[],suggestions:[],elapsedTime:n})}catch(e){return console.error(`Search error:`,e),Response.json({error:`Search failed`,results:[]},{status:500})}}}}function T(){return{GET:async e=>{try{let t=new URL(e.url).searchParams,n=t.get(`mode`)||`normal`,i=C[t.get(`topic`)||`tech`],a=[];if(n===`normal`){let e=new Set;a=(await Promise.all(i.links.flatMap(e=>i.query.map(async t=>(await(0,r.searchSearxng)(`site:${e} ${t}`,{engines:[`bing news`],pageno:1,language:`en`})).results)))).flat().filter(t=>{let n=t.url?.toLowerCase().trim();return e.has(n)?!1:(e.add(n),!0)}).sort(()=>Math.random()-.5)}else a=(await(0,r.searchSearxng)(`site:${i.links[Math.floor(Math.random()*i.links.length)]} ${i.query[Math.floor(Math.random()*i.query.length)]}`,{engines:[`bing news`],pageno:1,language:`en`})).results;return Response.json({blogs:a},{status:200})}catch(e){return console.error(`An error occurred in discover route: ${e}`),Response.json({message:`An error has occurred`},{status:500})}}}}var E=[`google`,`duckduckgo`,`wikipedia`],D=3,O=3,k=Object.entries(o.default).map(([e,t])=>({domain:e,name:typeof t?.[0]==`string`?t[0]:``,rank:typeof t?.[1]==`number`?t[1]:2**53-1})),A=null;function j(){return A||=new a.default(k,{keys:[{name:`name`,weight:.6},{name:`domain`,weight:.4}],threshold:.1,ignoreLocation:!0,includeScore:!0,minMatchCharLength:3}),A}function M(e){let t=e.split(/\s+/).filter(Boolean),n=t[t.length-1]||``;return n.length<3?[]:j().search(n,{limit:12}).sort((e,t)=>Math.round((e.score??1)*10)-Math.round((t.score??1)*10)||e.item.rank-t.item.rank).slice(0,O).map(({item:e})=>({domain:e.domain,name:e.name,favicon:`https://www.google.com/s2/favicons?domain=${encodeURIComponent(e.domain)}&sz=64`}))}async function N(e,t,n){let r=await(0,i.searchAutocompleteMulti)(e,t,n);if(r.length>0)return r;let a=t.split(/\s+/).filter(Boolean),o=Math.min(D,a.length-1);for(let r=o;r>=1;r--){let o=a.slice(-r).join(` `),s=a.slice(0,-r).join(` `),c=await(0,i.searchAutocompleteMulti)(e,o,n);if(c.length>0){let e=new Set;for(let n of c){let r=s?`${s} ${n}`:n;r.toLowerCase()!==t.toLowerCase()&&e.add(r)}if(e.size>0)return Array.from(e)}}return[]}function P(){return{GET:async e=>{let{searchParams:t}=new URL(e.url),n=t.get(`q`)?.trim(),r=t.get(`locale`)||`en-US`,i=t.get(`backends`),a=parseInt(t.get(`limit`)||`8`,10);if(!n)return Response.json({suggestions:[],domains:[]});let o=i?i.split(`,`).map(e=>e.trim()).filter(Boolean):E;try{let e=await N(o,n,r),t=M(n);return Response.json({suggestions:e.slice(0,a),domains:t})}catch(e){return console.error(`Autocomplete error:`,e),Response.json({suggestions:[],domains:[]},{status:500})}}}}function F(){return{POST:async e=>{let n=await e.json(),r=n.chatHistory.filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:String(e.content??``)})),i=await new t.default().loadChatModel(n.chatModel.providerId,n.chatModel.key),a=(await(0,s.default)({chat_history:r,maxQuestions:n.maxQuestions},i)).flatMap(e=>(e.match(/\?/g)||[]).length>1?e.split(/\?/).map(e=>e.trim()).filter(e=>e.length>0).map(e=>e+`?`):[e]);return Response.json({suggestions:a},{status:200})}}}function I(e){return{POST:async t=>{let r;try{r=await t.json()}catch{return Response.json({error:`Invalid JSON input`},{status:500})}r.ip=t.headers?.get?.(`x-forwarded-for`)||t.headers?.get?.(`x-real-ip`)||`unknown`;let i=e.getDB(),a=await e.getUserId(),o=null;return a&&(o=await i.query.user.findFirst({where:(0,n.eq)(e.userSchema.id,a)})),o&&(r.apiKey=o.settings?.providerApiKeys?.find(e=>e.provider==r.provider)?.key),r.apiKey||=r.provider==`groq`&&e.getEnv(`GROQ_API_KEY`),r.apiKey?Response.json({error:`Language generation endpoint is deprecated. Please use /api/agent/chat instead.`},{status:501}):Response.json({error:`API key is required`},{status:500})}}}function L(e){return{POST:async t=>{try{let{text:n,prompt:r}=await t.json();if(!n||typeof n!=`string`)return Response.json({error:`Text is required and must be a string`},{status:400});let i=e.getEnv(`GROQ_API_KEY`);if(!i)return console.error(`GROQ_API_KEY is not configured`),Response.json({error:`AI service is not configured. Please contact the administrator.`},{status:500});let a=e.createGroq({apiKey:i})(`llama-3.3-70b-versatile`),o=r||`Rewrite the following text to improve clarity, grammar, and style while maintaining the original meaning and tone. Only return the rewritten text without any explanation or additional commentary:
20
+ If the answer is not in the article, say so.`},{role:`user`,content:g}]),v=``;for await(let e of _)v+=e.content;return Response.json({content:v,success:!0})}catch(e){return console.error(`Error in article Q&A:`,e),Response.json({error:`An error occurred while generating the answer`,details:e instanceof Error?e.message:String(e)},{status:500})}}}function f(e){let{chats:t,messages:r}=e.schema;return{GET:async i=>{try{let i=e.getDB(),a=await e.requireUserId(),o=await i.select({id:t.id,title:t.title,createdAt:t.createdAt,focusMode:t.focusMode,userId:t.userId,files:t.files,messageCount:(0,n.count)(r.id)}).from(t).leftJoin(r,(0,n.and)((0,n.eq)(r.chatId,t.id),(0,n.eq)(r.role,`user`))).where((0,n.eq)(t.userId,a)).groupBy(t.id,t.title,t.createdAt,t.focusMode,t.userId,t.files).orderBy(n.sql`${t.createdAt} DESC`);return Response.json({chats:o},{status:200})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error in getting chats: `,e),Response.json({message:`An error has occurred.`},{status:500}))}},DELETE:async i=>{try{let i=e.getDB(),a=await e.requireUserId(),o=await i.query.chats.findMany({where:(0,n.eq)(t.userId,a),columns:{id:!0}});if(o.length>0){let e=o.map(e=>e.id);await i.delete(r).where((0,n.inArray)(r.chatId,e)),await i.delete(t).where((0,n.eq)(t.userId,a))}return Response.json({message:`All chats deleted`},{status:200})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error in deleting all chats: `,e),Response.json({message:`An error has occurred.`},{status:500}))}}}}function p(e){let{chats:t,messages:r}=e.schema;return{GET:async(i,{params:a})=>{try{let i=e.getDB(),{id:o}=await a,s;try{s=await e.requireUserId()}catch{s=void 0}let c=await i.query.chats.findFirst({where:(0,n.eq)(t.id,o)});if(!c)return Response.json({message:`Chat not found`},{status:404});if(!(c.userId===s||c.isPublic))return Response.json({message:`Unauthorized - this chat is private`},{status:403});let l=await i.query.messages.findMany({where:(0,n.eq)(r.chatId,o)});return Response.json({chat:c,messages:l},{status:200})}catch(e){return console.error(`Error in getting chat by id: `,e),Response.json({message:`An error has occurred.`},{status:500})}},DELETE:async(i,{params:a})=>{try{let i=e.getDB(),{id:o}=await a,s=await e.requireUserId();return await i.query.chats.findFirst({where:(0,n.and)((0,n.eq)(t.id,o),(0,n.eq)(t.userId,s))})?(await i.delete(t).where((0,n.eq)(t.id,o)).execute(),await i.delete(r).where((0,n.eq)(r.chatId,o)).execute(),Response.json({message:`Chat deleted successfully`},{status:200})):Response.json({message:`Chat not found`},{status:404})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error in deleting chat by id: `,e),Response.json({message:`An error has occurred.`},{status:500}))}}}}function m(e){let{chats:t,messages:r}=e.schema;return{GET:async i=>{try{let a=e.getDB(),o=await e.requireUserId(),{searchParams:s}=new URL(i.url),c=s.get(`q`);if(!c||c.trim().length===0)return Response.json({chats:[]},{status:200});let l=`%${c.trim()}%`,u=await a.select({id:t.id,title:t.title,createdAt:t.createdAt,focusMode:t.focusMode,userId:t.userId,files:t.files}).from(t).where((0,n.and)((0,n.eq)(t.userId,o),(0,n.like)(t.title,l))).orderBy(n.sql`${t.createdAt} DESC`),d=await a.selectDistinct({id:t.id,title:t.title,createdAt:t.createdAt,focusMode:t.focusMode,userId:t.userId,files:t.files}).from(r).innerJoin(t,(0,n.eq)(r.chatId,t.id)).where((0,n.and)((0,n.eq)(t.userId,o),(0,n.or)((0,n.like)(r.content,l)))).orderBy(n.sql`${t.createdAt} DESC`),f=[...u,...d],p=Array.from(new Map(f.map(e=>[e.id,e])).values()),m=p.map(e=>e.id),h=m.length?await a.select({chatId:r.chatId,count:n.sql`count(*)`}).from(r).where((0,n.and)(n.sql`${r.chatId} IN (${n.sql.join(m.map(e=>n.sql`${e}`),n.sql`, `)})`,(0,n.eq)(r.role,`user`))).groupBy(r.chatId):[],g=new Map(h.map(e=>[e.chatId,Number(e.count)])),_=p.map(e=>({...e,messageCount:g.get(e.id)||0}));return Response.json({chats:_},{status:200})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({message:`Authentication required`},{status:401}):(console.error(`Error searching chats:`,e),Response.json({message:`An error has occurred.`},{status:500}))}}}}function h(e){let{chats:t}=e.schema;return{POST:async r=>{try{let i=e.getDB(),{chatId:a}=await r.json();if(!a)return Response.json({success:!1,error:`Chat ID is required`},{status:400});let o=await e.requireUserId(),s=await i.query.chats.findFirst({where:(0,n.eq)(t.id,a)});if(!s)return Response.json({success:!1,error:`Chat not found`},{status:404});if(s.userId!==o)return Response.json({success:!1,error:`Unauthorized`},{status:403});await i.update(t).set({isPublic:1}).where((0,n.eq)(t.id,a)).execute();let c=`${new URL(r.url).origin}/c/${a}`;return Response.json({success:!0,data:{chatId:a,shareUrl:c}})}catch(e){return e instanceof Error&&e.message===`Unauthorized`?Response.json({success:!1,error:`Authentication required`},{status:401}):(console.error(`Error in making chat public: `,e),Response.json({success:!1,error:`An error has occurred.`},{status:500}))}}}}var g=[`assistant`,`user`,`source`,`suggestion`];function _(e){let t=[],n=e;for(let e=0;n!=null&&e<5;e++)t.push(n instanceof Error?n.message:String(n)),n=n instanceof Error?n.cause:void 0;return t.join(` <- caused by: `)}function v(e){return{POST:async t=>{try{let n=e.getDB(),r=await e.requireUserId(),{chatId:i,messageId:a,role:o,suggestions:s,content:c,sources:l}=await t.json();return!i||!a||!o?Response.json({message:`Missing required fields`},{status:400}):g.includes(o)?(await n.insert(e.messagesSchema).values({chatId:i,userId:r,messageId:a,role:o,content:c||``,suggestions:s||[],sources:l||[],createdAt:new Date().toISOString()}),Response.json({message:`Message saved successfully`},{status:200})):Response.json({message:`Invalid role: ${o}`},{status:400})}catch(e){return console.error(`Error saving message:`,_(e)),Response.json({message:`Failed to save message`},{status:500})}}}}function y(e){return{GET:async n=>{try{let r=new t.default,i=new URL(n.url).searchParams.get(`guest`),a=i===`true`;i===null&&(a=!await e.getSession());let o=(await r.getActiveProviders(a)).filter(e=>!e.chatModels.some(e=>e.key===`error`));return o.length===0?Response.json({providers:[],error:a?`No guest-safe AI providers available. Please sign in for more options.`:`No AI providers configured. Please add OPENROUTER_API_KEY to your environment variables or configure your own API keys in Settings.`},{status:200}):Response.json({providers:o,isGuest:a},{status:200})}catch(e){return console.error(`An error occurred while fetching providers`,e),Response.json({message:`An error has occurred.`},{status:500})}},POST:async e=>{try{let{type:n,config:r}=await e.json();if(!n||!r)return Response.json({message:`Missing required fields.`},{status:400});let i=await new t.default().addProvider(n,r);return Response.json({provider:i},{status:200})}catch(e){return console.error(`An error occurred while creating provider`,e),Response.json({message:`An error has occurred.`},{status:500})}}}}function b(){return{DELETE:async(e,{params:n})=>{try{let{id:e}=await n;return e?(await new t.default().removeProvider(e),Response.json({message:`Provider deleted successfully.`},{status:200})):Response.json({message:`Provider ID is required.`},{status:400})}catch(e){return console.error(`An error occurred while deleting provider`,e.message),Response.json({message:`An error has occurred.`},{status:500})}},PATCH:async(e,{params:n})=>{try{let{config:r}=await e.json(),{id:i}=await n;if(!i||!r)return Response.json({message:`Missing required fields.`},{status:400});let a=await new t.default().updateProvider(i,r);return Response.json({provider:a},{status:200})}catch(e){return console.error(`An error occurred while updating provider`,e.message),Response.json({message:`An error has occurred.`},{status:500})}}}}function x(){return{POST:async(e,{params:n})=>{try{let{id:r}=await n,i=await e.json();return!i.key||!i.name?Response.json({message:`Key and name must be provided`},{status:400}):(await new t.default().addProviderModel(r,i.type,i),Response.json({message:`Model added successfully`},{status:200}))}catch(e){return console.error(`An error occurred while adding provider model`,e),Response.json({message:`An error has occurred.`},{status:500})}},DELETE:async(e,{params:n})=>{try{let{id:r}=await n,i=await e.json();return i.key?(await new t.default().removeProviderModel(r,i.type,i.key),Response.json({message:`Model added successfully`},{status:200})):Response.json({message:`Key and name must be provided`},{status:400})}catch(e){return console.error(`An error occurred while deleting provider model`,e),Response.json({message:`An error has occurred.`},{status:500})}}}}function S(e){return{GET:async t=>{try{let t=e.getConfiguredMCPServers();return Response.json({servers:t},{status:200})}catch(e){return console.error(`An error occurred while fetching MCP servers`,e),Response.json({message:`An error has occurred.`},{status:500})}},POST:async t=>{try{let{type:n,name:r,config:i}=await t.json();if(!n||!r||!i)return Response.json({message:`Missing required fields.`},{status:400});let a=e.configManager.addMCPServer(n,r,i);return Response.json({server:a},{status:200})}catch(e){return console.error(`An error occurred while creating MCP server`,e),Response.json({message:`An error has occurred.`},{status:500})}}}}function C(e){return{DELETE:async(t,{params:n})=>{try{let{id:t}=await n;return t?(e.configManager.removeMCPServer(t),Response.json({message:`MCP server deleted successfully.`},{status:200})):Response.json({message:`MCP Server ID is required.`},{status:400})}catch(e){return console.error(`An error occurred while deleting MCP server`,e.message),Response.json({message:`An error has occurred.`},{status:500})}},PATCH:async(t,{params:n})=>{try{let{name:r,config:i}=await t.json(),{id:a}=await n;if(!a||!r||!i)return Response.json({message:`Missing required fields.`},{status:400});let o=await e.configManager.updateMCPServer(a,r,i);return Response.json({server:o},{status:200})}catch(e){return console.error(`An error occurred while updating MCP server`,e.message),Response.json({message:`An error has occurred.`},{status:500})}}}}function w(e){return{POST:async(t,{params:n})=>{try{let{enabled:r}=await t.json(),{id:i}=await n;if(!i||typeof r!=`boolean`)return Response.json({message:`Missing required fields.`},{status:400});let a=e.configManager.toggleMCPServer(i,r);return Response.json({server:a},{status:200})}catch(e){return console.error(`An error occurred while toggling MCP server`,e.message),Response.json({message:`An error has occurred.`},{status:500})}}}}var T={tech:{query:[`technology news`,`latest tech`,`AI`,`science and innovation`],links:[`techcrunch.com`,`wired.com`,`theverge.com`]},finance:{query:[`finance news`,`economy`,`stock market`,`investing`],links:[`bloomberg.com`,`cnbc.com`,`marketwatch.com`]},art:{query:[`art news`,`culture`,`modern art`,`cultural events`],links:[`artnews.com`,`hyperallergic.com`,`theartnewspaper.com`]},sports:{query:[`sports news`,`latest sports`,`cricket football tennis`],links:[`espn.com`,`bbc.com/sport`,`skysports.com`]},entertainment:{query:[`entertainment news`,`movies`,`TV shows`,`celebrities`],links:[`hollywoodreporter.com`,`variety.com`,`deadline.com`]}};function E(e={}){let t=e.searxngDomain??`https://search.qwksearch.com`;return{GET:async e=>{let n=new URL(e.url).searchParams,i=n.get(`q`),a=n.get(`cat`)||`general`,o=parseInt(n.get(`page`)||`1`,10),s=n.get(`lang`)||`en-US`,c=n.get(`safesearch`)===`true`,l=n.get(`recency`)||void 0,u=n.get(`publicInstances`)===`true`;if(!i)return Response.json({error:`Query parameter is required`},{status:400});let d=Date.now();try{let e=await(0,r.searchWeb)(i,{category:a,recency:l,safesearch:c,maxRetries:6,privateSearxng:!u&&t,proxy:``,lang:s,page:o});e&&(Array.isArray(e)?e.length>0:e.results&&e.results.length>0)||(e=await(0,r.searchWeb)(i,{category:a,recency:l,safesearch:c,maxRetries:6,privateSearxng:!1,proxy:``,lang:s,page:o}));let n=Date.now()-d;return e?Array.isArray(e)?Response.json({results:e,elapsedTime:n}):Response.json({...e,elapsedTime:n}):Response.json({results:[],suggestions:[],elapsedTime:n})}catch(e){return console.error(`Search error:`,e),Response.json({error:`Search failed`,results:[]},{status:500})}}}}function D(){return{GET:async e=>{try{let t=new URL(e.url).searchParams,n=t.get(`mode`)||`normal`,i=T[t.get(`topic`)||`tech`],a=[];if(n===`normal`){let e=new Set;a=(await Promise.all(i.links.flatMap(e=>i.query.map(async t=>(await(0,r.searchSearxng)(`site:${e} ${t}`,{engines:[`bing news`],pageno:1,language:`en`})).results)))).flat().filter(t=>{let n=t.url?.toLowerCase().trim();return e.has(n)?!1:(e.add(n),!0)}).sort(()=>Math.random()-.5)}else a=(await(0,r.searchSearxng)(`site:${i.links[Math.floor(Math.random()*i.links.length)]} ${i.query[Math.floor(Math.random()*i.query.length)]}`,{engines:[`bing news`],pageno:1,language:`en`})).results;return Response.json({blogs:a},{status:200})}catch(e){return console.error(`An error occurred in discover route: ${e}`),Response.json({message:`An error has occurred`},{status:500})}}}}var O=[`google`,`duckduckgo`,`wikipedia`],k=3,A=3,j=Object.entries(o.default).map(([e,t])=>({domain:e,name:typeof t?.[0]==`string`?t[0]:``,rank:typeof t?.[1]==`number`?t[1]:2**53-1})),M=null;function N(){return M||=new a.default(j,{keys:[{name:`name`,weight:.6},{name:`domain`,weight:.4}],threshold:.1,ignoreLocation:!0,includeScore:!0,minMatchCharLength:3}),M}function P(e){let t=e.split(/\s+/).filter(Boolean),n=t[t.length-1]||``;return n.length<3?[]:N().search(n,{limit:12}).sort((e,t)=>Math.round((e.score??1)*10)-Math.round((t.score??1)*10)||e.item.rank-t.item.rank).slice(0,A).map(({item:e})=>({domain:e.domain,name:e.name,favicon:`https://www.google.com/s2/favicons?domain=${encodeURIComponent(e.domain)}&sz=64`}))}async function F(e,t,n){let r=await(0,i.searchAutocompleteMulti)(e,t,n);if(r.length>0)return r;let a=t.split(/\s+/).filter(Boolean),o=Math.min(k,a.length-1);for(let r=o;r>=1;r--){let o=a.slice(-r).join(` `),s=a.slice(0,-r).join(` `),c=await(0,i.searchAutocompleteMulti)(e,o,n);if(c.length>0){let e=new Set;for(let n of c){let r=s?`${s} ${n}`:n;r.toLowerCase()!==t.toLowerCase()&&e.add(r)}if(e.size>0)return Array.from(e)}}return[]}function I(){return{GET:async e=>{let{searchParams:t}=new URL(e.url),n=t.get(`q`)?.trim(),r=t.get(`locale`)||`en-US`,i=t.get(`backends`),a=parseInt(t.get(`limit`)||`8`,10);if(!n)return Response.json({suggestions:[],domains:[]});let o=i?i.split(`,`).map(e=>e.trim()).filter(Boolean):O;try{let e=await F(o,n,r),t=P(n);return Response.json({suggestions:e.slice(0,a),domains:t})}catch(e){return console.error(`Autocomplete error:`,e),Response.json({suggestions:[],domains:[]},{status:500})}}}}function L(){return{POST:async e=>{let n=await e.json(),r=n.chatHistory.filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:String(e.content??``)})),i=await new t.default().loadChatModel(n.chatModel.providerId,n.chatModel.key),a=(await(0,s.default)({chat_history:r,maxQuestions:n.maxQuestions},i)).flatMap(e=>(e.match(/\?/g)||[]).length>1?e.split(/\?/).map(e=>e.trim()).filter(e=>e.length>0).map(e=>e+`?`):[e]);return Response.json({suggestions:a},{status:200})}}}function R(e){return{POST:async t=>{let r;try{r=await t.json()}catch{return Response.json({error:`Invalid JSON input`},{status:500})}r.ip=t.headers?.get?.(`x-forwarded-for`)||t.headers?.get?.(`x-real-ip`)||`unknown`;let i=e.getDB(),a=await e.getUserId(),o=null;return a&&(o=await i.query.user.findFirst({where:(0,n.eq)(e.userSchema.id,a)})),o&&(r.apiKey=o.settings?.providerApiKeys?.find(e=>e.provider==r.provider)?.key),r.apiKey||=r.provider==`groq`&&e.getEnv(`GROQ_API_KEY`),r.apiKey?Response.json({error:`Language generation endpoint is deprecated. Please use /api/agent/chat instead.`},{status:501}):Response.json({error:`API key is required`},{status:500})}}}function z(e){return{POST:async t=>{try{let{text:n,prompt:r}=await t.json();if(!n||typeof n!=`string`)return Response.json({error:`Text is required and must be a string`},{status:400});let i=e.getEnv(`GROQ_API_KEY`);if(!i)return console.error(`GROQ_API_KEY is not configured`),Response.json({error:`AI service is not configured. Please contact the administrator.`},{status:500});let a=e.createGroq({apiKey:i})(`llama-3.3-70b-versatile`),o=r||`Rewrite the following text to improve clarity, grammar, and style while maintaining the original meaning and tone. Only return the rewritten text without any explanation or additional commentary:
21
21
 
22
- ${n}`,s=(await e.generateText({model:a,prompt:o,temperature:.7})).text.trim();return Response.json({rewrittenText:s})}catch(e){return console.error(`AI rewrite error:`,e),Response.json({error:`Failed to process AI request. Please try again.`},{status:500})}}}}function R(e){return{POST:async t=>{let n,r,i;try{let e=await t.json();n=e.text,r=e.voice||e.speaker||`af_heart`,i=e.provider||`kokoro`}catch{return Response.json({error:`Invalid request body`},{status:400})}if(!n||typeof n!=`string`||n.trim().length===0)return Response.json({error:`text is required`},{status:400});let a=await e.getUserId()??t.headers?.get?.(`x-forwarded-for`)?.split(`,`)[0]?.trim()??t.headers?.get?.(`x-real-ip`)??`unknown`,{allowed:o}=e.checkTTSRateLimit(a);if(!o)return Response.json({error:`Daily TTS limit reached (10/day)`,rateLimited:!0},{status:429});try{let t=await e.generateSpeech({text:n.slice(0,5e3),provider:i,voice:r});return new Response(t.audio,{headers:{"Content-Type":t.contentType,"Cache-Control":`public, max-age=86400`,"Content-Disposition":`inline; filename="speech.${t.contentType.includes(`wav`)?`wav`:`mp3`}"`}})}catch(e){console.error(`[TTS] Error:`,e);let t=e instanceof Error?e.message:`TTS generation failed`;return t.includes(`Cloudflare AI binding`)?Response.json({error:`Deepgram provider requires Cloudflare AI binding. Use 'kokoro' provider instead.`},{status:503}):Response.json({error:t},{status:500})}}}}function z(e){return e===`small`||e===`fast`?`@cf/openai/whisper-tiny-en`:e===`medium`||e===`turbo`?`@cf/openai/whisper-large-v3-turbo`:e===`large`?`@cf/openai/whisper-large-v3`:`@cf/openai/whisper-large-v3-turbo`}function B(e){return{POST:async t=>{try{let n=await t.formData(),r=n.get(`file`);if(!r||!(r instanceof File))return Response.json({error:`file is required`},{status:400});let i=z(n.get(`model`)),a;try{a=e.getCloudflareContext().env?.AI}catch{}if(!a)return Response.json({error:`Cloudflare AI binding not available`},{status:503});let o=await r.arrayBuffer(),{text:s}=await a.run(i,{audio:[...new Uint8Array(o)]});return Response.json({text:s,model:i})}catch(e){return console.error(`Transcript error:`,e),Response.json({error:`Failed to transcribe audio`},{status:500})}}}}function V(){return{POST:async e=>{try{let{providerType:t,apiKey:n,onlyFree:r=!0}=await e.json();if(!t)return Response.json({error:`Provider type is required`},{status:400});if(!n)return Response.json({error:`API key is required`},{status:400});let i=l.LANGUAGE_MODELS.find(e=>e.provider.toLowerCase()===t.toLowerCase());if(!i)return Response.json({error:`Provider ${t} not found`},{status:404});let a=await(0,c.testProviderModels)(t,n,i.models,{onlyFree:r,concurrency:3,timeout:15e3});return Response.json(a)}catch(e){return console.error(`[test-models] Error:`,e),Response.json({error:e.message||`Failed to test models`},{status:500})}}}}var H=1440*60*1e3,U=null;function W(e){return{GET:async t=>{try{let t=Date.now();if(U&&t-U.timestamp<H)return Response.json({...U.result,cached:!0,cacheAge:t-U.timestamp});let n=await e.validateOpenRouterModels();return U={result:n,timestamp:t},Response.json({...n,cached:!1})}catch(e){return console.error(`[validate-openrouter] GET error:`,e),Response.json({error:e.message||`Validation failed`},{status:500})}},POST:async t=>{try{let{concurrency:n=3,timeout:r=15e3}=await t.json().catch(()=>({})),i=await e.validateOpenRouterModels(n,r);return U={result:i,timestamp:Date.now()},Response.json({...i,cached:!1})}catch(e){return console.error(`[validate-openrouter] POST error:`,e),Response.json({error:e.message||`Validation failed`},{status:500})}}}}exports.createAgentsHandler=I,exports.createArticleFollowupsHandler=u,exports.createArticleQAHandler=d,exports.createAutocompleteHandler=P,exports.createChatByIdHandler=p,exports.createChatsHandler=f,exports.createChatsSearchHandler=m,exports.createChatsShareHandler=h,exports.createDiscoverHandler=T,exports.createMCPServerByIdHandler=x,exports.createMCPServerToggleHandler=S,exports.createMCPServersHandler=b,exports.createMessagesHandler=g,exports.createProviderByIdHandler=v,exports.createProviderModelsHandler=y,exports.createProvidersHandler=_,exports.createRewriteHandler=L,exports.createSearchHandler=w,exports.createSuggestionsHandler=F,exports.createTestModelsHandler=V,exports.createTranscriptHandler=B,exports.createValidateOpenRouterHandler=W,exports.createVoiceHandler=R;
22
+ ${n}`,s=(await e.generateText({model:a,prompt:o,temperature:.7})).text.trim();return Response.json({rewrittenText:s})}catch(e){return console.error(`AI rewrite error:`,e),Response.json({error:`Failed to process AI request. Please try again.`},{status:500})}}}}function B(e){return{POST:async t=>{let n,r,i;try{let e=await t.json();n=e.text,r=e.voice||e.speaker||`af_heart`,i=e.provider||`kokoro`}catch{return Response.json({error:`Invalid request body`},{status:400})}if(!n||typeof n!=`string`||n.trim().length===0)return Response.json({error:`text is required`},{status:400});let a=await e.getUserId()??t.headers?.get?.(`x-forwarded-for`)?.split(`,`)[0]?.trim()??t.headers?.get?.(`x-real-ip`)??`unknown`,{allowed:o}=e.checkTTSRateLimit(a);if(!o)return Response.json({error:`Daily TTS limit reached (10/day)`,rateLimited:!0},{status:429});try{let t=await e.generateSpeech({text:n.slice(0,5e3),provider:i,voice:r});return new Response(t.audio,{headers:{"Content-Type":t.contentType,"Cache-Control":`public, max-age=86400`,"Content-Disposition":`inline; filename="speech.${t.contentType.includes(`wav`)?`wav`:`mp3`}"`}})}catch(e){console.error(`[TTS] Error:`,e);let t=e instanceof Error?e.message:`TTS generation failed`;return t.includes(`Cloudflare AI binding`)?Response.json({error:`Deepgram provider requires Cloudflare AI binding. Use 'kokoro' provider instead.`},{status:503}):Response.json({error:t},{status:500})}}}}function V(e){return e===`small`||e===`fast`?`@cf/openai/whisper-tiny-en`:e===`medium`||e===`turbo`?`@cf/openai/whisper-large-v3-turbo`:e===`large`?`@cf/openai/whisper-large-v3`:`@cf/openai/whisper-large-v3-turbo`}function H(e){return{POST:async t=>{try{let n=await t.formData(),r=n.get(`file`);if(!r||!(r instanceof File))return Response.json({error:`file is required`},{status:400});let i=V(n.get(`model`)),a;try{a=e.getCloudflareContext().env?.AI}catch{}if(!a)return Response.json({error:`Cloudflare AI binding not available`},{status:503});let o=await r.arrayBuffer(),{text:s}=await a.run(i,{audio:[...new Uint8Array(o)]});return Response.json({text:s,model:i})}catch(e){return console.error(`Transcript error:`,e),Response.json({error:`Failed to transcribe audio`},{status:500})}}}}function U(){return{POST:async e=>{try{let{providerType:t,apiKey:n,onlyFree:r=!0}=await e.json();if(!t)return Response.json({error:`Provider type is required`},{status:400});if(!n)return Response.json({error:`API key is required`},{status:400});let i=l.LANGUAGE_MODELS.find(e=>e.provider.toLowerCase()===t.toLowerCase());if(!i)return Response.json({error:`Provider ${t} not found`},{status:404});let a=await(0,c.testProviderModels)(t,n,i.models,{onlyFree:r,concurrency:3,timeout:15e3});return Response.json(a)}catch(e){return console.error(`[test-models] Error:`,e),Response.json({error:e.message||`Failed to test models`},{status:500})}}}}var W=1440*60*1e3,G=null;function K(e){return{GET:async t=>{try{let t=Date.now();if(G&&t-G.timestamp<W)return Response.json({...G.result,cached:!0,cacheAge:t-G.timestamp});let n=await e.validateOpenRouterModels();return G={result:n,timestamp:t},Response.json({...n,cached:!1})}catch(e){return console.error(`[validate-openrouter] GET error:`,e),Response.json({error:e.message||`Validation failed`},{status:500})}},POST:async t=>{try{let{concurrency:n=3,timeout:r=15e3}=await t.json().catch(()=>({})),i=await e.validateOpenRouterModels(n,r);return G={result:i,timestamp:Date.now()},Response.json({...i,cached:!1})}catch(e){return console.error(`[validate-openrouter] POST error:`,e),Response.json({error:e.message||`Validation failed`},{status:500})}}}}exports.createAgentsHandler=R,exports.createArticleFollowupsHandler=u,exports.createArticleQAHandler=d,exports.createAutocompleteHandler=I,exports.createChatByIdHandler=p,exports.createChatsHandler=f,exports.createChatsSearchHandler=m,exports.createChatsShareHandler=h,exports.createDiscoverHandler=D,exports.createMCPServerByIdHandler=C,exports.createMCPServerToggleHandler=w,exports.createMCPServersHandler=S,exports.createMessagesHandler=v,exports.createProviderByIdHandler=b,exports.createProviderModelsHandler=x,exports.createProvidersHandler=y,exports.createRewriteHandler=z,exports.createSearchHandler=E,exports.createSuggestionsHandler=L,exports.createTestModelsHandler=U,exports.createTranscriptHandler=H,exports.createValidateOpenRouterHandler=K,exports.createVoiceHandler=B,exports.describeError=_;
package/dist/api.mjs CHANGED
@@ -227,11 +227,22 @@ function x(e) {
227
227
  }
228
228
  //#endregion
229
229
  //#region src/api/handlers/messages.ts
230
- function S(e) {
230
+ var S = [
231
+ "assistant",
232
+ "user",
233
+ "source",
234
+ "suggestion"
235
+ ];
236
+ function C(e) {
237
+ let t = [], n = e;
238
+ for (let e = 0; n != null && e < 5; e++) t.push(n instanceof Error ? n.message : String(n)), n = n instanceof Error ? n.cause : void 0;
239
+ return t.join(" <- caused by: ");
240
+ }
241
+ function w(e) {
231
242
  return { POST: async (t) => {
232
243
  try {
233
244
  let n = e.getDB(), r = await e.requireUserId(), { chatId: i, messageId: a, role: o, suggestions: s, content: c, sources: l } = await t.json();
234
- return !i || !a || !o ? Response.json({ message: "Missing required fields" }, { status: 400 }) : (await n.insert(e.messagesSchema).values({
245
+ return !i || !a || !o ? Response.json({ message: "Missing required fields" }, { status: 400 }) : S.includes(o) ? (await n.insert(e.messagesSchema).values({
235
246
  chatId: i,
236
247
  userId: r,
237
248
  messageId: a,
@@ -240,15 +251,15 @@ function S(e) {
240
251
  suggestions: s || [],
241
252
  sources: l || [],
242
253
  createdAt: (/* @__PURE__ */ new Date()).toISOString()
243
- }), Response.json({ message: "Message saved successfully" }, { status: 200 }));
254
+ }), Response.json({ message: "Message saved successfully" }, { status: 200 })) : Response.json({ message: `Invalid role: ${o}` }, { status: 400 });
244
255
  } catch (e) {
245
- return console.error("Error saving message:", e), Response.json({ message: "Failed to save message" }, { status: 500 });
256
+ return console.error("Error saving message:", C(e)), Response.json({ message: "Failed to save message" }, { status: 500 });
246
257
  }
247
258
  } };
248
259
  }
249
260
  //#endregion
250
261
  //#region src/api/handlers/providers.ts
251
- function C(t) {
262
+ function T(t) {
252
263
  return {
253
264
  GET: async (n) => {
254
265
  try {
@@ -278,7 +289,7 @@ function C(t) {
278
289
  }
279
290
  };
280
291
  }
281
- function w() {
292
+ function E() {
282
293
  return {
283
294
  DELETE: async (t, { params: n }) => {
284
295
  try {
@@ -300,7 +311,7 @@ function w() {
300
311
  }
301
312
  };
302
313
  }
303
- function T() {
314
+ function D() {
304
315
  return {
305
316
  POST: async (t, { params: n }) => {
306
317
  try {
@@ -322,7 +333,7 @@ function T() {
322
333
  }
323
334
  //#endregion
324
335
  //#region src/api/handlers/mcpservers.ts
325
- function E(e) {
336
+ function O(e) {
326
337
  return {
327
338
  GET: async (t) => {
328
339
  try {
@@ -344,7 +355,7 @@ function E(e) {
344
355
  }
345
356
  };
346
357
  }
347
- function D(e) {
358
+ function k(e) {
348
359
  return {
349
360
  DELETE: async (t, { params: n }) => {
350
361
  try {
@@ -366,7 +377,7 @@ function D(e) {
366
377
  }
367
378
  };
368
379
  }
369
- function O(e) {
380
+ function A(e) {
370
381
  return { POST: async (t, { params: n }) => {
371
382
  try {
372
383
  let { enabled: r } = await t.json(), { id: i } = await n;
@@ -380,7 +391,7 @@ function O(e) {
380
391
  }
381
392
  //#endregion
382
393
  //#region src/api/handlers/search.ts
383
- var k = {
394
+ var j = {
384
395
  tech: {
385
396
  query: [
386
397
  "technology news",
@@ -446,7 +457,7 @@ var k = {
446
457
  ]
447
458
  }
448
459
  };
449
- function A(e = {}) {
460
+ function M(e = {}) {
450
461
  let t = e.searxngDomain ?? "https://search.qwksearch.com";
451
462
  return { GET: async (e) => {
452
463
  let n = new URL(e.url).searchParams, r = n.get("q"), i = n.get("cat") || "general", a = parseInt(n.get("page") || "1", 10), o = n.get("lang") || "en-US", s = n.get("safesearch") === "true", c = n.get("recency") || void 0, u = n.get("publicInstances") === "true";
@@ -493,10 +504,10 @@ function A(e = {}) {
493
504
  }
494
505
  } };
495
506
  }
496
- function j() {
507
+ function N() {
497
508
  return { GET: async (e) => {
498
509
  try {
499
- let t = new URL(e.url).searchParams, n = t.get("mode") || "normal", r = k[t.get("topic") || "tech"], i = [];
510
+ let t = new URL(e.url).searchParams, n = t.get("mode") || "normal", r = j[t.get("topic") || "tech"], i = [];
500
511
  if (n === "normal") {
501
512
  let e = /* @__PURE__ */ new Set();
502
513
  i = (await Promise.all(r.links.flatMap((e) => r.query.map(async (t) => (await c(`site:${e} ${t}`, {
@@ -520,17 +531,17 @@ function j() {
520
531
  }
521
532
  //#endregion
522
533
  //#region src/api/handlers/autocomplete.ts
523
- var M = [
534
+ var P = [
524
535
  "google",
525
536
  "duckduckgo",
526
537
  "wikipedia"
527
- ], N = 3, P = 3, F = Object.entries(f).map(([e, t]) => ({
538
+ ], F = 3, I = 3, L = Object.entries(f).map(([e, t]) => ({
528
539
  domain: e,
529
540
  name: typeof t?.[0] == "string" ? t[0] : "",
530
541
  rank: typeof t?.[1] == "number" ? t[1] : 2 ** 53 - 1
531
- })), I = null;
532
- function L() {
533
- return I ||= new d(F, {
542
+ })), R = null;
543
+ function z() {
544
+ return R ||= new d(L, {
534
545
  keys: [{
535
546
  name: "name",
536
547
  weight: .6
@@ -542,20 +553,20 @@ function L() {
542
553
  ignoreLocation: !0,
543
554
  includeScore: !0,
544
555
  minMatchCharLength: 3
545
- }), I;
556
+ }), R;
546
557
  }
547
- function R(e) {
558
+ function B(e) {
548
559
  let t = e.split(/\s+/).filter(Boolean), n = t[t.length - 1] || "";
549
- return n.length < 3 ? [] : L().search(n, { limit: 12 }).sort((e, t) => Math.round((e.score ?? 1) * 10) - Math.round((t.score ?? 1) * 10) || e.item.rank - t.item.rank).slice(0, P).map(({ item: e }) => ({
560
+ return n.length < 3 ? [] : z().search(n, { limit: 12 }).sort((e, t) => Math.round((e.score ?? 1) * 10) - Math.round((t.score ?? 1) * 10) || e.item.rank - t.item.rank).slice(0, I).map(({ item: e }) => ({
550
561
  domain: e.domain,
551
562
  name: e.name,
552
563
  favicon: `https://www.google.com/s2/favicons?domain=${encodeURIComponent(e.domain)}&sz=64`
553
564
  }));
554
565
  }
555
- async function z(e, t, n) {
566
+ async function V(e, t, n) {
556
567
  let r = await u(e, t, n);
557
568
  if (r.length > 0) return r;
558
- let i = t.split(/\s+/).filter(Boolean), a = Math.min(N, i.length - 1);
569
+ let i = t.split(/\s+/).filter(Boolean), a = Math.min(F, i.length - 1);
559
570
  for (let r = a; r >= 1; r--) {
560
571
  let a = i.slice(-r).join(" "), o = i.slice(0, -r).join(" "), s = await u(e, a, n);
561
572
  if (s.length > 0) {
@@ -569,16 +580,16 @@ async function z(e, t, n) {
569
580
  }
570
581
  return [];
571
582
  }
572
- function B() {
583
+ function H() {
573
584
  return { GET: async (e) => {
574
585
  let { searchParams: t } = new URL(e.url), n = t.get("q")?.trim(), r = t.get("locale") || "en-US", i = t.get("backends"), a = parseInt(t.get("limit") || "8", 10);
575
586
  if (!n) return Response.json({
576
587
  suggestions: [],
577
588
  domains: []
578
589
  });
579
- let o = i ? i.split(",").map((e) => e.trim()).filter(Boolean) : M;
590
+ let o = i ? i.split(",").map((e) => e.trim()).filter(Boolean) : P;
580
591
  try {
581
- let e = await z(o, n, r), t = R(n);
592
+ let e = await V(o, n, r), t = B(n);
582
593
  return Response.json({
583
594
  suggestions: e.slice(0, a),
584
595
  domains: t
@@ -593,7 +604,7 @@ function B() {
593
604
  }
594
605
  //#endregion
595
606
  //#region src/api/handlers/suggestions.ts
596
- function V() {
607
+ function U() {
597
608
  return { POST: async (t) => {
598
609
  let n = await t.json(), r = n.chatHistory.filter((e) => e.role === "user" || e.role === "assistant").map((e) => ({
599
610
  role: e.role,
@@ -607,7 +618,7 @@ function V() {
607
618
  }
608
619
  //#endregion
609
620
  //#region src/api/handlers/agents.ts
610
- function H(e) {
621
+ function W(e) {
611
622
  return { POST: async (t) => {
612
623
  let n;
613
624
  try {
@@ -622,7 +633,7 @@ function H(e) {
622
633
  }
623
634
  //#endregion
624
635
  //#region src/api/handlers/rewrite.ts
625
- function U(e) {
636
+ function G(e) {
626
637
  return { POST: async (t) => {
627
638
  try {
628
639
  let { text: n, prompt: r } = await t.json();
@@ -644,7 +655,7 @@ ${n}`, s = (await e.generateText({
644
655
  }
645
656
  //#endregion
646
657
  //#region src/api/handlers/voice.ts
647
- function W(e) {
658
+ function K(e) {
648
659
  return { POST: async (t) => {
649
660
  let n, r, i;
650
661
  try {
@@ -679,15 +690,15 @@ function W(e) {
679
690
  }
680
691
  //#endregion
681
692
  //#region src/api/handlers/transcript.ts
682
- function G(e) {
693
+ function q(e) {
683
694
  return e === "small" || e === "fast" ? "@cf/openai/whisper-tiny-en" : e === "medium" || e === "turbo" ? "@cf/openai/whisper-large-v3-turbo" : e === "large" ? "@cf/openai/whisper-large-v3" : "@cf/openai/whisper-large-v3-turbo";
684
695
  }
685
- function K(e) {
696
+ function J(e) {
686
697
  return { POST: async (t) => {
687
698
  try {
688
699
  let n = await t.formData(), r = n.get("file");
689
700
  if (!r || !(r instanceof File)) return Response.json({ error: "file is required" }, { status: 400 });
690
- let i = G(n.get("model")), a;
701
+ let i = q(n.get("model")), a;
691
702
  try {
692
703
  a = e.getCloudflareContext().env?.AI;
693
704
  } catch {}
@@ -704,7 +715,7 @@ function K(e) {
704
715
  }
705
716
  //#endregion
706
717
  //#region src/api/handlers/test-models.ts
707
- function q() {
718
+ function Y() {
708
719
  return { POST: async (e) => {
709
720
  try {
710
721
  let { providerType: t, apiKey: n, onlyFree: r = !0 } = await e.json();
@@ -725,19 +736,19 @@ function q() {
725
736
  }
726
737
  //#endregion
727
738
  //#region src/api/handlers/validate-openrouter.ts
728
- var J = 1440 * 60 * 1e3, Y = null;
729
- function X(e) {
739
+ var X = 1440 * 60 * 1e3, Z = null;
740
+ function Q(e) {
730
741
  return {
731
742
  GET: async (t) => {
732
743
  try {
733
744
  let t = Date.now();
734
- if (Y && t - Y.timestamp < J) return Response.json({
735
- ...Y.result,
745
+ if (Z && t - Z.timestamp < X) return Response.json({
746
+ ...Z.result,
736
747
  cached: !0,
737
- cacheAge: t - Y.timestamp
748
+ cacheAge: t - Z.timestamp
738
749
  });
739
750
  let n = await e.validateOpenRouterModels();
740
- return Y = {
751
+ return Z = {
741
752
  result: n,
742
753
  timestamp: t
743
754
  }, Response.json({
@@ -751,7 +762,7 @@ function X(e) {
751
762
  POST: async (t) => {
752
763
  try {
753
764
  let { concurrency: n = 3, timeout: r = 15e3 } = await t.json().catch(() => ({})), i = await e.validateOpenRouterModels(n, r);
754
- return Y = {
765
+ return Z = {
755
766
  result: i,
756
767
  timestamp: Date.now()
757
768
  }, Response.json({
@@ -765,4 +776,4 @@ function X(e) {
765
776
  };
766
777
  }
767
778
  //#endregion
768
- export { H as createAgentsHandler, g as createArticleFollowupsHandler, _ as createArticleQAHandler, B as createAutocompleteHandler, y as createChatByIdHandler, v as createChatsHandler, b as createChatsSearchHandler, x as createChatsShareHandler, j as createDiscoverHandler, D as createMCPServerByIdHandler, O as createMCPServerToggleHandler, E as createMCPServersHandler, S as createMessagesHandler, w as createProviderByIdHandler, T as createProviderModelsHandler, C as createProvidersHandler, U as createRewriteHandler, A as createSearchHandler, V as createSuggestionsHandler, q as createTestModelsHandler, K as createTranscriptHandler, X as createValidateOpenRouterHandler, W as createVoiceHandler };
779
+ export { W as createAgentsHandler, g as createArticleFollowupsHandler, _ as createArticleQAHandler, H as createAutocompleteHandler, y as createChatByIdHandler, v as createChatsHandler, b as createChatsSearchHandler, x as createChatsShareHandler, N as createDiscoverHandler, k as createMCPServerByIdHandler, A as createMCPServerToggleHandler, O as createMCPServersHandler, w as createMessagesHandler, E as createProviderByIdHandler, D as createProviderModelsHandler, T as createProvidersHandler, G as createRewriteHandler, M as createSearchHandler, U as createSuggestionsHandler, Y as createTestModelsHandler, J as createTranscriptHandler, Q as createValidateOpenRouterHandler, K as createVoiceHandler, C as describeError };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "research-agent-ui",
3
3
  "description": "Chat research agent UI: conversation window, article reader, search config, file uploads, and chat history",
4
- "version": "0.1.26",
4
+ "version": "0.1.27",
5
5
  "author": "vtempest",
6
6
  "repository": {
7
7
  "type": "git",
@@ -60,14 +60,14 @@
60
60
  "@radix-ui/react-slot": "^1.2.5",
61
61
  "@radix-ui/react-tooltip": "^1.2.9",
62
62
  "@ricky0123/vad-web": "^0.0.30",
63
- "chat-agent-toolkit": "^1.2.44",
64
- "domain-rank": "^0.1.33",
63
+ "chat-agent-toolkit": "^1.2.46",
64
+ "domain-rank": "^0.1.35",
65
65
  "drizzle-orm": "^0.45.2",
66
66
  "fuse.js": "^7.1.0",
67
67
  "class-variance-authority": "^0.7.1",
68
68
  "clsx": "^2.1.1",
69
69
  "dompurify": "^3.4.9",
70
- "extract-webpage": "^1.2.46",
70
+ "extract-webpage": "^1.2.47",
71
71
  "framer-motion": "^12.40.0",
72
72
  "grab-url": "^1.6.22",
73
73
  "qwksearch-api-client": "^0.9.1",