dewee-webchat 0.1.1 → 0.3.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.
- package/README.md +92 -3
- package/astro/DeweeChat.astro +21 -21
- package/dist/chunk-W6A4HVFB.js +111 -0
- package/dist/{chunk-D4JM2FOB.js → chunk-ZTVGWFXL.js} +650 -33
- package/dist/dewee-webchat.js +85 -14
- package/dist/index.d.ts +157 -41
- package/dist/index.js +4 -2
- package/dist/{protocol-CS8_4zC0.d.ts → protocol-B72Ry-fY.d.ts} +22 -1
- package/dist/react.d.ts +6 -3
- package/dist/react.js +10 -5
- package/dist/server.d.ts +27 -3
- package/dist/server.js +28 -5
- package/dist/vue.d.ts +67 -3
- package/dist/vue.js +14 -5
- package/package.json +1 -1
- package/dist/chunk-WD6V3TAX.js +0 -10
package/dist/dewee-webchat.js
CHANGED
|
@@ -1,13 +1,42 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
1
|
+
"use strict";(()=>{var W=Object.defineProperty;var bt=(i,s,t)=>s in i?W(i,s,{enumerable:!0,configurable:!0,writable:!0,value:t}):i[s]=t;var xt=(i,s)=>{for(var t in s)W(i,t,{get:s[t],enumerable:!0})};var h=(i,s,t)=>bt(i,typeof s!="symbol"?s+"":s,t);var G={};xt(G,{ApiClient:()=>E,ApiError:()=>v,DeweeChatElement:()=>P,RESERVED_HEADERS:()=>K,defineDeweeChat:()=>F,mount:()=>Dt,renderMarkdown:()=>S});var Y="dewee-action",Z="dewee-action-result",L={maxCalls:8,maxBlockBytes:8192},yt=/^[A-Za-z0-9_.:-]{1,64}$/,vt=/^\s{0,3}```\s*$/,Q=i=>new RegExp("^\\s{0,3}```"+i.replace(/[.-]/g,"\\$&")+"\\s*$"),X=Q(Y),tt=Q(Z);function N(i,s){let t=[];for(let n=0;n<i.length;n++){if(!s.test(i[n]))continue;let e=n,r=[],o=!1;for(n++;n<i.length;n++){if(vt.test(i[n])){o=!0;break}r.push(i[n])}t.push({start:e,end:Math.min(n,i.length-1),body:r,closed:o})}return t}var et=(i,s)=>{let t=new Set;for(let n of s)for(let e=n.start;e<=n.end;e++)t.add(e);return i.filter((n,e)=>!t.has(e)).join(`
|
|
2
|
+
`).replace(/\n{3,}/g,`
|
|
2
3
|
|
|
3
|
-
`)
|
|
4
|
-
`).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,`
|
|
4
|
+
`).trim()};function _(i){let s=i.replace(/\r\n?/g,`
|
|
6
5
|
`).split(`
|
|
7
|
-
`),
|
|
8
|
-
`),
|
|
9
|
-
`)
|
|
10
|
-
`)
|
|
6
|
+
`),t=N(s,X),n=[],e=new Set;return t.forEach((r,o)=>{let a=`call-${o+1}`,c=r.body.join(`
|
|
7
|
+
`),l=(m,w=a,b="")=>n.push({ok:!1,id:w,name:b,error:m});if(o>=L.maxCalls)return l(`Too many action calls in one reply (max ${L.maxCalls})`);if(!r.closed)return l("Unclosed dewee-action block");if(new TextEncoder().encode(c).length>L.maxBlockBytes)return l(`Action block exceeds ${L.maxBlockBytes} bytes`);let d;try{d=JSON.parse(c)}catch{return l("Action block is not valid JSON")}if(typeof d!="object"||d===null||Array.isArray(d))return l("Action block must be a JSON object");let g=typeof d.id=="string"&&yt.test(d.id)?d.id:a,p=typeof d.name=="string"?d.name.slice(0,64):"";if(e.has(g))return l(`Duplicate action call id "${g}"`,`${g}-${o+1}`,p);if(e.add(g),!p)return l("Action name is required",g);let u=d.args??{};if(typeof u!="object"||u===null||Array.isArray(u))return l("args must be a JSON object",g,p);n.push({ok:!0,id:g,name:p,args:u})}),{text:t.length?et(s,t):i,calls:n}}function nt(i){if(!i.includes("```"+Y))return i;let s=i.replace(/\r\n?/g,`
|
|
8
|
+
`).split(`
|
|
9
|
+
`);return et(s,N(s,X))}function O(i){return tt.test(i.trimStart().split(`
|
|
10
|
+
`,1)[0]??"")}function it(i){let s=i.replace(/\r\n?/g,`
|
|
11
|
+
`).split(`
|
|
12
|
+
`),t=[];for(let n of N(s,tt))try{let e=JSON.parse(n.body.join(`
|
|
13
|
+
`));e&&typeof e.id=="string"&&["ok","denied","error"].includes(e.status)&&t.push(e)}catch{}return t}var R=i=>"```"+Z+`
|
|
14
|
+
`+JSON.stringify(i)+"\n```";function st(i,s=4e3){let t=Math.max(64,Math.floor((s-16)/Math.max(1,i.length)));return i.map(e=>{let r={...e,result:B(e.result)};if(r.result===void 0&&delete r.result,R(r).length<=t)return R(r);let o=JSON.stringify(r.result??null),a=t-R({...r,result:{truncated:!0,preview:""}}).length-8,c=R({...r,result:{truncated:!0,preview:o.slice(0,Math.max(0,a))}});return c.length<=t?c:R({id:e.id,name:e.name.slice(0,64),status:e.status,result:{truncated:!0}})}).join(`
|
|
15
|
+
|
|
16
|
+
`).slice(0,s)}function B(i){if(i!==void 0)try{let s=JSON.stringify(i);return s===void 0?null:JSON.parse(s)}catch{return"[unserializable result]"}}var D=i=>i===null?"null":Array.isArray(i)?"array":typeof i=="number"?Number.isInteger(i)?"integer":"number":typeof i,kt=(i,s)=>{let t=D(i);return t===s||s==="number"&&t==="integer"};function I(i,s,t="args",n=0){if(!s||typeof s!="object")return null;if(n>32)return`${t}: schema is nested too deeply`;let e=s;if(e.type!==void 0){let r=Array.isArray(e.type)?e.type:[e.type];if(!r.some(o=>kt(i,o)))return`${t}: expected ${r.join(" or ")}, got ${D(i)}`}if(Array.isArray(e.enum)&&!e.enum.some(r=>rt(r,i)))return`${t}: must be one of ${e.enum.map(r=>JSON.stringify(r)).join(", ")}`;if("const"in e&&!rt(e.const,i))return`${t}: must equal ${JSON.stringify(e.const)}`;if(typeof i=="string"){if(typeof e.minLength=="number"&&i.length<e.minLength)return`${t}: shorter than ${e.minLength} characters`;if(typeof e.maxLength=="number"&&i.length>e.maxLength)return`${t}: longer than ${e.maxLength} characters`;if(typeof e.pattern=="string"){let r=null;try{r=new RegExp(e.pattern,"u")}catch{return`${t}: schema pattern is invalid`}if(!r.test(i))return`${t}: does not match ${e.pattern}`}}if(typeof i=="number"){if(typeof e.minimum=="number"&&i<e.minimum)return`${t}: must be >= ${e.minimum}`;if(typeof e.maximum=="number"&&i>e.maximum)return`${t}: must be <= ${e.maximum}`}if(Array.isArray(i)){if(typeof e.minItems=="number"&&i.length<e.minItems)return`${t}: needs at least ${e.minItems} items`;if(typeof e.maxItems=="number"&&i.length>e.maxItems)return`${t}: allows at most ${e.maxItems} items`;if(e.items&&typeof e.items=="object")for(let r=0;r<i.length;r++){let o=I(i[r],e.items,`${t}[${r}]`,n+1);if(o)return o}}if(D(i)==="object"){let r=i,o=e.properties&&typeof e.properties=="object"?e.properties:{};for(let a of Array.isArray(e.required)?e.required:[])if(!(a in r))return`${t}.${a}: is required`;for(let[a,c]of Object.entries(r))if(Object.prototype.hasOwnProperty.call(o,a)){let l=I(c,o[a],`${t}.${a}`,n+1);if(l)return l}else if(e.additionalProperties===!1)return`${t}.${a}: is not allowed`}return null}function rt(i,s){return JSON.stringify(i)===JSON.stringify(s)}var at=/^[a-z][a-z0-9_.-]{0,63}$/,z=["read","navigate","mutate","destructive"],C={maxActions:32,maxDescription:1e3,maxParametersBytes:4096,maxManifestBytes:16384,maxPageContextBytes:4096},Ct="[[dewee-page v1]]",ot="[[/dewee-page]]";function j(i){if(!i.startsWith(Ct))return i;let s=i.indexOf(`
|
|
17
|
+
`+ot);return s<0?i:i.slice(s+ot.length+1).replace(/^\n+/,"")}var At=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 n of t)Et(n);if(new Set([...this.map.keys(),...t.map(n=>n.name)]).size>C.maxActions)throw new TypeError(`dewee-webchat: at most ${C.maxActions} page actions`);for(let n of t)this.map.set(n.name,n)}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 Et(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"||!at.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`),z.includes(i.sensitivity)||s(`sensitivity must be one of ${z.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 ct(i,s){let t=c=>(s.onStatus?.("error"),{id:i.id,name:i.name,status:"error",error:c});if(!i.ok)return t(i.error);if(s.signal.aborted)return t("Cancelled");let n=s.registry.get(i.name);if(!n)return t(`Unknown action "${i.name}". Available: ${s.registry.names().join(", ")||"none"}`);let e=I(i.args,n.parameters??{type:"object"});if(e)return t(`Invalid arguments: ${e}`);if(At(n.sensitivity)){s.onStatus?.("awaiting-confirmation");let{handler:c,...l}=n,d=!1;try{d=await lt(Promise.resolve(s.confirm({...l,callId:i.id},i.args)),s.signal)===!0}catch{d=!1}if(!d||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 c=await lt(Promise.resolve().then(()=>n.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:B(c)??null}}catch(c){return t(r.signal.aborted?s.signal.aborted?"Cancelled":"Timed out":String(c?.message??c).slice(0,500)||"Action failed")}finally{clearTimeout(a),s.signal.removeEventListener("abort",o)}}function lt(i,s){return s.aborted?Promise.reject(new Error("aborted")):new Promise((t,n)=>{let e=()=>n(new Error("aborted"));s.addEventListener("abort",e,{once:!0}),i.then(t,n).finally(()=>s.removeEventListener("abort",e))})}var q="x-dewee-gateway-url",J="x-dewee-gateway-token";var K=["content-type","authorization",q,J],v=class extends Error{constructor(t,n,e){super(t);h(this,"status",n);h(this,"code",e)}},V={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{}}},E=class{constructor(s){h(this,"o",s);h(this,"session",null);h(this,"config",null);h(this,"sessionPromise",null)}url(s,t){let n=this.o.endpoint.replace(/\/+$/,""),e=t?"?"+new URLSearchParams(t).toString():"";return`${n}/${s}${e}`}get storageKey(){return`dewee-webchat:session:${this.o.endpoint}`}fresh(s){let t=s.obtainedAt?s.expiresAt-s.obtainedAt:1/0,n=Math.min(864e5,Math.max(3e4,t*.1));return s.expiresAt-Date.now()>n}request(s,t){return(this.o.fetch??globalThis.fetch)(s,t)}async headers(s=!1){let t={},n=typeof this.o.headers=="function"?await this.o.headers():this.o.headers;for(let[e,r]of Object.entries(n??{}))typeof r=="string"&&!K.includes(e.toLowerCase())&&(t[e.toLowerCase()]=r);return t["content-type"]="application/json",this.o.gatewayUrl&&this.o.gatewayToken&&(t[q]=this.o.gatewayUrl,t[J]=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 this.request(this.url("config"),{headers:await this.headers()})),this.config)}ensureSession(){if(this.session&&this.fresh(this.session))return Promise.resolve(this.session);if(!this.session){let s=V.get(this.storageKey);if(s)try{let t=JSON.parse(s);if(this.fresh(t))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 n=await this.parse(await this.request(this.url("session"),{method:"POST",headers:await this.headers(),body:JSON.stringify(t)}));return this.session={...n,obtainedAt:Date.now()},V.set(this.storageKey,JSON.stringify(this.session)),this.session}forgetSession(){this.session=null,V.del(this.storageKey)}async history(s,t){await this.ensureSession();let n=await this.request(this.url("history",{agent:s,conversationId:t}),{headers:await this.headers(!0)});return(await this.parse(n)).messages}async chat(s,t,n){await this.ensureSession();let e=await this.request(this.url("chat"),{method:"POST",headers:await this.headers(!0),body:JSON.stringify(s),signal:n});e.status===401&&(this.forgetSession(),await this.ensureSession(),e=await this.request(this.url("chat"),{method:"POST",headers:await this.headers(!0),body:JSON.stringify(s),signal:n})),(!e.ok||!e.body)&&await this.parse(e);let r=e.body.pipeThrough(new TextDecoderStream).getReader(),o="";for(;;){let{done:a,value:c}=await r.read();if(a)break;o+=c;let l;for(;(l=o.indexOf(`
|
|
18
|
+
|
|
19
|
+
`))>=0;){let d=o.slice(0,l);o=o.slice(l+2);let g=d.split(`
|
|
20
|
+
`).filter(p=>p.startsWith("data:")).map(p=>p.slice(5).trimStart()).join(`
|
|
21
|
+
`);if(g)try{t(JSON.parse(g))}catch{}}}}};var St=0;function dt(i,s,t,n,e){let r=`dw-confirm-${++St}`,o=i.getRootNode(),a=o.activeElement,c=document.createElement("div");c.className="confirm-backdrop",c.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 l=w=>c.querySelector(w);l("h3").textContent=s.confirmTitle,l("code").textContent=t.name;let d=l(".sens");if(d.textContent=t.sensitivity,d.dataset.level=t.sensitivity,l(".confirm-text").textContent=t.description,t.sensitivity==="destructive"){let w=l(".confirm-warn");w.hidden=!1,w.textContent=s.confirmDestructive}let g=JSON.stringify(n,null,2),p=l(".confirm-args");g&&g!=="{}"?p.textContent=g:p.remove();let u=l(".deny"),m=l(".allow");return u.textContent=s.deny,m.textContent=s.allow,t.sensitivity==="destructive"&&m.classList.add("danger"),new Promise(w=>{let b=!1,y=A=>{b||(b=!0,e?.removeEventListener("abort",M),c.remove(),a?.focus?.(),w(A))},M=()=>y(!1);if(e?.aborted)return y(!1);e?.addEventListener("abort",M,{once:!0}),u.addEventListener("click",()=>y(!1)),m.addEventListener("click",()=>y(!0)),c.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(c),u.focus()})}var Tt={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.`},Mt={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 U(i){return(i||(typeof document<"u"?document.documentElement.lang:"")||(typeof navigator<"u"?navigator.language:"")||"en").toLowerCase().startsWith("vi")?Mt:Tt}var x={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 n=i.createElement(s);return t&&(n.className=t),n}function Rt(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 n=new RegExp(Pt.source,"g"),e=0;for(let r;r=n.exec(s);)if(r.index>e&&t.appendChild(i.createTextNode(s.slice(e,r.index))),e=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=Rt(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)}e<s.length&&t.appendChild(i.createTextNode(s.slice(e)))}var pt=i=>/^\s*\|?\s*:?-{2,}:?\s*(\|\s*:?-{2,}:?\s*)*\|?\s*$/.test(i),gt=i=>i.trim().replace(/^\||\|$/g,"").split("|").map(s=>s.trim());function S(i,s){let t=i.createDocumentFragment(),n=s.replace(/\r\n?/g,`
|
|
35
|
+
`).split(`
|
|
36
|
+
`),e=0;for(;e<n.length;){let r=n[e];if(!r.trim()){e++;continue}let o=r.match(/^\s*(```+|~~~+)\s*([\w+-]*)/);if(o){let g=[];for(e++;e<n.length&&!n[e].trim().startsWith(o[1]);)g.push(n[e++]);e++;let p=f(i,"pre"),u=f(i,"code");o[2]&&(u.dataset.lang=o[2]),u.textContent=g.join(`
|
|
37
|
+
`),p.appendChild(u),t.appendChild(p);continue}let a=r.match(/^(#{1,6})\s+(.*)$/);if(a){let g=`h${Math.min(6,a[1].length+2)}`,p=f(i,g);k(i,a[2],p),t.appendChild(p),e++;continue}if(/^\s*([-*_])(\s*\1){2,}\s*$/.test(r)){t.appendChild(f(i,"hr")),e++;continue}if(r.includes("|")&&e+1<n.length&&pt(n[e+1])){let g=f(i,"div","table"),p=f(i,"table"),u=f(i,"thead"),m=f(i,"tr");for(let b of gt(r)){let y=f(i,"th");k(i,b,y),m.appendChild(y)}u.appendChild(m),p.appendChild(u);let w=f(i,"tbody");for(e+=2;e<n.length&&n[e].includes("|")&&n[e].trim();){let b=f(i,"tr");for(let y of gt(n[e])){let M=f(i,"td");k(i,y,M),b.appendChild(M)}w.appendChild(b),e++}p.appendChild(w),g.appendChild(p),t.appendChild(g);continue}if(/^\s*>/.test(r)){let g=[];for(;e<n.length&&/^\s*>/.test(n[e]);)g.push(n[e++].replace(/^\s*>\s?/,""));let p=f(i,"blockquote");p.appendChild(S(i,g.join(`
|
|
38
|
+
`))),t.appendChild(p);continue}let c=r.match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);if(c){let g=/\d/.test(c[2]),p=f(i,g?"ol":"ul");g&&parseInt(c[2],10)!==1&&p.setAttribute("start",String(parseInt(c[2],10)));let u=c[1].length;for(;e<n.length;){let m=n[e].match(/^(\s*)([-*+]|\d+[.)])\s+(.*)$/);if(!m||m[1].length<u||/\d/.test(m[2])!==g)break;if(m[1].length>u){let b=[];for(;e<n.length&&/^\s+/.test(n[e])&&n[e].match(/^(\s*)/)[1].length>u;)b.push(n[e++].slice(u+2));p.lastElementChild?.appendChild(S(i,b.join(`
|
|
39
|
+
`)));continue}let w=f(i,"li");k(i,m[3],w),p.appendChild(w),e++}t.appendChild(p);continue}let l=[];for(;e<n.length&&n[e].trim()&&!/^\s*(```|~~~|#{1,6}\s|>|([-*+]|\d+[.)])\s)/.test(n[e])&&!(n[e].includes("|")&&e+1<n.length&&pt(n[e+1]));)l.push(n[e++]);l.length||l.push(n[e++]);let d=f(i,"p");l.forEach((g,p)=>{p&&d.appendChild(f(i,"br")),k(i,g,d)}),t.appendChild(d)}return t}var ht=`
|
|
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>${
|
|
304
|
+
`;var wt=["show-reasoning","show-tool-calls","allow-agent-switch","open","persist","hide-branding","launcher-avatar"],ut=["endpoint","agent","title","subtitle","greeting","intro","placeholder","suggestions","avatar","position","mode","theme","accent-color","locale","gateway-url","gateway-token","width","height","z-index",...wt],ft=i=>i.replace(/-([a-z])/g,(s,t)=>t.toUpperCase()),Lt=i=>i!==null&&!/^(false|0|off|no)$/i.test(i),mt=()=>{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{}}},$t=null;function Ht(){return $t??($t=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,P=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",U());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 ut}get config(){let t={endpoint:"/api/dewee"};for(let n of ut){let e=this.getAttribute(n);e!==null&&(wt.includes(n)?t[ft(n)]=Lt(e):n==="suggestions"?t.suggestions=e.trim().startsWith("[")?Ot(e,[]):e.split("|").map(r=>r.trim()).filter(Boolean):n==="z-index"?t.zIndex=Number(e):t[ft(n)]=e)}return{...t,...this.overrides,...this.hooks}}configure(t){let{actions:n,confirm:e,getPageContext:r,headers:o,fetch:a,...c}=t,l=d=>Object.prototype.hasOwnProperty.call(t,d);l("actions")&&this.setPropActions(n??[]),l("confirm")&&(this.hooks.confirm=e),l("getPageContext")&&(this.hooks.getPageContext=r),l("headers")&&(this.hooks.headers=o),l("fetch")&&(this.hooks.fetch=a),Object.keys(c).length&&(this.overrides={...this.overrides,...c},this.els&&this.applyConfig())}registerActions(t){this.registry.register(t)}unregisterAction(t){return this.propActionNames.delete(t),this.registry.unregister(t)}get headers(){return this.hooks.headers}set headers(t){this.hooks.headers=t}get fetch(){return this.hooks.fetch}set fetch(t){this.hooks.fetch=t}get actionNames(){return this.registry.names()}setPropActions(t){let n=new Set(t.map(e=>e.name));for(let e of this.propActionNames)n.has(e)||this.registry.unregister(e);t.length&&this.registry.register(t),this.propActionNames=n}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 n=t.trim();if(!n||this.running)return;this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.open(),await this.activate(),this.els.input.value="",this.autosize();let e={message:n,hidden:!1};for(let r=0;e;r++){let o=await this.runTurn(e.message,e.hidden);if(e=null,o.status!=="done"||o.stopped||!this.registry.size)break;let{calls:a}=_(o.content);if(!a.length)break;o.actions=a.map(d=>({id:d.id,name:d.name,args:d.ok?d.args:void 0,status:"pending"}));let c=this.config.maxActionRounds??5;if(r>=c){for(let d of o.actions)Object.assign(d,{status:"error",error:"Automatic action limit reached"});this.updateMessage(o),this.showNotice(this.strings.actionLimit(c));break}this.updateMessage(o);let l=await this.runActions(o,a);l&&(e={message:st(l,this.server?.maxMessageLength??4e3),hidden:!0})}}async runTurn(t,n){this.pushMessage({role:"user",content:t,hidden:n});let e={role:"assistant",content:"",status:"streaming",startedAt:Date.now()};this.pushMessage(e),this.setRunning(new AbortController),this.emit("dewee:send",{message:t,agent:this.agentId,conversationId:this.conversationId,auto:n||void 0});try{await this.client().chat(this.chatBody(t),r=>this.onStreamEvent(e,r),this.running.signal),e.status==="streaming"&&(e.status="done")}catch(r){r.name==="AbortError"?(e.status="done",e.stopped=!0,e.content||(e.content=`_${this.strings.stopped}_`)):(e.status="error",this.showError(e,r))}finally{this.finishThinking(e),this.updateMessage(e),this.setRunning(null),e.status==="done"&&(e.actionsHash&&!e.stopped&&this.setAck(e.actionsHash),this.emit("dewee:reply",{content:e.content,agent:this.agentId,conversationId:this.conversationId}),this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.setAttribute("data-unread",""))}return e}chatBody(t){let n={message:t,agent:this.agentId,conversationId:this.conversationId};if(this.registry.size){n.actions=this.registry.manifest();let r=this.getAck();r&&(n.actionsHash=r)}let e=this.pageContext();return e!==void 0&&(n.pageContext=e),n}pageContext(){let t=this.hooks.getPageContext;if(t)try{let n=t();if(n==null)return;let e=new TextEncoder().encode(JSON.stringify(n)).length;return e<=C.maxPageContextBytes?n:(console.warn(`[dewee-webchat] getPageContext() returned ${e} bytes; the limit is ${C.maxPageContextBytes}. Context not sent.`),{truncated:!0})}catch(n){console.warn("[dewee-webchat] getPageContext() failed:",n);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,n){let e=new AbortController;this.setRunning(e);let r=[],o={agent:this.agentId,conversationId:this.conversationId};try{for(let[a,c]of n.entries()){let l=t.actions[a],d=c.ok?this.registry.get(c.name)?.sensitivity:void 0,g=c.ok?c.args:void 0;this.emit("dewee:action",{phase:"start",id:c.id,name:c.name,sensitivity:d,args:g,...o});let p=await ct(c,{registry:this.registry,confirm:(u,m)=>this.confirmAction(u,m,e.signal),signal:e.signal,timeoutMs:this.config.actionTimeoutMs,...o,onStatus:u=>{l.status=u,this.updateMessage(t)}});p.error&&(l.error=p.error),this.updateMessage(t),r.push(p),this.emit("dewee:action",{phase:"result",id:p.id,name:p.name,sensitivity:d,args:g,status:p.status,result:p.result,error:p.error,...o})}}finally{this.setRunning(null)}return e.signal.aborted?null:r}confirmAction(t,n,e){return this.hooks.confirm?this.hooks.confirm(t,n):(this.config.mode!=="inline"&&!this.hasAttribute("data-open")&&this.open(),dt(this.els.panel,this.strings,t,n,e))}showNotice(t){let n=document.createElement("div");n.className="notice",n.setAttribute("role","status"),n.textContent=t,this.els.log.appendChild(n),this.scrollToBottom(!0)}stop(){this.running?.abort()}newConversation(){this.stop(),this.conversationId=mt(),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,n){this.dispatchEvent(new CustomEvent(t,{detail:n,bubbles:!0,composed:!0}))}client(){let t=this.config,n=[t.endpoint,t.gatewayUrl,t.gatewayToken].join("|");return(!this.api||n!==this.apiKey)&&(this.apiKey=n,this.api=new E({endpoint:t.endpoint,gatewayUrl:t.gatewayUrl,gatewayToken:t.gatewayToken,turnstile:e=>this.challenge(e),headers:()=>{let e=this.hooks.headers;return(typeof e=="function"?e():e)??{}},fetch:(e,r)=>(this.hooks.fetch??globalThis.fetch)(e,r)})),this.api}convKey(){return`dewee-webchat:conv:${this.config.endpoint}:${this.config.gatewayUrl||""}:${this.agentId}`}applyTheme(){let t=this.config.theme||"light",n=t==="dark"||t==="auto"&&!!this.mql?.matches;this.setAttribute("data-theme",n?"dark":"light")}applyConfig(){let t=this.config;this.strings=U(t.locale);let n=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 e=(o,a)=>a!==void 0&&a!==""?this.style.setProperty(o,String(a)):this.style.removeProperty(o);e("--dw-accent",t.accentColor),e("--dw-width",t.width),e("--dw-height",t.height),e("--dw-z",t.zIndex);let r=this.els;if(r.title.textContent=t.title||n.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||n.title).trim().charAt(0).toUpperCase();if(r.launcher.innerHTML=t.avatar&&t.launcherAvatar?"":x.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",n.open),r.close.setAttribute("aria-label",n.close),r.close.title=n.close,r.newChat.setAttribute("aria-label",n.newChat),r.newChat.title=n.newChat,r.input.placeholder=t.placeholder||n.placeholder,r.foot.hidden=!!t.hideBranding,r.foot.querySelector(".by").textContent=n.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>${ht}</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">${
|
|
245
|
-
<button class="icon-btn close">${
|
|
314
|
+
<button class="icon-btn new">${x.newChat}</button>
|
|
315
|
+
<button class="icon-btn close">${x.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
|
|
326
|
+
</section>`;let t=e=>this.root.querySelector(e);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 n=this.els;n.launcher.addEventListener("click",()=>this.toggle()),n.close.addEventListener("click",()=>this.close()),n.log.addEventListener("scroll",()=>{this.following=this.nearBottom()},{passive:!0}),n.newChat.addEventListener("click",()=>this.newConversation()),n.select.addEventListener("change",()=>this.switchAgent(n.select.value)),t("form").addEventListener("submit",e=>{e.preventDefault(),this.running?this.stop():this.send(n.input.value)}),n.input.addEventListener("keydown",e=>{e.key==="Enter"&&!e.shiftKey&&!e.isComposing&&e.keyCode!==229&&(e.preventDefault(),this.running||this.send(n.input.value))}),n.input.addEventListener("input",()=>{this.autosize(),this.updateSendButton()}),n.panel.addEventListener("keydown",e=>{e.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?x.stop:x.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,n=this.config,e=this.server?.agents??[],r=n.allowAgentSwitch!==!1&&!!this.server?.allowAgentSwitch&&e.length>1;t.select.hidden=!r,t.status.hidden=r,r&&(t.select.replaceChildren(...e.map(a=>new Option(a.name||a.id,a.id,!1,a.id===this.agentId))),t.select.setAttribute("aria-label","Agent"));let o=e.find(a=>a.id===this.agentId);t.status.textContent=n.subtitle||(o?.name&&o.name!==n.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,n=e=>!!e&&(this.server.agents.length===0||this.server.agents.some(r=>r.id===e));this.agentId=n(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,n=t?T.get(this.convKey()):null;if(this.conversationId=n||mt(),t&&!n&&T.set(this.convKey(),this.conversationId),this.messages=[],this.renderLog(),!!n)try{let e=await this.client().history(this.agentId,this.conversationId);this.messages=_t(e.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 n of this.messages)t.appendChild(this.renderMessage(n));t.scrollTop=t.scrollHeight}renderWelcome(){let t=this.config,n=this.strings,e=document.createElement("div");e.className="welcome";let r=document.createElement("h2");r.textContent=t.greeting||n.greeting;let o=document.createElement("p");if(o.textContent=t.intro||n.greetingBody,e.append(r,o),t.suggestions?.length){let a=document.createElement("div");a.className="suggestions";for(let c of t.suggestions){let l=document.createElement("button");l.className="chip",l.type="button",l.textContent=c,l.addEventListener("click",()=>this.send(c)),a.appendChild(l)}e.appendChild(a)}return e}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 n=document.createElement("div");n.className=`msg ${t.role}${t.status==="error"?" error":""}`,n.hidden=!!t.hidden;let e=document.createElement("div");e.className="bubble",n.appendChild(e);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"&&e.appendChild(r),e.appendChild(o),t.role==="assistant"&&e.appendChild(a),t.view={root:n,trace:r,md:o,tools:new Map,actions:a},this.updateMessage(t),n}updateMessage(t){let n=t.view;if(!n)return;let e=this.config;if(t.role==="user"){n.md.textContent=t.content;return}if(n.root.classList.toggle("error",t.status==="error"),e.showReasoning!==!1&&t.thinking){n.thinking||(n.thinking=document.createElement("details"),n.thinking.className="thinking",n.thinking.innerHTML='<summary></summary><div class="thinking-body"></div>',n.trace.prepend(n.thinking));let a=t.status==="streaming"&&!t.thinkingMs,c=a?this.strings.thinking:t.thinkingMs?this.strings.thoughtFor(Math.max(1,Math.round(t.thinkingMs/1e3))):this.strings.reasoning,l=n.thinking.querySelector("summary");l.innerHTML=`${a?'<span class="spin"></span>':x.brain}<span></span>${x.down.replace("<svg",'<svg class="chev"')}`,l.querySelector("span:not(.spin)").textContent=c,n.thinking.querySelector(".thinking-body").textContent=t.thinking}else n.thinking&&(n.thinking.remove(),n.thinking=void 0);if(e.showToolCalls!==!1)for(let a of t.toolCalls??[])this.renderTool(n,a);else n.tools.forEach(a=>a.remove()),n.tools.clear();n.trace.hidden=!n.trace.childElementCount;let r=this.registry.size||t.actions?nt(t.content):t.content,o=t.status==="streaming"&&!r;n.md.hidden=!o&&!r&&!!t.actions?.length,o?n.md.innerHTML=`<span class="typing" aria-label="${this.strings.thinking}"><i></i><i></i><i></i></span>`:(n.md.replaceChildren(S(document,r)),n.md.classList.toggle("cursor",t.status==="streaming")),this.renderActions(n,t.actions??[])}renderActions(t,n){t.actions.hidden=!n.length,t.actions.replaceChildren(...n.map(e=>{let r=document.createElement("div");r.className="action",r.dataset.status=e.status;let o=e.status==="running"||e.status==="awaiting-confirmation";r.innerHTML=`${o?'<span class="spin"></span>':x.action}<span class="action-name"></span><span class="action-state"></span>`,r.querySelector(".action-name").textContent=e.name||"?",r.querySelector(".action-state").textContent=this.strings.actionStatus[e.status];let a=[e.args&&Object.keys(e.args).length?JSON.stringify(e.args):"",e.error??""].filter(Boolean).join(`
|
|
327
|
+
`);return a&&(r.title=a),r}))}renderTool(t,n){let e=t.tools.get(n.id);e||(e=document.createElement("details"),e.className="tool",e.innerHTML=`<summary><span class="lead"></span><span class="tool-name"></span><span class="tool-state"></span>${x.down.replace("<svg",'<svg class="chev"')}</summary><div class="tool-body"></div>`,t.tools.set(n.id,e),t.trace.appendChild(e)),e.dataset.status=n.status,e.querySelector(".lead").innerHTML=n.status==="running"?'<span class="spin"></span>':x.tool;let r=e.querySelector(".tool-name");r.textContent=It(n.name),r.setAttribute("title",n.name),e.querySelector(".tool-state").textContent=n.status==="running"?this.strings.toolRunning:n.status==="error"?this.strings.toolError:this.strings.toolDone;let o=e.querySelector(".tool-body");o.replaceChildren();let a=(c,l)=>{if(l==null||l==="")return;let d=document.createElement("div");d.className="label",d.textContent=c;let g=document.createElement("pre");g.textContent=typeof l=="string"?Bt(l):JSON.stringify(l,null,2),o.append(d,g)};a(this.strings.args,n.arguments),a(this.strings.result,n.result)}onStreamEvent(t,n){switch(n.type){case"start":n.actionsHash&&(t.actionsHash=n.actionsHash),n.conversationId&&n.conversationId!==this.conversationId&&(this.conversationId=n.conversationId,this.config.persist!==!1&&T.set(this.convKey(),n.conversationId));break;case"thinking":t.thinking=(t.thinking||"")+n.text;break;case"delta":this.finishThinking(t),t.content+=n.text;break;case"tool_call":this.finishThinking(t),(t.toolCalls??(t.toolCalls=[])).push({id:n.id,name:n.name,arguments:n.arguments,status:"running"});break;case"tool_result":{let e=t.toolCalls?.find(r=>r.id===n.id)??(t.toolCalls??(t.toolCalls=[]))[t.toolCalls.push({id:n.id,name:n.name,status:"running"})-1];e.status=n.isError?"error":"done",e.result=n.result,e.isError=n.isError;break}case"done":this.finishThinking(t),n.content&&n.content.length>=t.content.length&&(t.content=n.content),t.status="done";break;case"error":t.status="error",this.showError(t,new v(n.message,500,n.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 n=this.els.log;(t||this.nearBottom())&&(n.scrollTop=n.scrollHeight,this.following=!0)}showError(t,n){let e=n.message||this.strings.errorGeneric;if(this.emit("dewee:error",{message:e,code:n.code}),t){t.content=t.content?`${t.content}
|
|
257
328
|
|
|
258
|
-
> \u26A0\uFE0F ${
|
|
329
|
+
> \u26A0\uFE0F ${e}`:`\u26A0\uFE0F ${e}`,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 ${e}`,this.els.log.appendChild(r)}async challenge(t){await Ht();let n=document.createElement("div");n.slot="challenge",this.appendChild(n);try{return await new Promise((e,r)=>{window.turnstile.render(n,{sitekey:t,appearance:"interaction-only",theme:this.getAttribute("data-theme")==="dark"?"dark":"light",callback:e,"error-callback":()=>r(new v("Verification failed",403,"turnstile_failed"))})})}finally{n.remove()}}};function _t(i){return i.forEach((s,t)=>{if(s.role==="user"){s.content=j(s.content),O(s.content)&&(s.hidden=!0);return}if(!s.content.includes("```dewee-action"))return;let{calls:n}=_(s.content);if(!n.length)return;let e=i[t+1],r=e?.role==="user"?j(e.content):"",o=O(r)?it(r):[];s.actions=n.map(a=>{let c=o.find(d=>d.id===a.id),l=c?c.status==="ok"?"done":c.status:"error";return{id:a.id,name:a.name,args:a.ok?a.args:void 0,status:l,error:c?c.error:"Not run"}})}),i}function Ot(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 F(i="dewee-chat"){typeof window>"u"||!window.customElements||customElements.get(i)||customElements.define(i,class extends P{})}function Dt(i={},s){F();let t=document.createElement("dewee-chat");return t.configure(i),((typeof s=="string"?document.querySelector(s):s)??document.body).appendChild(t),t}F();var zt=document.currentScript,H=zt?.dataset;if(H&&H.endpoint&&H.autoMount!=="false"){let i=()=>{let s=document.createElement("dewee-chat");for(let[t,n]of Object.entries(H))t==="autoMount"||n===void 0||s.setAttribute(t.replace(/[A-Z]/g,e=>"-"+e.toLowerCase()),n);document.body.appendChild(s)};document.readyState==="loading"?document.addEventListener("DOMContentLoaded",i):i()}window.DeweeWebchat=G;})();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,91 @@
|
|
|
1
|
-
import { P as PublicConfig, S as SessionResponse, H as HistoryMessage, C as ChatStreamEvent } from './protocol-
|
|
2
|
-
export { A as AgentInfo, T as ToolCallView } from './protocol-
|
|
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";
|
|
41
|
+
|
|
42
|
+
/** Extra request headers: a static map, or a function evaluated before every request. */
|
|
43
|
+
type RequestHeadersOption = Record<string, string> | (() => Record<string, string> | Promise<Record<string, string>>);
|
|
44
|
+
/** Headers the widget owns; `headers` cannot override them (compared case-insensitively). */
|
|
45
|
+
declare const RESERVED_HEADERS: readonly string[];
|
|
46
|
+
interface ApiClientOptions {
|
|
47
|
+
/** Backend base URL, e.g. "/api/dewee" or "https://example.com/api/dewee". */
|
|
48
|
+
endpoint: string;
|
|
49
|
+
/** Bring-your-own gateway credentials (only if the backend allows it). */
|
|
50
|
+
gatewayUrl?: string;
|
|
51
|
+
gatewayToken?: string;
|
|
52
|
+
/** Called when the backend requires a Turnstile challenge; must resolve to a token. */
|
|
53
|
+
turnstile?: (siteKey: string) => Promise<string>;
|
|
54
|
+
/** Extra headers merged into every request (reserved headers excluded). */
|
|
55
|
+
headers?: RequestHeadersOption;
|
|
56
|
+
/** Replaces `globalThis.fetch` for every request. */
|
|
57
|
+
fetch?: typeof fetch;
|
|
58
|
+
}
|
|
59
|
+
declare class ApiError extends Error {
|
|
60
|
+
status: number;
|
|
61
|
+
code?: string | undefined;
|
|
62
|
+
constructor(message: string, status: number, code?: string | undefined);
|
|
63
|
+
}
|
|
64
|
+
declare class ApiClient {
|
|
65
|
+
private o;
|
|
66
|
+
private session;
|
|
67
|
+
private config;
|
|
68
|
+
private sessionPromise;
|
|
69
|
+
constructor(o: ApiClientOptions);
|
|
70
|
+
private url;
|
|
71
|
+
private get storageKey();
|
|
72
|
+
/** Session reuse: refresh once less than 10% of the token lifetime (at most 24 h, at least 30 s) remains. */
|
|
73
|
+
private fresh;
|
|
74
|
+
private request;
|
|
75
|
+
private headers;
|
|
76
|
+
private parse;
|
|
77
|
+
getConfig(force?: boolean): Promise<PublicConfig>;
|
|
78
|
+
/** Returns a valid visitor session, creating or refreshing it when needed. */
|
|
79
|
+
ensureSession(): Promise<SessionResponse>;
|
|
80
|
+
private createSession;
|
|
81
|
+
forgetSession(): void;
|
|
82
|
+
history(agent: string, conversationId: string): Promise<HistoryMessage[]>;
|
|
83
|
+
/** Sends a message and calls `onEvent` for every streamed event. Resolves when the run ends. */
|
|
84
|
+
chat(input: ChatRequestBody & {
|
|
85
|
+
agent: string;
|
|
86
|
+
conversationId: string;
|
|
87
|
+
}, onEvent: (e: ChatStreamEvent) => void, signal?: AbortSignal): Promise<void>;
|
|
88
|
+
}
|
|
3
89
|
|
|
4
90
|
interface DeweeChatConfig {
|
|
5
91
|
/** Backend base URL (the server handler). Default: "/api/dewee". */
|
|
@@ -40,6 +126,44 @@ interface DeweeChatConfig {
|
|
|
40
126
|
width?: string;
|
|
41
127
|
height?: string;
|
|
42
128
|
zIndex?: number;
|
|
129
|
+
/** Page actions the agent may invoke. Replaces the set previously passed through this option. */
|
|
130
|
+
actions?: PageAction[];
|
|
131
|
+
/** Approval for `mutate`/`destructive` actions. Default: the built-in confirm dialog. Only `true` approves. */
|
|
132
|
+
confirm?: ActionConfirmHook;
|
|
133
|
+
/** Small, host-redacted snapshot of page state sent with every message (max 4 KB as JSON). */
|
|
134
|
+
getPageContext?: () => unknown;
|
|
135
|
+
/** Automatic action rounds allowed per visitor message. Default 5. */
|
|
136
|
+
maxActionRounds?: number;
|
|
137
|
+
/** Per-handler timeout. Default 30000 ms. */
|
|
138
|
+
actionTimeoutMs?: number;
|
|
139
|
+
/**
|
|
140
|
+
* Extra headers for every request to `endpoint` (e.g. a CSRF token). A function is called before
|
|
141
|
+
* each request. Cannot override content-type, authorization or the gateway credential headers.
|
|
142
|
+
*/
|
|
143
|
+
headers?: RequestHeadersOption;
|
|
144
|
+
/** Replaces `globalThis.fetch` for every widget request (e.g. to add credentials or tracing). */
|
|
145
|
+
fetch?: typeof fetch;
|
|
146
|
+
}
|
|
147
|
+
/** A page action call as shown in the transcript. */
|
|
148
|
+
interface ActionCallView {
|
|
149
|
+
id: string;
|
|
150
|
+
name: string;
|
|
151
|
+
args?: Record<string, unknown>;
|
|
152
|
+
status: ActionCallStatus;
|
|
153
|
+
error?: string;
|
|
154
|
+
}
|
|
155
|
+
/** `detail` of the `dewee:action` event (host telemetry). */
|
|
156
|
+
interface ActionEventDetail {
|
|
157
|
+
phase: "start" | "result";
|
|
158
|
+
id: string;
|
|
159
|
+
name: string;
|
|
160
|
+
sensitivity?: ActionSensitivity;
|
|
161
|
+
args?: Record<string, unknown>;
|
|
162
|
+
status?: ActionResultStatus;
|
|
163
|
+
result?: unknown;
|
|
164
|
+
error?: string;
|
|
165
|
+
agent: string;
|
|
166
|
+
conversationId: string;
|
|
43
167
|
}
|
|
44
168
|
declare const ElementBase: typeof HTMLElement;
|
|
45
169
|
declare class DeweeChatElement extends ElementBase {
|
|
@@ -56,17 +180,46 @@ declare class DeweeChatElement extends ElementBase {
|
|
|
56
180
|
private activated;
|
|
57
181
|
private strings;
|
|
58
182
|
private mql;
|
|
183
|
+
private registry;
|
|
184
|
+
private propActionNames;
|
|
185
|
+
private hooks;
|
|
186
|
+
private acks;
|
|
59
187
|
private els;
|
|
60
188
|
constructor();
|
|
61
189
|
/** Current effective configuration (attributes merged with `configure()` overrides). */
|
|
62
190
|
get config(): DeweeChatConfig;
|
|
63
191
|
/** Updates configuration at runtime (wins over attributes). */
|
|
64
192
|
configure(partial: Partial<DeweeChatConfig>): void;
|
|
193
|
+
/** Adds or replaces page actions the agent may invoke. Throws TypeError on an invalid definition. */
|
|
194
|
+
registerActions(actions: PageAction | PageAction[]): void;
|
|
195
|
+
/** Removes a page action. Returns false when it was not registered. */
|
|
196
|
+
unregisterAction(name: string): boolean;
|
|
197
|
+
/** Extra request headers (property only; same as `configure({ headers })`). */
|
|
198
|
+
get headers(): RequestHeadersOption | undefined;
|
|
199
|
+
set headers(v: RequestHeadersOption | undefined);
|
|
200
|
+
/** Custom fetch for widget requests (property only; same as `configure({ fetch })`). */
|
|
201
|
+
get fetch(): typeof fetch | undefined;
|
|
202
|
+
set fetch(v: typeof fetch | undefined);
|
|
203
|
+
/** Names of the currently registered page actions. */
|
|
204
|
+
get actionNames(): string[];
|
|
205
|
+
private setPropActions;
|
|
65
206
|
open(): void;
|
|
66
207
|
close(): void;
|
|
67
208
|
toggle(): void;
|
|
68
209
|
/** Sends a message programmatically (opens the widget first). */
|
|
69
210
|
send(text: string): Promise<void>;
|
|
211
|
+
/** One request/response with the agent. */
|
|
212
|
+
private runTurn;
|
|
213
|
+
private chatBody;
|
|
214
|
+
/** Host snapshot, dropped (with a warning) when it fails or exceeds the backend cap. */
|
|
215
|
+
private pageContext;
|
|
216
|
+
private ackKey;
|
|
217
|
+
private getAck;
|
|
218
|
+
private setAck;
|
|
219
|
+
/** Executes the calls of one answer in order. Resolves null when the visitor stopped the chain. */
|
|
220
|
+
private runActions;
|
|
221
|
+
private confirmAction;
|
|
222
|
+
private showNotice;
|
|
70
223
|
/** Stops the running reply. */
|
|
71
224
|
stop(): void;
|
|
72
225
|
/** Starts a fresh conversation with the current agent. */
|
|
@@ -94,6 +247,7 @@ declare class DeweeChatElement extends ElementBase {
|
|
|
94
247
|
private pushMessage;
|
|
95
248
|
private renderMessage;
|
|
96
249
|
private updateMessage;
|
|
250
|
+
private renderActions;
|
|
97
251
|
private renderTool;
|
|
98
252
|
private onStreamEvent;
|
|
99
253
|
private pendingFrame;
|
|
@@ -107,44 +261,6 @@ declare class DeweeChatElement extends ElementBase {
|
|
|
107
261
|
private challenge;
|
|
108
262
|
}
|
|
109
263
|
|
|
110
|
-
interface ApiClientOptions {
|
|
111
|
-
/** Backend base URL, e.g. "/api/dewee" or "https://example.com/api/dewee". */
|
|
112
|
-
endpoint: string;
|
|
113
|
-
/** Bring-your-own gateway credentials (only if the backend allows it). */
|
|
114
|
-
gatewayUrl?: string;
|
|
115
|
-
gatewayToken?: string;
|
|
116
|
-
/** Called when the backend requires a Turnstile challenge; must resolve to a token. */
|
|
117
|
-
turnstile?: (siteKey: string) => Promise<string>;
|
|
118
|
-
}
|
|
119
|
-
declare class ApiError extends Error {
|
|
120
|
-
status: number;
|
|
121
|
-
code?: string | undefined;
|
|
122
|
-
constructor(message: string, status: number, code?: string | undefined);
|
|
123
|
-
}
|
|
124
|
-
declare class ApiClient {
|
|
125
|
-
private o;
|
|
126
|
-
private session;
|
|
127
|
-
private config;
|
|
128
|
-
private sessionPromise;
|
|
129
|
-
constructor(o: ApiClientOptions);
|
|
130
|
-
private url;
|
|
131
|
-
private get storageKey();
|
|
132
|
-
private headers;
|
|
133
|
-
private parse;
|
|
134
|
-
getConfig(force?: boolean): Promise<PublicConfig>;
|
|
135
|
-
/** Returns a valid visitor session, creating or refreshing it when needed. */
|
|
136
|
-
ensureSession(): Promise<SessionResponse>;
|
|
137
|
-
private createSession;
|
|
138
|
-
forgetSession(): void;
|
|
139
|
-
history(agent: string, conversationId: string): Promise<HistoryMessage[]>;
|
|
140
|
-
/** Sends a message and calls `onEvent` for every streamed event. Resolves when the run ends. */
|
|
141
|
-
chat(input: {
|
|
142
|
-
message: string;
|
|
143
|
-
agent: string;
|
|
144
|
-
conversationId: string;
|
|
145
|
-
}, onEvent: (e: ChatStreamEvent) => void, signal?: AbortSignal): Promise<void>;
|
|
146
|
-
}
|
|
147
|
-
|
|
148
264
|
type Doc = Document;
|
|
149
265
|
declare function renderMarkdown(doc: Doc, src: string): DocumentFragment;
|
|
150
266
|
|
|
@@ -158,4 +274,4 @@ declare global {
|
|
|
158
274
|
}
|
|
159
275
|
}
|
|
160
276
|
|
|
161
|
-
export { ApiClient, type ApiClientOptions, ApiError, ChatStreamEvent, type DeweeChatConfig, DeweeChatElement, HistoryMessage, PublicConfig, SessionResponse, defineDeweeChat, mount, renderMarkdown };
|
|
277
|
+
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, RESERVED_HEADERS, type RequestHeadersOption, SessionResponse, defineDeweeChat, mount, renderMarkdown };
|
package/dist/index.js
CHANGED
|
@@ -2,15 +2,17 @@ import {
|
|
|
2
2
|
ApiClient,
|
|
3
3
|
ApiError,
|
|
4
4
|
DeweeChatElement,
|
|
5
|
+
RESERVED_HEADERS,
|
|
5
6
|
defineDeweeChat,
|
|
6
7
|
mount,
|
|
7
8
|
renderMarkdown
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-ZTVGWFXL.js";
|
|
10
|
+
import "./chunk-W6A4HVFB.js";
|
|
10
11
|
export {
|
|
11
12
|
ApiClient,
|
|
12
13
|
ApiError,
|
|
13
14
|
DeweeChatElement,
|
|
15
|
+
RESERVED_HEADERS,
|
|
14
16
|
defineDeweeChat,
|
|
15
17
|
mount,
|
|
16
18
|
renderMarkdown
|