dewee-webchat 0.1.1 → 0.2.0

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,13 +1,42 @@
1
- "use strict";(()=>{var z=Object.defineProperty;var K=(i,r,e)=>r in i?z(i,r,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[r]=e;var j=(i,r)=>{for(var e in r)z(i,e,{get:r[e],enumerable:!0})};var l=(i,r,e)=>K(i,typeof r!="symbol"?r+"":r,e);var I={};j(I,{ApiClient:()=>y,ApiError:()=>w,DeweeChatElement:()=>E,defineDeweeChat:()=>H,mount:()=>ne,renderMarkdown:()=>k});var _="x-dewee-gateway-url",P="x-dewee-gateway-token";var w=class extends Error{constructor(e,t,n){super(e);l(this,"status",t);l(this,"code",n)}},A={get(i){try{return localStorage.getItem(i)}catch{return null}},set(i,r){try{localStorage.setItem(i,r)}catch{}},del(i){try{localStorage.removeItem(i)}catch{}}},y=class{constructor(r){l(this,"o",r);l(this,"session",null);l(this,"config",null);l(this,"sessionPromise",null)}url(r,e){let t=this.o.endpoint.replace(/\/+$/,""),n=e?"?"+new URLSearchParams(e).toString():"";return`${t}/${r}${n}`}get storageKey(){return`dewee-webchat:session:${this.o.endpoint}`}headers(r=!1){let e={"content-type":"application/json"};return this.o.gatewayUrl&&this.o.gatewayToken&&(e[_]=this.o.gatewayUrl,e[P]=this.o.gatewayToken),r&&this.session&&(e.authorization=`Bearer ${this.session.token}`),e}async parse(r){let e=await r.json().catch(()=>({}));if(!r.ok)throw new w(e?.error?.message||`HTTP ${r.status}`,r.status,e?.error?.code);return e}async getConfig(r=!1){return this.config&&!r?this.config:(this.config=await this.parse(await fetch(this.url("config"),{headers:this.headers()})),this.config)}ensureSession(){if(this.session&&this.session.expiresAt-Date.now()>864e5)return Promise.resolve(this.session);if(!this.session){let r=A.get(this.storageKey);if(r)try{let e=JSON.parse(r);if(e.expiresAt-Date.now()>864e5)return Promise.resolve(this.session=e);this.session=e}catch{}}return this.sessionPromise??(this.sessionPromise=this.createSession().finally(()=>this.sessionPromise=null))}async createSession(){let r=await this.getConfig(),e={};if(this.session?.token&&(e.token=this.session.token),r.turnstileSiteKey){if(!this.o.turnstile)throw new w("Verification is required but no Turnstile handler is set",403,"turnstile_required");e.turnstileToken=await this.o.turnstile(r.turnstileSiteKey)}let t=await this.parse(await fetch(this.url("session"),{method:"POST",headers:this.headers(),body:JSON.stringify(e)}));return this.session=t,A.set(this.storageKey,JSON.stringify(t)),t}forgetSession(){this.session=null,A.del(this.storageKey)}async history(r,e){await this.ensureSession();let t=await fetch(this.url("history",{agent:r,conversationId:e}),{headers:this.headers(!0)});return(await this.parse(t)).messages}async chat(r,e,t){await this.ensureSession();let n=await fetch(this.url("chat"),{method:"POST",headers:this.headers(!0),body:JSON.stringify(r),signal:t});n.status===401&&(this.forgetSession(),await this.ensureSession(),n=await fetch(this.url("chat"),{method:"POST",headers:this.headers(!0),body:JSON.stringify(r),signal:t})),(!n.ok||!n.body)&&await this.parse(n);let s=n.body.pipeThrough(new TextDecoderStream).getReader(),o="";for(;;){let{done:a,value:g}=await s.read();if(a)break;o+=g;let p;for(;(p=o.indexOf(`
1
+ "use strict";(()=>{var U=Object.defineProperty;var wt=(i,s,t)=>s in i?U(i,s,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[s]=t;var xt=(i,s)=>{for(var t in s)U(i,t,{get:s[t],enumerable:!0})};var h=(i,s,t)=>wt(i,typeof s!="symbol"?s+"":s,t);var K={};xt(K,{ApiClient:()=>S,ApiError:()=>v,DeweeChatElement:()=>L,defineDeweeChat:()=>V,mount:()=>Ot,renderMarkdown:()=>E});var F="dewee-action",G="dewee-action-result",I={maxCalls:8,maxBlockBytes:8192},bt=/^[A-Za-z0-9_.:-]{1,64}$/,yt=/^\s{0,3}```\s*$/,W=i=>new RegExp("^\\s{0,3}```"+i.replace(/[.-]/g,"\\$&")+"\\s*$"),Y=W(F),Z=W(G);function _(i,s){let t=[];for(let e=0;e<i.length;e++){if(!s.test(i[e]))continue;let n=e,r=[],o=!1;for(e++;e<i.length;e++){if(yt.test(i[e])){o=!0;break}r.push(i[e])}t.push({start:n,end:Math.min(e,i.length-1),body:r,closed:o})}return t}var Q=(i,s)=>{let t=new Set;for(let e of s)for(let n=e.start;n<=e.end;n++)t.add(n);return i.filter((e,n)=>!t.has(n)).join(`
2
+ `).replace(/\n{3,}/g,`
2
3
 
3
- `))>=0;){let f=o.slice(0,p);o=o.slice(p+2);let h=f.split(`
4
+ `).trim()};function H(i){let s=i.replace(/\r\n?/g,`
5
+ `).split(`
6
+ `),t=_(s,Y),e=[],n=new Set;return t.forEach((r,o)=>{let a=`call-${o+1}`,l=r.body.join(`
7
+ `),c=(m,w=a,x="")=>e.push({ok:!1,id:w,name:x,error:m});if(o>=I.maxCalls)return c(`Too many action calls in one reply (max ${I.maxCalls})`);if(!r.closed)return c("Unclosed dewee-action block");if(new TextEncoder().encode(l).length>I.maxBlockBytes)return c(`Action block exceeds ${I.maxBlockBytes} bytes`);let g;try{g=JSON.parse(l)}catch{return c("Action block is not valid JSON")}if(typeof g!="object"||g===null||Array.isArray(g))return c("Action block must be a JSON object");let p=typeof g.id=="string"&&bt.test(g.id)?g.id:a,d=typeof g.name=="string"?g.name.slice(0,64):"";if(n.has(p))return c(`Duplicate action call id "${p}"`,`${p}-${o+1}`,d);if(n.add(p),!d)return c("Action name is required",p);let u=g.args??{};if(typeof u!="object"||u===null||Array.isArray(u))return c("args must be a JSON object",p,d);e.push({ok:!0,id:p,name:d,args:u})}),{text:t.length?Q(s,t):i,calls:e}}function X(i){if(!i.includes("```"+F))return i;let s=i.replace(/\r\n?/g,`
8
+ `).split(`
9
+ `);return Q(s,_(s,Y))}function B(i){return Z.test(i.trimStart().split(`
10
+ `,1)[0]??"")}function tt(i){let s=i.replace(/\r\n?/g,`
11
+ `).split(`
12
+ `),t=[];for(let e of _(s,Z))try{let n=JSON.parse(e.body.join(`
13
+ `));n&&typeof n.id=="string"&&["ok","denied","error"].includes(n.status)&&t.push(n)}catch{}return t}var P=i=>"```"+G+`
14
+ `+JSON.stringify(i)+"\n```";function et(i,s=4e3){let t=Math.max(64,Math.floor((s-16)/Math.max(1,i.length)));return i.map(n=>{let r={...n,result:O(n.result)};if(r.result===void 0&&delete r.result,P(r).length<=t)return P(r);let o=JSON.stringify(r.result??null),a=t-P({...r,result:{truncated:!0,preview:""}}).length-8,l=P({...r,result:{truncated:!0,preview:o.slice(0,Math.max(0,a))}});return l.length<=t?l:P({id:n.id,name:n.name.slice(0,64),status:n.status,result:{truncated:!0}})}).join(`
15
+
16
+ `).slice(0,s)}function O(i){if(i!==void 0)try{let s=JSON.stringify(i);return s===void 0?null:JSON.parse(s)}catch{return"[unserializable result]"}}var z=i=>i===null?"null":Array.isArray(i)?"array":typeof i=="number"?Number.isInteger(i)?"integer":"number":typeof i,vt=(i,s)=>{let t=z(i);return t===s||s==="number"&&t==="integer"};function R(i,s,t="args",e=0){if(!s||typeof s!="object")return null;if(e>32)return`${t}: schema is nested too deeply`;let n=s;if(n.type!==void 0){let r=Array.isArray(n.type)?n.type:[n.type];if(!r.some(o=>vt(i,o)))return`${t}: expected ${r.join(" or ")}, got ${z(i)}`}if(Array.isArray(n.enum)&&!n.enum.some(r=>nt(r,i)))return`${t}: must be one of ${n.enum.map(r=>JSON.stringify(r)).join(", ")}`;if("const"in n&&!nt(n.const,i))return`${t}: must equal ${JSON.stringify(n.const)}`;if(typeof i=="string"){if(typeof n.minLength=="number"&&i.length<n.minLength)return`${t}: shorter than ${n.minLength} characters`;if(typeof n.maxLength=="number"&&i.length>n.maxLength)return`${t}: longer than ${n.maxLength} characters`;if(typeof n.pattern=="string"){let r=null;try{r=new RegExp(n.pattern,"u")}catch{return`${t}: schema pattern is invalid`}if(!r.test(i))return`${t}: does not match ${n.pattern}`}}if(typeof i=="number"){if(typeof n.minimum=="number"&&i<n.minimum)return`${t}: must be >= ${n.minimum}`;if(typeof n.maximum=="number"&&i>n.maximum)return`${t}: must be <= ${n.maximum}`}if(Array.isArray(i)){if(typeof n.minItems=="number"&&i.length<n.minItems)return`${t}: needs at least ${n.minItems} items`;if(typeof n.maxItems=="number"&&i.length>n.maxItems)return`${t}: allows at most ${n.maxItems} items`;if(n.items&&typeof n.items=="object")for(let r=0;r<i.length;r++){let o=R(i[r],n.items,`${t}[${r}]`,e+1);if(o)return o}}if(z(i)==="object"){let r=i,o=n.properties&&typeof n.properties=="object"?n.properties:{};for(let a of Array.isArray(n.required)?n.required:[])if(!(a in r))return`${t}.${a}: is required`;for(let[a,l]of Object.entries(r))if(Object.prototype.hasOwnProperty.call(o,a)){let c=R(l,o[a],`${t}.${a}`,e+1);if(c)return c}else if(n.additionalProperties===!1)return`${t}.${a}: is not allowed`}return null}function nt(i,s){return JSON.stringify(i)===JSON.stringify(s)}var st=/^[a-z][a-z0-9_.-]{0,63}$/,D=["read","navigate","mutate","destructive"],C={maxActions:32,maxDescription:1e3,maxParametersBytes:4096,maxManifestBytes:16384,maxPageContextBytes:4096},kt="[[dewee-page v1]]",it="[[/dewee-page]]";function j(i){if(!i.startsWith(kt))return i;let s=i.indexOf(`
17
+ `+it);return s<0?i:i.slice(s+it.length+1).replace(/^\n+/,"")}var Ct=i=>i==="mutate"||i==="destructive",$=class{constructor(){h(this,"map",new Map)}get size(){return this.map.size}get(s){return this.map.get(s)}names(){return[...this.map.keys()]}register(s){let t=Array.isArray(s)?s:[s];for(let e of t)At(e);if(new Set([...this.map.keys(),...t.map(e=>e.name)]).size>C.maxActions)throw new TypeError(`dewee-webchat: at most ${C.maxActions} page actions`);for(let e of t)this.map.set(e.name,e)}unregister(s){return this.map.delete(s)}manifest(){return[...this.map.values()].map(s=>({name:s.name,description:s.description,sensitivity:s.sensitivity,parameters:s.parameters??{type:"object",properties:{}}}))}};function At(i){let s=t=>{throw new TypeError(`dewee-webchat: invalid page action ${JSON.stringify(i?.name)}: ${t}`)};(!i||typeof i!="object")&&s("not an object"),(typeof i.name!="string"||!st.test(i.name))&&s("name must match ^[a-z][a-z0-9_.-]{0,63}$"),(typeof i.description!="string"||i.description.length>C.maxDescription)&&s(`description must be a string up to ${C.maxDescription} chars`),D.includes(i.sensitivity)||s(`sensitivity must be one of ${D.join(", ")}`),typeof i.handler!="function"&&s("handler must be a function"),i.parameters!==void 0&&(typeof i.parameters!="object"||i.parameters===null||Array.isArray(i.parameters))&&s("parameters must be a JSON Schema object")}async function ot(i,s){let t=l=>(s.onStatus?.("error"),{id:i.id,name:i.name,status:"error",error:l});if(!i.ok)return t(i.error);if(s.signal.aborted)return t("Cancelled");let e=s.registry.get(i.name);if(!e)return t(`Unknown action "${i.name}". Available: ${s.registry.names().join(", ")||"none"}`);let n=R(i.args,e.parameters??{type:"object"});if(n)return t(`Invalid arguments: ${n}`);if(Ct(e.sensitivity)){s.onStatus?.("awaiting-confirmation");let{handler:l,...c}=e,g=!1;try{g=await rt(Promise.resolve(s.confirm({...c,callId:i.id},i.args)),s.signal)===!0}catch{g=!1}if(!g||s.signal.aborted)return s.onStatus?.("denied"),{id:i.id,name:i.name,status:"denied",error:"The user declined this action."}}s.onStatus?.("running");let r=new AbortController,o=()=>r.abort();s.signal.addEventListener("abort",o,{once:!0});let a=setTimeout(o,s.timeoutMs??3e4);try{let l=await rt(Promise.resolve().then(()=>e.handler(i.args,{callId:i.id,conversationId:s.conversationId,agent:s.agent,signal:r.signal})),r.signal);return s.onStatus?.("done"),{id:i.id,name:i.name,status:"ok",result:O(l)??null}}catch(l){return t(r.signal.aborted?s.signal.aborted?"Cancelled":"Timed out":String(l?.message??l).slice(0,500)||"Action failed")}finally{clearTimeout(a),s.signal.removeEventListener("abort",o)}}function rt(i,s){return s.aborted?Promise.reject(new Error("aborted")):new Promise((t,e)=>{let n=()=>e(new Error("aborted"));s.addEventListener("abort",n,{once:!0}),i.then(t,e).finally(()=>s.removeEventListener("abort",n))})}var at="x-dewee-gateway-url",lt="x-dewee-gateway-token";var v=class extends Error{constructor(t,e,n){super(t);h(this,"status",e);h(this,"code",n)}},J={get(i){try{return localStorage.getItem(i)}catch{return null}},set(i,s){try{localStorage.setItem(i,s)}catch{}},del(i){try{localStorage.removeItem(i)}catch{}}},S=class{constructor(s){h(this,"o",s);h(this,"session",null);h(this,"config",null);h(this,"sessionPromise",null)}url(s,t){let e=this.o.endpoint.replace(/\/+$/,""),n=t?"?"+new URLSearchParams(t).toString():"";return`${e}/${s}${n}`}get storageKey(){return`dewee-webchat:session:${this.o.endpoint}`}headers(s=!1){let t={"content-type":"application/json"};return this.o.gatewayUrl&&this.o.gatewayToken&&(t[at]=this.o.gatewayUrl,t[lt]=this.o.gatewayToken),s&&this.session&&(t.authorization=`Bearer ${this.session.token}`),t}async parse(s){let t=await s.json().catch(()=>({}));if(!s.ok)throw new v(t?.error?.message||`HTTP ${s.status}`,s.status,t?.error?.code);return t}async getConfig(s=!1){return this.config&&!s?this.config:(this.config=await this.parse(await fetch(this.url("config"),{headers:this.headers()})),this.config)}ensureSession(){if(this.session&&this.session.expiresAt-Date.now()>864e5)return Promise.resolve(this.session);if(!this.session){let s=J.get(this.storageKey);if(s)try{let t=JSON.parse(s);if(t.expiresAt-Date.now()>864e5)return Promise.resolve(this.session=t);this.session=t}catch{}}return this.sessionPromise??(this.sessionPromise=this.createSession().finally(()=>this.sessionPromise=null))}async createSession(){let s=await this.getConfig(),t={};if(this.session?.token&&(t.token=this.session.token),s.turnstileSiteKey){if(!this.o.turnstile)throw new v("Verification is required but no Turnstile handler is set",403,"turnstile_required");t.turnstileToken=await this.o.turnstile(s.turnstileSiteKey)}let e=await this.parse(await fetch(this.url("session"),{method:"POST",headers:this.headers(),body:JSON.stringify(t)}));return this.session=e,J.set(this.storageKey,JSON.stringify(e)),e}forgetSession(){this.session=null,J.del(this.storageKey)}async history(s,t){await this.ensureSession();let e=await fetch(this.url("history",{agent:s,conversationId:t}),{headers:this.headers(!0)});return(await this.parse(e)).messages}async chat(s,t,e){await this.ensureSession();let n=await fetch(this.url("chat"),{method:"POST",headers:this.headers(!0),body:JSON.stringify(s),signal:e});n.status===401&&(this.forgetSession(),await this.ensureSession(),n=await fetch(this.url("chat"),{method:"POST",headers:this.headers(!0),body:JSON.stringify(s),signal:e})),(!n.ok||!n.body)&&await this.parse(n);let r=n.body.pipeThrough(new TextDecoderStream).getReader(),o="";for(;;){let{done:a,value:l}=await r.read();if(a)break;o+=l;let c;for(;(c=o.indexOf(`
18
+
19
+ `))>=0;){let g=o.slice(0,c);o=o.slice(c+2);let p=g.split(`
4
20
  `).filter(d=>d.startsWith("data:")).map(d=>d.slice(5).trimStart()).join(`
5
- `);if(h)try{e(JSON.parse(h))}catch{}}}}};var U={title:"Assistant",greeting:"Hi there \u{1F44B}",greetingBody:"Ask me anything. I can look things up and use tools to help you.",placeholder:"Type a message\u2026",send:"Send",stop:"Stop",newChat:"New conversation",close:"Close chat",open:"Open chat",thinking:"Thinking\u2026",thoughtFor:i=>`Thought for ${i}s`,reasoning:"Reasoning",toolRunning:"running",toolDone:"done",toolError:"error",args:"Arguments",result:"Result",online:"Online",poweredBy:"Powered by",errorGeneric:"Something went wrong. Please try again.",stopped:"Stopped."},F={title:"Tr\u1EE3 l\xFD",greeting:"Xin ch\xE0o \u{1F44B}",greetingBody:"B\u1EA1n c\u1EA7n h\u1ECFi g\xEC c\u1EE9 nh\u1EAFn nh\xE9. M\xECnh c\xF3 th\u1EC3 tra c\u1EE9u v\xE0 d\xF9ng c\xF4ng c\u1EE5 \u0111\u1EC3 h\u1ED7 tr\u1EE3 b\u1EA1n.",placeholder:"Nh\u1EADp tin nh\u1EAFn\u2026",send:"G\u1EEDi",stop:"D\u1EEBng",newChat:"Cu\u1ED9c tr\xF2 chuy\u1EC7n m\u1EDBi",close:"\u0110\xF3ng khung chat",open:"M\u1EDF khung chat",thinking:"\u0110ang suy ngh\u0129\u2026",thoughtFor:i=>`\u0110\xE3 suy ngh\u0129 ${i} gi\xE2y`,reasoning:"Suy lu\u1EADn",toolRunning:"\u0111ang ch\u1EA1y",toolDone:"xong",toolError:"l\u1ED7i",args:"Tham s\u1ED1",result:"K\u1EBFt qu\u1EA3",online:"\u0110ang tr\u1EF1c tuy\u1EBFn",poweredBy:"V\u1EADn h\xE0nh b\u1EDFi",errorGeneric:"C\xF3 l\u1ED7i x\u1EA3y ra. B\u1EA1n th\u1EED l\u1EA1i gi\xFAp m\xECnh nh\xE9.",stopped:"\u0110\xE3 d\u1EEBng."};function L(i){return(i||(typeof document<"u"?document.documentElement.lang:"")||(typeof navigator<"u"?navigator.language:"")||"en").toLowerCase().startsWith("vi")?F:U}var m={chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8.5 8.5 0 0 1-12.4 7.6L3 21l1.4-5.1A8.5 8.5 0 1 1 21 12Z"/><path d="M8.5 11h.01M12 11h.01M15.5 11h.01"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>',down:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>',newChat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"/><path d="M16.4 3.6a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4Z"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>',stop:'<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2.5"/></svg>',brain:'<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24A2.5 2.5 0 0 1 9.5 2Z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24A2.5 2.5 0 0 0 14.5 2Z"/></svg>',tool:'<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76Z"/></svg>'};function c(i,r,e){let t=i.createElement(r);return e&&(t.className=e),t}function J(i){let r=i.trim();return/^(https?:|mailto:|tel:)/i.test(r)||/^[/#?]/.test(r)&&!r.startsWith("//")?r:null}var W=/(`+)([\s\S]*?[^`])\1(?!`)|\*\*([^*]+?)\*\*|__([^_]+?)__|~~([^~]+?)~~|\*([^*\s][^*]*?)\*|(?<![\w])_([^_\s][^_]*?)_(?![\w])|\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)|(https?:\/\/[^\s<>()]+[^\s<>().,;:!?'"])/;function b(i,r,e){let t=new RegExp(W.source,"g"),n=0;for(let s;s=t.exec(r);)if(s.index>n&&e.appendChild(i.createTextNode(r.slice(n,s.index))),n=s.index+s[0].length,s[2]!==void 0){let o=c(i,"code");o.textContent=s[2],e.appendChild(o)}else if(s[3]!==void 0||s[4]!==void 0){let o=c(i,"strong");b(i,s[3]??s[4],o),e.appendChild(o)}else if(s[5]!==void 0){let o=c(i,"del");b(i,s[5],o),e.appendChild(o)}else if(s[6]!==void 0||s[7]!==void 0){let o=c(i,"em");b(i,s[6]??s[7],o),e.appendChild(o)}else if(s[8]!==void 0){let o=J(s[9]);if(o){let a=c(i,"a");a.href=o,a.target="_blank",a.rel="noopener noreferrer nofollow",b(i,s[8],a),e.appendChild(a)}else e.appendChild(i.createTextNode(s[8]))}else if(s[10]!==void 0){let o=c(i,"a");o.href=s[10],o.target="_blank",o.rel="noopener noreferrer nofollow",o.textContent=s[10],e.appendChild(o)}n<r.length&&e.appendChild(i.createTextNode(r.slice(n)))}var B=i=>/^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(i),D=i=>i.trim().replace(/^\||\|$/g,"").split("|").map(r=>r.trim());function k(i,r){let e=i.createDocumentFragment(),t=r.replace(/\r\n?/g,`
21
+ `);if(p)try{t(JSON.parse(p))}catch{}}}}};var St=0;function ct(i,s,t,e,n){let r=`dw-confirm-${++St}`,o=i.getRootNode(),a=o.activeElement,l=document.createElement("div");l.className="confirm-backdrop",l.innerHTML=`
22
+ <div class="confirm" role="alertdialog" aria-modal="true" aria-labelledby="${r}-t" aria-describedby="${r}-d">
23
+ <h3 id="${r}-t"></h3>
24
+ <div id="${r}-d" class="confirm-desc">
25
+ <div class="confirm-action"><code></code><span class="sens"></span></div>
26
+ <p class="confirm-text"></p>
27
+ <p class="confirm-warn" hidden></p>
28
+ </div>
29
+ <pre class="confirm-args"></pre>
30
+ <div class="confirm-buttons">
31
+ <button type="button" class="btn deny"></button>
32
+ <button type="button" class="btn allow"></button>
33
+ </div>
34
+ </div>`;let c=w=>l.querySelector(w);c("h3").textContent=s.confirmTitle,c("code").textContent=t.name;let g=c(".sens");if(g.textContent=t.sensitivity,g.dataset.level=t.sensitivity,c(".confirm-text").textContent=t.description,t.sensitivity==="destructive"){let w=c(".confirm-warn");w.hidden=!1,w.textContent=s.confirmDestructive}let p=JSON.stringify(e,null,2),d=c(".confirm-args");p&&p!=="{}"?d.textContent=p:d.remove();let u=c(".deny"),m=c(".allow");return u.textContent=s.deny,m.textContent=s.allow,t.sensitivity==="destructive"&&m.classList.add("danger"),new Promise(w=>{let x=!1,y=A=>{x||(x=!0,n?.removeEventListener("abort",M),l.remove(),a?.focus?.(),w(A))},M=()=>y(!1);if(n?.aborted)return y(!1);n?.addEventListener("abort",M,{once:!0}),u.addEventListener("click",()=>y(!1)),m.addEventListener("click",()=>y(!0)),l.addEventListener("keydown",A=>{A.key==="Escape"?(A.preventDefault(),A.stopPropagation(),y(!1)):A.key==="Tab"&&(A.preventDefault(),(o.activeElement===u?m:u).focus())}),i.appendChild(l),u.focus()})}var Et={title:"Assistant",greeting:"Hi there \u{1F44B}",greetingBody:"Ask me anything. I can look things up and use tools to help you.",placeholder:"Type a message\u2026",send:"Send",stop:"Stop",newChat:"New conversation",close:"Close chat",open:"Open chat",thinking:"Thinking\u2026",thoughtFor:i=>`Thought for ${i}s`,reasoning:"Reasoning",toolRunning:"running",toolDone:"done",toolError:"error",args:"Arguments",result:"Result",online:"Online",poweredBy:"Powered by",errorGeneric:"Something went wrong. Please try again.",stopped:"Stopped.",actionStatus:{pending:"queued","awaiting-confirmation":"needs approval",running:"running",done:"done",denied:"declined",error:"failed"},confirmTitle:"Allow this action?",confirmDestructive:"This can't be undone.",allow:"Allow",deny:"Deny",actionLimit:i=>`Stopped after ${i} automatic action rounds. Send a message to continue.`},Tt={title:"Tr\u1EE3 l\xFD",greeting:"Xin ch\xE0o \u{1F44B}",greetingBody:"B\u1EA1n c\u1EA7n h\u1ECFi g\xEC c\u1EE9 nh\u1EAFn nh\xE9. M\xECnh c\xF3 th\u1EC3 tra c\u1EE9u v\xE0 d\xF9ng c\xF4ng c\u1EE5 \u0111\u1EC3 h\u1ED7 tr\u1EE3 b\u1EA1n.",placeholder:"Nh\u1EADp tin nh\u1EAFn\u2026",send:"G\u1EEDi",stop:"D\u1EEBng",newChat:"Cu\u1ED9c tr\xF2 chuy\u1EC7n m\u1EDBi",close:"\u0110\xF3ng khung chat",open:"M\u1EDF khung chat",thinking:"\u0110ang suy ngh\u0129\u2026",thoughtFor:i=>`\u0110\xE3 suy ngh\u0129 ${i} gi\xE2y`,reasoning:"Suy lu\u1EADn",toolRunning:"\u0111ang ch\u1EA1y",toolDone:"xong",toolError:"l\u1ED7i",args:"Tham s\u1ED1",result:"K\u1EBFt qu\u1EA3",online:"\u0110ang tr\u1EF1c tuy\u1EBFn",poweredBy:"V\u1EADn h\xE0nh b\u1EDFi",errorGeneric:"C\xF3 l\u1ED7i x\u1EA3y ra. B\u1EA1n th\u1EED l\u1EA1i gi\xFAp m\xECnh nh\xE9.",stopped:"\u0110\xE3 d\u1EEBng.",actionStatus:{pending:"ch\u1EDD","awaiting-confirmation":"c\u1EA7n x\xE1c nh\u1EADn",running:"\u0111ang ch\u1EA1y",done:"xong",denied:"\u0111\xE3 t\u1EEB ch\u1ED1i",error:"l\u1ED7i"},confirmTitle:"Cho ph\xE9p thao t\xE1c n\xE0y?",confirmDestructive:"Thao t\xE1c n\xE0y kh\xF4ng th\u1EC3 ho\xE0n t\xE1c.",allow:"Cho ph\xE9p",deny:"T\u1EEB ch\u1ED1i",actionLimit:i=>`\u0110\xE3 d\u1EEBng sau ${i} l\u01B0\u1EE3t thao t\xE1c t\u1EF1 \u0111\u1ED9ng. G\u1EEDi tin nh\u1EAFn \u0111\u1EC3 ti\u1EBFp t\u1EE5c.`};function q(i){return(i||(typeof document<"u"?document.documentElement.lang:"")||(typeof navigator<"u"?navigator.language:"")||"en").toLowerCase().startsWith("vi")?Tt:Et}var b={action:'<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z"/></svg>',chat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 12a8.5 8.5 0 0 1-12.4 7.6L3 21l1.4-5.1A8.5 8.5 0 1 1 21 12Z"/><path d="M8.5 11h.01M12 11h.01M15.5 11h.01"/></svg>',close:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg>',down:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m6 9 6 6 6-6"/></svg>',newChat:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 20h9"/><path d="M16.4 3.6a2.1 2.1 0 1 1 3 3L7 19l-4 1 1-4Z"/></svg>',send:'<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 19V5M5 12l7-7 7 7"/></svg>',stop:'<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><rect x="6" y="6" width="12" height="12" rx="2.5"/></svg>',brain:'<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M9.5 2A2.5 2.5 0 0 1 12 4.5v15a2.5 2.5 0 0 1-4.96.44 2.5 2.5 0 0 1-2.96-3.08 3 3 0 0 1-.34-5.58 2.5 2.5 0 0 1 1.32-4.24A2.5 2.5 0 0 1 9.5 2Z"/><path d="M14.5 2A2.5 2.5 0 0 0 12 4.5v15a2.5 2.5 0 0 0 4.96.44 2.5 2.5 0 0 0 2.96-3.08 3 3 0 0 0 .34-5.58 2.5 2.5 0 0 0-1.32-4.24A2.5 2.5 0 0 0 14.5 2Z"/></svg>',tool:'<svg class="ic" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76Z"/></svg>'};function f(i,s,t){let e=i.createElement(s);return t&&(e.className=t),e}function Mt(i){let s=i.trim();return/^(https?:|mailto:|tel:)/i.test(s)||/^[/#?]/.test(s)&&!s.startsWith("//")?s:null}var Pt=/(`+)([\s\S]*?[^`])\1(?!`)|\*\*([^*]+?)\*\*|__([^_]+?)__|~~([^~]+?)~~|\*([^*\s][^*]*?)\*|(?<![\w])_([^_\s][^_]*?)_(?![\w])|\[([^\]]+)\]\(([^)\s]+)(?:\s+"[^"]*")?\)|(https?:\/\/[^\s<>()]+[^\s<>().,;:!?'"])/;function k(i,s,t){let e=new RegExp(Pt.source,"g"),n=0;for(let r;r=e.exec(s);)if(r.index>n&&t.appendChild(i.createTextNode(s.slice(n,r.index))),n=r.index+r[0].length,r[2]!==void 0){let o=f(i,"code");o.textContent=r[2],t.appendChild(o)}else if(r[3]!==void 0||r[4]!==void 0){let o=f(i,"strong");k(i,r[3]??r[4],o),t.appendChild(o)}else if(r[5]!==void 0){let o=f(i,"del");k(i,r[5],o),t.appendChild(o)}else if(r[6]!==void 0||r[7]!==void 0){let o=f(i,"em");k(i,r[6]??r[7],o),t.appendChild(o)}else if(r[8]!==void 0){let o=Mt(r[9]);if(o){let a=f(i,"a");a.href=o,a.target="_blank",a.rel="noopener noreferrer nofollow",k(i,r[8],a),t.appendChild(a)}else t.appendChild(i.createTextNode(r[8]))}else if(r[10]!==void 0){let o=f(i,"a");o.href=r[10],o.target="_blank",o.rel="noopener noreferrer nofollow",o.textContent=r[10],t.appendChild(o)}n<s.length&&t.appendChild(i.createTextNode(s.slice(n)))}var dt=i=>/^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(i),gt=i=>i.trim().replace(/^\||\|$/g,"").split("|").map(s=>s.trim());function E(i,s){let t=i.createDocumentFragment(),e=s.replace(/\r\n?/g,`
6
35
  `).split(`
7
- `),n=0;for(;n<t.length;){let s=t[n];if(!s.trim()){n++;continue}let o=s.match(/^\s*(```+|~~~+)\s*([\w+-]*)/);if(o){let h=[];for(n++;n<t.length&&!t[n].trim().startsWith(o[1]);)h.push(t[n++]);n++;let d=c(i,"pre"),u=c(i,"code");o[2]&&(u.dataset.lang=o[2]),u.textContent=h.join(`
8
- `),d.appendChild(u),e.appendChild(d);continue}let a=s.match(/^(#{1,6})\s+(.*)$/);if(a){let h=`h${Math.min(6,a[1].length+2)}`,d=c(i,h);b(i,a[2],d),e.appendChild(d),n++;continue}if(/^\s*([-*_])(\s*\1){2,}\s*$/.test(s)){e.appendChild(c(i,"hr")),n++;continue}if(s.includes("|")&&n+1<t.length&&B(t[n+1])){let h=c(i,"div","table"),d=c(i,"table"),u=c(i,"thead"),v=c(i,"tr");for(let x of D(s)){let T=c(i,"th");b(i,x,T),v.appendChild(T)}u.appendChild(v),d.appendChild(u);let C=c(i,"tbody");for(n+=2;n<t.length&&t[n].includes("|")&&t[n].trim();){let x=c(i,"tr");for(let T of D(t[n])){let R=c(i,"td");b(i,T,R),x.appendChild(R)}C.appendChild(x),n++}d.appendChild(C),h.appendChild(d),e.appendChild(h);continue}if(/^\s*>/.test(s)){let h=[];for(;n<t.length&&/^\s*>/.test(t[n]);)h.push(t[n++].replace(/^\s*>\s?/,""));let d=c(i,"blockquote");d.appendChild(k(i,h.join(`
9
- `))),e.appendChild(d);continue}let g=s.match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);if(g){let h=/\d/.test(g[2]),d=c(i,h?"ol":"ul");h&&parseInt(g[2],10)!==1&&d.setAttribute("start",String(parseInt(g[2],10)));let u=g[1].length;for(;n<t.length;){let v=t[n].match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);if(!v||v[1].length<u||/\d/.test(v[2])!==h)break;if(v[1].length>u){let x=[];for(;n<t.length&&/^\s+/.test(t[n])&&t[n].match(/^(\s*)/)[1].length>u;)x.push(t[n++].slice(u+2));d.lastElementChild?.appendChild(k(i,x.join(`
10
- `)));continue}let C=c(i,"li");b(i,v[3],C),d.appendChild(C),n++}e.appendChild(d);continue}let p=[];for(;n<t.length&&t[n].trim()&&!/^\s*(```|~~~|#{1,6}\s|>|([-*+]|\d+[.)])\s)/.test(t[n])&&!(t[n].includes("|")&&n+1<t.length&&B(t[n+1]));)p.push(t[n++]);p.length||p.push(t[n++]);let f=c(i,"p");p.forEach((h,d)=>{d&&f.appendChild(c(i,"br")),b(i,h,f)}),e.appendChild(f)}return e}var N=`
36
+ `),n=0;for(;n<e.length;){let r=e[n];if(!r.trim()){n++;continue}let o=r.match(/^\s*(```+|~~~+)\s*([\w+-]*)/);if(o){let p=[];for(n++;n<e.length&&!e[n].trim().startsWith(o[1]);)p.push(e[n++]);n++;let d=f(i,"pre"),u=f(i,"code");o[2]&&(u.dataset.lang=o[2]),u.textContent=p.join(`
37
+ `),d.appendChild(u),t.appendChild(d);continue}let a=r.match(/^(#{1,6})\s+(.*)$/);if(a){let p=`h${Math.min(6,a[1].length+2)}`,d=f(i,p);k(i,a[2],d),t.appendChild(d),n++;continue}if(/^\s*([-*_])(\s*\1){2,}\s*$/.test(r)){t.appendChild(f(i,"hr")),n++;continue}if(r.includes("|")&&n+1<e.length&&dt(e[n+1])){let p=f(i,"div","table"),d=f(i,"table"),u=f(i,"thead"),m=f(i,"tr");for(let x of gt(r)){let y=f(i,"th");k(i,x,y),m.appendChild(y)}u.appendChild(m),d.appendChild(u);let w=f(i,"tbody");for(n+=2;n<e.length&&e[n].includes("|")&&e[n].trim();){let x=f(i,"tr");for(let y of gt(e[n])){let M=f(i,"td");k(i,y,M),x.appendChild(M)}w.appendChild(x),n++}d.appendChild(w),p.appendChild(d),t.appendChild(p);continue}if(/^\s*>/.test(r)){let p=[];for(;n<e.length&&/^\s*>/.test(e[n]);)p.push(e[n++].replace(/^\s*>\s?/,""));let d=f(i,"blockquote");d.appendChild(E(i,p.join(`
38
+ `))),t.appendChild(d);continue}let l=r.match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);if(l){let p=/\d/.test(l[2]),d=f(i,p?"ol":"ul");p&&parseInt(l[2],10)!==1&&d.setAttribute("start",String(parseInt(l[2],10)));let u=l[1].length;for(;n<e.length;){let m=e[n].match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);if(!m||m[1].length<u||/\d/.test(m[2])!==p)break;if(m[1].length>u){let x=[];for(;n<e.length&&/^\s+/.test(e[n])&&e[n].match(/^(\s*)/)[1].length>u;)x.push(e[n++].slice(u+2));d.lastElementChild?.appendChild(E(i,x.join(`
39
+ `)));continue}let w=f(i,"li");k(i,m[3],w),d.appendChild(w),n++}t.appendChild(d);continue}let c=[];for(;n<e.length&&e[n].trim()&&!/^\s*(```|~~~|#{1,6}\s|>|([-*+]|\d+[.)])\s)/.test(e[n])&&!(e[n].includes("|")&&n+1<e.length&&dt(e[n+1]));)c.push(e[n++]);c.length||c.push(e[n++]);let g=f(i,"p");c.forEach((p,d)=>{d&&g.appendChild(f(i,"br")),k(i,p,g)}),t.appendChild(g)}return t}var pt=`
11
40
  :host {
12
41
  --dw-accent: #5446e8;
13
42
  --dw-accent-contrast: #fff;
@@ -37,6 +66,7 @@
37
66
  }
38
67
  * { box-sizing: border-box; }
39
68
  button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; padding: 0; }
69
+ [hidden] { display: none !important; }
40
70
  .sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
41
71
 
42
72
  /* ---------- launcher ---------- */
@@ -202,6 +232,46 @@ details > summary svg.ic { width: 14px; height: 14px; flex: none; }
202
232
  .typing i:nth-child(2) { animation-delay: .15s; } .typing i:nth-child(3) { animation-delay: .3s; }
203
233
  @keyframes bounce { 0%, 60%, 100% { transform: none; opacity: .35; } 30% { transform: translateY(-4px); opacity: 1; } }
204
234
 
235
+ /* page actions */
236
+ .actions { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 8px; }
237
+ .md[hidden] + .actions { margin-top: 0; }
238
+ .action {
239
+ display: inline-flex; align-items: center; gap: 6px; max-width: 100%; padding: 4px 9px 4px 8px; border-radius: 999px;
240
+ border: 1px solid var(--dw-border); background: var(--dw-surface); font-size: 12px; color: var(--dw-muted);
241
+ }
242
+ .action svg.ic { width: 13px; height: 13px; flex: none; color: var(--dw-accent); }
243
+ .action-name { font-family: var(--dw-mono); font-size: 11.5px; color: var(--dw-fg); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
244
+ .action-state { font-size: 11px; flex: none; }
245
+ .action[data-status="done"] .action-state { color: #13a06f; }
246
+ .action[data-status="awaiting-confirmation"] { border-color: color-mix(in srgb, #d98a00 45%, transparent); }
247
+ .action[data-status="awaiting-confirmation"] .action-state { color: #b06f00; }
248
+ .action[data-status="denied"] .action-state, .action[data-status="error"] .action-state { color: #c2334f; }
249
+ .notice { margin: -6px 0 16px; font-size: 12px; color: var(--dw-muted); text-align: center; }
250
+ .confirm-backdrop {
251
+ position: absolute; inset: 0; z-index: 2; display: flex; align-items: flex-end; justify-content: center; padding: 12px;
252
+ background: color-mix(in srgb, var(--dw-fg) 28%, transparent); animation: rise .18s ease both;
253
+ }
254
+ .confirm {
255
+ width: 100%; max-height: 100%; overflow: auto; background: var(--dw-bg); color: var(--dw-fg);
256
+ border: 1px solid var(--dw-border); border-radius: 16px; padding: 16px; box-shadow: var(--dw-shadow);
257
+ }
258
+ .confirm h3 { margin: 0 0 10px; font-size: 15px; font-weight: 650; }
259
+ .confirm-action { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
260
+ .confirm-action code { font-family: var(--dw-mono); font-size: 12.5px; background: var(--dw-surface); padding: 2px 6px; border-radius: 6px; }
261
+ .sens { font-size: 11px; padding: 1px 7px; border-radius: 999px; border: 1px solid var(--dw-border); color: var(--dw-muted); }
262
+ .sens[data-level="destructive"] { color: #c2334f; border-color: color-mix(in srgb, #c2334f 40%, transparent); }
263
+ .confirm-text { margin: 8px 0 0; font-size: 13.5px; line-height: 1.5; color: var(--dw-muted); }
264
+ .confirm-warn { margin: 8px 0 0; font-size: 13px; font-weight: 600; color: #c2334f; }
265
+ .confirm-args {
266
+ margin: 10px 0 0; font-family: var(--dw-mono); font-size: 11.5px; line-height: 1.5; background: var(--dw-surface);
267
+ border: 1px solid var(--dw-border); border-radius: 8px; padding: 8px; max-height: 160px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere;
268
+ }
269
+ .confirm-buttons { display: flex; justify-content: flex-end; gap: 8px; margin-top: 14px; }
270
+ .btn { font: inherit; font-size: 13.5px; font-weight: 600; padding: 8px 14px; border-radius: 10px; border: 1px solid var(--dw-border); background: var(--dw-bg); color: var(--dw-fg); min-height: 38px; }
271
+ .btn.allow { background: var(--dw-accent); border-color: var(--dw-accent); color: var(--dw-accent-contrast); }
272
+ .btn.allow.danger { background: #c2334f; border-color: #c2334f; color: #fff; }
273
+ .btn:focus-visible { outline: 3px solid color-mix(in srgb, var(--dw-accent) 45%, transparent); outline-offset: 2px; }
274
+
205
275
  /* ---------- composer ---------- */
206
276
  .composer { padding: 10px 12px 12px; border-top: 1px solid var(--dw-border); background: var(--dw-bg); }
207
277
  .box {
@@ -231,8 +301,8 @@ textarea::placeholder { color: var(--dw-muted); }
231
301
  .agent-select { font-size: 16px; max-width: 200px; }
232
302
  }
233
303
  @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation: none !important; transition: none !important; } }
234
- `;var q=["show-reasoning","show-tool-calls","allow-agent-switch","open","persist","hide-branding","launcher-avatar"],$=["endpoint","agent","title","subtitle","greeting","intro","placeholder","suggestions","avatar","position","mode","theme","accent-color","locale","gateway-url","gateway-token","width","height","z-index",...q],O=i=>i.replace(/-([a-z])/g,(r,e)=>e.toUpperCase()),Y=i=>i!==null&&!/^(false|0|off|no)$/i.test(i),V=()=>{let i=crypto.getRandomValues(new Uint8Array(9));return Array.from(i,r=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"[r&63]).join("")},G=i=>i.replace(/^mcp_[^_]+(?:_[^_]+)*?__/,"").replace(/_/g," "),S={get(i){try{return localStorage.getItem(i)}catch{return null}},set(i,r){try{localStorage.setItem(i,r)}catch{}}},Z=null;function Q(){return Z??(Z=new Promise((i,r)=>{if(window.turnstile)return i();let e=document.createElement("script");e.src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit",e.async=!0,e.onload=()=>i(),e.onerror=()=>r(new Error("Could not load Turnstile")),document.head.appendChild(e)}))}var X=typeof HTMLElement>"u"?class{}:HTMLElement,E=class extends X{constructor(){super();l(this,"root");l(this,"overrides",{});l(this,"api",null);l(this,"apiKey","");l(this,"server",null);l(this,"agentId","");l(this,"conversationId","");l(this,"messages",[]);l(this,"running",null);l(this,"activated",!1);l(this,"strings",L());l(this,"mql",null);l(this,"els");l(this,"onScheme",()=>this.applyTheme());l(this,"pendingFrame",0);l(this,"following",!0);this.root=this.attachShadow({mode:"open"})}static get observedAttributes(){return $}get config(){let e={endpoint:"/api/dewee"};for(let t of $){let n=this.getAttribute(t);n!==null&&(q.includes(t)?e[O(t)]=Y(n):t==="suggestions"?e.suggestions=n.trim().startsWith("[")?ee(n,[]):n.split("|").map(s=>s.trim()).filter(Boolean):t==="z-index"?e.zIndex=Number(n):e[O(t)]=n)}return{...e,...this.overrides}}configure(e){this.overrides={...this.overrides,...e},this.els&&this.applyConfig()}open(){this.config.mode!=="inline"&&(this.setAttribute("data-open",""),this.removeAttribute("data-unread"),this.els.launcher.setAttribute("aria-expanded","true"),this.activate(),setTimeout(()=>this.els.input.focus(),120),this.emit("dewee:open"))}close(){this.config.mode!=="inline"&&(this.removeAttribute("data-open"),this.els.launcher.setAttribute("aria-expanded","false"),this.emit("dewee:close"))}toggle(){this.hasAttribute("data-open")?this.close():this.open()}async send(e){let t=e.trim();if(!t||this.running)return;this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.open(),await this.activate(),this.els.input.value="",this.autosize(),this.pushMessage({role:"user",content:t});let n={role:"assistant",content:"",status:"streaming",startedAt:Date.now()};this.pushMessage(n),this.setRunning(new AbortController),this.emit("dewee:send",{message:t,agent:this.agentId,conversationId:this.conversationId});try{await this.client().chat({message:t,agent:this.agentId,conversationId:this.conversationId},s=>this.onStreamEvent(n,s),this.running.signal),n.status==="streaming"&&(n.status="done")}catch(s){s.name==="AbortError"?(n.status="done",n.content||(n.content=`_${this.strings.stopped}_`)):(n.status="error",this.showError(n,s))}finally{this.finishThinking(n),this.updateMessage(n),this.setRunning(null),n.status==="done"&&(this.emit("dewee:reply",{content:n.content,agent:this.agentId,conversationId:this.conversationId}),this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.setAttribute("data-unread",""))}}stop(){this.running?.abort()}newConversation(){this.stop(),this.conversationId=V(),this.config.persist!==!1&&S.set(this.convKey(),this.conversationId),this.messages=[],this.renderLog(),this.els.input.focus()}connectedCallback(){this.els||this.renderShell(),this.applyConfig(),(this.config.mode==="inline"||this.config.open)&&(this.config.mode!=="inline"?this.open():this.activate())}disconnectedCallback(){this.stop(),this.mql?.removeEventListener("change",this.onScheme)}attributeChangedCallback(){this.els&&this.applyConfig()}emit(e,t){this.dispatchEvent(new CustomEvent(e,{detail:t,bubbles:!0,composed:!0}))}client(){let e=this.config,t=[e.endpoint,e.gatewayUrl,e.gatewayToken].join("|");return(!this.api||t!==this.apiKey)&&(this.apiKey=t,this.api=new y({endpoint:e.endpoint,gatewayUrl:e.gatewayUrl,gatewayToken:e.gatewayToken,turnstile:n=>this.challenge(n)})),this.api}convKey(){return`dewee-webchat:conv:${this.config.endpoint}:${this.config.gatewayUrl||""}:${this.agentId}`}applyTheme(){let e=this.config.theme||"light",t=e==="dark"||e==="auto"&&!!this.mql?.matches;this.setAttribute("data-theme",t?"dark":"light")}applyConfig(){let e=this.config;this.strings=L(e.locale);let t=this.strings;this.setAttribute("data-position",e.position||"bottom-right"),this.setAttribute("data-mode",e.mode||"floating"),e.theme==="auto"&&!this.mql&&(this.mql=matchMedia("(prefers-color-scheme: dark)"),this.mql.addEventListener("change",this.onScheme)),this.applyTheme();let n=(o,a)=>a!==void 0&&a!==""?this.style.setProperty(o,String(a)):this.style.removeProperty(o);n("--dw-accent",e.accentColor),n("--dw-width",e.width),n("--dw-height",e.height),n("--dw-z",e.zIndex);let s=this.els;if(s.title.textContent=e.title||t.title,s.avatar.replaceChildren(),e.avatar){let o=document.createElement("img");o.src=e.avatar,o.alt="",s.avatar.appendChild(o)}else s.avatar.textContent=(e.title||t.title).trim().charAt(0).toUpperCase();if(s.launcher.innerHTML=e.avatar&&e.launcherAvatar?"":m.chat,e.avatar&&e.launcherAvatar){let o=document.createElement("img");o.src=e.avatar,o.alt="",s.launcher.appendChild(o)}s.launcher.insertAdjacentHTML("beforeend",'<span class="badge"></span>'),s.launcher.setAttribute("aria-label",t.open),s.close.setAttribute("aria-label",t.close),s.close.title=t.close,s.newChat.setAttribute("aria-label",t.newChat),s.newChat.title=t.newChat,s.input.placeholder=e.placeholder||t.placeholder,s.foot.hidden=!!e.hideBranding,s.foot.querySelector(".by").textContent=t.poweredBy+" ",this.renderSubtitle(),this.updateSendButton(),this.activated&&this.api&&this.apiKey!==[e.endpoint,e.gatewayUrl,e.gatewayToken].join("|")?(this.activated=!1,this.server=null,this.activate()):this.activated&&e.agent&&e.agent!==this.agentId&&this.server?this.switchAgent(e.agent):this.activated&&this.renderLog()}renderShell(){this.root.innerHTML=`
235
- <style>${N}</style>
304
+ `;var mt=["show-reasoning","show-tool-calls","allow-agent-switch","open","persist","hide-branding","launcher-avatar"],ht=["endpoint","agent","title","subtitle","greeting","intro","placeholder","suggestions","avatar","position","mode","theme","accent-color","locale","gateway-url","gateway-token","width","height","z-index",...mt],ut=i=>i.replace(/-([a-z])/g,(s,t)=>t.toUpperCase()),Lt=i=>i!==null&&!/^(false|0|off|no)$/i.test(i),ft=()=>{let i=crypto.getRandomValues(new Uint8Array(9));return Array.from(i,s=>"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"[s&63]).join("")},It=i=>i.replace(/^mcp_[^_]+(?:_[^_]+)*?__/,"").replace(/_/g," "),T={get(i){try{return localStorage.getItem(i)}catch{return null}},set(i,s){try{localStorage.setItem(i,s)}catch{}}},Rt=null;function $t(){return Rt??(Rt=new Promise((i,s)=>{if(window.turnstile)return i();let t=document.createElement("script");t.src="https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit",t.async=!0,t.onload=()=>i(),t.onerror=()=>s(new Error("Could not load Turnstile")),document.head.appendChild(t)}))}var Nt=typeof HTMLElement>"u"?class{}:HTMLElement,L=class extends Nt{constructor(){super();h(this,"root");h(this,"overrides",{});h(this,"api",null);h(this,"apiKey","");h(this,"server",null);h(this,"agentId","");h(this,"conversationId","");h(this,"messages",[]);h(this,"running",null);h(this,"activated",!1);h(this,"strings",q());h(this,"mql",null);h(this,"registry",new $);h(this,"propActionNames",new Set);h(this,"hooks",{});h(this,"acks",new Map);h(this,"els");h(this,"onScheme",()=>this.applyTheme());h(this,"pendingFrame",0);h(this,"following",!0);this.root=this.attachShadow({mode:"open"})}static get observedAttributes(){return ht}get config(){let t={endpoint:"/api/dewee"};for(let e of ht){let n=this.getAttribute(e);n!==null&&(mt.includes(e)?t[ut(e)]=Lt(n):e==="suggestions"?t.suggestions=n.trim().startsWith("[")?Ht(n,[]):n.split("|").map(r=>r.trim()).filter(Boolean):e==="z-index"?t.zIndex=Number(n):t[ut(e)]=n)}return{...t,...this.overrides,...this.hooks}}configure(t){let{actions:e,confirm:n,getPageContext:r,...o}=t,a=l=>Object.prototype.hasOwnProperty.call(t,l);a("actions")&&this.setPropActions(e??[]),a("confirm")&&(this.hooks.confirm=n),a("getPageContext")&&(this.hooks.getPageContext=r),Object.keys(o).length&&(this.overrides={...this.overrides,...o},this.els&&this.applyConfig())}registerActions(t){this.registry.register(t)}unregisterAction(t){return this.propActionNames.delete(t),this.registry.unregister(t)}get actionNames(){return this.registry.names()}setPropActions(t){let e=new Set(t.map(n=>n.name));for(let n of this.propActionNames)e.has(n)||this.registry.unregister(n);t.length&&this.registry.register(t),this.propActionNames=e}open(){this.config.mode!=="inline"&&(this.setAttribute("data-open",""),this.removeAttribute("data-unread"),this.els.launcher.setAttribute("aria-expanded","true"),this.activate(),setTimeout(()=>this.els.input.focus(),120),this.emit("dewee:open"))}close(){this.config.mode!=="inline"&&(this.removeAttribute("data-open"),this.els.launcher.setAttribute("aria-expanded","false"),this.emit("dewee:close"))}toggle(){this.hasAttribute("data-open")?this.close():this.open()}async send(t){let e=t.trim();if(!e||this.running)return;this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.open(),await this.activate(),this.els.input.value="",this.autosize();let n={message:e,hidden:!1};for(let r=0;n;r++){let o=await this.runTurn(n.message,n.hidden);if(n=null,o.status!=="done"||o.stopped||!this.registry.size)break;let{calls:a}=H(o.content);if(!a.length)break;o.actions=a.map(g=>({id:g.id,name:g.name,args:g.ok?g.args:void 0,status:"pending"}));let l=this.config.maxActionRounds??5;if(r>=l){for(let g of o.actions)Object.assign(g,{status:"error",error:"Automatic action limit reached"});this.updateMessage(o),this.showNotice(this.strings.actionLimit(l));break}this.updateMessage(o);let c=await this.runActions(o,a);c&&(n={message:et(c,this.server?.maxMessageLength??4e3),hidden:!0})}}async runTurn(t,e){this.pushMessage({role:"user",content:t,hidden:e});let n={role:"assistant",content:"",status:"streaming",startedAt:Date.now()};this.pushMessage(n),this.setRunning(new AbortController),this.emit("dewee:send",{message:t,agent:this.agentId,conversationId:this.conversationId,auto:e||void 0});try{await this.client().chat(this.chatBody(t),r=>this.onStreamEvent(n,r),this.running.signal),n.status==="streaming"&&(n.status="done")}catch(r){r.name==="AbortError"?(n.status="done",n.stopped=!0,n.content||(n.content=`_${this.strings.stopped}_`)):(n.status="error",this.showError(n,r))}finally{this.finishThinking(n),this.updateMessage(n),this.setRunning(null),n.status==="done"&&(n.actionsHash&&!n.stopped&&this.setAck(n.actionsHash),this.emit("dewee:reply",{content:n.content,agent:this.agentId,conversationId:this.conversationId}),this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.setAttribute("data-unread",""))}return n}chatBody(t){let e={message:t,agent:this.agentId,conversationId:this.conversationId};if(this.registry.size){e.actions=this.registry.manifest();let r=this.getAck();r&&(e.actionsHash=r)}let n=this.pageContext();return n!==void 0&&(e.pageContext=n),e}pageContext(){let t=this.hooks.getPageContext;if(t)try{let e=t();if(e==null)return;let n=new TextEncoder().encode(JSON.stringify(e)).length;return n<=C.maxPageContextBytes?e:(console.warn(`[dewee-webchat] getPageContext() returned ${n} bytes; the limit is ${C.maxPageContextBytes}. Context not sent.`),{truncated:!0})}catch(e){console.warn("[dewee-webchat] getPageContext() failed:",e);return}}ackKey(){return`dewee-webchat:actions:${this.config.endpoint}:${this.agentId}:${this.conversationId}`}getAck(){return this.acks.get(this.ackKey())??(this.config.persist!==!1?T.get(this.ackKey())??void 0:void 0)}setAck(t){this.acks.set(this.ackKey(),t),this.config.persist!==!1&&T.set(this.ackKey(),t)}async runActions(t,e){let n=new AbortController;this.setRunning(n);let r=[],o={agent:this.agentId,conversationId:this.conversationId};try{for(let[a,l]of e.entries()){let c=t.actions[a],g=l.ok?this.registry.get(l.name)?.sensitivity:void 0,p=l.ok?l.args:void 0;this.emit("dewee:action",{phase:"start",id:l.id,name:l.name,sensitivity:g,args:p,...o});let d=await ot(l,{registry:this.registry,confirm:(u,m)=>this.confirmAction(u,m,n.signal),signal:n.signal,timeoutMs:this.config.actionTimeoutMs,...o,onStatus:u=>{c.status=u,this.updateMessage(t)}});d.error&&(c.error=d.error),this.updateMessage(t),r.push(d),this.emit("dewee:action",{phase:"result",id:d.id,name:d.name,sensitivity:g,args:p,status:d.status,result:d.result,error:d.error,...o})}}finally{this.setRunning(null)}return n.signal.aborted?null:r}confirmAction(t,e,n){return this.hooks.confirm?this.hooks.confirm(t,e):(this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.open(),ct(this.els.panel,this.strings,t,e,n))}showNotice(t){let e=document.createElement("div");e.className="notice",e.setAttribute("role","status"),e.textContent=t,this.els.log.appendChild(e),this.scrollToBottom(!0)}stop(){this.running?.abort()}newConversation(){this.stop(),this.conversationId=ft(),this.config.persist!==!1&&T.set(this.convKey(),this.conversationId),this.messages=[],this.renderLog(),this.els.input.focus()}connectedCallback(){this.els||this.renderShell(),this.applyConfig(),(this.config.mode==="inline"||this.config.open)&&(this.config.mode!=="inline"?this.open():this.activate())}disconnectedCallback(){this.stop(),this.mql?.removeEventListener("change",this.onScheme)}attributeChangedCallback(){this.els&&this.applyConfig()}emit(t,e){this.dispatchEvent(new CustomEvent(t,{detail:e,bubbles:!0,composed:!0}))}client(){let t=this.config,e=[t.endpoint,t.gatewayUrl,t.gatewayToken].join("|");return(!this.api||e!==this.apiKey)&&(this.apiKey=e,this.api=new S({endpoint:t.endpoint,gatewayUrl:t.gatewayUrl,gatewayToken:t.gatewayToken,turnstile:n=>this.challenge(n)})),this.api}convKey(){return`dewee-webchat:conv:${this.config.endpoint}:${this.config.gatewayUrl||""}:${this.agentId}`}applyTheme(){let t=this.config.theme||"light",e=t==="dark"||t==="auto"&&!!this.mql?.matches;this.setAttribute("data-theme",e?"dark":"light")}applyConfig(){let t=this.config;this.strings=q(t.locale);let e=this.strings;this.setAttribute("data-position",t.position||"bottom-right"),this.setAttribute("data-mode",t.mode||"floating"),t.theme==="auto"&&!this.mql&&(this.mql=matchMedia("(prefers-color-scheme: dark)"),this.mql.addEventListener("change",this.onScheme)),this.applyTheme();let n=(o,a)=>a!==void 0&&a!==""?this.style.setProperty(o,String(a)):this.style.removeProperty(o);n("--dw-accent",t.accentColor),n("--dw-width",t.width),n("--dw-height",t.height),n("--dw-z",t.zIndex);let r=this.els;if(r.title.textContent=t.title||e.title,r.avatar.replaceChildren(),t.avatar){let o=document.createElement("img");o.src=t.avatar,o.alt="",r.avatar.appendChild(o)}else r.avatar.textContent=(t.title||e.title).trim().charAt(0).toUpperCase();if(r.launcher.innerHTML=t.avatar&&t.launcherAvatar?"":b.chat,t.avatar&&t.launcherAvatar){let o=document.createElement("img");o.src=t.avatar,o.alt="",r.launcher.appendChild(o)}r.launcher.insertAdjacentHTML("beforeend",'<span class="badge"></span>'),r.launcher.setAttribute("aria-label",e.open),r.close.setAttribute("aria-label",e.close),r.close.title=e.close,r.newChat.setAttribute("aria-label",e.newChat),r.newChat.title=e.newChat,r.input.placeholder=t.placeholder||e.placeholder,r.foot.hidden=!!t.hideBranding,r.foot.querySelector(".by").textContent=e.poweredBy+" ",this.renderSubtitle(),this.updateSendButton(),this.activated&&this.api&&this.apiKey!==[t.endpoint,t.gatewayUrl,t.gatewayToken].join("|")?(this.activated=!1,this.server=null,this.activate()):this.activated&&t.agent&&t.agent!==this.agentId&&this.server?this.switchAgent(t.agent):this.activated&&this.renderLog()}renderShell(){this.root.innerHTML=`
305
+ <style>${pt}</style>
236
306
  <button class="launcher" part="launcher" aria-expanded="false" aria-haspopup="dialog"></button>
237
307
  <section class="panel" part="panel" role="dialog" aria-label="Chat">
238
308
  <header class="head" part="header">
@@ -241,8 +311,8 @@ textarea::placeholder { color: var(--dw-muted); }
241
311
  <div class="title"></div>
242
312
  <div class="subtitle"><span class="dot"></span><span class="status"></span><select class="agent-select" hidden></select></div>
243
313
  </div>
244
- <button class="icon-btn new">${m.newChat}</button>
245
- <button class="icon-btn close">${m.close}</button>
314
+ <button class="icon-btn new">${b.newChat}</button>
315
+ <button class="icon-btn close">${b.close}</button>
246
316
  </header>
247
317
  <div class="log" part="log" role="log" aria-live="polite"></div>
248
318
  <div class="challenge"><slot name="challenge"></slot></div>
@@ -253,6 +323,7 @@ textarea::placeholder { color: var(--dw-muted); }
253
323
  </div>
254
324
  <div class="foot"><span><span class="by"></span><a href="https://dewee.sh" target="_blank" rel="noopener">dewee</a></span><span class="meta"></span></div>
255
325
  </form>
256
- </section>`;let e=n=>this.root.querySelector(n);this.els={launcher:e(".launcher"),panel:e(".panel"),log:e(".log"),title:e(".title"),subtitle:e(".subtitle"),status:e(".status"),avatar:e(".avatar"),select:e(".agent-select"),input:e("textarea"),send:e(".send"),newChat:e(".new"),close:e(".close"),foot:e(".foot")};let t=this.els;t.launcher.addEventListener("click",()=>this.toggle()),t.close.addEventListener("click",()=>this.close()),t.log.addEventListener("scroll",()=>{this.following=this.nearBottom()},{passive:!0}),t.newChat.addEventListener("click",()=>this.newConversation()),t.select.addEventListener("change",()=>this.switchAgent(t.select.value)),e("form").addEventListener("submit",n=>{n.preventDefault(),this.running?this.stop():this.send(t.input.value)}),t.input.addEventListener("keydown",n=>{n.key==="Enter"&&!n.shiftKey&&!n.isComposing&&n.keyCode!==229&&(n.preventDefault(),this.running||this.send(t.input.value))}),t.input.addEventListener("input",()=>{this.autosize(),this.updateSendButton()}),t.panel.addEventListener("keydown",n=>{n.key==="Escape"&&this.close()})}autosize(){let e=this.els.input;e.style.height="auto",e.style.height=Math.min(e.scrollHeight,140)+"px"}updateSendButton(){let e=this.els.send;e.innerHTML=this.running?m.stop:m.send,e.setAttribute("aria-label",this.running?this.strings.stop:this.strings.send),e.title=e.getAttribute("aria-label"),e.disabled=!this.running&&!this.els.input.value.trim()}setRunning(e){this.running=e,this.updateSendButton()}renderSubtitle(){let e=this.els,t=this.config,n=this.server?.agents??[],s=t.allowAgentSwitch!==!1&&!!this.server?.allowAgentSwitch&&n.length>1;e.select.hidden=!s,e.status.hidden=s,s&&(e.select.replaceChildren(...n.map(a=>new Option(a.name||a.id,a.id,!1,a.id===this.agentId))),e.select.setAttribute("aria-label","Agent"));let o=n.find(a=>a.id===this.agentId);e.status.textContent=t.subtitle||(o?.name&&o.name!==t.title?`${this.strings.online} \xB7 ${o.name}`:this.strings.online)}async activate(){if(!this.activated){this.activated=!0,this.renderLog();try{this.server=await this.client().getConfig(!0),this.els.input.maxLength=this.server.maxMessageLength;let e=this.config.agent,t=n=>!!n&&(this.server.agents.length===0||this.server.agents.some(s=>s.id===n));this.agentId=t(e)?e:this.server.defaultAgent||this.server.agents[0]?.id||e||"",await this.loadConversation()}catch(e){this.activated=!1,this.renderLog(),this.showError(null,e)}this.renderSubtitle(),this.emit("dewee:ready",{agent:this.agentId,config:this.server})}}async switchAgent(e){e!==this.agentId&&(this.stop(),this.agentId=e,this.renderSubtitle(),await this.loadConversation())}async loadConversation(){let e=this.config.persist!==!1,t=e?S.get(this.convKey()):null;if(this.conversationId=t||V(),e&&!t&&S.set(this.convKey(),this.conversationId),this.messages=[],this.renderLog(),!!t)try{let n=await this.client().history(this.agentId,this.conversationId);this.messages=n.map(s=>({...s,status:"done"})),this.renderLog()}catch{}}renderLog(){let e=this.els.log;e.replaceChildren(),this.messages.length||e.appendChild(this.renderWelcome());for(let t of this.messages)e.appendChild(this.renderMessage(t));e.scrollTop=e.scrollHeight}renderWelcome(){let e=this.config,t=this.strings,n=document.createElement("div");n.className="welcome";let s=document.createElement("h2");s.textContent=e.greeting||t.greeting;let o=document.createElement("p");if(o.textContent=e.intro||t.greetingBody,n.append(s,o),e.suggestions?.length){let a=document.createElement("div");a.className="suggestions";for(let g of e.suggestions){let p=document.createElement("button");p.className="chip",p.type="button",p.textContent=g,p.addEventListener("click",()=>this.send(g)),a.appendChild(p)}n.appendChild(a)}return n}pushMessage(e){this.messages.length||this.els.log.replaceChildren(),this.messages.push(e),this.els.log.appendChild(this.renderMessage(e)),this.scrollToBottom(!0)}renderMessage(e){let t=document.createElement("div");t.className=`msg ${e.role}${e.status==="error"?" error":""}`;let n=document.createElement("div");n.className="bubble",t.appendChild(n);let s=document.createElement("div");s.className="trace";let o=document.createElement("div");return o.className=e.role==="assistant"?"md":"",e.role==="assistant"&&n.appendChild(s),n.appendChild(o),e.view={root:t,trace:s,md:o,tools:new Map},this.updateMessage(e),t}updateMessage(e){let t=e.view;if(!t)return;let n=this.config;if(e.role==="user"){t.md.textContent=e.content;return}if(t.root.classList.toggle("error",e.status==="error"),n.showReasoning!==!1&&e.thinking){t.thinking||(t.thinking=document.createElement("details"),t.thinking.className="thinking",t.thinking.innerHTML='<summary></summary><div class="thinking-body"></div>',t.trace.prepend(t.thinking));let o=e.status==="streaming"&&!e.thinkingMs,a=o?this.strings.thinking:e.thinkingMs?this.strings.thoughtFor(Math.max(1,Math.round(e.thinkingMs/1e3))):this.strings.reasoning,g=t.thinking.querySelector("summary");g.innerHTML=`${o?'<span class="spin"></span>':m.brain}<span></span>${m.down.replace("<svg",'<svg class="chev"')}`,g.querySelector("span:not(.spin)").textContent=a,t.thinking.querySelector(".thinking-body").textContent=e.thinking}else t.thinking&&(t.thinking.remove(),t.thinking=void 0);if(n.showToolCalls!==!1)for(let o of e.toolCalls??[])this.renderTool(t,o);else t.tools.forEach(o=>o.remove()),t.tools.clear();t.trace.hidden=!t.trace.childElementCount,e.status==="streaming"&&!e.content?t.md.innerHTML=`<span class="typing" aria-label="${this.strings.thinking}"><i></i><i></i><i></i></span>`:(t.md.replaceChildren(k(document,e.content)),t.md.classList.toggle("cursor",e.status==="streaming"))}renderTool(e,t){let n=e.tools.get(t.id);n||(n=document.createElement("details"),n.className="tool",n.innerHTML=`<summary><span class="lead"></span><span class="tool-name"></span><span class="tool-state"></span>${m.down.replace("<svg",'<svg class="chev"')}</summary><div class="tool-body"></div>`,e.tools.set(t.id,n),e.trace.appendChild(n)),n.dataset.status=t.status,n.querySelector(".lead").innerHTML=t.status==="running"?'<span class="spin"></span>':m.tool;let s=n.querySelector(".tool-name");s.textContent=G(t.name),s.setAttribute("title",t.name),n.querySelector(".tool-state").textContent=t.status==="running"?this.strings.toolRunning:t.status==="error"?this.strings.toolError:this.strings.toolDone;let o=n.querySelector(".tool-body");o.replaceChildren();let a=(g,p)=>{if(p==null||p==="")return;let f=document.createElement("div");f.className="label",f.textContent=g;let h=document.createElement("pre");h.textContent=typeof p=="string"?te(p):JSON.stringify(p,null,2),o.append(f,h)};a(this.strings.args,t.arguments),a(this.strings.result,t.result)}onStreamEvent(e,t){switch(t.type){case"start":t.conversationId&&t.conversationId!==this.conversationId&&(this.conversationId=t.conversationId,this.config.persist!==!1&&S.set(this.convKey(),t.conversationId));break;case"thinking":e.thinking=(e.thinking||"")+t.text;break;case"delta":this.finishThinking(e),e.content+=t.text;break;case"tool_call":this.finishThinking(e),(e.toolCalls??(e.toolCalls=[])).push({id:t.id,name:t.name,arguments:t.arguments,status:"running"});break;case"tool_result":{let n=e.toolCalls?.find(s=>s.id===t.id)??(e.toolCalls??(e.toolCalls=[]))[e.toolCalls.push({id:t.id,name:t.name,status:"running"})-1];n.status=t.isError?"error":"done",n.result=t.result,n.isError=t.isError;break}case"done":this.finishThinking(e),t.content&&t.content.length>=e.content.length&&(e.content=t.content),e.status="done";break;case"error":e.status="error",this.showError(e,new w(t.message,500,t.code));break}this.scheduleUpdate(e)}scheduleUpdate(e){this.pendingFrame||(this.pendingFrame=requestAnimationFrame(()=>{this.pendingFrame=0,this.updateMessage(e),this.following&&this.scrollToBottom(!0)}))}finishThinking(e){e.thinking&&!e.thinkingMs&&e.startedAt&&(e.thinkingMs=Date.now()-e.startedAt)}nearBottom(){let e=this.els.log;return e.scrollHeight-e.scrollTop-e.clientHeight<96}scrollToBottom(e=!1){let t=this.els.log;(e||this.nearBottom())&&(t.scrollTop=t.scrollHeight,this.following=!0)}showError(e,t){let n=t.message||this.strings.errorGeneric;if(this.emit("dewee:error",{message:n,code:t.code}),e){e.content=e.content?`${e.content}
326
+ </section>`;let t=n=>this.root.querySelector(n);this.els={launcher:t(".launcher"),panel:t(".panel"),log:t(".log"),title:t(".title"),subtitle:t(".subtitle"),status:t(".status"),avatar:t(".avatar"),select:t(".agent-select"),input:t("textarea"),send:t(".send"),newChat:t(".new"),close:t(".close"),foot:t(".foot")};let e=this.els;e.launcher.addEventListener("click",()=>this.toggle()),e.close.addEventListener("click",()=>this.close()),e.log.addEventListener("scroll",()=>{this.following=this.nearBottom()},{passive:!0}),e.newChat.addEventListener("click",()=>this.newConversation()),e.select.addEventListener("change",()=>this.switchAgent(e.select.value)),t("form").addEventListener("submit",n=>{n.preventDefault(),this.running?this.stop():this.send(e.input.value)}),e.input.addEventListener("keydown",n=>{n.key==="Enter"&&!n.shiftKey&&!n.isComposing&&n.keyCode!==229&&(n.preventDefault(),this.running||this.send(e.input.value))}),e.input.addEventListener("input",()=>{this.autosize(),this.updateSendButton()}),e.panel.addEventListener("keydown",n=>{n.key==="Escape"&&this.close()})}autosize(){let t=this.els.input;t.style.height="auto",t.style.height=Math.min(t.scrollHeight,140)+"px"}updateSendButton(){let t=this.els.send;t.innerHTML=this.running?b.stop:b.send,t.setAttribute("aria-label",this.running?this.strings.stop:this.strings.send),t.title=t.getAttribute("aria-label"),t.disabled=!this.running&&!this.els.input.value.trim()}setRunning(t){this.running=t,this.updateSendButton()}renderSubtitle(){let t=this.els,e=this.config,n=this.server?.agents??[],r=e.allowAgentSwitch!==!1&&!!this.server?.allowAgentSwitch&&n.length>1;t.select.hidden=!r,t.status.hidden=r,r&&(t.select.replaceChildren(...n.map(a=>new Option(a.name||a.id,a.id,!1,a.id===this.agentId))),t.select.setAttribute("aria-label","Agent"));let o=n.find(a=>a.id===this.agentId);t.status.textContent=e.subtitle||(o?.name&&o.name!==e.title?`${this.strings.online} \xB7 ${o.name}`:this.strings.online)}async activate(){if(!this.activated){this.activated=!0,this.renderLog();try{this.server=await this.client().getConfig(!0),this.els.input.maxLength=this.server.maxMessageLength;let t=this.config.agent,e=n=>!!n&&(this.server.agents.length===0||this.server.agents.some(r=>r.id===n));this.agentId=e(t)?t:this.server.defaultAgent||this.server.agents[0]?.id||t||"",await this.loadConversation()}catch(t){this.activated=!1,this.renderLog(),this.showError(null,t)}this.renderSubtitle(),this.emit("dewee:ready",{agent:this.agentId,config:this.server})}}async switchAgent(t){t!==this.agentId&&(this.stop(),this.agentId=t,this.renderSubtitle(),await this.loadConversation())}async loadConversation(){let t=this.config.persist!==!1,e=t?T.get(this.convKey()):null;if(this.conversationId=e||ft(),t&&!e&&T.set(this.convKey(),this.conversationId),this.messages=[],this.renderLog(),!!e)try{let n=await this.client().history(this.agentId,this.conversationId);this.messages=_t(n.map(r=>({...r,status:"done"}))),this.renderLog()}catch{}}renderLog(){let t=this.els.log;t.replaceChildren(),this.messages.length||t.appendChild(this.renderWelcome());for(let e of this.messages)t.appendChild(this.renderMessage(e));t.scrollTop=t.scrollHeight}renderWelcome(){let t=this.config,e=this.strings,n=document.createElement("div");n.className="welcome";let r=document.createElement("h2");r.textContent=t.greeting||e.greeting;let o=document.createElement("p");if(o.textContent=t.intro||e.greetingBody,n.append(r,o),t.suggestions?.length){let a=document.createElement("div");a.className="suggestions";for(let l of t.suggestions){let c=document.createElement("button");c.className="chip",c.type="button",c.textContent=l,c.addEventListener("click",()=>this.send(l)),a.appendChild(c)}n.appendChild(a)}return n}pushMessage(t){this.messages.length||this.els.log.replaceChildren(),this.messages.push(t),this.els.log.appendChild(this.renderMessage(t)),this.scrollToBottom(!0)}renderMessage(t){let e=document.createElement("div");e.className=`msg ${t.role}${t.status==="error"?" error":""}`,e.hidden=!!t.hidden;let n=document.createElement("div");n.className="bubble",e.appendChild(n);let r=document.createElement("div");r.className="trace";let o=document.createElement("div");o.className=t.role==="assistant"?"md":"";let a=document.createElement("div");return a.className="actions",a.hidden=!0,t.role==="assistant"&&n.appendChild(r),n.appendChild(o),t.role==="assistant"&&n.appendChild(a),t.view={root:e,trace:r,md:o,tools:new Map,actions:a},this.updateMessage(t),e}updateMessage(t){let e=t.view;if(!e)return;let n=this.config;if(t.role==="user"){e.md.textContent=t.content;return}if(e.root.classList.toggle("error",t.status==="error"),n.showReasoning!==!1&&t.thinking){e.thinking||(e.thinking=document.createElement("details"),e.thinking.className="thinking",e.thinking.innerHTML='<summary></summary><div class="thinking-body"></div>',e.trace.prepend(e.thinking));let a=t.status==="streaming"&&!t.thinkingMs,l=a?this.strings.thinking:t.thinkingMs?this.strings.thoughtFor(Math.max(1,Math.round(t.thinkingMs/1e3))):this.strings.reasoning,c=e.thinking.querySelector("summary");c.innerHTML=`${a?'<span class="spin"></span>':b.brain}<span></span>${b.down.replace("<svg",'<svg class="chev"')}`,c.querySelector("span:not(.spin)").textContent=l,e.thinking.querySelector(".thinking-body").textContent=t.thinking}else e.thinking&&(e.thinking.remove(),e.thinking=void 0);if(n.showToolCalls!==!1)for(let a of t.toolCalls??[])this.renderTool(e,a);else e.tools.forEach(a=>a.remove()),e.tools.clear();e.trace.hidden=!e.trace.childElementCount;let r=this.registry.size||t.actions?X(t.content):t.content,o=t.status==="streaming"&&!r;e.md.hidden=!o&&!r&&!!t.actions?.length,o?e.md.innerHTML=`<span class="typing" aria-label="${this.strings.thinking}"><i></i><i></i><i></i></span>`:(e.md.replaceChildren(E(document,r)),e.md.classList.toggle("cursor",t.status==="streaming")),this.renderActions(e,t.actions??[])}renderActions(t,e){t.actions.hidden=!e.length,t.actions.replaceChildren(...e.map(n=>{let r=document.createElement("div");r.className="action",r.dataset.status=n.status;let o=n.status==="running"||n.status==="awaiting-confirmation";r.innerHTML=`${o?'<span class="spin"></span>':b.action}<span class="action-name"></span><span class="action-state"></span>`,r.querySelector(".action-name").textContent=n.name||"?",r.querySelector(".action-state").textContent=this.strings.actionStatus[n.status];let a=[n.args&&Object.keys(n.args).length?JSON.stringify(n.args):"",n.error??""].filter(Boolean).join(`
327
+ `);return a&&(r.title=a),r}))}renderTool(t,e){let n=t.tools.get(e.id);n||(n=document.createElement("details"),n.className="tool",n.innerHTML=`<summary><span class="lead"></span><span class="tool-name"></span><span class="tool-state"></span>${b.down.replace("<svg",'<svg class="chev"')}</summary><div class="tool-body"></div>`,t.tools.set(e.id,n),t.trace.appendChild(n)),n.dataset.status=e.status,n.querySelector(".lead").innerHTML=e.status==="running"?'<span class="spin"></span>':b.tool;let r=n.querySelector(".tool-name");r.textContent=It(e.name),r.setAttribute("title",e.name),n.querySelector(".tool-state").textContent=e.status==="running"?this.strings.toolRunning:e.status==="error"?this.strings.toolError:this.strings.toolDone;let o=n.querySelector(".tool-body");o.replaceChildren();let a=(l,c)=>{if(c==null||c==="")return;let g=document.createElement("div");g.className="label",g.textContent=l;let p=document.createElement("pre");p.textContent=typeof c=="string"?Bt(c):JSON.stringify(c,null,2),o.append(g,p)};a(this.strings.args,e.arguments),a(this.strings.result,e.result)}onStreamEvent(t,e){switch(e.type){case"start":e.actionsHash&&(t.actionsHash=e.actionsHash),e.conversationId&&e.conversationId!==this.conversationId&&(this.conversationId=e.conversationId,this.config.persist!==!1&&T.set(this.convKey(),e.conversationId));break;case"thinking":t.thinking=(t.thinking||"")+e.text;break;case"delta":this.finishThinking(t),t.content+=e.text;break;case"tool_call":this.finishThinking(t),(t.toolCalls??(t.toolCalls=[])).push({id:e.id,name:e.name,arguments:e.arguments,status:"running"});break;case"tool_result":{let n=t.toolCalls?.find(r=>r.id===e.id)??(t.toolCalls??(t.toolCalls=[]))[t.toolCalls.push({id:e.id,name:e.name,status:"running"})-1];n.status=e.isError?"error":"done",n.result=e.result,n.isError=e.isError;break}case"done":this.finishThinking(t),e.content&&e.content.length>=t.content.length&&(t.content=e.content),t.status="done";break;case"error":t.status="error",this.showError(t,new v(e.message,500,e.code));break}this.scheduleUpdate(t)}scheduleUpdate(t){this.pendingFrame||(this.pendingFrame=requestAnimationFrame(()=>{this.pendingFrame=0,this.updateMessage(t),this.following&&this.scrollToBottom(!0)}))}finishThinking(t){t.thinking&&!t.thinkingMs&&t.startedAt&&(t.thinkingMs=Date.now()-t.startedAt)}nearBottom(){let t=this.els.log;return t.scrollHeight-t.scrollTop-t.clientHeight<96}scrollToBottom(t=!1){let e=this.els.log;(t||this.nearBottom())&&(e.scrollTop=e.scrollHeight,this.following=!0)}showError(t,e){let n=e.message||this.strings.errorGeneric;if(this.emit("dewee:error",{message:n,code:e.code}),t){t.content=t.content?`${t.content}
257
328
 
258
- > \u26A0\uFE0F ${n}`:`\u26A0\uFE0F ${n}`,e.status="error",this.updateMessage(e);return}let s=document.createElement("div");s.className="msg error",s.innerHTML='<div class="bubble"></div>',s.firstElementChild.textContent=`\u26A0\uFE0F ${n}`,this.els.log.appendChild(s)}async challenge(e){await Q();let t=document.createElement("div");t.slot="challenge",this.appendChild(t);try{return await new Promise((n,s)=>{window.turnstile.render(t,{sitekey:e,appearance:"interaction-only",theme:this.getAttribute("data-theme")==="dark"?"dark":"light",callback:n,"error-callback":()=>s(new w("Verification failed",403,"turnstile_failed"))})})}finally{t.remove()}}};function ee(i,r){try{return JSON.parse(i)}catch{return r}}function te(i){let r=i.trim();if(!/^[[{]/.test(r))return i;try{return JSON.stringify(JSON.parse(r),null,2)}catch{return i}}function H(i="dewee-chat"){typeof window>"u"||!window.customElements||customElements.get(i)||customElements.define(i,class extends E{})}function ne(i={},r){H();let e=document.createElement("dewee-chat");return e.configure(i),((typeof r=="string"?document.querySelector(r):r)??document.body).appendChild(e),e}H();var ie=document.currentScript,M=ie?.dataset;if(M&&M.endpoint&&M.autoMount!=="false"){let i=()=>{let r=document.createElement("dewee-chat");for(let[e,t]of Object.entries(M))e==="autoMount"||t===void 0||r.setAttribute(e.replace(/[A-Z]/g,n=>"-"+n.toLowerCase()),t);document.body.appendChild(r)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",i):i()}window.DeweeWebchat=I;})();
329
+ > \u26A0\uFE0F ${n}`:`\u26A0\uFE0F ${n}`,t.status="error",this.updateMessage(t);return}let r=document.createElement("div");r.className="msg error",r.innerHTML='<div class="bubble"></div>',r.firstElementChild.textContent=`\u26A0\uFE0F ${n}`,this.els.log.appendChild(r)}async challenge(t){await $t();let e=document.createElement("div");e.slot="challenge",this.appendChild(e);try{return await new Promise((n,r)=>{window.turnstile.render(e,{sitekey:t,appearance:"interaction-only",theme:this.getAttribute("data-theme")==="dark"?"dark":"light",callback:n,"error-callback":()=>r(new v("Verification failed",403,"turnstile_failed"))})})}finally{e.remove()}}};function _t(i){return i.forEach((s,t)=>{if(s.role==="user"){s.content=j(s.content),B(s.content)&&(s.hidden=!0);return}if(!s.content.includes("```dewee-action"))return;let{calls:e}=H(s.content);if(!e.length)return;let n=i[t+1],r=n?.role==="user"?j(n.content):"",o=B(r)?tt(r):[];s.actions=e.map(a=>{let l=o.find(g=>g.id===a.id),c=l?l.status==="ok"?"done":l.status:"error";return{id:a.id,name:a.name,args:a.ok?a.args:void 0,status:c,error:l?l.error:"Not run"}})}),i}function Ht(i,s){try{return JSON.parse(i)}catch{return s}}function Bt(i){let s=i.trim();if(!/^[[{]/.test(s))return i;try{return JSON.stringify(JSON.parse(s),null,2)}catch{return i}}function V(i="dewee-chat"){typeof window>"u"||!window.customElements||customElements.get(i)||customElements.define(i,class extends L{})}function Ot(i={},s){V();let t=document.createElement("dewee-chat");return t.configure(i),((typeof s=="string"?document.querySelector(s):s)??document.body).appendChild(t),t}V();var zt=document.currentScript,N=zt?.dataset;if(N&&N.endpoint&&N.autoMount!=="false"){let i=()=>{let s=document.createElement("dewee-chat");for(let[t,e]of Object.entries(N))t==="autoMount"||e===void 0||s.setAttribute(t.replace(/[A-Z]/g,n=>"-"+n.toLowerCase()),e);document.body.appendChild(s)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",i):i()}window.DeweeWebchat=K;})();
package/dist/index.d.ts CHANGED
@@ -1,5 +1,43 @@
1
- import { P as PublicConfig, S as SessionResponse, H as HistoryMessage, C as ChatStreamEvent } from './protocol-CS8_4zC0.js';
2
- export { A as AgentInfo, T as ToolCallView } from './protocol-CS8_4zC0.js';
1
+ import { b as ActionSensitivity, P as PublicConfig, S as SessionResponse, H as HistoryMessage, c as ChatRequestBody, C as ChatStreamEvent } from './protocol-B72Ry-fY.js';
2
+ export { a as ActionManifestEntry, A as AgentInfo, T as ToolCallView } from './protocol-B72Ry-fY.js';
3
+
4
+ type ActionResultStatus = "ok" | "denied" | "error";
5
+ interface ActionResult {
6
+ id: string;
7
+ name: string;
8
+ status: ActionResultStatus;
9
+ result?: unknown;
10
+ error?: string;
11
+ }
12
+
13
+ type JsonSchema = Record<string, unknown>;
14
+
15
+ interface PageActionContext {
16
+ /** Id the agent gave this call. */
17
+ callId: string;
18
+ conversationId: string;
19
+ agent: string;
20
+ /** Aborted when the visitor stops the run, starts a new conversation, or the handler times out. */
21
+ signal: AbortSignal;
22
+ }
23
+ interface PageAction<Args = any> {
24
+ /** `^[a-z][a-z0-9_.-]{0,63}$` */
25
+ name: string;
26
+ /** What the action does, written for the agent. */
27
+ description: string;
28
+ /** JSON Schema subset for `args` (an object schema). */
29
+ parameters?: JsonSchema;
30
+ sensitivity: ActionSensitivity;
31
+ /** Runs in the page. Must return JSON-serializable data. Agent args are untrusted: validate before acting. */
32
+ handler: (args: Args, ctx: PageActionContext) => unknown | Promise<unknown>;
33
+ }
34
+ /** An action as shown to the confirm hook (no handler). */
35
+ type PageActionInfo = Omit<PageAction, "handler">;
36
+ /** Host-owned approval for `mutate`/`destructive` calls. Only a resolved `true` approves. */
37
+ type ActionConfirmHook = (action: PageActionInfo & {
38
+ callId: string;
39
+ }, args: Record<string, unknown>) => boolean | Promise<boolean>;
40
+ type ActionCallStatus = "pending" | "awaiting-confirmation" | "running" | "done" | "denied" | "error";
3
41
 
4
42
  interface DeweeChatConfig {
5
43
  /** Backend base URL (the server handler). Default: "/api/dewee". */
@@ -40,6 +78,37 @@ interface DeweeChatConfig {
40
78
  width?: string;
41
79
  height?: string;
42
80
  zIndex?: number;
81
+ /** Page actions the agent may invoke. Replaces the set previously passed through this option. */
82
+ actions?: PageAction[];
83
+ /** Approval for `mutate`/`destructive` actions. Default: the built-in confirm dialog. Only `true` approves. */
84
+ confirm?: ActionConfirmHook;
85
+ /** Small, host-redacted snapshot of page state sent with every message (max 4 KB as JSON). */
86
+ getPageContext?: () => unknown;
87
+ /** Automatic action rounds allowed per visitor message. Default 5. */
88
+ maxActionRounds?: number;
89
+ /** Per-handler timeout. Default 30000 ms. */
90
+ actionTimeoutMs?: number;
91
+ }
92
+ /** A page action call as shown in the transcript. */
93
+ interface ActionCallView {
94
+ id: string;
95
+ name: string;
96
+ args?: Record<string, unknown>;
97
+ status: ActionCallStatus;
98
+ error?: string;
99
+ }
100
+ /** `detail` of the `dewee:action` event (host telemetry). */
101
+ interface ActionEventDetail {
102
+ phase: "start" | "result";
103
+ id: string;
104
+ name: string;
105
+ sensitivity?: ActionSensitivity;
106
+ args?: Record<string, unknown>;
107
+ status?: ActionResultStatus;
108
+ result?: unknown;
109
+ error?: string;
110
+ agent: string;
111
+ conversationId: string;
43
112
  }
44
113
  declare const ElementBase: typeof HTMLElement;
45
114
  declare class DeweeChatElement extends ElementBase {
@@ -56,17 +125,40 @@ declare class DeweeChatElement extends ElementBase {
56
125
  private activated;
57
126
  private strings;
58
127
  private mql;
128
+ private registry;
129
+ private propActionNames;
130
+ private hooks;
131
+ private acks;
59
132
  private els;
60
133
  constructor();
61
134
  /** Current effective configuration (attributes merged with `configure()` overrides). */
62
135
  get config(): DeweeChatConfig;
63
136
  /** Updates configuration at runtime (wins over attributes). */
64
137
  configure(partial: Partial<DeweeChatConfig>): void;
138
+ /** Adds or replaces page actions the agent may invoke. Throws TypeError on an invalid definition. */
139
+ registerActions(actions: PageAction | PageAction[]): void;
140
+ /** Removes a page action. Returns false when it was not registered. */
141
+ unregisterAction(name: string): boolean;
142
+ /** Names of the currently registered page actions. */
143
+ get actionNames(): string[];
144
+ private setPropActions;
65
145
  open(): void;
66
146
  close(): void;
67
147
  toggle(): void;
68
148
  /** Sends a message programmatically (opens the widget first). */
69
149
  send(text: string): Promise<void>;
150
+ /** One request/response with the agent. */
151
+ private runTurn;
152
+ private chatBody;
153
+ /** Host snapshot, dropped (with a warning) when it fails or exceeds the backend cap. */
154
+ private pageContext;
155
+ private ackKey;
156
+ private getAck;
157
+ private setAck;
158
+ /** Executes the calls of one answer in order. Resolves null when the visitor stopped the chain. */
159
+ private runActions;
160
+ private confirmAction;
161
+ private showNotice;
70
162
  /** Stops the running reply. */
71
163
  stop(): void;
72
164
  /** Starts a fresh conversation with the current agent. */
@@ -94,6 +186,7 @@ declare class DeweeChatElement extends ElementBase {
94
186
  private pushMessage;
95
187
  private renderMessage;
96
188
  private updateMessage;
189
+ private renderActions;
97
190
  private renderTool;
98
191
  private onStreamEvent;
99
192
  private pendingFrame;
@@ -138,8 +231,7 @@ declare class ApiClient {
138
231
  forgetSession(): void;
139
232
  history(agent: string, conversationId: string): Promise<HistoryMessage[]>;
140
233
  /** Sends a message and calls `onEvent` for every streamed event. Resolves when the run ends. */
141
- chat(input: {
142
- message: string;
234
+ chat(input: ChatRequestBody & {
143
235
  agent: string;
144
236
  conversationId: string;
145
237
  }, onEvent: (e: ChatStreamEvent) => void, signal?: AbortSignal): Promise<void>;
@@ -158,4 +250,4 @@ declare global {
158
250
  }
159
251
  }
160
252
 
161
- export { ApiClient, type ApiClientOptions, ApiError, ChatStreamEvent, type DeweeChatConfig, DeweeChatElement, HistoryMessage, PublicConfig, SessionResponse, defineDeweeChat, mount, renderMarkdown };
253
+ export { type ActionCallStatus, type ActionCallView, type ActionConfirmHook, type ActionEventDetail, type ActionResult, type ActionResultStatus, ActionSensitivity, ApiClient, type ApiClientOptions, ApiError, ChatRequestBody, ChatStreamEvent, type DeweeChatConfig, DeweeChatElement, HistoryMessage, type JsonSchema, type PageAction, type PageActionContext, type PageActionInfo, PublicConfig, SessionResponse, defineDeweeChat, mount, renderMarkdown };
package/dist/index.js CHANGED
@@ -5,8 +5,8 @@ import {
5
5
  defineDeweeChat,
6
6
  mount,
7
7
  renderMarkdown
8
- } from "./chunk-D4JM2FOB.js";
9
- import "./chunk-WD6V3TAX.js";
8
+ } from "./chunk-YV6PXYJZ.js";
9
+ import "./chunk-JX6AH37X.js";
10
10
  export {
11
11
  ApiClient,
12
12
  ApiError,
@@ -4,6 +4,7 @@ type ChatStreamEvent = {
4
4
  runId?: string;
5
5
  conversationId: string;
6
6
  agent: string;
7
+ actionsHash?: string;
7
8
  } | {
8
9
  type: "thinking";
9
10
  text: string;
@@ -67,5 +68,25 @@ interface HistoryMessage {
67
68
  toolCalls?: ToolCallView[];
68
69
  createdAt?: string;
69
70
  }
71
+ /** How much an agent-invoked page action can change. `mutate`/`destructive` always need user approval. */
72
+ type ActionSensitivity = "read" | "navigate" | "mutate" | "destructive";
73
+ /** What the backend (and the agent) learns about a page action. Handlers never leave the browser. */
74
+ interface ActionManifestEntry {
75
+ name: string;
76
+ description: string;
77
+ /** JSON Schema subset describing `args` (object). */
78
+ parameters: Record<string, unknown>;
79
+ sensitivity: ActionSensitivity;
80
+ }
81
+ /** Body of `POST {basePath}/chat`. `actions`/`actionsHash`/`pageContext` are optional (page actions). */
82
+ interface ChatRequestBody {
83
+ message: string;
84
+ agent?: string;
85
+ conversationId?: string;
86
+ actions?: ActionManifestEntry[];
87
+ /** Hash from the `start` event of the last completed turn; the manifest is re-sent to the agent only when it differs. */
88
+ actionsHash?: string;
89
+ pageContext?: unknown;
90
+ }
70
91
 
71
- export type { AgentInfo as A, ChatStreamEvent as C, HistoryMessage as H, PublicConfig as P, SessionResponse as S, ToolCallView as T };
92
+ export type { AgentInfo as A, ChatStreamEvent as C, HistoryMessage as H, PublicConfig as P, SessionResponse as S, ToolCallView as T, ActionManifestEntry as a, ActionSensitivity as b, ChatRequestBody as c };
package/dist/react.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import * as react from 'react';
2
2
  import { CSSProperties } from 'react';
3
- import { DeweeChatConfig, DeweeChatElement } from './index.js';
4
- import './protocol-CS8_4zC0.js';
3
+ import { DeweeChatConfig, ActionEventDetail, DeweeChatElement } from './index.js';
4
+ export { ActionConfirmHook, PageAction, PageActionContext } from './index.js';
5
+ import './protocol-B72Ry-fY.js';
5
6
 
6
7
  interface DeweeChatProps extends Partial<DeweeChatConfig> {
7
8
  className?: string;
@@ -12,6 +13,8 @@ interface DeweeChatProps extends Partial<DeweeChatConfig> {
12
13
  onError?: (e: CustomEvent) => void;
13
14
  onOpen?: (e: CustomEvent) => void;
14
15
  onClose?: (e: CustomEvent) => void;
16
+ /** Page action telemetry (`dewee:action`, detail: ActionEventDetail). */
17
+ onAction?: (e: CustomEvent<ActionEventDetail>) => void;
15
18
  }
16
19
  declare const DeweeChat: react.ForwardRefExoticComponent<DeweeChatProps & react.RefAttributes<DeweeChatElement | null>>;
17
20
 
@@ -23,4 +26,4 @@ declare module "react" {
23
26
  }
24
27
  }
25
28
 
26
- export { DeweeChat, DeweeChatConfig, DeweeChatElement, type DeweeChatProps, DeweeChat as default };
29
+ export { ActionEventDetail, DeweeChat, DeweeChatConfig, DeweeChatElement, type DeweeChatProps, DeweeChat as default };
package/dist/react.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  defineDeweeChat
3
- } from "./chunk-D4JM2FOB.js";
4
- import "./chunk-WD6V3TAX.js";
3
+ } from "./chunk-YV6PXYJZ.js";
4
+ import "./chunk-JX6AH37X.js";
5
5
 
6
6
  // src/react.ts
7
7
  import { createElement, forwardRef, useEffect, useImperativeHandle, useRef } from "react";
@@ -11,12 +11,13 @@ var EVENTS = {
11
11
  onReply: "dewee:reply",
12
12
  onError: "dewee:error",
13
13
  onOpen: "dewee:open",
14
- onClose: "dewee:close"
14
+ onClose: "dewee:close",
15
+ onAction: "dewee:action"
15
16
  };
16
17
  var DeweeChat = forwardRef(function DeweeChat2(props, ref) {
17
18
  const el = useRef(null);
18
- const { className, style, onReady, onSend, onReply, onError, onOpen, onClose, ...config } = props;
19
- const handlers = { onReady, onSend, onReply, onError, onOpen, onClose };
19
+ const { className, style, onReady, onSend, onReply, onError, onOpen, onClose, onAction, actions, confirm, getPageContext, ...config } = props;
20
+ const handlers = { onReady, onSend, onReply, onError, onOpen, onClose, onAction };
20
21
  const handlersRef = useRef(handlers);
21
22
  handlersRef.current = handlers;
22
23
  useImperativeHandle(ref, () => el.current, []);
@@ -25,6 +26,10 @@ var DeweeChat = forwardRef(function DeweeChat2(props, ref) {
25
26
  defineDeweeChat();
26
27
  el.current?.configure(JSON.parse(configKey));
27
28
  }, [configKey]);
29
+ useEffect(() => {
30
+ defineDeweeChat();
31
+ el.current?.configure({ actions, confirm, getPageContext });
32
+ });
28
33
  useEffect(() => {
29
34
  const node = el.current;
30
35
  if (!node) return;