research-agent-ui 0.1.128 → 0.1.130
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/api/handlers/topic-searches.d.ts +2 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api.cjs +11 -3
- package/dist/api.mjs +91 -49
- package/package.json +7 -7
package/dist/api/index.d.ts
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
export * from "./types";
|
|
5
5
|
export * from "./handlers/article-followups";
|
|
6
6
|
export * from "./handlers/page-tips";
|
|
7
|
+
export * from "./handlers/topic-searches";
|
|
7
8
|
export * from "./handlers/article-qa";
|
|
8
9
|
export * from "./handlers/chats";
|
|
9
10
|
export * from "./handlers/chat-title";
|
package/dist/api.cjs
CHANGED
|
@@ -15,7 +15,15 @@ Page content:
|
|
|
15
15
|
${i.slice(0,15e3)}
|
|
16
16
|
|
|
17
17
|
Generate ${a} short tips about this page.`,{text:d}=await(0,t.generateText)({model:c,messages:[{role:`system`,content:l},{role:`user`,content:u}]}),f=d.split(`
|
|
18
|
-
`).map(e=>e.trim()).filter(e=>e.length>0).map(e=>e.replace(/^[\d\-\*\.\)]+\s*/,``).trim()).filter(e=>e.length>10).slice(0,a);return Response.json({tips:f,success:!0})}catch(e){return console.error(`Error generating page tips:`,e),Response.json({error:`An error occurred while generating page tips`,details:e instanceof Error?e.message:String(e)},{status:500})}}}function h(e){return async e=>{try{let{
|
|
18
|
+
`).map(e=>e.trim()).filter(e=>e.length>0).map(e=>e.replace(/^[\d\-\*\.\)]+\s*/,``).trim()).filter(e=>e.length>10).slice(0,a);return Response.json({tips:f,success:!0})}catch(e){return console.error(`Error generating page tips:`,e),Response.json({error:`An error occurred while generating page tips`,details:e instanceof Error?e.message:String(e)},{status:500})}}}function h(e){return async e=>{try{let{title:r=``,content:i,maxTopics:a=4,chatModel:o}=await e.json();if(!i)return Response.json({error:`Content is required`},{status:400});let s=new n.default,c;try{c=await s.loadChatModel(o?.providerId,o?.key)}catch(e){return Response.json({error:e instanceof Error?e.message:`Failed to load language model`},{status:500})}let l=`You are a helpful AI that suggests related searches for a reader based on a page they currently have open.
|
|
19
|
+
Generate ${a} short search queries (each a few words, phrased the way someone would type it into a search box) that dig deeper into topics related to the page.
|
|
20
|
+
Return ONLY the search queries, one per line, without numbering or bullet points.`,u=`Page title: ${r}
|
|
21
|
+
|
|
22
|
+
Page content:
|
|
23
|
+
${i.slice(0,15e3)}
|
|
24
|
+
|
|
25
|
+
Generate ${a} short related search queries for this page.`,{text:d}=await(0,t.generateText)({model:c,messages:[{role:`system`,content:l},{role:`user`,content:u}]}),f=d.split(`
|
|
26
|
+
`).map(e=>e.trim()).filter(e=>e.length>0).map(e=>e.replace(/^[\d\-\*\.\)]+\s*/,``).trim()).filter(e=>e.length>2).slice(0,a);return Response.json({topics:f,success:!0})}catch(e){return console.error(`Error generating topic searches:`,e),Response.json({error:`An error occurred while generating topic searches`,details:e instanceof Error?e.message:String(e)},{status:500})}}}function g(e){return async e=>{try{let{article:r,question:i,chatHistory:a=[],chatModel:o}=await e.json();if(!r||!i)return Response.json({error:`Article and question are required`},{status:400});let s=new n.default,c;try{c=await s.loadChatModel(o?.providerId,o?.key)}catch(e){return Response.json({error:e instanceof Error?e.message:`Failed to load language model`},{status:500})}let l=a.length>0?`\n\nPrevious conversation:\n${a.map(e=>`${e.role===`user`?`User`:`Assistant`}: ${e.content}`).join(`
|
|
19
27
|
`)}`:``,u=`Article content:
|
|
20
28
|
${r.slice(0,15e3)}
|
|
21
29
|
|
|
@@ -25,6 +33,6 @@ User question: ${i}
|
|
|
25
33
|
|
|
26
34
|
Please provide a helpful answer based on the article content above.`,{text:d}=await(0,t.generateText)({model:c,messages:[{role:`system`,content:`You are a helpful AI assistant that answers questions about articles.
|
|
27
35
|
Provide clear, concise, and accurate answers based on the article content provided.
|
|
28
|
-
If the answer is not in the article, say so.`},{role:`user`,content:u}]});return Response.json({content:d,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 g(e){let{chats:t,messages:n}=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,r.count)(n.id),lastMessageAt:(0,r.max)(n.createdAt)}).from(t).leftJoin(n,(0,r.and)((0,r.eq)(n.chatId,t.id),(0,r.eq)(n.role,`user`))).where((0,r.eq)(t.userId,a)).groupBy(t.id,t.title,t.createdAt,t.focusMode,t.userId,t.files).orderBy(r.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,r.eq)(t.userId,a),columns:{id:!0}});if(o.length>0){let e=o.map(e=>e.id);await i.delete(n).where((0,r.inArray)(n.chatId,e)),await i.delete(t).where((0,r.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 _(e){let{chats:t,messages:n}=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,r.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,r.eq)(n.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,r.and)((0,r.eq)(t.id,o),(0,r.eq)(t.userId,s))})?(await i.delete(t).where((0,r.eq)(t.id,o)).execute(),await i.delete(n).where((0,r.eq)(n.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 v(e){let{chats:t,messages:n}=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,r.and)((0,r.eq)(t.userId,o),(0,r.like)(t.title,l))).orderBy(r.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(n).innerJoin(t,(0,r.eq)(n.chatId,t.id)).where((0,r.and)((0,r.eq)(t.userId,o),(0,r.or)((0,r.like)(n.content,l)))).orderBy(r.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:n.chatId,count:r.sql`count(*)`}).from(n).where((0,r.and)(r.sql`${n.chatId} IN (${r.sql.join(m.map(e=>r.sql`${e}`),r.sql`, `)})`,(0,r.eq)(n.role,`user`))).groupBy(n.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 y(e){let{chats:t}=e.schema;return{POST:async n=>{try{let i=e.getDB(),{chatId:a}=await n.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,r.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,r.eq)(t.id,a)).execute();let c=`${new URL(n.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 b(e){let{chats:t}=e.schema;return{POST:async a=>{try{let o=await a.json(),s=o.chatHistory.filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:String(e.content??``)}));if(s.length===0)return Response.json({message:`No conversation content`},{status:400});let c=await new n.default().loadChatModel(o.chatModel.providerId,o.chatModel.key),l=await(0,i.default)({chat_history:s},c);if(!l)return Response.json({message:`Failed to generate title`},{status:500});let u=e.getUserId?await e.getUserId():null;if(u&&o.chatId)try{let n=e.getDB(),i=await n.query.chats.findFirst({where:(0,r.eq)(t.id,o.chatId)});i&&i.userId===u&&await n.update(t).set({title:l}).where((0,r.eq)(t.id,o.chatId)).execute()}catch(e){console.error(`Failed to persist chat title:`,e)}return Response.json({title:l},{status:200})}catch(e){return console.error(`Error generating chat title:`,e),Response.json({message:`Failed to generate title`},{status:500})}}}}var x=[`assistant`,`user`,`source`,`suggestion`];function S(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 C(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}):x.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:`,S(e)),Response.json({message:`Failed to save message`},{status:500})}}}}function w(e){return{GET:async t=>{try{let r=new n.default,i=new URL(t.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:t,config:r}=await e.json();if(!t||!r)return Response.json({message:`Missing required fields.`},{status:400});let i=await new n.default().addProvider(t,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 T(){return{DELETE:async(e,{params:t})=>{try{let{id:e}=await t;return e?(await new n.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:t})=>{try{let{config:r}=await e.json(),{id:i}=await t;if(!i||!r)return Response.json({message:`Missing required fields.`},{status:400});let a=await new n.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 E(){return{POST:async(e,{params:t})=>{try{let{id:r}=await t,i=await e.json();return!i.key||!i.name?Response.json({message:`Key and name must be provided`},{status:400}):(await new n.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:t})=>{try{let{id:r}=await t,i=await e.json();return i.key?(await new n.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 D(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 O(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 k(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 A={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 j(e={}){let t=e.searxngDomain??`https://search.qwksearch.com`;return{GET:async e=>{let n=new URL(e.url).searchParams,r=n.get(`q`),i=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(!r)return Response.json({error:`Query parameter is required`},{status:400});let d=Date.now();try{let e=await(0,a.searchWeb)(r,{category:i,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,a.searchWeb)(r,{category:i,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 M(){return{GET:async e=>{try{let t=new URL(e.url).searchParams,n=t.get(`mode`)||`normal`,r=A[t.get(`topic`)||`tech`],i=[];if(n===`normal`){let e=new Set;i=(await Promise.all(r.links.flatMap(e=>r.query.map(async t=>(await(0,a.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)&&(e.add(n),!0)}).sort(()=>Math.random()-.5)}else i=(await(0,a.searchSearxng)(`site:${r.links[Math.floor(Math.random()*r.links.length)]} ${r.query[Math.floor(Math.random()*r.query.length)]}`,{engines:[`bing news`],pageno:1,language:`en`})).results;return Response.json({blogs:i},{status:200})}catch(e){return console.error(`An error occurred in discover route: ${e}`),Response.json({message:`An error has occurred`},{status:500})}}}}var N=[`google`,`duckduckgo`,`wikipedia`],P=3,F=3,I=Object.entries(l.default).map(([e,t])=>({domain:e,name:typeof t?.[0]==`string`?t[0]:``,rank:typeof t?.[1]==`number`?t[1]:2**53-1})),L=null;function R(){return L||=new s.default(I,{keys:[{name:`name`,weight:.6},{name:`domain`,weight:.4}],threshold:.1,ignoreLocation:!0,includeScore:!0,minMatchCharLength:3}),L}function z(e,t,n){return{domain:e,name:t,favicon:`https://www.google.com/s2/favicons?domain=${encodeURIComponent(e)}&sz=64`,rank:n}}function B(e){let t=(0,c.parse)(e);return t.domain&&t.isIcann?t.hostname:null}function V(e){let t=e.split(/\s+/).filter(Boolean),n=t[t.length-1]||``;if(n.length<3)return[];let r=R().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).map(({item:e})=>z(e.domain,e.name,e.rank)),i=B(n);return i&&!r.some(e=>e.domain===i)&&r.unshift(z(i,``,2**53-1)),r.slice(0,F)}async function H(e,t,n){let r=await(0,o.searchAutocompleteMulti)(e,t,n);if(r.length>0)return r;let i=t.split(/\s+/).filter(Boolean),a=Math.min(P,i.length-1);for(let r=a;r>=1;r--){let a=i.slice(-r).join(` `),s=i.slice(0,-r).join(` `),c=await(0,o.searchAutocompleteMulti)(e,a,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 U(){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):N;try{let e=await H(o,n,r),t=V(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 W(){return{POST:async e=>{let t=await e.json(),r=t.chatHistory.filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:String(e.content??``)})),i=await new n.default().loadChatModel(t.chatModel.providerId,t.chatModel.key),a=(await(0,u.default)({chat_history:r,maxQuestions:t.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 G(e){return{POST:async t=>{let n;try{n=await t.json()}catch{return Response.json({error:`Invalid JSON input`},{status:500})}n.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,r.eq)(e.userSchema.id,a)})),o&&(n.apiKey=o.settings?.providerApiKeys?.find(e=>e.provider==n.provider)?.key),n.apiKey||(n.apiKey=n.provider==`groq`&&e.getEnv(`GROQ_API_KEY`)),n.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 K(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:
|
|
36
|
+
If the answer is not in the article, say so.`},{role:`user`,content:u}]});return Response.json({content:d,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 _(e){let{chats:t,messages:n}=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,r.count)(n.id),lastMessageAt:(0,r.max)(n.createdAt)}).from(t).leftJoin(n,(0,r.and)((0,r.eq)(n.chatId,t.id),(0,r.eq)(n.role,`user`))).where((0,r.eq)(t.userId,a)).groupBy(t.id,t.title,t.createdAt,t.focusMode,t.userId,t.files).orderBy(r.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,r.eq)(t.userId,a),columns:{id:!0}});if(o.length>0){let e=o.map(e=>e.id);await i.delete(n).where((0,r.inArray)(n.chatId,e)),await i.delete(t).where((0,r.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 v(e){let{chats:t,messages:n}=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,r.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,r.eq)(n.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,r.and)((0,r.eq)(t.id,o),(0,r.eq)(t.userId,s))})?(await i.delete(t).where((0,r.eq)(t.id,o)).execute(),await i.delete(n).where((0,r.eq)(n.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 y(e){let{chats:t,messages:n}=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,r.and)((0,r.eq)(t.userId,o),(0,r.like)(t.title,l))).orderBy(r.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(n).innerJoin(t,(0,r.eq)(n.chatId,t.id)).where((0,r.and)((0,r.eq)(t.userId,o),(0,r.or)((0,r.like)(n.content,l)))).orderBy(r.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:n.chatId,count:r.sql`count(*)`}).from(n).where((0,r.and)(r.sql`${n.chatId} IN (${r.sql.join(m.map(e=>r.sql`${e}`),r.sql`, `)})`,(0,r.eq)(n.role,`user`))).groupBy(n.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 b(e){let{chats:t}=e.schema;return{POST:async n=>{try{let i=e.getDB(),{chatId:a}=await n.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,r.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,r.eq)(t.id,a)).execute();let c=`${new URL(n.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 x(e){let{chats:t}=e.schema;return{POST:async a=>{try{let o=await a.json(),s=o.chatHistory.filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:String(e.content??``)}));if(s.length===0)return Response.json({message:`No conversation content`},{status:400});let c=await new n.default().loadChatModel(o.chatModel.providerId,o.chatModel.key),l=await(0,i.default)({chat_history:s},c);if(!l)return Response.json({message:`Failed to generate title`},{status:500});let u=e.getUserId?await e.getUserId():null;if(u&&o.chatId)try{let n=e.getDB(),i=await n.query.chats.findFirst({where:(0,r.eq)(t.id,o.chatId)});i&&i.userId===u&&await n.update(t).set({title:l}).where((0,r.eq)(t.id,o.chatId)).execute()}catch(e){console.error(`Failed to persist chat title:`,e)}return Response.json({title:l},{status:200})}catch(e){return console.error(`Error generating chat title:`,e),Response.json({message:`Failed to generate title`},{status:500})}}}}var S=[`assistant`,`user`,`source`,`suggestion`];function C(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 w(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}):S.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:`,C(e)),Response.json({message:`Failed to save message`},{status:500})}}}}function T(e){return{GET:async t=>{try{let r=new n.default,i=new URL(t.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:t,config:r}=await e.json();if(!t||!r)return Response.json({message:`Missing required fields.`},{status:400});let i=await new n.default().addProvider(t,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 E(){return{DELETE:async(e,{params:t})=>{try{let{id:e}=await t;return e?(await new n.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:t})=>{try{let{config:r}=await e.json(),{id:i}=await t;if(!i||!r)return Response.json({message:`Missing required fields.`},{status:400});let a=await new n.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 D(){return{POST:async(e,{params:t})=>{try{let{id:r}=await t,i=await e.json();return!i.key||!i.name?Response.json({message:`Key and name must be provided`},{status:400}):(await new n.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:t})=>{try{let{id:r}=await t,i=await e.json();return i.key?(await new n.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 O(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 k(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 A(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 j={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 M(e={}){let t=e.searxngDomain??`https://search.qwksearch.com`;return{GET:async e=>{let n=new URL(e.url).searchParams,r=n.get(`q`),i=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(!r)return Response.json({error:`Query parameter is required`},{status:400});let d=Date.now();try{let e=await(0,a.searchWeb)(r,{category:i,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,a.searchWeb)(r,{category:i,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 N(){return{GET:async e=>{try{let t=new URL(e.url).searchParams,n=t.get(`mode`)||`normal`,r=j[t.get(`topic`)||`tech`],i=[];if(n===`normal`){let e=new Set;i=(await Promise.all(r.links.flatMap(e=>r.query.map(async t=>(await(0,a.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)&&(e.add(n),!0)}).sort(()=>Math.random()-.5)}else i=(await(0,a.searchSearxng)(`site:${r.links[Math.floor(Math.random()*r.links.length)]} ${r.query[Math.floor(Math.random()*r.query.length)]}`,{engines:[`bing news`],pageno:1,language:`en`})).results;return Response.json({blogs:i},{status:200})}catch(e){return console.error(`An error occurred in discover route: ${e}`),Response.json({message:`An error has occurred`},{status:500})}}}}var P=[`google`,`duckduckgo`,`wikipedia`],F=3,I=3,L=Object.entries(l.default).map(([e,t])=>({domain:e,name:typeof t?.[0]==`string`?t[0]:``,rank:typeof t?.[1]==`number`?t[1]:2**53-1})),R=null;function z(){return R||=new s.default(L,{keys:[{name:`name`,weight:.6},{name:`domain`,weight:.4}],threshold:.1,ignoreLocation:!0,includeScore:!0,minMatchCharLength:3}),R}function B(e,t,n){return{domain:e,name:t,favicon:`https://www.google.com/s2/favicons?domain=${encodeURIComponent(e)}&sz=64`,rank:n}}function V(e){let t=(0,c.parse)(e);return t.domain&&t.isIcann?t.hostname:null}function H(e){let t=e.split(/\s+/).filter(Boolean),n=t[t.length-1]||``;if(n.length<3)return[];let r=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).map(({item:e})=>B(e.domain,e.name,e.rank)),i=V(n);return i&&!r.some(e=>e.domain===i)&&r.unshift(B(i,``,2**53-1)),r.slice(0,I)}async function U(e,t,n){let r=await(0,o.searchAutocompleteMulti)(e,t,n);if(r.length>0)return r;let i=t.split(/\s+/).filter(Boolean),a=Math.min(F,i.length-1);for(let r=a;r>=1;r--){let a=i.slice(-r).join(` `),s=i.slice(0,-r).join(` `),c=await(0,o.searchAutocompleteMulti)(e,a,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 W(){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):P;try{let e=await U(o,n,r),t=H(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 G(){return{POST:async e=>{let t=await e.json(),r=t.chatHistory.filter(e=>e.role===`user`||e.role===`assistant`).map(e=>({role:e.role,content:String(e.content??``)})),i=await new n.default().loadChatModel(t.chatModel.providerId,t.chatModel.key),a=(await(0,u.default)({chat_history:r,maxQuestions:t.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 K(e){return{POST:async t=>{let n;try{n=await t.json()}catch{return Response.json({error:`Invalid JSON input`},{status:500})}n.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,r.eq)(e.userSchema.id,a)})),o&&(n.apiKey=o.settings?.providerApiKeys?.find(e=>e.provider==n.provider)?.key),n.apiKey||(n.apiKey=n.provider==`groq`&&e.getEnv(`GROQ_API_KEY`)),n.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 q(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:
|
|
29
37
|
|
|
30
|
-
${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
|
|
38
|
+
${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 J(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 Y(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 X(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=Y(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 Z(){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=f.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,d.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 Q=864e5,$=null;function ee(e){return{GET:async t=>{try{let t=Date.now();if($&&t-$.timestamp<Q)return Response.json({...$.result,cached:!0,cacheAge:t-$.timestamp});let n=await e.validateOpenRouterModels();return $={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 $={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=K,exports.createArticleFollowupsHandler=p,exports.createArticleQAHandler=g,exports.createAutocompleteHandler=W,exports.createChatByIdHandler=v,exports.createChatTitleHandler=x,exports.createChatsHandler=_,exports.createChatsSearchHandler=y,exports.createChatsShareHandler=b,exports.createDiscoverHandler=N,exports.createMCPServerByIdHandler=k,exports.createMCPServerToggleHandler=A,exports.createMCPServersHandler=O,exports.createMessagesHandler=w,exports.createPageTipsHandler=m,exports.createProviderByIdHandler=E,exports.createProviderModelsHandler=D,exports.createProvidersHandler=T,exports.createRewriteHandler=q,exports.createSearchHandler=M,exports.createSuggestionsHandler=G,exports.createTestModelsHandler=Z,exports.createTopicSearchesHandler=h,exports.createTranscriptHandler=X,exports.createValidateOpenRouterHandler=ee,exports.createVoiceHandler=J,exports.describeError=C;
|
package/dist/api.mjs
CHANGED
|
@@ -94,8 +94,50 @@ Generate ${a} short tips about this page.`, { text: d } = await e({
|
|
|
94
94
|
};
|
|
95
95
|
}
|
|
96
96
|
//#endregion
|
|
97
|
-
//#region src/api/handlers/
|
|
97
|
+
//#region src/api/handlers/topic-searches.ts
|
|
98
98
|
function S(n) {
|
|
99
|
+
return async (n) => {
|
|
100
|
+
try {
|
|
101
|
+
let { title: r = "", content: i, maxTopics: a = 4, chatModel: o } = await n.json();
|
|
102
|
+
if (!i) return Response.json({ error: "Content is required" }, { status: 400 });
|
|
103
|
+
let s = new t(), c;
|
|
104
|
+
try {
|
|
105
|
+
c = await s.loadChatModel(o?.providerId, o?.key);
|
|
106
|
+
} catch (e) {
|
|
107
|
+
return Response.json({ error: e instanceof Error ? e.message : "Failed to load language model" }, { status: 500 });
|
|
108
|
+
}
|
|
109
|
+
let l = `You are a helpful AI that suggests related searches for a reader based on a page they currently have open.
|
|
110
|
+
Generate ${a} short search queries (each a few words, phrased the way someone would type it into a search box) that dig deeper into topics related to the page.
|
|
111
|
+
Return ONLY the search queries, one per line, without numbering or bullet points.`, u = `Page title: ${r}
|
|
112
|
+
|
|
113
|
+
Page content:
|
|
114
|
+
${i.slice(0, 15e3)}
|
|
115
|
+
|
|
116
|
+
Generate ${a} short related search queries for this page.`, { text: d } = await e({
|
|
117
|
+
model: c,
|
|
118
|
+
messages: [{
|
|
119
|
+
role: "system",
|
|
120
|
+
content: l
|
|
121
|
+
}, {
|
|
122
|
+
role: "user",
|
|
123
|
+
content: u
|
|
124
|
+
}]
|
|
125
|
+
}), f = d.split("\n").map((e) => e.trim()).filter((e) => e.length > 0).map((e) => e.replace(/^[\d\-\*\.\)]+\s*/, "").trim()).filter((e) => e.length > 2).slice(0, a);
|
|
126
|
+
return Response.json({
|
|
127
|
+
topics: f,
|
|
128
|
+
success: !0
|
|
129
|
+
});
|
|
130
|
+
} catch (e) {
|
|
131
|
+
return console.error("Error generating topic searches:", e), Response.json({
|
|
132
|
+
error: "An error occurred while generating topic searches",
|
|
133
|
+
details: e instanceof Error ? e.message : String(e)
|
|
134
|
+
}, { status: 500 });
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region src/api/handlers/article-qa.ts
|
|
140
|
+
function C(n) {
|
|
99
141
|
return async (n) => {
|
|
100
142
|
try {
|
|
101
143
|
let { article: r, question: i, chatHistory: a = [], chatModel: o } = await n.json();
|
|
@@ -137,7 +179,7 @@ Please provide a helpful answer based on the article content above.`, { text: d
|
|
|
137
179
|
}
|
|
138
180
|
//#endregion
|
|
139
181
|
//#region src/api/handlers/chats.ts
|
|
140
|
-
function
|
|
182
|
+
function w(e) {
|
|
141
183
|
let { chats: t, messages: o } = e.schema;
|
|
142
184
|
return {
|
|
143
185
|
GET: async (a) => {
|
|
@@ -174,7 +216,7 @@ function C(e) {
|
|
|
174
216
|
}
|
|
175
217
|
};
|
|
176
218
|
}
|
|
177
|
-
function
|
|
219
|
+
function T(e) {
|
|
178
220
|
let { chats: t, messages: r } = e.schema;
|
|
179
221
|
return {
|
|
180
222
|
GET: async (n, { params: a }) => {
|
|
@@ -207,7 +249,7 @@ function w(e) {
|
|
|
207
249
|
}
|
|
208
250
|
};
|
|
209
251
|
}
|
|
210
|
-
function
|
|
252
|
+
function ee(e) {
|
|
211
253
|
let { chats: t, messages: r } = e.schema;
|
|
212
254
|
return { GET: async (a) => {
|
|
213
255
|
try {
|
|
@@ -240,7 +282,7 @@ function T(e) {
|
|
|
240
282
|
}
|
|
241
283
|
} };
|
|
242
284
|
}
|
|
243
|
-
function
|
|
285
|
+
function E(e) {
|
|
244
286
|
let { chats: t } = e.schema;
|
|
245
287
|
return { POST: async (n) => {
|
|
246
288
|
try {
|
|
@@ -280,7 +322,7 @@ function ee(e) {
|
|
|
280
322
|
}
|
|
281
323
|
//#endregion
|
|
282
324
|
//#region src/api/handlers/chat-title.ts
|
|
283
|
-
function
|
|
325
|
+
function D(e) {
|
|
284
326
|
let { chats: n } = e.schema;
|
|
285
327
|
return { POST: async (r) => {
|
|
286
328
|
try {
|
|
@@ -306,22 +348,22 @@ function E(e) {
|
|
|
306
348
|
}
|
|
307
349
|
//#endregion
|
|
308
350
|
//#region src/api/handlers/messages.ts
|
|
309
|
-
var
|
|
351
|
+
var O = [
|
|
310
352
|
"assistant",
|
|
311
353
|
"user",
|
|
312
354
|
"source",
|
|
313
355
|
"suggestion"
|
|
314
356
|
];
|
|
315
|
-
function
|
|
357
|
+
function k(e) {
|
|
316
358
|
let t = [], n = e;
|
|
317
359
|
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;
|
|
318
360
|
return t.join(" <- caused by: ");
|
|
319
361
|
}
|
|
320
|
-
function
|
|
362
|
+
function A(e) {
|
|
321
363
|
return { POST: async (t) => {
|
|
322
364
|
try {
|
|
323
365
|
let n = e.getDB(), r = await e.requireUserId(), { chatId: i, messageId: a, role: o, suggestions: s, content: c, sources: l } = await t.json();
|
|
324
|
-
return !i || !a || !o ? Response.json({ message: "Missing required fields" }, { status: 400 }) :
|
|
366
|
+
return !i || !a || !o ? Response.json({ message: "Missing required fields" }, { status: 400 }) : O.includes(o) ? (await n.insert(e.messagesSchema).values({
|
|
325
367
|
chatId: i,
|
|
326
368
|
userId: r,
|
|
327
369
|
messageId: a,
|
|
@@ -332,13 +374,13 @@ function k(e) {
|
|
|
332
374
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
333
375
|
}), Response.json({ message: "Message saved successfully" }, { status: 200 })) : Response.json({ message: `Invalid role: ${o}` }, { status: 400 });
|
|
334
376
|
} catch (e) {
|
|
335
|
-
return console.error("Error saving message:",
|
|
377
|
+
return console.error("Error saving message:", k(e)), Response.json({ message: "Failed to save message" }, { status: 500 });
|
|
336
378
|
}
|
|
337
379
|
} };
|
|
338
380
|
}
|
|
339
381
|
//#endregion
|
|
340
382
|
//#region src/api/handlers/providers.ts
|
|
341
|
-
function
|
|
383
|
+
function j(e) {
|
|
342
384
|
return {
|
|
343
385
|
GET: async (n) => {
|
|
344
386
|
try {
|
|
@@ -368,7 +410,7 @@ function A(e) {
|
|
|
368
410
|
}
|
|
369
411
|
};
|
|
370
412
|
}
|
|
371
|
-
function
|
|
413
|
+
function M() {
|
|
372
414
|
return {
|
|
373
415
|
DELETE: async (e, { params: n }) => {
|
|
374
416
|
try {
|
|
@@ -390,7 +432,7 @@ function j() {
|
|
|
390
432
|
}
|
|
391
433
|
};
|
|
392
434
|
}
|
|
393
|
-
function
|
|
435
|
+
function N() {
|
|
394
436
|
return {
|
|
395
437
|
POST: async (e, { params: n }) => {
|
|
396
438
|
try {
|
|
@@ -412,7 +454,7 @@ function M() {
|
|
|
412
454
|
}
|
|
413
455
|
//#endregion
|
|
414
456
|
//#region src/api/handlers/mcpservers.ts
|
|
415
|
-
function
|
|
457
|
+
function P(e) {
|
|
416
458
|
return {
|
|
417
459
|
GET: async (t) => {
|
|
418
460
|
try {
|
|
@@ -434,7 +476,7 @@ function N(e) {
|
|
|
434
476
|
}
|
|
435
477
|
};
|
|
436
478
|
}
|
|
437
|
-
function
|
|
479
|
+
function F(e) {
|
|
438
480
|
return {
|
|
439
481
|
DELETE: async (t, { params: n }) => {
|
|
440
482
|
try {
|
|
@@ -456,7 +498,7 @@ function P(e) {
|
|
|
456
498
|
}
|
|
457
499
|
};
|
|
458
500
|
}
|
|
459
|
-
function
|
|
501
|
+
function I(e) {
|
|
460
502
|
return { POST: async (t, { params: n }) => {
|
|
461
503
|
try {
|
|
462
504
|
let { enabled: r } = await t.json(), { id: i } = await n;
|
|
@@ -470,7 +512,7 @@ function F(e) {
|
|
|
470
512
|
}
|
|
471
513
|
//#endregion
|
|
472
514
|
//#region src/api/handlers/search.ts
|
|
473
|
-
var
|
|
515
|
+
var L = {
|
|
474
516
|
tech: {
|
|
475
517
|
query: [
|
|
476
518
|
"technology news",
|
|
@@ -536,7 +578,7 @@ var I = {
|
|
|
536
578
|
]
|
|
537
579
|
}
|
|
538
580
|
};
|
|
539
|
-
function
|
|
581
|
+
function R(e = {}) {
|
|
540
582
|
let t = e.searxngDomain ?? "https://search.qwksearch.com";
|
|
541
583
|
return { GET: async (e) => {
|
|
542
584
|
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, l = n.get("publicInstances") === "true";
|
|
@@ -583,10 +625,10 @@ function L(e = {}) {
|
|
|
583
625
|
}
|
|
584
626
|
} };
|
|
585
627
|
}
|
|
586
|
-
function
|
|
628
|
+
function z() {
|
|
587
629
|
return { GET: async (e) => {
|
|
588
630
|
try {
|
|
589
|
-
let t = new URL(e.url).searchParams, n = t.get("mode") || "normal", r =
|
|
631
|
+
let t = new URL(e.url).searchParams, n = t.get("mode") || "normal", r = L[t.get("topic") || "tech"], i = [];
|
|
590
632
|
if (n === "normal") {
|
|
591
633
|
let e = /* @__PURE__ */ new Set();
|
|
592
634
|
i = (await Promise.all(r.links.flatMap((e) => r.query.map(async (t) => (await d(`site:${e} ${t}`, {
|
|
@@ -610,17 +652,17 @@ function R() {
|
|
|
610
652
|
}
|
|
611
653
|
//#endregion
|
|
612
654
|
//#region src/api/handlers/autocomplete.ts
|
|
613
|
-
var
|
|
655
|
+
var B = [
|
|
614
656
|
"google",
|
|
615
657
|
"duckduckgo",
|
|
616
658
|
"wikipedia"
|
|
617
|
-
],
|
|
659
|
+
], V = 3, te = 3, H = Object.entries(g).map(([e, t]) => ({
|
|
618
660
|
domain: e,
|
|
619
661
|
name: typeof t?.[0] == "string" ? t[0] : "",
|
|
620
662
|
rank: typeof t?.[1] == "number" ? t[1] : 2 ** 53 - 1
|
|
621
|
-
})),
|
|
622
|
-
function
|
|
623
|
-
return
|
|
663
|
+
})), U = null;
|
|
664
|
+
function W() {
|
|
665
|
+
return U ||= new m(H, {
|
|
624
666
|
keys: [{
|
|
625
667
|
name: "name",
|
|
626
668
|
weight: .6
|
|
@@ -632,9 +674,9 @@ function U() {
|
|
|
632
674
|
ignoreLocation: !0,
|
|
633
675
|
includeScore: !0,
|
|
634
676
|
minMatchCharLength: 3
|
|
635
|
-
}),
|
|
677
|
+
}), U;
|
|
636
678
|
}
|
|
637
|
-
function
|
|
679
|
+
function G(e, t, n) {
|
|
638
680
|
return {
|
|
639
681
|
domain: e,
|
|
640
682
|
name: t,
|
|
@@ -642,20 +684,20 @@ function W(e, t, n) {
|
|
|
642
684
|
rank: n
|
|
643
685
|
};
|
|
644
686
|
}
|
|
645
|
-
function
|
|
687
|
+
function K(e) {
|
|
646
688
|
let t = h(e);
|
|
647
689
|
return t.domain && t.isIcann ? t.hostname : null;
|
|
648
690
|
}
|
|
649
|
-
function
|
|
691
|
+
function q(e) {
|
|
650
692
|
let t = e.split(/\s+/).filter(Boolean), n = t[t.length - 1] || "";
|
|
651
693
|
if (n.length < 3) return [];
|
|
652
|
-
let r =
|
|
653
|
-
return i && !r.some((e) => e.domain === i) && r.unshift(
|
|
694
|
+
let r = W().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).map(({ item: e }) => G(e.domain, e.name, e.rank)), i = K(n);
|
|
695
|
+
return i && !r.some((e) => e.domain === i) && r.unshift(G(i, "", 2 ** 53 - 1)), r.slice(0, te);
|
|
654
696
|
}
|
|
655
|
-
async function
|
|
697
|
+
async function J(e, t, n) {
|
|
656
698
|
let r = await p(e, t, n);
|
|
657
699
|
if (r.length > 0) return r;
|
|
658
|
-
let i = t.split(/\s+/).filter(Boolean), a = Math.min(
|
|
700
|
+
let i = t.split(/\s+/).filter(Boolean), a = Math.min(V, i.length - 1);
|
|
659
701
|
for (let r = a; r >= 1; r--) {
|
|
660
702
|
let a = i.slice(-r).join(" "), o = i.slice(0, -r).join(" "), s = await p(e, a, n);
|
|
661
703
|
if (s.length > 0) {
|
|
@@ -669,16 +711,16 @@ async function q(e, t, n) {
|
|
|
669
711
|
}
|
|
670
712
|
return [];
|
|
671
713
|
}
|
|
672
|
-
function
|
|
714
|
+
function Y() {
|
|
673
715
|
return { GET: async (e) => {
|
|
674
716
|
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);
|
|
675
717
|
if (!n) return Response.json({
|
|
676
718
|
suggestions: [],
|
|
677
719
|
domains: []
|
|
678
720
|
});
|
|
679
|
-
let o = i ? i.split(",").map((e) => e.trim()).filter(Boolean) :
|
|
721
|
+
let o = i ? i.split(",").map((e) => e.trim()).filter(Boolean) : B;
|
|
680
722
|
try {
|
|
681
|
-
let e = await
|
|
723
|
+
let e = await J(o, n, r), t = q(n);
|
|
682
724
|
return Response.json({
|
|
683
725
|
suggestions: e.slice(0, a),
|
|
684
726
|
domains: t
|
|
@@ -693,7 +735,7 @@ function J() {
|
|
|
693
735
|
}
|
|
694
736
|
//#endregion
|
|
695
737
|
//#region src/api/handlers/suggestions.ts
|
|
696
|
-
function
|
|
738
|
+
function X() {
|
|
697
739
|
return { POST: async (e) => {
|
|
698
740
|
let n = await e.json(), r = n.chatHistory.filter((e) => e.role === "user" || e.role === "assistant").map((e) => ({
|
|
699
741
|
role: e.role,
|
|
@@ -707,7 +749,7 @@ function Y() {
|
|
|
707
749
|
}
|
|
708
750
|
//#endregion
|
|
709
751
|
//#region src/api/handlers/agents.ts
|
|
710
|
-
function
|
|
752
|
+
function Z(e) {
|
|
711
753
|
return { POST: async (t) => {
|
|
712
754
|
let n;
|
|
713
755
|
try {
|
|
@@ -722,7 +764,7 @@ function X(e) {
|
|
|
722
764
|
}
|
|
723
765
|
//#endregion
|
|
724
766
|
//#region src/api/handlers/rewrite.ts
|
|
725
|
-
function
|
|
767
|
+
function Q(e) {
|
|
726
768
|
return { POST: async (t) => {
|
|
727
769
|
try {
|
|
728
770
|
let { text: n, prompt: r } = await t.json();
|
|
@@ -744,7 +786,7 @@ ${n}`, s = (await e.generateText({
|
|
|
744
786
|
}
|
|
745
787
|
//#endregion
|
|
746
788
|
//#region src/api/handlers/voice.ts
|
|
747
|
-
function
|
|
789
|
+
function ne(e) {
|
|
748
790
|
return { POST: async (t) => {
|
|
749
791
|
let n, r, i;
|
|
750
792
|
try {
|
|
@@ -779,15 +821,15 @@ function Q(e) {
|
|
|
779
821
|
}
|
|
780
822
|
//#endregion
|
|
781
823
|
//#region src/api/handlers/transcript.ts
|
|
782
|
-
function
|
|
824
|
+
function re(e) {
|
|
783
825
|
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";
|
|
784
826
|
}
|
|
785
|
-
function
|
|
827
|
+
function ie(e) {
|
|
786
828
|
return { POST: async (t) => {
|
|
787
829
|
try {
|
|
788
830
|
let n = await t.formData(), r = n.get("file");
|
|
789
831
|
if (!r || !(r instanceof File)) return Response.json({ error: "file is required" }, { status: 400 });
|
|
790
|
-
let i =
|
|
832
|
+
let i = re(n.get("model")), a;
|
|
791
833
|
try {
|
|
792
834
|
a = e.getCloudflareContext().env?.AI;
|
|
793
835
|
} catch {}
|
|
@@ -804,7 +846,7 @@ function re(e) {
|
|
|
804
846
|
}
|
|
805
847
|
//#endregion
|
|
806
848
|
//#region src/api/handlers/test-models.ts
|
|
807
|
-
function
|
|
849
|
+
function ae() {
|
|
808
850
|
return { POST: async (e) => {
|
|
809
851
|
try {
|
|
810
852
|
let { providerType: t, apiKey: n, onlyFree: r = !0 } = await e.json();
|
|
@@ -825,13 +867,13 @@ function ie() {
|
|
|
825
867
|
}
|
|
826
868
|
//#endregion
|
|
827
869
|
//#region src/api/handlers/validate-openrouter.ts
|
|
828
|
-
var
|
|
829
|
-
function
|
|
870
|
+
var oe = 864e5, $ = null;
|
|
871
|
+
function se(e) {
|
|
830
872
|
return {
|
|
831
873
|
GET: async (t) => {
|
|
832
874
|
try {
|
|
833
875
|
let t = Date.now();
|
|
834
|
-
if ($ && t - $.timestamp <
|
|
876
|
+
if ($ && t - $.timestamp < oe) return Response.json({
|
|
835
877
|
...$.result,
|
|
836
878
|
cached: !0,
|
|
837
879
|
cacheAge: t - $.timestamp
|
|
@@ -865,4 +907,4 @@ function oe(e) {
|
|
|
865
907
|
};
|
|
866
908
|
}
|
|
867
909
|
//#endregion
|
|
868
|
-
export {
|
|
910
|
+
export { Z as createAgentsHandler, b as createArticleFollowupsHandler, C as createArticleQAHandler, Y as createAutocompleteHandler, T as createChatByIdHandler, D as createChatTitleHandler, w as createChatsHandler, ee as createChatsSearchHandler, E as createChatsShareHandler, z as createDiscoverHandler, F as createMCPServerByIdHandler, I as createMCPServerToggleHandler, P as createMCPServersHandler, A as createMessagesHandler, x as createPageTipsHandler, M as createProviderByIdHandler, N as createProviderModelsHandler, j as createProvidersHandler, Q as createRewriteHandler, R as createSearchHandler, X as createSuggestionsHandler, ae as createTestModelsHandler, S as createTopicSearchesHandler, ie as createTranscriptHandler, se as createValidateOpenRouterHandler, ne as createVoiceHandler, k 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.
|
|
4
|
+
"version": "0.1.130",
|
|
5
5
|
"author": "vtempest",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -80,13 +80,13 @@
|
|
|
80
80
|
"@radix-ui/react-tooltip": "^1.2.9",
|
|
81
81
|
"@ricky0123/vad-web": "^0.0.30",
|
|
82
82
|
"ai": "^5.0.0",
|
|
83
|
-
"chat-agent-toolkit": "^1.2.
|
|
83
|
+
"chat-agent-toolkit": "^1.2.259",
|
|
84
84
|
"class-variance-authority": "^0.7.1",
|
|
85
85
|
"clsx": "^2.1.1",
|
|
86
|
-
"domain-rank": "^0.1.
|
|
86
|
+
"domain-rank": "^0.1.248",
|
|
87
87
|
"dompurify": "^3.4.9",
|
|
88
88
|
"drizzle-orm": "^0.45.2",
|
|
89
|
-
"extract-webpage": "^1.2.
|
|
89
|
+
"extract-webpage": "^1.2.258",
|
|
90
90
|
"framer-motion": "^12.40.0",
|
|
91
91
|
"fuse.js": "^7.1.0",
|
|
92
92
|
"grab-url": "^1.6.22",
|
|
@@ -96,13 +96,13 @@
|
|
|
96
96
|
"markdown-to-jsx": "^9.8.2",
|
|
97
97
|
"motion": "^12.40.0",
|
|
98
98
|
"quantum-sphere-loading-icon": "^1.0.3",
|
|
99
|
-
"qwksearch-api-client": "^0.9.
|
|
99
|
+
"qwksearch-api-client": "^0.9.205",
|
|
100
100
|
"react-icons": "^5.6.0",
|
|
101
101
|
"react-native-app-buttons": "^0.1.4",
|
|
102
102
|
"react-textarea-autosize": "^8.5.9",
|
|
103
103
|
"trending-news-api": "^0.1.0",
|
|
104
|
-
"use-weather-forecast": "^0.1.
|
|
105
|
-
"search-web-api": "^1.0.
|
|
104
|
+
"use-weather-forecast": "^0.1.75",
|
|
105
|
+
"search-web-api": "^1.0.112",
|
|
106
106
|
"sonner": "^2.0.7",
|
|
107
107
|
"streamdown": "^2.5.0",
|
|
108
108
|
"tailwind-merge": "^3.6.0",
|