research-agent-ui 0.1.233 → 0.1.235

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,5 +1,16 @@
1
1
  /**
2
2
  * @fileoverview Handler that rewrites user-supplied text for clarity/grammar/style via Groq.
3
+ *
4
+ * Answers in one of two shapes, chosen by the request:
5
+ *
6
+ * - `{ rewrittenText }` JSON by default — the original contract, and what
7
+ * every existing caller reads.
8
+ * - a `text/plain` stream when the body sets `stream: true` and the host
9
+ * wired `deps.streamText`. This is what the Reason Editor's writing
10
+ * assistant asks for, so its review panel fills in as the model writes
11
+ * instead of jumping from a spinner to a finished answer.
12
+ *
13
+ * Both run the same prompt against the same model; only the transport differs.
3
14
  */
4
15
  import type { RewriteDeps } from "../types";
5
16
  export declare function createRewriteHandler(deps: RewriteDeps): {
@@ -70,6 +70,14 @@ export interface RewriteDeps extends EnvDeps {
70
70
  generateText: (opts: any) => Promise<{
71
71
  text: string;
72
72
  }>;
73
+ /**
74
+ * Streaming counterpart of `generateText`, used only when the request asks
75
+ * for `stream: true`. Optional so a host that has not wired it keeps serving
76
+ * the JSON contract rather than failing the request.
77
+ */
78
+ streamText?: (opts: any) => {
79
+ textStream: AsyncIterable<string>;
80
+ };
73
81
  createGroq: (opts: {
74
82
  apiKey: string;
75
83
  }) => (modelId: string) => any;
package/dist/api.cjs CHANGED
@@ -33,6 +33,6 @@ User question: ${i}
33
33
 
34
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.
35
35
  Provide clear, concise, and accurate answers based on the article content provided.
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=Number.isFinite(o)&&o>0?o:1,c=n.get(`lang`)||`en-US`,l=n.get(`safesearch`)===`true`,u=n.get(`recency`)||void 0,d=n.get(`publicInstances`)===`true`;if(!r)return Response.json({error:`Query parameter is required`},{status:400});let f=Date.now();try{let e=await(0,a.searchWeb)(r,{category:i,recency:u,safesearch:l,maxRetries:6,privateSearxng:!d&&t,proxy:``,lang:c,page:s});e&&(Array.isArray(e)?e.length>0:e.results&&e.results.length>0)||(e=await(0,a.searchWeb)(r,{category:i,recency:u,safesearch:l,maxRetries:6,privateSearxng:!1,proxy:``,lang:c,page:s}));let n=Date.now()-f;return e?Array.isArray(e)?Response.json({results:e,elapsedTime:n}):Response.json({...e,elapsedTime:n}):Response.json({results:[],suggestions:[],elapsedTime:n})}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(`Search error for q="${r}" cat="${i}" page=${s}: ${t}`,e instanceof Error?e.stack:void 0),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,promptTemplate:t.promptTemplate},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:
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=Number.isFinite(o)&&o>0?o:1,c=n.get(`lang`)||`en-US`,l=n.get(`safesearch`)===`true`,u=n.get(`recency`)||void 0,d=n.get(`publicInstances`)===`true`;if(!r)return Response.json({error:`Query parameter is required`},{status:400});let f=Date.now();try{let e=await(0,a.searchWeb)(r,{category:i,recency:u,safesearch:l,maxRetries:6,privateSearxng:!d&&t,proxy:``,lang:c,page:s});e&&(Array.isArray(e)?e.length>0:e.results&&e.results.length>0)||(e=await(0,a.searchWeb)(r,{category:i,recency:u,safesearch:l,maxRetries:6,privateSearxng:!1,proxy:``,lang:c,page:s}));let n=Date.now()-f;return e?Array.isArray(e)?Response.json({results:e,elapsedTime:n}):Response.json({...e,elapsedTime:n}):Response.json({results:[],suggestions:[],elapsedTime:n})}catch(e){let t=e instanceof Error?e.message:String(e);return console.error(`Search error for q="${r}" cat="${i}" page=${s}: ${t}`,e instanceof Error?e.stack:void 0),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,promptTemplate:t.promptTemplate},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,stream:i}=await t.json();if(!n||typeof n!=`string`)return Response.json({error:`Text is required and must be a string`},{status:400});let a=e.getEnv(`GROQ_API_KEY`);if(!a)return console.error(`GROQ_API_KEY is not configured`),Response.json({error:`AI service is not configured. Please contact the administrator.`},{status:500});let o=e.createGroq({apiKey:a})(`llama-3.3-70b-versatile`),s=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:
37
37
 
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;
38
+ ${n}`;if(i&&e.streamText){let{textStream:t}=e.streamText({model:o,prompt:s,temperature:.7}),n=new ReadableStream({async start(e){let n=new TextEncoder;try{for await(let r of t)e.enqueue(n.encode(r));e.close()}catch(t){console.error(`AI rewrite stream error:`,t),e.error(t)}}});return new Response(n,{headers:{"Content-Type":`text/plain; charset=utf-8`,"Cache-Control":`no-store`,"X-Accel-Buffering":`no`}})}let c=(await e.generateText({model:o,prompt:s,temperature:.7})).text.trim();return Response.json({rewrittenText:c})}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
@@ -769,18 +769,39 @@ function Z(e) {
769
769
  function Q(e) {
770
770
  return { POST: async (t) => {
771
771
  try {
772
- let { text: n, prompt: r } = await t.json();
772
+ let { text: n, prompt: r, stream: i } = await t.json();
773
773
  if (!n || typeof n != "string") return Response.json({ error: "Text is required and must be a string" }, { status: 400 });
774
- let i = e.getEnv("GROQ_API_KEY");
775
- 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 });
776
- 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:
774
+ let a = e.getEnv("GROQ_API_KEY");
775
+ if (!a) return console.error("GROQ_API_KEY is not configured"), Response.json({ error: "AI service is not configured. Please contact the administrator." }, { status: 500 });
776
+ let o = e.createGroq({ apiKey: a })("llama-3.3-70b-versatile"), s = 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:
777
777
 
778
- ${n}`, s = (await e.generateText({
779
- model: a,
780
- prompt: o,
778
+ ${n}`;
779
+ if (i && e.streamText) {
780
+ let { textStream: t } = e.streamText({
781
+ model: o,
782
+ prompt: s,
783
+ temperature: .7
784
+ }), n = new ReadableStream({ async start(e) {
785
+ let n = new TextEncoder();
786
+ try {
787
+ for await (let r of t) e.enqueue(n.encode(r));
788
+ e.close();
789
+ } catch (t) {
790
+ console.error("AI rewrite stream error:", t), e.error(t);
791
+ }
792
+ } });
793
+ return new Response(n, { headers: {
794
+ "Content-Type": "text/plain; charset=utf-8",
795
+ "Cache-Control": "no-store",
796
+ "X-Accel-Buffering": "no"
797
+ } });
798
+ }
799
+ let c = (await e.generateText({
800
+ model: o,
801
+ prompt: s,
781
802
  temperature: .7
782
803
  })).text.trim();
783
- return Response.json({ rewrittenText: s });
804
+ return Response.json({ rewrittenText: c });
784
805
  } catch (e) {
785
806
  return console.error("AI rewrite error:", e), Response.json({ error: "Failed to process AI request. Please try again." }, { status: 500 });
786
807
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "research-agent-ui",
3
3
  "description": "The QwkSearch app UI: conversation window, article reader, search config, file uploads, chat history, and the app shell — exported both with and without the REASON editor and its sidebar",
4
- "version": "0.1.233",
4
+ "version": "0.1.235",
5
5
  "author": "vtempest",
6
6
  "repository": {
7
7
  "type": "git",
@@ -90,13 +90,13 @@
90
90
  "@radix-ui/react-tooltip": "^1.2.16",
91
91
  "@ricky0123/vad-web": "^0.0.30",
92
92
  "ai": "^7.0.94",
93
- "chat-agent-toolkit": "^1.2.364",
93
+ "chat-agent-toolkit": "^1.2.366",
94
94
  "class-variance-authority": "^0.7.1",
95
95
  "clsx": "^2.1.1",
96
- "domain-rank": "^0.1.353",
96
+ "domain-rank": "^0.1.355",
97
97
  "dompurify": "^3.4.15",
98
98
  "drizzle-orm": "^0.45.2",
99
- "extract-webpage": "^1.2.358",
99
+ "extract-webpage": "^1.2.360",
100
100
  "framer-motion": "^13.2.0",
101
101
  "fuse.js": "^7.5.0",
102
102
  "grab-url": "^1.6.22",
@@ -106,21 +106,21 @@
106
106
  "markdown-to-jsx": "^9.10.2",
107
107
  "motion": "^13.2.0",
108
108
  "quantum-sphere-loading-icon": "^1.0.3",
109
- "qwksearch-api-client": "^1.0.36",
109
+ "qwksearch-api-client": "^1.0.38",
110
110
  "react-icons": "^5.7.0",
111
111
  "react-native-app-buttons": "^0.1.4",
112
112
  "react-textarea-autosize": "^8.5.9",
113
- "search-web-api": "^1.0.216",
114
- "shadcn-app-dock": "^0.1.214",
113
+ "search-web-api": "^1.0.218",
114
+ "shadcn-app-dock": "^0.1.216",
115
115
  "shadcn-theme-menu": "^1.1.47",
116
116
  "sonner": "^2.0.8",
117
117
  "streamdown": "^2.6.0",
118
118
  "tailwind-merge": "^3.6.0",
119
119
  "tldts": "^7.4.12",
120
- "trending-news-api": "^0.1.92",
120
+ "trending-news-api": "^0.1.94",
121
121
  "turndown": "^7.2.4",
122
122
  "use-voice-control": "^0.1.95",
123
- "use-weather-forecast": "^0.1.178"
123
+ "use-weather-forecast": "^0.1.180"
124
124
  },
125
125
  "devDependencies": {
126
126
  "@cloudflare/workers-types": "^5.20260908.1",
@@ -139,8 +139,8 @@
139
139
  "next": "^16.3.4",
140
140
  "react": "^19.2.8",
141
141
  "react-dom": "^19.2.8",
142
- "react-reason-editor": "^1.0.166",
143
- "react-reason-editor-sidebar": "^0.1.83",
142
+ "react-reason-editor": "^1.0.168",
143
+ "react-reason-editor-sidebar": "^0.1.85",
144
144
  "storybook": "^10.6.0",
145
145
  "tailwindcss": "^4.3.3",
146
146
  "typescript": "^7.0.2",