@chatpanel/events 0.161.2 → 0.189.1

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.
@@ -0,0 +1,2 @@
1
+ const x="permission_request",f=Object.freeze({ALLOW:"allow",ALLOW_CHAT:"allow_chat",DENY:"deny"}),O=600*1e3,A="permission_prompt";function w(){return{name:A,description:"ChatPanel-internal: the person answers the agent's permission prompt. Not for the model.",parameters:{type:"object",properties:{tool:{type:"string"},input:{type:"object"},description:{type:"string"},path:{type:"string"},rules:{type:"array"}}}}}const $=e=>e===A,u=e=>e!==null&&typeof e=="object"&&!Array.isArray(e),a=e=>typeof e=="string"?e:e==null?"":String(e);function P(e={}){const t=u(e)?e:{},o=a(t.tool_name||t.toolName||t.tool),n=[];for(const s of Array.isArray(t.permission_suggestions)?t.permission_suggestions:[])if(!(!u(s)||s.type!=="addRules"||s.behavior==="deny"))for(const i of Array.isArray(s.rules)?s.rules:[]){if(!u(i))continue;const c=a(i.toolName||o),l=a(i.ruleContent);c&&!n.some(d=>d.tool===c&&d.content===l)&&n.push({tool:c,content:l})}return{tool:o,displayName:a(t.display_name||t.displayName)||o,input:u(t.input)?t.input:{},description:a(t.description),path:a(t.blocked_path||t.path)||null,rules:n,toolUseId:a(t.tool_use_id||t.toolUseId)||null}}function y(e={}){const t=Array.isArray(e.rules)?e.rules.filter(o=>o&&o.tool):[];return t.length?t.map(o=>o.content?`${o.tool}(${o.content})`:o.tool):e.tool?[String(e.tool)]:[]}function _(e={}){const t=a(e.tool),o=u(e.input)?e.input:{},n=(r,p=240)=>r.length>p?`${r.slice(0,p-1)}…`:r;let s,i;if(t==="Bash")s="Run a command",i=n(a(o.command).trim()||a(e.description)||"a shell command");else if(t==="Edit"||t==="MultiEdit"||t==="NotebookEdit")s="Edit a file",i=a(o.file_path||o.notebook_path||e.path)||"a file";else if(t==="Write"){s="Write a file";const r=a(o.file_path||e.path)||"a file",p=a(o.content).length;i=p?`${r} (${p.toLocaleString()} chars)`:r}else if(/^mcp__/.test(t))s="Use a connected server",i=t.replace(/^mcp__/,"").replace(/__/," › ");else{s=`Use ${e.displayName||t||"a tool"}`;let r="";try{r=JSON.stringify(o)}catch{r=""}i=a(e.description)||(r&&r!=="{}"?n(r,200):t)}const c=y(e),l=Array.isArray(e.rules)?e.rules.filter(r=>r?.content):[],d=l.length&&l.some(r=>r.content!==i)?l.map(r=>r.content).join(", "):c.length&&!l.length?`every ${t} call`:null;return{title:s,detail:i,scope:d,description:a(e.description)||null}}function m(e,t=""){return e===f.ALLOW?{behavior:"allow",scope:"once"}:e===f.ALLOW_CHAT?{behavior:"allow",scope:"chat"}:{behavior:"deny",scope:"once",...t?{message:String(t)}:{}}}function b(e){return u(e)&&e.behavior==="allow"}function N(e,t){const o=new Set(Array.isArray(e)?e:[]);for(const n of y(t))o.add(n);return[...o].sort()}function E(e,t){const o=y(t);if(!o.length)return null;const n=new Set(Array.isArray(e)?e:[]);return o.every(s=>n.has(s))?m(f.ALLOW):null}function k(e,t,o={}){const n=u(o)?o:{},s=b(t);let i;if(s){if(i={behavior:"allow",updatedInput:u(n.input)?n.input:{}},t.scope==="chat"){const c=(Array.isArray(n.permission_suggestions)?n.permission_suggestions:[]).filter(l=>u(l)&&l.type==="addRules"&&l.behavior!=="deny"&&Array.isArray(l.rules)&&l.rules.length).map(l=>({type:"addRules",rules:l.rules,behavior:"allow",destination:"session"}));c.length&&(i.updatedPermissions=c)}}else i={behavior:"deny",message:a(t?.message)||"The user declined this action in ChatPanel. Continue without it, or explain what it was for and ask."};return{type:"control_response",response:{subtype:"success",request_id:String(e),response:i}}}function R(e,t){const{detail:o}=_(e),n=b(t),s=n&&t.scope==="chat"?" for this chat":"";return`${n?"Allowed":"Declined"}${s}: ${o}`}function L(e){return e==="Bash"?"code":/^(Edit|MultiEdit|NotebookEdit)$/.test(String(e))?"pencil":e==="Write"?"file":/^mcp__/.test(String(e))?"plug":"bot"}function T(){const e=new Map;async function t(o,{convId:n=null,confirm:s,agentName:i="The agent"}={}){const c=E(e.get(n)||[],o);if(c)return c;const{title:l,detail:d,scope:r,description:p}=_(o),S=[d,p&&p!==d?p:"",r?`“Allow for this chat” also covers: ${r}`:""].filter(Boolean).join(`
2
+ `);let h;try{if(typeof s!="function")throw new Error("no card");h=await s(S,{title:`${i} asks — ${l.toLowerCase()}?`,iconName:L(o.tool),scopeLabel:"Allow for this chat"})}catch(g){return m(f.DENY,`ChatPanel could not show the permission card (${g?.message||g}).`)}return h==="site"||h==="always"?(e.set(n,N(e.get(n)||[],o)),m(f.ALLOW_CHAT)):m(h==="allow"?f.ALLOW:f.DENY)}return{ask:t,forget(o){e.delete(o)},standing(o){return e.get(o)||[]},provider({convId:o=null,confirm:n,agentName:s="The agent"}={}){return{id:"permission",specs:[w()],execute:async(i,c)=>JSON.stringify(await t(c&&typeof c=="object"?c:{},{convId:o,confirm:n,agentName:s}))}}}}export{f as PERMISSION_ANSWERS,x as PERMISSION_EVENT,O as PERMISSION_TIMEOUT_MS,A as PERMISSION_TOOL_NAME,k as claudePermissionResponse,T as createPermissionDesk,_ as describePermission,$ as isPermissionTool,b as permissionAllowed,m as permissionAnswer,L as permissionIcon,y as permissionKeys,R as permissionLine,P as permissionRequestFromClaude,w as permissionToolSpec,E as recallPermission,N as rememberPermission};
@@ -1 +1 @@
1
- class a extends Error{constructor(t){super(t),this.name="BackupError"}}const S="chatpanel-backup-encrypted",w=25e4,U=Object.freeze(["brotli","gzip","none"]),b=32768;function y(e){if(typeof Buffer<"u")return Buffer.from(e).toString("base64");let t="";for(let n=0;n<e.length;n+=b)t+=String.fromCharCode.apply(null,e.subarray(n,n+b));return btoa(t)}function d(e){const t=String(e||"");if(typeof Buffer<"u")return new Uint8Array(Buffer.from(t,"base64"));const n=atob(t),o=new Uint8Array(n.length);for(let r=0;r<n.length;r++)o[r]=n.charCodeAt(r);return o}const k=Object.freeze({name:"none",async compress(e){return e},async decompress(e){return e}});function C(e="gzip"){if(typeof CompressionStream>"u"||typeof DecompressionStream>"u")return null;try{new CompressionStream(e),new DecompressionStream(e)}catch{return null}const t=async(n,o)=>{const r=new Blob([n]).stream().pipeThrough(new o(e));return new Uint8Array(await new Response(r).arrayBuffer())};return Object.freeze({name:e,compress:n=>t(n,CompressionStream),decompress:n=>t(n,DecompressionStream)})}function x(e,t="brotli"){if(!e)return null;const n=t==="brotli"?[e.brotliCompressSync,e.brotliDecompressSync]:t==="gzip"?[e.gzipSync,e.gunzipSync]:null;if(!n||!n[0]||!n[1])return null;const[o,r]=n;return Object.freeze({name:t,async compress(c){return new Uint8Array(o(Buffer.from(c)))},async decompress(c){return new Uint8Array(r(Buffer.from(c)))}})}function m({zlib:e=null}={}){return e?x(e,"brotli")||x(e,"gzip")||k:C("brotli")||C("gzip")||k}async function h(e,t,n,o,r){const c=r||globalThis.crypto?.subtle;if(!c)throw new a("no WebCrypto available on this runtime");const s=await c.importKey("raw",new TextEncoder().encode(String(e)),"PBKDF2",!1,["deriveKey"]);return c.deriveKey({name:"PBKDF2",salt:t,iterations:n,hash:"SHA-256"},s,{name:"AES-GCM",length:256},!1,o)}function R(e){return!!e&&typeof e=="object"&&e.type===S}async function D(e,t,{codec:n=null,iterations:o=w,subtle:r=null,random:c=null,version:s=3}={}){if(!t)throw new a("a passphrase is required to encrypt a backup");const i=n||m(),p=c||(v=>globalThis.crypto.getRandomValues(new Uint8Array(v))),u=new TextEncoder().encode(JSON.stringify(e)),l=await i.compress(u),f=p(16),g=p(12),B=await h(t,f,o,["encrypt"],r),E=r||globalThis.crypto.subtle,T=new Uint8Array(await E.encrypt({name:"AES-GCM",iv:g},B,l));return{type:S,version:s,kdf:{iterations:o,salt:y(f)},cipher:"AES-GCM",compression:i.name,iv:y(g),ct:y(T)}}async function K(e,t,{codec:n=null,subtle:o=null}={}){if(!R(e))throw new a("not an encrypted ChatPanel backup");if(!t)throw new a("a passphrase is required to decrypt this backup");const r=d(e.kdf?.salt),c=Number(e.kdf?.iterations)||w,s=await h(t,r,c,["decrypt"],o),i=o||globalThis.crypto?.subtle;if(!i)throw new a("no WebCrypto available on this runtime");let p;try{p=new Uint8Array(await i.decrypt({name:"AES-GCM",iv:d(e.iv)},s,d(e.ct)))}catch{throw new a("wrong passphrase, or the backup file is corrupted")}const u=e.compression||"none";if(u!=="none"){const l=n||m();if(l.name!==u)throw new a(`this backup is ${u}-compressed; supply a matching codec`);p=await l.decompress(p)}return JSON.parse(new TextDecoder().decode(p))}const A="chatpanel-record-encrypted";async function N(e,{salt:t=null,iterations:n=w,subtle:o=null,random:r=null}={}){if(!e)throw new a("a passphrase is required to derive a backup key");const s=t?typeof t=="string"?d(t):t:(r||(p=>globalThis.crypto.getRandomValues(new Uint8Array(p))))(16),i=await h(e,s,n,["encrypt","decrypt"],o);return Object.freeze({key:i,salt:y(s),iterations:n})}async function M(e,t,{codec:n=null,subtle:o=null,random:r=null}={}){if(!t?.key)throw new a("sealRecord needs a key from deriveBackupKey");const c=n||m(),s=r||(f=>globalThis.crypto.getRandomValues(new Uint8Array(f))),i=o||globalThis.crypto?.subtle;if(!i)throw new a("no WebCrypto available on this runtime");const p=await c.compress(new TextEncoder().encode(JSON.stringify(e))),u=s(12),l=new Uint8Array(await i.encrypt({name:"AES-GCM",iv:u},t.key,p));return{type:A,kdf:{iterations:t.iterations,salt:t.salt},cipher:"AES-GCM",compression:c.name,iv:y(u),ct:y(l)}}function O(e){return!!e&&typeof e=="object"&&e.type===A}async function P(e,t,{codec:n=null,subtle:o=null}={}){if(!O(e))throw new a("not a sealed ChatPanel record");if(!t?.key)throw new a("openRecord needs a key from deriveBackupKey");if(e.kdf?.salt!==t.salt)throw new a("this record was sealed under a different salt; derive a key for it");const r=o||globalThis.crypto?.subtle;if(!r)throw new a("no WebCrypto available on this runtime");let c;try{c=new Uint8Array(await r.decrypt({name:"AES-GCM",iv:d(e.iv)},t.key,d(e.ct)))}catch{throw new a("wrong passphrase, or the record is corrupted")}const s=e.compression||"none";if(s!=="none"){const i=n||m();if(i.name!==s)throw new a(`this record is ${s}-compressed; supply a matching codec`);c=await i.decompress(c)}return JSON.parse(new TextDecoder().decode(c))}function G(e){const t=new Map;return n=>{const o=n?.kdf?.salt,r=Number(n?.kdf?.iterations)||w;if(!o)throw new a("a sealed record carries no salt");const c=`${r}:${o}`;return t.has(c)||t.set(c,e(o,r)),t.get(c)}}export{a as BackupError,U as COMPRESSIONS,S as ENCRYPTED_TYPE,w as KDF_ITERATIONS,A as RECORD_TYPE,m as bestCodec,K as decryptBackup,N as deriveBackupKey,D as encryptBackup,d as fromB64,k as identityCodec,R as isEncryptedBackup,O as isSealedRecord,G as keyCache,x as nodeCodec,P as openRecord,M as sealRecord,C as streamCodec,y as toB64};
1
+ class s extends Error{constructor(t){super(t),this.name="BackupError"}}const S="chatpanel-backup-encrypted",f=25e4,O=Object.freeze(["brotli","gzip","none"]);import{toB64 as J,fromB64 as W}from"./bytes-b64.js";import{toB64 as y,fromB64 as d}from"./bytes-b64.js";const b=Object.freeze({name:"none",async compress(e){return e},async decompress(e){return e}});function g(e="gzip"){if(typeof CompressionStream>"u"||typeof DecompressionStream>"u")return null;try{new CompressionStream(e),new DecompressionStream(e)}catch{return null}const t=async(r,o)=>{const c=new Blob([r]).stream().pipeThrough(new o(e));return new Uint8Array(await new Response(c).arrayBuffer())};return Object.freeze({name:e,compress:r=>t(r,CompressionStream),decompress:r=>t(r,DecompressionStream)})}function C(e,t="brotli"){if(!e)return null;const r=t==="brotli"?[e.brotliCompressSync,e.brotliDecompressSync]:t==="gzip"?[e.gzipSync,e.gunzipSync]:null;if(!r||!r[0]||!r[1])return null;const[o,c]=r;return Object.freeze({name:t,async compress(n){return new Uint8Array(o(Buffer.from(n)))},async decompress(n){return new Uint8Array(c(Buffer.from(n)))}})}function m({zlib:e=null}={}){return e?C(e,"brotli")||C(e,"gzip")||b:g("brotli")||g("gzip")||b}async function h(e,t,r,o,c){const n=c||globalThis.crypto?.subtle;if(!n)throw new s("no WebCrypto available on this runtime");const a=await n.importKey("raw",new TextEncoder().encode(String(e)),"PBKDF2",!1,["deriveKey"]);return n.deriveKey({name:"PBKDF2",salt:t,iterations:r,hash:"SHA-256"},a,{name:"AES-GCM",length:256},!1,o)}function v(e){return!!e&&typeof e=="object"&&e.type===S}async function K(e,t,{codec:r=null,iterations:o=f,subtle:c=null,random:n=null,version:a=3}={}){if(!t)throw new s("a passphrase is required to encrypt a backup");const i=r||m(),p=n||(T=>globalThis.crypto.getRandomValues(new Uint8Array(T))),u=new TextEncoder().encode(JSON.stringify(e)),l=await i.compress(u),w=p(16),k=p(12),E=await h(t,w,o,["encrypt"],c),A=c||globalThis.crypto.subtle,B=new Uint8Array(await A.encrypt({name:"AES-GCM",iv:k},E,l));return{type:S,version:a,kdf:{iterations:o,salt:y(w)},cipher:"AES-GCM",compression:i.name,iv:y(k),ct:y(B)}}async function U(e,t,{codec:r=null,subtle:o=null}={}){if(!v(e))throw new s("not an encrypted ChatPanel backup");if(!t)throw new s("a passphrase is required to decrypt this backup");const c=d(e.kdf?.salt),n=Number(e.kdf?.iterations)||f,a=await h(t,c,n,["decrypt"],o),i=o||globalThis.crypto?.subtle;if(!i)throw new s("no WebCrypto available on this runtime");let p;try{p=new Uint8Array(await i.decrypt({name:"AES-GCM",iv:d(e.iv)},a,d(e.ct)))}catch{throw new s("wrong passphrase, or the backup file is corrupted")}const u=e.compression||"none";if(u!=="none"){const l=r||m();if(l.name!==u)throw new s(`this backup is ${u}-compressed; supply a matching codec`);p=await l.decompress(p)}return JSON.parse(new TextDecoder().decode(p))}const x="chatpanel-record-encrypted";async function M(e,{salt:t=null,iterations:r=f,subtle:o=null,random:c=null}={}){if(!e)throw new s("a passphrase is required to derive a backup key");const a=t?typeof t=="string"?d(t):t:(c||(p=>globalThis.crypto.getRandomValues(new Uint8Array(p))))(16),i=await h(e,a,r,["encrypt","decrypt"],o);return Object.freeze({key:i,salt:y(a),iterations:r})}async function N(e,t,{codec:r=null,subtle:o=null,random:c=null}={}){if(!t?.key)throw new s("sealRecord needs a key from deriveBackupKey");const n=r||m(),a=c||(w=>globalThis.crypto.getRandomValues(new Uint8Array(w))),i=o||globalThis.crypto?.subtle;if(!i)throw new s("no WebCrypto available on this runtime");const p=await n.compress(new TextEncoder().encode(JSON.stringify(e))),u=a(12),l=new Uint8Array(await i.encrypt({name:"AES-GCM",iv:u},t.key,p));return{type:x,kdf:{iterations:t.iterations,salt:t.salt},cipher:"AES-GCM",compression:n.name,iv:y(u),ct:y(l)}}function R(e){return!!e&&typeof e=="object"&&e.type===x}async function P(e,t,{codec:r=null,subtle:o=null}={}){if(!R(e))throw new s("not a sealed ChatPanel record");if(!t?.key)throw new s("openRecord needs a key from deriveBackupKey");if(e.kdf?.salt!==t.salt)throw new s("this record was sealed under a different salt; derive a key for it");const c=o||globalThis.crypto?.subtle;if(!c)throw new s("no WebCrypto available on this runtime");let n;try{n=new Uint8Array(await c.decrypt({name:"AES-GCM",iv:d(e.iv)},t.key,d(e.ct)))}catch{throw new s("wrong passphrase, or the record is corrupted")}const a=e.compression||"none";if(a!=="none"){const i=r||m();if(i.name!==a)throw new s(`this record is ${a}-compressed; supply a matching codec`);n=await i.decompress(n)}return JSON.parse(new TextDecoder().decode(n))}function G(e){const t=new Map;return r=>{const o=r?.kdf?.salt,c=Number(r?.kdf?.iterations)||f;if(!o)throw new s("a sealed record carries no salt");const n=`${c}:${o}`;return t.has(n)||t.set(n,e(o,c)),t.get(n)}}export{s as BackupError,O as COMPRESSIONS,S as ENCRYPTED_TYPE,f as KDF_ITERATIONS,x as RECORD_TYPE,m as bestCodec,U as decryptBackup,M as deriveBackupKey,K as encryptBackup,W as fromB64,b as identityCodec,v as isEncryptedBackup,R as isSealedRecord,G as keyCache,C as nodeCodec,P as openRecord,N as sealRecord,g as streamCodec,J as toB64};
@@ -0,0 +1 @@
1
+ import{toB64 as p,fromB64 as d}from"./bytes-b64.js";const b="chatpanel-blob-sealed",h=1,A="A256GCM",u=32,E=12;class i extends Error{constructor(n,o){super(o),this.name="SealError",this.code=n}}const S=new TextEncoder,m=new TextDecoder,f=e=>e instanceof Uint8Array?e:S.encode(String(e??""));function v(e=globalThis.crypto?.subtle,n=o=>globalThis.crypto.getRandomValues(new Uint8Array(o))){if(!e)throw new i("NO_CRYPTO","blob-envelope: WebCrypto subtle is required");const o=t=>e.importKey("raw",t,{name:"AES-GCM"},!1,["encrypt","decrypt"]);return{async:!0,random:n,async encrypt(t,c,r,a){return new Uint8Array(await e.encrypt({name:"AES-GCM",iv:c,additionalData:a},await o(t),r))},async decrypt(t,c,r,a){return new Uint8Array(await e.decrypt({name:"AES-GCM",iv:c,additionalData:a},await o(t),r))}}}function T(e){if(!e?.createCipheriv)throw new i("NO_CRYPTO","blob-envelope: node:crypto is required");return{async:!1,random:n=>new Uint8Array(e.randomBytes(n)),encrypt(n,o,t,c){const r=e.createCipheriv("aes-256-gcm",n,o);r.setAAD(c);const a=Buffer.concat([r.update(t),r.final()]);return new Uint8Array(Buffer.concat([a,r.getAuthTag()]))},decrypt(n,o,t,c){const r=e.createDecipheriv("aes-256-gcm",n,o);return r.setAAD(c),r.setAuthTag(t.subarray(t.length-16)),new Uint8Array(Buffer.concat([r.update(t.subarray(0,t.length-16)),r.final()]))}}}function x(e){return e.random(u)}const l=(e,n)=>e&&typeof e.then=="function"?e.then(n):n(e);function U(e,n,o,t){if(!(n instanceof Uint8Array)||n.length!==u)throw new i("BAD_KEY","blob-envelope: the device key is 32 bytes");if(typeof o!="string"||!o)throw new i("BAD_HASH","blob-envelope: the content hash is required");const c=t.random(u),r=t.random(E),a=t.random(E),s=f(o);return l(t.encrypt(n,r,c,s),y=>l(t.encrypt(c,a,f(e),s),g=>({type:b,v:h,alg:A,wrap:{iv:p(r),ct:p(y)},iv:p(a),ct:p(g)})))}function w(e){return!!e&&typeof e=="object"&&e.type===b&&e.v===h&&e.alg===A&&typeof e.iv=="string"&&typeof e.ct=="string"}function B(e){return w(e)&&e.wrap==null}function _(e,n,o,t){if(!w(e))throw new i("SHAPE","blob-envelope: not a sealed blob");if(B(e))throw new i("SHREDDED","blob-envelope: the key was shredded; the content is gone by design");const c=f(o),r=a=>{throw new i("OPEN",`blob-envelope: could not open (${a?.message||a})`)};try{const a=l(t.decrypt(n,d(e.wrap.iv),d(e.wrap.ct),c),s=>l(t.decrypt(s,d(e.iv),d(e.ct),c),y=>m.decode(y)));return a&&typeof a.then=="function"?a.catch(r):a}catch(a){return r(a)}}function C(e){if(!w(e))throw new i("SHAPE","blob-envelope: not a sealed blob");const{wrap:n,...o}=e;return o}export{b as SEALED_TYPE,h as SEALED_VERSION,i as SealError,w as isSealedBlob,B as isShredded,x as newDeviceKey,T as nodeSealer,_ as openBlob,U as sealBlob,C as shredBlob,v as webCryptoSealer};
package/bytes-b64.js ADDED
@@ -0,0 +1 @@
1
+ const f=32768;function i(t){if(typeof Buffer<"u")return Buffer.from(t).toString("base64");let n="";for(let r=0;r<t.length;r+=32768)n+=String.fromCharCode.apply(null,t.subarray(r,r+32768));return btoa(n)}function u(t){const n=String(t||"");if(typeof Buffer<"u")return new Uint8Array(Buffer.from(n,"base64"));const r=atob(n),o=new Uint8Array(r.length);for(let e=0;e<r.length;e++)o[e]=r.charCodeAt(e);return o}export{u as fromB64,i as toB64};
@@ -1 +1 @@
1
- import{EventError as v}from"./event.js";const q=Object.freeze(["detect","decide","rerank","embed","stt","tts","search","read","extract"]),p=Object.freeze({detect:"/v1/detect",decide:"/v1/decide",rerank:"/v1/rerank",embed:"/v1/embeddings",stt:"/v1/audio/transcriptions",tts:"/v1/audio/speech",search:"/v1/search",read:"/v1/read",extract:"/v1/extract"}),f=Object.freeze(new Set(["search","read","extract"])),g=Object.freeze(["day","week","month","year"]),b=Object.freeze(["login","paywall","rate_limited","robots","tdm"]),c=Object.freeze(["markdown","text"]),S="/v1/capabilities",$="over_budget",a=e=>!!e&&typeof e=="object"&&!Array.isArray(e),i=e=>typeof e=="string"&&e.length>0,d=e=>typeof e=="number"&&Number.isFinite(e),t=(e,s)=>{if(!e)throw new v("SHAPE",s)};function x(e,s){if(!a(e)||!(e.calls>0))return null;const r=d(e.p50Ms)?e.p50Ms:0,n=d(e.charsPerSec)&&e.charsPerSec>0&&d(s)?s/e.charsPerSec*1e3:0;return Math.round(Math.max(r,n))}function R(e,s,r){if(!d(r)||r<=0)return null;const n=x(e,s);return n===null||n<=r?null:{error:{type:$,message:`predicted ${n} ms is over the ${r} ms budget`,predictedMs:n,budgetMs:r}}}function j(e){t(a(e),"detect: body must be an object"),t(typeof e.text=="string","detect: text (string) required");const s={text:e.text};return e.model!=null&&(t(i(e.model),"detect: model must be a non-empty string"),s.model=e.model),e.labels!=null&&(t(Array.isArray(e.labels)&&e.labels.every(i),"detect: labels must be string[]"),s.labels=e.labels),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"detect: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function w(e,s=null){t(a(e),"detect: response must be an object"),t(Array.isArray(e.entities),"detect: entities[] required"),t(i(e.model),"detect: model required"),t(d(e.ms)&&e.ms>=0,"detect: ms required");for(const r of e.entities)t(a(r)&&i(r.value)&&i(r.type),"detect: entity needs value and type"),t(Number.isInteger(r.start)&&Number.isInteger(r.end)&&r.start>=0&&r.end>r.start,`detect: entity ${JSON.stringify(r.value)} needs start < end`),t(d(r.score)&&r.score>=0&&r.score<=1,`detect: entity ${JSON.stringify(r.value)} needs a score in [0,1]`),typeof s=="string"&&t(s.slice(r.start,r.end)===r.value,`detect: entity ${JSON.stringify(r.value)} is not at ${r.start}–${r.end} of the text`);return e}const m=e=>{if(!i(e))return!1;try{const s=new URL(e);return s.protocol==="http:"||s.protocol==="https:"}catch{return!1}};function I(e){t(a(e),"search: body must be an object"),t(i(e.q)&&e.q.trim().length>0,"search: q (non-empty string) required");const s={q:e.q.trim()};return e.limit!=null&&(t(Number.isInteger(e.limit)&&e.limit>=1&&e.limit<=50,"search: limit must be an integer 1–50"),s.limit=e.limit),e.lang!=null&&(t(i(e.lang)&&/^[a-z]{2}(-[A-Za-z]{2})?$/.test(e.lang),"search: lang must be a BCP-47 tag like en or en-US"),s.lang=e.lang),e.site!=null&&(t(i(e.site)&&!/[\s/]/.test(e.site),"search: site must be a hostname"),s.site=e.site.toLowerCase()),e.freshness!=null&&(t(g.includes(e.freshness),`search: freshness must be one of ${g.join(", ")}`),s.freshness=e.freshness),e.read!=null&&(t(Number.isInteger(e.read)&&e.read>=0&&e.read<=10,"search: read must be an integer 0–10"),s.read=e.read),e.provider!=null&&(t(i(e.provider),"search: provider must be a non-empty string"),s.provider=e.provider),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"search: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function _(e){return t(a(e),"search: response must be an object"),t(Array.isArray(e.results),"search: results[] required"),t(i(e.provider),"search: provider required"),t(d(e.ms)&&e.ms>=0,"search: ms required"),e.results.forEach((s,r)=>{t(a(s)&&s.rank===r+1,`search: result ${r} must carry rank ${r+1}`),t(m(s.url),`search: result ${r+1} needs an absolute http(s) url`),t(i(s.title),`search: result ${r+1} needs a title`),t(typeof s.snippet=="string",`search: result ${r+1} needs a snippet (may be empty)`),s.read!=null&&A(s.read)}),e}function O(e){t(a(e),"read: body must be an object"),t(m(e.url),"read: url (absolute http(s)) required");const s={url:e.url,format:"markdown"};return e.format!=null&&(t(c.includes(e.format),`read: format must be one of ${c.join(", ")}`),s.format=e.format),e.maxChars!=null&&(t(Number.isInteger(e.maxChars)&&e.maxChars>=200,"read: maxChars must be an integer ≥ 200"),s.maxChars=e.maxChars),e.snippet!=null&&(t(typeof e.snippet=="string","read: snippet must be a string"),s.snippet=e.snippet),e.provider!=null&&(t(i(e.provider),"read: provider must be a non-empty string"),s.provider=e.provider),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"read: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function A(e){t(a(e),"read: response must be an object"),t(m(e.url),"read: url (absolute, where the page landed) required"),t(typeof e.title=="string","read: title (string, may be empty) required"),t(c.includes(e.format),"read: format required");const s=e[e.format];t(typeof s=="string",`read: ${e.format} (string) required`),t(Number.isInteger(e.chars)&&e.chars===s.length,"read: chars must equal the content length"),t(typeof e.truncated=="boolean","read: truncated (boolean) required"),t(i(e.provider),"read: provider required"),t(d(e.ms)&&e.ms>=0,"read: ms required"),t(Array.isArray(e.sections),"read: sections[] required");for(const r of e.sections)t(a(r)&&i(r.id)&&i(r.heading),"read: section needs id and heading"),t(Number.isInteger(r.level)&&r.level>=1&&r.level<=6,`read: section ${r.id} needs level 1–6`),t(Number.isInteger(r.offset)&&r.offset>=0&&r.offset<=s.length,`read: section ${r.id} offset must index the content`);return e.restricted!=null&&t(a(e.restricted)&&b.includes(e.restricted.reason),`read: restricted.reason must be one of ${b.join(", ")}`),e}const h=Object.freeze(["choice","score","noul"]),k=/^[A-Za-z_][A-Za-z0-9_]*$/;function E(e){t(a(e),"decide: body must be an object"),t(i(e.state),"decide: state (non-empty string) required"),t(a(e.questions)&&Object.keys(e.questions).length>0,"decide: questions {} required");const s={};for(const[n,u]of Object.entries(e.questions)){t(k.test(n),`decide: question key ${JSON.stringify(n)} must be an identifier`),t(a(u)&&h.includes(u.type),`decide: question ${n}.type must be one of ${h.join(", ")}`),t(i(u.instructions),`decide: question ${n} needs instructions`);const l={type:u.type,instructions:u.instructions};u.type==="noul"?t(u.options==null,`decide: question ${n}: a noul has no options`):(t(Array.isArray(u.options)&&u.options.length>=2&&u.options.length<=255,`decide: question ${n}.options needs 2–255 entries`),l.options=u.options.map(o=>i(o)?{value:o}:(t(a(o)&&i(o.value),`decide: question ${n}: an option is a string or { value, describe? }`),o.describe!=null?{value:o.value,describe:String(o.describe)}:{value:o.value})),t(new Set(l.options.map(o=>o.value)).size===l.options.length,`decide: question ${n}.options must be distinct`)),s[n]=l}const r={state:e.state,questions:s};return e.model!=null&&(t(i(e.model),"decide: model must be a non-empty string"),r.model=e.model),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"decide: budgetMs must be a number ≥ 0"),r.budgetMs=e.budgetMs),r}function N(e,s=null){t(a(e),"decide: response must be an object"),t(a(e.answers),"decide: answers {} required"),t(i(e.model),"decide: model required"),t(d(e.ms)&&e.ms>=0,"decide: ms required"),e.calibrated!=null&&t(typeof e.calibrated=="boolean","decide: calibrated must be a boolean");const r=n=>d(n)&&n>=0&&n<=1;for(const n of Object.keys(s?s.questions:e.answers)){const u=e.answers[n];t(a(u),`decide: answer ${n} missing`),t(r(u.p),`decide: answer ${n}.p must be in [0,1]`),t(Array.isArray(u.options)&&u.options.every(o=>a(o)&&o.value!==void 0&&r(o.p)),`decide: answer ${n}.options must be [{ value, p }]`),u.confidence!=null&&t(r(u.confidence),`decide: answer ${n}.confidence must be in [0,1]`);const l=s?.questions?.[n];l?.type==="choice"&&t(l.options.some(o=>o.value===u.value),`decide: answer ${n}.value must be one of the options`),l?.type==="noul"&&t(typeof u.value=="boolean",`decide: answer ${n}.value must be a boolean`),l?.type==="score"&&t(d(u.value),`decide: answer ${n}.value must be a number`)}return e}function C(e){t(a(e),"rerank: body must be an object"),t(i(e.query),"rerank: query (non-empty string) required"),t(Array.isArray(e.documents)&&e.documents.length>=1&&e.documents.length<=1e3&&e.documents.every(r=>typeof r=="string"),"rerank: documents must be 1–1000 strings");const s={query:e.query,documents:e.documents.slice()};return e.top_n!=null&&(t(Number.isInteger(e.top_n)&&e.top_n>=1,"rerank: top_n must be an integer ≥ 1"),s.top_n=e.top_n),e.model!=null&&(t(i(e.model),"rerank: model must be a non-empty string"),s.model=e.model),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"rerank: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function z(e,s=null){t(a(e),"rerank: response must be an object"),t(Array.isArray(e.results),"rerank: results[] required"),t(i(e.model),"rerank: model required"),t(d(e.ms)&&e.ms>=0,"rerank: ms required");const r=s?s.documents.length:1/0,n=new Set;let u=1/0;return e.results.forEach((l,o)=>{t(a(l)&&Number.isInteger(l.index)&&l.index>=0&&l.index<r,`rerank: result ${o} needs an index into the documents`),t(!n.has(l.index),`rerank: index ${l.index} listed twice`),n.add(l.index),t(d(l.relevance_score),`rerank: result ${o} needs relevance_score`),t(l.relevance_score<=u,"rerank: results must be ordered best first"),u=l.relevance_score}),s?.top_n!=null&&t(e.results.length<=s.top_n,`rerank: more than top_n (${s.top_n}) results`),e}function D(e){t(a(e),"capabilities: response must be an object"),t(Array.isArray(e.capabilities),"capabilities: capabilities[] required"),t(a(e.server)&&i(e.server.name)&&i(e.server.version),"capabilities: server {name, version} required");const s=new Set;for(const r of e.capabilities)t(a(r)&&q.includes(r.id),`capabilities: unknown capability id ${JSON.stringify(r?.id)}`),t(!s.has(r.id),`capabilities: ${r.id} listed twice`),s.add(r.id),t(r.route===p[r.id],`capabilities: ${r.id} must be served at ${p[r.id]}`),f.has(r.id)?(t(Array.isArray(r.providers)&&r.providers.length>0&&r.providers.every(i),`capabilities: ${r.id}.providers must be a non-empty string[]`),r.default!=null&&t(r.providers.includes(r.default),`capabilities: ${r.id}.default must be one of its providers`)):(t(Array.isArray(r.models)&&r.models.every(i),`capabilities: ${r.id}.models must be string[]`),r.default!=null&&t(r.models.includes(r.default),`capabilities: ${r.id}.default must be one of its models`)),r.labels!=null&&t(Array.isArray(r.labels)&&r.labels.every(i),`capabilities: ${r.id}.labels must be string[]`),r.stats!=null&&t(a(r.stats)&&(f.has(r.id)||d(r.stats.calls)),`capabilities: ${r.id}.stats needs calls`),r.runtime!=null&&t(a(r.runtime)&&i(r.runtime.state),`capabilities: ${r.id}.runtime needs state`);return e}function T(e){return(e?.capabilities||[]).map(s=>({id:s.id,route:s.route,models:s.models||[],providers:s.providers||[],ready:!s.runtime||["ready","external","idle"].includes(s.runtime.state),stats:s.stats||null,labels:s.labels||null}))}export{q as CAPABILITIES,p as CAPABILITY_ROUTES,h as DECIDE_QUESTION_TYPES,S as DISCOVERY_ROUTE,$ as OVER_BUDGET,f as PROVIDER_CAPABILITIES,c as READ_FORMATS,b as READ_RESTRICTIONS,g as SEARCH_FRESHNESS,T as offeredCapabilities,R as overBudget,x as predictMs,D as validateCapabilitiesResponse,E as validateDecideRequest,N as validateDecideResponse,j as validateDetectRequest,w as validateDetectResponse,O as validateReadRequest,A as validateReadResponse,C as validateRerankRequest,z as validateRerankResponse,I as validateSearchRequest,_ as validateSearchResponse};
1
+ import{EventError as q}from"./event.js";const x=Object.freeze(["detect","decide","rerank","embed","stt","tts","search","read","extract","chat","s2s"]),p=Object.freeze(["embedded","container","remote","harness","router","none"]),f=Object.freeze(["none","loopback","lan","internet","configurable"]),b=Object.freeze({detect:"/v1/detect",decide:"/v1/decide",rerank:"/v1/rerank",embed:"/v1/embeddings",stt:"/v1/audio/transcriptions",tts:"/v1/audio/speech",search:"/v1/search",read:"/v1/read",extract:"/v1/extract",chat:"/v1/chat/completions",s2s:"/v1/audio/conversations"}),g=Object.freeze(new Set(["search","read","extract"])),v=Object.freeze(["day","week","month","year"]),h=Object.freeze(["login","paywall","rate_limited","robots","tdm"]),c=Object.freeze(["markdown","text"]),I="/v1/capabilities",A="over_budget",a=e=>!!e&&typeof e=="object"&&!Array.isArray(e),n=e=>typeof e=="string"&&e.length>0,d=e=>typeof e=="number"&&Number.isFinite(e),t=(e,s)=>{if(!e)throw new q("SHAPE",s)};function k(e,s){if(!a(e)||!(e.calls>0))return null;const r=d(e.p50Ms)?e.p50Ms:0,i=d(e.charsPerSec)&&e.charsPerSec>0&&d(s)?s/e.charsPerSec*1e3:0;return Math.round(Math.max(r,i))}function _(e,s,r){if(!d(r)||r<=0)return null;const i=k(e,s);return i===null||i<=r?null:{error:{type:A,message:`predicted ${i} ms is over the ${r} ms budget`,predictedMs:i,budgetMs:r}}}function O(e){t(a(e),"detect: body must be an object"),t(typeof e.text=="string","detect: text (string) required");const s={text:e.text};return e.model!=null&&(t(n(e.model),"detect: model must be a non-empty string"),s.model=e.model),e.labels!=null&&(t(Array.isArray(e.labels)&&e.labels.every(n),"detect: labels must be string[]"),s.labels=e.labels),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"detect: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function w(e,s=null){t(a(e),"detect: response must be an object"),t(Array.isArray(e.entities),"detect: entities[] required"),t(n(e.model),"detect: model required"),t(d(e.ms)&&e.ms>=0,"detect: ms required");for(const r of e.entities)t(a(r)&&n(r.value)&&n(r.type),"detect: entity needs value and type"),t(Number.isInteger(r.start)&&Number.isInteger(r.end)&&r.start>=0&&r.end>r.start,`detect: entity ${JSON.stringify(r.value)} needs start < end`),t(d(r.score)&&r.score>=0&&r.score<=1,`detect: entity ${JSON.stringify(r.value)} needs a score in [0,1]`),typeof s=="string"&&t(s.slice(r.start,r.end)===r.value,`detect: entity ${JSON.stringify(r.value)} is not at ${r.start}–${r.end} of the text`);return e}const m=e=>{if(!n(e))return!1;try{const s=new URL(e);return s.protocol==="http:"||s.protocol==="https:"}catch{return!1}};function E(e){t(a(e),"search: body must be an object"),t(n(e.q)&&e.q.trim().length>0,"search: q (non-empty string) required");const s={q:e.q.trim()};return e.limit!=null&&(t(Number.isInteger(e.limit)&&e.limit>=1&&e.limit<=50,"search: limit must be an integer 1–50"),s.limit=e.limit),e.lang!=null&&(t(n(e.lang)&&/^[a-z]{2}(-[A-Za-z]{2})?$/.test(e.lang),"search: lang must be a BCP-47 tag like en or en-US"),s.lang=e.lang),e.site!=null&&(t(n(e.site)&&!/[\s/]/.test(e.site),"search: site must be a hostname"),s.site=e.site.toLowerCase()),e.freshness!=null&&(t(v.includes(e.freshness),`search: freshness must be one of ${v.join(", ")}`),s.freshness=e.freshness),e.read!=null&&(t(Number.isInteger(e.read)&&e.read>=0&&e.read<=10,"search: read must be an integer 0–10"),s.read=e.read),e.provider!=null&&(t(n(e.provider),"search: provider must be a non-empty string"),s.provider=e.provider),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"search: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function N(e){return t(a(e),"search: response must be an object"),t(Array.isArray(e.results),"search: results[] required"),t(n(e.provider),"search: provider required"),t(d(e.ms)&&e.ms>=0,"search: ms required"),e.results.forEach((s,r)=>{t(a(s)&&s.rank===r+1,`search: result ${r} must carry rank ${r+1}`),t(m(s.url),`search: result ${r+1} needs an absolute http(s) url`),t(n(s.title),`search: result ${r+1} needs a title`),t(typeof s.snippet=="string",`search: result ${r+1} needs a snippet (may be empty)`),s.read!=null&&S(s.read)}),e}function C(e){t(a(e),"read: body must be an object"),t(m(e.url),"read: url (absolute http(s)) required");const s={url:e.url,format:"markdown"};return e.format!=null&&(t(c.includes(e.format),`read: format must be one of ${c.join(", ")}`),s.format=e.format),e.maxChars!=null&&(t(Number.isInteger(e.maxChars)&&e.maxChars>=200,"read: maxChars must be an integer ≥ 200"),s.maxChars=e.maxChars),e.snippet!=null&&(t(typeof e.snippet=="string","read: snippet must be a string"),s.snippet=e.snippet),e.provider!=null&&(t(n(e.provider),"read: provider must be a non-empty string"),s.provider=e.provider),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"read: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function S(e){t(a(e),"read: response must be an object"),t(m(e.url),"read: url (absolute, where the page landed) required"),t(typeof e.title=="string","read: title (string, may be empty) required"),t(c.includes(e.format),"read: format required");const s=e[e.format];t(typeof s=="string",`read: ${e.format} (string) required`),t(Number.isInteger(e.chars)&&e.chars===s.length,"read: chars must equal the content length"),t(typeof e.truncated=="boolean","read: truncated (boolean) required"),t(n(e.provider),"read: provider required"),t(d(e.ms)&&e.ms>=0,"read: ms required"),t(Array.isArray(e.sections),"read: sections[] required");for(const r of e.sections)t(a(r)&&n(r.id)&&n(r.heading),"read: section needs id and heading"),t(Number.isInteger(r.level)&&r.level>=1&&r.level<=6,`read: section ${r.id} needs level 1–6`),t(Number.isInteger(r.offset)&&r.offset>=0&&r.offset<=s.length,`read: section ${r.id} offset must index the content`);return e.restricted!=null&&t(a(e.restricted)&&h.includes(e.restricted.reason),`read: restricted.reason must be one of ${h.join(", ")}`),e}const $=Object.freeze(["choice","score","noul"]),M=/^[A-Za-z_][A-Za-z0-9_]*$/;function D(e){t(a(e),"decide: body must be an object"),t(n(e.state),"decide: state (non-empty string) required"),t(a(e.questions)&&Object.keys(e.questions).length>0,"decide: questions {} required");const s={};for(const[i,u]of Object.entries(e.questions)){t(M.test(i),`decide: question key ${JSON.stringify(i)} must be an identifier`),t(a(u)&&$.includes(u.type),`decide: question ${i}.type must be one of ${$.join(", ")}`),t(n(u.instructions),`decide: question ${i} needs instructions`);const l={type:u.type,instructions:u.instructions};u.type==="noul"?t(u.options==null,`decide: question ${i}: a noul has no options`):(t(Array.isArray(u.options)&&u.options.length>=2&&u.options.length<=255,`decide: question ${i}.options needs 2–255 entries`),l.options=u.options.map(o=>n(o)?{value:o}:(t(a(o)&&n(o.value),`decide: question ${i}: an option is a string or { value, describe? }`),o.describe!=null?{value:o.value,describe:String(o.describe)}:{value:o.value})),t(new Set(l.options.map(o=>o.value)).size===l.options.length,`decide: question ${i}.options must be distinct`)),s[i]=l}const r={state:e.state,questions:s};return e.model!=null&&(t(n(e.model),"decide: model must be a non-empty string"),r.model=e.model),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"decide: budgetMs must be a number ≥ 0"),r.budgetMs=e.budgetMs),r}function z(e,s=null){t(a(e),"decide: response must be an object"),t(a(e.answers),"decide: answers {} required"),t(n(e.model),"decide: model required"),t(d(e.ms)&&e.ms>=0,"decide: ms required"),e.calibrated!=null&&t(typeof e.calibrated=="boolean","decide: calibrated must be a boolean");const r=i=>d(i)&&i>=0&&i<=1;for(const i of Object.keys(s?s.questions:e.answers)){const u=e.answers[i];t(a(u),`decide: answer ${i} missing`),t(r(u.p),`decide: answer ${i}.p must be in [0,1]`),t(Array.isArray(u.options)&&u.options.every(o=>a(o)&&o.value!==void 0&&r(o.p)),`decide: answer ${i}.options must be [{ value, p }]`),u.confidence!=null&&t(r(u.confidence),`decide: answer ${i}.confidence must be in [0,1]`);const l=s?.questions?.[i];l?.type==="choice"&&t(l.options.some(o=>o.value===u.value),`decide: answer ${i}.value must be one of the options`),l?.type==="noul"&&t(typeof u.value=="boolean",`decide: answer ${i}.value must be a boolean`),l?.type==="score"&&t(d(u.value),`decide: answer ${i}.value must be a number`)}return e}function P(e){t(a(e),"rerank: body must be an object"),t(n(e.query),"rerank: query (non-empty string) required"),t(Array.isArray(e.documents)&&e.documents.length>=1&&e.documents.length<=1e3&&e.documents.every(r=>typeof r=="string"),"rerank: documents must be 1–1000 strings");const s={query:e.query,documents:e.documents.slice()};return e.top_n!=null&&(t(Number.isInteger(e.top_n)&&e.top_n>=1,"rerank: top_n must be an integer ≥ 1"),s.top_n=e.top_n),e.model!=null&&(t(n(e.model),"rerank: model must be a non-empty string"),s.model=e.model),e.budgetMs!=null&&(t(d(e.budgetMs)&&e.budgetMs>=0,"rerank: budgetMs must be a number ≥ 0"),s.budgetMs=e.budgetMs),s}function T(e,s=null){t(a(e),"rerank: response must be an object"),t(Array.isArray(e.results),"rerank: results[] required"),t(n(e.model),"rerank: model required"),t(d(e.ms)&&e.ms>=0,"rerank: ms required");const r=s?s.documents.length:1/0,i=new Set;let u=1/0;return e.results.forEach((l,o)=>{t(a(l)&&Number.isInteger(l.index)&&l.index>=0&&l.index<r,`rerank: result ${o} needs an index into the documents`),t(!i.has(l.index),`rerank: index ${l.index} listed twice`),i.add(l.index),t(d(l.relevance_score),`rerank: result ${o} needs relevance_score`),t(l.relevance_score<=u,"rerank: results must be ordered best first"),u=l.relevance_score}),s?.top_n!=null&&t(e.results.length<=s.top_n,`rerank: more than top_n (${s.top_n}) results`),e}function y(e){t(a(e),"capabilities: response must be an object"),t(Array.isArray(e.capabilities),"capabilities: capabilities[] required"),t(a(e.server)&&n(e.server.name)&&n(e.server.version),"capabilities: server {name, version} required");const s=new Set;for(const r of e.capabilities)t(a(r)&&x.includes(r.id),`capabilities: unknown capability id ${JSON.stringify(r?.id)}`),t(!s.has(r.id),`capabilities: ${r.id} listed twice`),s.add(r.id),t(r.route===b[r.id],`capabilities: ${r.id} must be served at ${b[r.id]}`),g.has(r.id)?(t(Array.isArray(r.providers)&&r.providers.length>0&&r.providers.every(n),`capabilities: ${r.id}.providers must be a non-empty string[]`),r.default!=null&&t(r.providers.includes(r.default),`capabilities: ${r.id}.default must be one of its providers`)):(t(Array.isArray(r.models)&&r.models.every(n),`capabilities: ${r.id}.models must be string[]`),r.default!=null&&t(r.models.includes(r.default),`capabilities: ${r.id}.default must be one of its models`)),r.labels!=null&&t(Array.isArray(r.labels)&&r.labels.every(n),`capabilities: ${r.id}.labels must be string[]`),r.stats!=null&&t(a(r.stats)&&(g.has(r.id)||d(r.stats.calls)),`capabilities: ${r.id}.stats needs calls`),r.runtime!=null&&t(a(r.runtime)&&n(r.runtime.state),`capabilities: ${r.id}.runtime needs state`),r.provider!=null&&j(r.provider,r.id);return e}function j(e,s="capability"){return t(a(e)&&p.includes(e.kind),`capabilities: ${s}.provider.kind must be one of ${p.join(", ")}`),e.egress!=null&&t(f.includes(e.egress),`capabilities: ${s}.provider.egress must be one of ${f.join(", ")}`),e.url!=null&&t(n(e.url)&&/^https?:\/\//.test(e.url),`capabilities: ${s}.provider.url must be http(s)`),e.adapter!=null&&t(n(e.adapter),`capabilities: ${s}.provider.adapter must be a string`),e.model!=null&&t(n(e.model),`capabilities: ${s}.provider.model must be a string`),e.label!=null&&t(n(e.label),`capabilities: ${s}.provider.label must be a string`),e}function B(e){return(e?.capabilities||[]).map(s=>({id:s.id,route:s.route,models:s.models||[],providers:s.providers||[],ready:!s.runtime||["ready","external","idle"].includes(s.runtime.state),stats:s.stats||null,labels:s.labels||null}))}export{x as CAPABILITIES,b as CAPABILITY_ROUTES,$ as DECIDE_QUESTION_TYPES,I as DISCOVERY_ROUTE,f as EGRESS_KINDS,A as OVER_BUDGET,g as PROVIDER_CAPABILITIES,p as PROVIDER_KINDS,c as READ_FORMATS,h as READ_RESTRICTIONS,v as SEARCH_FRESHNESS,B as offeredCapabilities,_ as overBudget,k as predictMs,y as validateCapabilitiesResponse,D as validateDecideRequest,z as validateDecideResponse,O as validateDetectRequest,w as validateDetectResponse,j as validateProvider,C as validateReadRequest,S as validateReadResponse,P as validateRerankRequest,T as validateRerankResponse,E as validateSearchRequest,N as validateSearchResponse};
@@ -0,0 +1 @@
1
+ import{CAPABILITIES as r}from"./capability-endpoints.js";const i=Object.freeze({chat:[{id:"chat",label:"Chat",what:"answers and drafts in the thread"},{id:"notes",label:"Notes",what:"the co-writer and the note actions"},{id:"meetings",label:"Meetings",what:"the running summary, insights and monitors"},{id:"jobs",label:"Jobs & teams",what:"scheduled and triggered work, team runs"}],stt:[{id:"dictation",label:"Dictation",what:"speaking into a composer"},{id:"voice",label:"Voice conversation",what:"talking with the assistant"},{id:"meetings",label:"Meetings",what:"the audio scribe — what is playing and the room"}],tts:[{id:"read-aloud",label:"Read aloud",what:"a reply spoken on request"},{id:"voice",label:"Voice conversation",what:"the assistant’s replies spoken"}],detect:[{id:"redaction",label:"Redaction",what:"names, places and secrets replaced before a model sees them"},{id:"fast-path",label:"Fast path",what:"an extraction asked in chat answered without a language model"}],decide:[{id:"routing",label:"Model routing",what:"which model a message goes to, when the decision model is set to route Auto (Routing › Decision model routes Auto)"},{id:"fast-path",label:"Fast path",what:"a classification asked in chat answered without a language model"},{id:"tools",label:"Tools for the model",what:"a turn’s decide tool, when the model asks for a typed judgement"},{id:"mcp",label:"MCP tool choice",what:"which server’s tools a message needs"},{id:"speaker-names",label:"Speaker naming",what:"“speaker 2 must be Priya” read from a chat message"},{id:"teams",label:"Teams",what:"the assignments a team run makes"}],rerank:[{id:"search",label:"Search",what:"history and web results ordered by relevance"},{id:"tools",label:"Tools for the model",what:"a turn’s rerank tool"},{id:"notes",label:"Notes research",what:"sources ordered for a plan note"}],embed:[{id:"search",label:"Semantic search",what:"meaning-based retrieval over notes, chats and meetings"}],search:[{id:"chat",label:"Chat",what:"web search in a turn"},{id:"notes",label:"Notes research",what:"sources for a plan note"}],read:[{id:"chat",label:"Chat",what:"a page read for a turn"},{id:"notes",label:"Notes research",what:"sources read for a note"}],extract:[{id:"attachments",label:"Attachments",what:"documents attached by reference, read by page"}],s2s:[{id:"voice",label:"Voice conversation",what:"speech in, speech out, no text in between"}]});for(const e of r)if(!i[e])throw new Error(`capability-uses: ${e} has no uses listed`);function l(e,a,t){return e?.ui?.capabilityUses?.[a]?.[t]!==!1}function h(e,a){return(i[a]||[]).map(t=>({...t,on:l(e,a,t.id)}))}function c(e,a,t,n){const s={...e?.ui?.capabilityUses||{}},o={...s[a]||{}};return n?delete o[t]:o[t]=!1,Object.keys(o).length?s[a]=o:delete s[a],{ui:{capabilityUses:s}}}export{i as CAPABILITY_USES,c as setUse,l as useAllowed,h as usesOf};
package/composer-chips.js CHANGED
@@ -1 +1 @@
1
- const r={off:"Off",deterministic:"On",model:"On + AI"},c={auto:"Auto",on:"Always",off:"Off"},l={off:"Off",chats:"Chats",meetings:"Meetings",all:"All"},f={off:"Off",ask:"Ask",allowlist:"Allowed sites",always:"Always"};function p(e={},t={}){const o=e?.ui||{},s=o.piiRedaction?.mode||"off",n=c[o.mcpToolsMode]?o.mcpToolsMode:"auto",i=l[o.historyContextMode]?o.historyContextMode:"off",a=f[o.pageActions]?o.pageActions:"off";return[{id:"privacy",label:"Privacy",value:r[s]||"Off",on:s!=="off",title:s==="off"?"Redaction off — a model sees what you type":s==="model"?"Redaction on, patterns + AI detection":"Redaction on, patterns + dictionary"},{id:"tools",label:"Tools",value:c[n],on:n!=="off",title:n==="auto"?"MCP tools: the servers whose tools match the message":n==="on"?"MCP tools: every enabled server, every turn":"MCP tools: off"},{id:"history",label:"History",value:l[i],on:i!=="off",title:i==="off"?"History context: nothing from past chats is added":`History context: ${l[i].toLowerCase()} are searched for each message`},{id:"page",label:"Page",value:t.pageArmed?"Armed":f[a],on:a!=="off",title:t.pageArmed?"Act on page: armed for this site":a==="off"?"Act on page: off":a==="ask"?"Act on page: offered when a known app opens":a==="allowlist"?"Act on page: only on sites you allowed":"Act on page: every readable tab"},{id:"voice",label:"Voice",value:t.voiceActive?"On":"",on:!!t.voiceActive,title:t.voiceActive?"Voice conversation — listening":"Voice conversation — talk, listen, repeat"}]}function A(e){return e.value?`${e.label}: ${e.value}`:e.label}export{A as chipText,p as composerChips};
1
+ const g={off:"Off",deterministic:"On",model:"On + AI"},r={auto:"Auto",on:"Always",off:"Off"},c={off:"Off",chats:"Chats",meetings:"Meetings",all:"All"},f={off:"Off",ask:"Ask",allowlist:"Allowed sites",always:"Always"},d={dictating:"Dictating",talking:"Talking",transcribing:"Transcribing"},p={dictating:"Dictating — your words go into the box",talking:"Voice conversation — listening",transcribing:"Transcribing — the meeting is being written as it happens"},l=o=>d[o.voice]?o.voice:o.voiceActive?"talking":"";function y(o={},e={}){const t=o?.ui||{},n=t.piiRedaction?.mode||"off",i=r[t.mcpToolsMode]?t.mcpToolsMode:"auto",s=c[t.historyContextMode]?t.historyContextMode:"off",a=f[t.pageActions]?t.pageActions:"off";return[{id:"privacy",label:"Privacy",value:g[n]||"Off",on:n!=="off",title:n==="off"?"Redaction off — a model sees what you type":n==="model"?"Redaction on, patterns + AI detection":"Redaction on, patterns + dictionary"},{id:"tools",label:"Tools",value:r[i],on:i!=="off",title:i==="auto"?"MCP tools: the servers whose tools match the message":i==="on"?"MCP tools: every enabled server, every turn":"MCP tools: off"},{id:"history",label:"History",value:c[s],on:s!=="off",title:s==="off"?"History context: nothing from past chats is added":`History context: ${c[s].toLowerCase()} are searched for each message`},{id:"page",label:"Page",value:e.pageArmed?"Armed":f[a],on:a!=="off",title:e.pageArmed?"Act on page: armed for this site":a==="off"?"Act on page: off":a==="ask"?"Act on page: offered when a known app opens":a==="allowlist"?"Act on page: only on sites you allowed":"Act on page: every readable tab"},{id:"voice",label:"Voice",value:d[l(e)]||"",on:!!l(e),title:p[l(e)]||"Voice — dictate, talk, or transcribe what’s playing and the room"}]}function u(o){return o.value?`${o.label}: ${o.value}`:o.label}export{u as chipText,y as composerChips};
package/context-window.js CHANGED
@@ -1 +1 @@
1
- const a=[[/gpt-4\.1/,1e6],[/gpt-5|o3|o4|o1/,2e5],[/gpt-4o|gpt-4-turbo/,128e3],[/claude-(3|4|5|opus|sonnet|haiku|fable)/,2e5],[/gemini-(1\.5|2|2\.5|3)/,1e6],[/gemini/,1e6],[/deepseek/,128e3],[/mistral-large|mixtral|codestral/,128e3],[/grok/,128e3],[/llama-3\.[1-3]|llama-4/,128e3]];function l(t={},e=null){const i=String(t.id||""),r=String(t.model||t.id||"").toLowerCase(),u=e&&(e[i]||e[r]||e[String(t.model||"")]);if(Number(u)>0)return Number(u);const o=Number(t.window||t.contextLength||t.contextWindow||0);if(o>0)return o;if(t.reach==="device"||t.kind==="webllm")return 0;for(const[n,c]of a)if(n.test(r))return c;return 0}const s=.85;function d({promptTokens:t=0,floorTokens:e=0,window:i=0,reserve:r=1024,headroom:u=s}={}){const o=Number(i)||0;if(!o)return{status:"unknown",budget:0,over:0,window:0};const n=Math.max(0,Math.floor(o*u)-Math.max(0,Number(r)||0)),c=Math.max(0,Number(t)||0),m=Math.max(0,Number(e)||0);return c<=n?{status:"ok",budget:n,over:0,window:o}:m<=n?{status:"compact",budget:n,over:c-n,window:o}:{status:"too-big",budget:n,over:m-n,window:o}}function f(t=0){const e=Number(t)||0;return e?e<=8e3?2:e<=32768?4:e<=128e3?8:12:4}function x({floorTokens:t=0,reserve:e=1024,headroom:i=s}={}){const r=Math.max(0,Number(t)||0);return r?Math.ceil((r+Math.max(0,Number(e)||0))/i):0}function w(t){return/context.{0,8}(length|window|size)|context_length_exceeded|prompt is too long|too many tokens|maximum context|exceed.{0,20}context|reduce the (length|number|size)|input is too long|token limit|n_ctx|kv cache/i.test(String(t?.message||t||""))}export{s as FIT_HEADROOM,d as fitFor,w as isContextLimitError,f as keepRecentFor,x as minWindowFor,l as windowOf};
1
+ const l=[[/gpt-4\.1/,1e6],[/gpt-5|o3|o4|o1/,2e5],[/gpt-4o|gpt-4-turbo/,128e3],[/claude-(3|4|5|opus|sonnet|haiku|fable)/,2e5],[/gemini-(1\.5|2|2\.5|3)/,1e6],[/gemini/,1e6],[/deepseek/,128e3],[/mistral-large|mixtral|codestral/,128e3],[/grok/,128e3],[/llama-3\.[1-3]|llama-4/,128e3]];function a(t={},n=null){const e=String(t.id||""),i=String(t.model||t.id||"").toLowerCase(),u=n&&(n[d(t)]||n[i]||n[String(t.model||"")]||(t.gateway?0:n[e]));if(Number(u)>0)return Number(u);const r=Number(t.window||t.contextLength||t.contextWindow||0);if(r>0)return r;if(t.reach==="device"||t.kind==="webllm")return 0;for(const[o,c]of l)if(o.test(i))return c;return 0}function d(t={}){const n=String(t.id||""),e=String(t.model||"");return e?`${n}:${e}`:n}const s=.85;function f({promptTokens:t=0,floorTokens:n=0,window:e=0,reserve:i=1024,headroom:u=s}={}){const r=Number(e)||0;if(!r)return{status:"unknown",budget:0,over:0,window:0};const o=Math.max(0,Math.floor(r*u)-Math.max(0,Number(i)||0)),c=Math.max(0,Number(t)||0),m=Math.max(0,Number(n)||0);return c<=o?{status:"ok",budget:o,over:0,window:r}:m<=o?{status:"compact",budget:o,over:c-o,window:r}:{status:"too-big",budget:o,over:m-o,window:r}}function x(t=0){const n=Number(t)||0;return n?n<=8e3?2:n<=32768?4:n<=128e3?8:12:4}function w({floorTokens:t=0,reserve:n=1024,headroom:e=s}={}){const i=Math.max(0,Number(t)||0);return i?Math.ceil((i+Math.max(0,Number(n)||0))/e):0}function p(t){return/context.{0,8}(length|window|size)|context_length_exceeded|prompt is too long|too many tokens|maximum context|exceed.{0,20}context|reduce the (length|number|size)|input is too long|token limit|n_ctx|kv cache/i.test(String(t?.message||t||""))}export{s as FIT_HEADROOM,f as fitFor,p as isContextLimitError,x as keepRecentFor,w as minWindowFor,d as observedKey,a as windowOf};
package/event-stats.js ADDED
@@ -0,0 +1 @@
1
+ const j=864e5,m=n=>{try{return JSON.stringify(n).length}catch{return 0}},D=n=>{const s=[],a=(e,l)=>{if(!(!e||typeof e!="object"||l>3)){if(typeof e.hash=="string"&&typeof e.kind=="string"){s.push(e.hash);return}for(const y of Array.isArray(e)?e:Object.values(e))a(y,l+1)}};return a(n,0),s},k=n=>Math.round(n*1e3)/10;function I(n=[]){const s=Array.isArray(n)?n.filter(t=>t&&typeof t=="object"):[];let a=0,e=1/0,l=-1/0;const y={},g={},b=new Map,c=[];let v=0,M=0;for(const t of s){const r=m(t);a+=r,Number.isFinite(t.at)&&(t.at<e&&(e=t.at),t.at>l&&(l=t.at));const u=y[t.host]||(y[t.host]={events:0,bytes:0});u.events+=1,u.bytes+=r,g[t.type]=(g[t.type]||0)+1;const d=t.payload?.turnId;if(typeof d=="string"&&d){const p=b.get(d)||{events:0,bytes:0,surface:null};p.events+=1,p.bytes+=r,t.type==="turn.started"&&typeof t.payload.surface=="string"&&(p.surface=t.payload.surface),b.set(d,p)}c.push(...D(t.payload)),t.type==="capability.invoked"&&(v+=1),t.type==="capability.resulted"&&t.payload?.ok===!1&&(M+=1)}const i=s.length&&l>e?Math.max(1,(l-e)/864e5):s.length?1:0,o=[...b.values()],h=o.map(t=>t.events).sort((t,r)=>t-r),f={};for(const t of o){const r=t.surface||"unknown",u=f[r]||(f[r]={turns:0,events:0,bytes:0});u.turns+=1,u.events+=t.events,u.bytes+=t.bytes}for(const t of Object.values(f))t.avgEvents=Math.round(t.events/t.turns),t.avgBytes=Math.round(t.bytes/t.turns),delete t.events,delete t.bytes;const A=new Set(c).size;return{events:s.length,bytes:a,avgBytes:s.length?Math.round(a/s.length):0,span:{fromAt:Number.isFinite(e)?e:null,toAt:Number.isFinite(l)?l:null,days:Math.round(i*10)/10},perDay:{events:i?Math.round(s.length/i):0,bytes:i?Math.round(a/i):0},hosts:y,types:g,turns:{count:o.length,avgEvents:o.length?Math.round(o.reduce((t,r)=>t+r.events,0)/o.length):0,avgBytes:o.length?Math.round(o.reduce((t,r)=>t+r.bytes,0)/o.length):0,p95Events:h.length?h[Math.min(h.length-1,Math.floor(h.length*.95))]:0,bySurface:f},refs:{total:c.length,distinct:A,dedupHitRate:c.length?k(1-A/c.length):0},toolCalls:{total:v,perTurn:o.length?Math.round(v/o.length*10)/10:0,failed:M}}}function Y(n,{capEvents:s=2e4}={}){if(!n||!n.span?.days)return null;const a=Math.round(n.perDay.events*365),e=Math.round(n.perDay.bytes*365);return{eventsPerYear:a,bytesPerYear:e,daysToCap:n.perDay.events?Math.round(s/n.perDay.events):null}}export{I as eventStats,Y as projectYear};
package/event-sync.js ADDED
@@ -0,0 +1 @@
1
+ import{toCloudEvent as g,fromCloudEvent as m}from"./cloudevents.js";const d=Object.freeze({maxEvents:500,maxBytes:512*1024});function h({events:o=[],cursor:t={},host:e,maxEvents:r=d.maxEvents,maxBytes:n=d.maxBytes}={}){const c=Number.isInteger(t?.[e])?t[e]:-1,u=o.filter(s=>s&&s.host===e&&s.seq>c).sort((s,p)=>s.seq-p.seq),i=[];let f=0,a=null;for(const s of u){const p=g(s),l=JSON.stringify(p).length;if(i.length&&(i.length>=r||f+l>n))break;i.push(p),f+=l,a=s.seq}return{batch:i,seq:a,remaining:u.length-i.length}}function v(o,t){const e={appended:0,duplicates:0,rejected:[],events:[]};for(const r of Array.isArray(t)?t:[]){let n;try{n=m(r),o.append(n).appended?(e.appended+=1,e.events.push(n)):e.duplicates+=1}catch(c){e.rejected.push({id:typeof r?.id=="string"?r.id:null,code:c?.code||"INGEST",message:String(c?.message||c)})}}return e}function x(o){const t=o?.cursor??o;if(!t||typeof t!="object"||Array.isArray(t))return{};const e={};for(const[r,n]of Object.entries(t))typeof r=="string"&&Number.isInteger(n)&&n>=0&&(e[r]=n);return e}export{d as PUSH_LIMITS,x as cursorOf,v as ingestCloudEvents,h as planEventPush};
package/failover.js CHANGED
@@ -1 +1 @@
1
- const p=6;function m(r,t){const s=Array.isArray(r)?r.length:Number(r)||0,n=new Error(`${s} model${s===1?"":"s"} tried, none could answer. Last error — ${t?.message||t}`);return n.cause=t,n.tried=Array.isArray(r)?[...r]:[],n}async function T({first:r,call:t,chose:s=!1,health:n=null,next:d=null,onHop:w=null,labelOf:l=E,signal:y=null,maxAttempts:f=6}={}){if(typeof t!="function")throw new Error("runWithFailover: call required");const u=[];let o=r,h=null;for(let c=0;c<f;c+=1)try{const e=await t(o);return o?.id&&n&&n.markHealthy(o.id),e}catch(e){if(h=e,!s||y?.aborted||!n||typeof d!="function")throw e;const a=n.markUnhealthy(o?.id,e,o?.model);if(!a)throw e;if(u.push(o?.id),c===f-1)throw m(u,e);const i=await d({current:o,tried:[...u],reason:a.reason,marked:a,error:e});if(!i)throw m(u,e);const A={from:l(o),to:l(i),reason:a.reason,reasons:[`${l(o)} declined (${a.reason})`,...i.routedVia?.reasons||[]],next:i};try{w?.(A)}catch{}o=i}throw h}function E(r){return r?.routedVia?.model||r?.name||r?.label||r?.model||r?.id||"model"}export{p as FAILOVER_MAX_ATTEMPTS,m as failoverExhausted,T as runWithFailover};
1
+ const $=6,x=Object.freeze(["context","down","gone"]);function p(r,t){const a=Array.isArray(r)?r.length:Number(r)||0,n=new Error(`${a} model${a===1?"":"s"} tried, none could answer. Last error — ${t?.message||t}`);return n.cause=t,n.tried=Array.isArray(r)?[...r]:[],n}async function k({first:r,call:t,chose:a=!1,health:n=null,next:d=null,onHop:A=null,labelOf:c=_,signal:E=null,maxAttempts:f=6,alsoWhenPicked:h=x,classify:y=null}={}){if(typeof t!="function")throw new Error("runWithFailover: call required");const u=[];let e=r,w=null;for(let l=0;l<f;l+=1)try{const o=await t(e);return e?.id&&n&&n.markHealthy(e.id),o}catch(o){if(w=o,E?.aborted||!n||typeof d!="function")throw o;const m=typeof y=="function"?y(o):typeof n.classify=="function"?n.classify(o):null;if(!a&&!(m&&h.includes(m)))throw o;const i=n.markUnhealthy(e?.id,o,e?.model);if(!i)throw o;if(u.push(e?.id),l===f-1)throw p(u,o);const s=await d({current:e,tried:[...u],reason:i.reason,marked:i,error:o,picked:!a});if(!s)throw p(u,o);const T={from:c(e),to:c(s),reason:i.reason,reasons:[`${c(e)} declined (${i.reason})`,...s.routedVia?.reasons||[]],next:s};try{A?.(T)}catch{}e=s}throw w}function _(r){return r?.routedVia?.model||r?.name||r?.label||r?.model||r?.id||"model"}export{x as CANNOT_ANSWER,$ as FAILOVER_MAX_ATTEMPTS,p as failoverExhausted,k as runWithFailover};
package/fast-path.js CHANGED
@@ -1,8 +1,8 @@
1
- const T=/\b(extract|list|find|pull( out)?|identify|get|show( me)?|give me|what are|who are|which)\b/i,P=/\b(names?|people|persons?|person names?|places?|locations?|cities|countries|emails?|e-mails?|email addresses|phone numbers?|phones?|addresses|organi[sz]ations?|companies|company names|entities|named entities|pii|personal (data|information|info)|account numbers?|credit cards?|secrets?|passwords?)\b/i,_=/\b(in|from|of)\s+(this|that|these|the|the following|below|above|here|it)\b|:\s*$|\n/i,j=/\b(explain|why|how|summari[sz]e|summary|rewrite|translate|describe|analy[sz]e|compare|tell me about|what does|what do|opinion|think)\b/i,A=[["PERSON",/\b(names?|people|persons?)\b/i],["LOCATION",/\b(places?|locations?|cities|countries)\b/i],["ADDRESS",/\baddresses\b/i],["EMAIL",/\be-?mails?\b|email addresses/i],["PHONE",/\bphones?\b|phone numbers?/i],["ORG",/\borgani[sz]ations?|compan(y|ies)\b/i],["ID",/\baccount numbers?\b/i],["CREDITCARD",/\bcredit cards?\b/i],["SECRET",/\bsecrets?|passwords?\b/i]],I=A.map(([n])=>n),M=/\b(sentiment|tone)\b|\b(is|was) (this|that|it|the)( (review|message|email|comment|feedback|text|ticket|post|reply))?\s+(positive|negative|happy|angry|a complaint|spam|urgent|toxic|offensive|abusive)\b/i,q=[[/\bspam\b/i,{spam:{type:"noul",instructions:"Is this message spam or unsolicited promotion?"}}],[/\burgent\b/i,{urgent:{type:"noul",instructions:"Does this convey urgency — something that needs attention now?"}}],[/\ba complaint\b/i,{complaint:{type:"noul",instructions:"Is the writer complaining about a product, a service or an experience?"}}],[/\b(toxic|offensive|abusive)\b/i,{toxic:{type:"noul",instructions:"Is this text toxic, offensive or abusive?"}}]];function F(n){for(const[a,t]of q)if(a.test(n))return t;return{sentiment:{type:"choice",instructions:"The overall sentiment of the text.",options:["positive","negative","neutral","mixed"]}}}function z(n){const a=String(n||""),t=/^(.*?)(?::\s*|\n\s*\n)([\s\S]{20,})$/s.exec(a);if(t)return{instruction:t[1].trim(),inline:t[2].trim()};const s=/^(.*?)["“]([\s\S]{20,})["”]\s*$/s.exec(a);return s?{instruction:s[1].trim(),inline:s[2].trim()}:{instruction:a.trim(),inline:""}}function B(n,{material:a="",providers:t={}}={}){const{instruction:s,inline:i}=z(n),r=i||String(a||"");if(!r||r.trim().length<20||j.test(s)||s.length>240)return null;if(t.detect&&T.test(s)&&P.test(s)&&(i||_.test(n)||a)){const c=A.filter(([,o])=>o.test(s)).map(([o])=>o),l=!c.length||/\b(entities|named entities|pii|personal (data|information|info))\b/i.test(s);return{capability:"detect",families:l?I:c,text:r,reason:`an extraction of ${l?"entities":c.join(", ").toLowerCase()} over ${i?"the pasted text":"the material"}`}}if(t.decide&&M.test(s)){const c=F(s),l=Object.keys(c)[0];return{capability:"decide",question:c,text:r,reason:`a ${l==="sentiment"?"sentiment":l} judgement over the material`}}return null}const R={PERSON:"People",LOCATION:"Places",ADDRESS:"Addresses",EMAIL:"Emails",PHONE:"Phone numbers",ORG:"Organisations",ID:"Identifiers",CREDITCARD:"Card numbers",SECRET:"Secrets",SSN:"National IDs",IBAN:"IBANs"};function G(n,a,t={}){const s=new Set(n.families),i=new Map;for(const e of a||[]){if(!e?.value||!s.has(e.type))continue;i.has(e.type)||i.set(e.type,[]);const u=i.get(e.type);u.some(g=>g.toLowerCase()===e.value.toLowerCase())||u.push(e.value)}const r=[];for(const e of n.families){const u=i.get(e);u?.length&&r.push(`**${R[e]||e}** (${u.length}): ${u.join(", ")}`)}const c=n.families.length===I.length?"entities":n.families.map(e=>(R[e]||e).toLowerCase()).join(", "),l=r.length?r.join(`
2
- `):`No ${c} found in the text (${n.text.length} characters checked).`,o=t.models?.length?t.models.join(" + "):"the local detector",m=t.where||"this device",d=typeof t.ms=="number"?` in ${t.ms} ms`:"";return`${l}
1
+ const _=/\b(extract|list|find|pull( out)?|identify|get|show( me)?|give me|what are|who are|which)\b/i,T=/\b(names?|people|persons?|person names?|places?|locations?|cities|countries|emails?|e-mails?|email addresses|phone numbers?|phones?|addresses|organi[sz]ations?|companies|company names|entities|named entities|pii|personal (data|information|info)|account numbers?|credit cards?|secrets?|passwords?)\b/i,P=/\b(in|from|of)\s+(this|that|these|the|the following|below|above|here|it)\b|:\s*$|\n/i,j=/\b(explain|why|how|summari[sz]e|summary|rewrite|translate|describe|analy[sz]e|compare|tell me about|what does|what do|opinion|think)\b/i,k=[["PERSON",/\b(names?|people|persons?)\b/i],["LOCATION",/\b(places?|locations?|cities|countries)\b/i],["ADDRESS",/\baddresses\b/i],["EMAIL",/\be-?mails?\b|email addresses/i],["PHONE",/\bphones?\b|phone numbers?/i],["ORG",/\borgani[sz]ations?|compan(y|ies)\b/i],["ID",/\baccount numbers?\b/i],["CREDITCARD",/\bcredit cards?\b/i],["SECRET",/\bsecrets?|passwords?\b/i]],v=k.map(([i])=>i),M=/\b(sentiment|tone)\b|\b(is|was) (this|that|it|the)( (review|message|email|comment|feedback|text|ticket|post|reply))?\s+(positive|negative|happy|angry|a complaint|spam|urgent|toxic|offensive|abusive)\b/i,q=[[/\bspam\b/i,{spam:{type:"noul",instructions:"Is this message spam or unsolicited promotion?"}}],[/\burgent\b/i,{urgent:{type:"noul",instructions:"Does this convey urgency — something that needs attention now?"}}],[/\ba complaint\b/i,{complaint:{type:"noul",instructions:"Is the writer complaining about a product, a service or an experience?"}}],[/\b(toxic|offensive|abusive)\b/i,{toxic:{type:"noul",instructions:"Is this text toxic, offensive or abusive?"}}]];function F(i){for(const[r,t]of q)if(r.test(i))return t;return{sentiment:{type:"choice",instructions:"The overall sentiment of the text.",options:["positive","negative","neutral","mixed"]}}}const z=/^(?:please\s+)?(?:classify|categori[sz]e|label|tag|bucket|triage|sort|file)\b.*?\b(?:as|into|under|between|among|(?:to\s+)?one of)\s+(.+)$/i,B=/^(?:which|what)\s+(category|label|type|kind|class|bucket|topic|department|team|priority|intent|language|genre)\b(?:\s+(?:is|does|fits|best fits|describes)\s+(?:this|it|that)(?:\s+\w+)?)?\s*[,:—–-]?\s*(.+)$/i,H=/(?:this|it|that|the)(?:\s+(?:review|message|email|e-mail|comment|feedback|text|ticket|post|reply|request|issue|document|page|article|note|transcript|one))?/.source,U=new RegExp(`^(?:is|was)\\s+${H}\\s+(?:about\\s+|a\\s+|an\\s+)?(.+?\\bor\\b.+)$`,"i"),G=20;function Q(i){const t=String(i||"").replace(/^(?:one of)?\s*:?\s*/i,"").replace(/[?.!]+\s*$/,"").split(/\s*(?:,|\/|\||\bor\b)\s*/i).map(o=>o.trim().replace(/^["'“‘]|["'”’]$/g,"").replace(/^(?:a|an|the)\s+/i,"").trim()).filter(Boolean),s=new Set,e=[];for(const o of t){const l=o.toLowerCase();if(!s.has(l)){if(o.length>40||o.split(/\s+/).length>5)return null;s.add(l),e.push(o)}}return e.length>=2&&e.length<=G?e:null}function X(i){const r=String(i||"").trim();let t="label",s=null,e=z.exec(r);if(e?s=e[1]:(e=B.exec(r))&&/\bor\b|,|\//.test(e[2])?(t=e[1].toLowerCase(),s=e[2].replace(/^(?:is|does|fits|best fits|describes)\s+(?:this|it|that)(?:\s+\w+)?\s*[,:—–-]?\s*/i,"")):(e=U.exec(r))&&(s=e[1]),!s)return null;const o=Q(s);return o?{[t]:{type:"choice",instructions:`Which of these ${t==="label"?"labels":`${t} values`} best describes the text?`,options:o}}:null}function J(i){const r=String(i||""),t=/^(.*?)\n\s*\n([\s\S]{20,})$/s.exec(r);if(t&&!/\n\s*\n/.test(t[1]))return{instruction:t[1].trim(),inline:t[2].trim()};const s=/^(.*?)(?::\s*|\n\s*\n)([\s\S]{20,})$/s.exec(r);if(s)return{instruction:s[1].trim(),inline:s[2].trim()};const e=/^(.*?)["“]([\s\S]{20,})["”]\s*$/s.exec(r);return e?{instruction:e[1].trim(),inline:e[2].trim()}:{instruction:r.trim(),inline:""}}function K(i,{material:r="",providers:t={}}={}){const{instruction:s,inline:e}=J(i),o=e||String(r||"");if(!o||o.trim().length<20||j.test(s)||s.length>240)return null;if(t.detect&&_.test(s)&&T.test(s)&&(e||P.test(i)||r)){const c=k.filter(([,p])=>p.test(s)).map(([p])=>p),a=!c.length||/\b(entities|named entities|pii|personal (data|information|info))\b/i.test(s);return{capability:"detect",families:a?v:c,text:o,reason:`an extraction of ${a?"entities":c.join(", ").toLowerCase()} over ${e?"the pasted text":"the material"}`}}const l=t.decide?X(s):null;if(l){const c=Object.keys(l)[0];return{capability:"decide",question:l,text:o,reason:`a choice of ${c} among ${l[c].options.length} labels over the material`}}if(t.decide&&M.test(s)){const c=F(s),a=Object.keys(c)[0];return{capability:"decide",question:c,text:o,reason:`a ${a==="sentiment"?"sentiment":a} judgement over the material`}}return null}const A={PERSON:"People",LOCATION:"Places",ADDRESS:"Addresses",EMAIL:"Emails",PHONE:"Phone numbers",ORG:"Organisations",ID:"Identifiers",CREDITCARD:"Card numbers",SECRET:"Secrets",SSN:"National IDs",IBAN:"IBANs"};function V(i,r,t={}){const s=new Set(i.families),e=new Map;for(const n of r||[]){if(!n?.value||!s.has(n.type))continue;e.has(n.type)||e.set(n.type,[]);const u=e.get(n.type);u.some(g=>g.toLowerCase()===n.value.toLowerCase())||u.push(n.value)}const o=[];for(const n of i.families){const u=e.get(n);u?.length&&o.push(`**${A[n]||n}** (${u.length}): ${u.join(", ")}`)}const l=i.families.length===v.length?"entities":i.families.map(n=>(A[n]||n).toLowerCase()).join(", "),c=o.length?o.join(`
2
+ `):`No ${l} found in the text (${i.text.length} characters checked).`,a=t.models?.length?t.models.join(" + "):"the local detector",p=t.where||"this device",m=typeof t.ms=="number"?` in ${t.ms} ms`:"";return`${c}
3
3
 
4
- _Answered by ${o} on ${m}${d} — entity detection, no language model._`}function H(n,a,t={}){const s=Object.keys(n.question)[0],i=a?.[s];if(!i)return null;const r=e=>`${Math.round((e||0)*100)}%`,c=typeof i.value=="boolean"?i.value?"yes":"no":i.value,l=typeof i.value=="boolean"?"":(i.options||[]).filter(e=>e.value!==i.value).sort((e,u)=>u.p-e.p).slice(0,2).map(e=>`${e.value} ${r(e.p)}`).join(", "),o=t.models?.length?t.models.map(e=>String(e).split("/").pop()).join(" + "):"the local decision model",m=typeof t.ms=="number"?` in ${t.ms} ms`:"",d=t.calibrated===!1?" The percentage is the model’s preference, not a calibrated probability.":"";return`**${s}: ${c}** (${r(i.p)}${l?`; ${l}`:""})
4
+ _Answered by ${a} on ${p}${m} — entity detection, no language model._`}function W(i,r,t={}){const s=Object.keys(i.question)[0],e=r?.[s];if(!e)return null;const o=n=>`${Math.round((n||0)*100)}%`,l=typeof e.value=="boolean"?e.value?"yes":"no":e.value,c=typeof e.value=="boolean"?"":(e.options||[]).filter(n=>n.value!==e.value).sort((n,u)=>u.p-n.p).slice(0,2).map(n=>`${n.value} ${o(n.p)}`).join(", "),a=t.models?.length?t.models.map(n=>String(n).split("/").pop()).join(" + "):"the local decision model",p=typeof t.ms=="number"?` in ${t.ms} ms`:"",m=t.calibrated===!1?" The percentage is the model’s preference, not a calibrated probability.":"";return`**${s}: ${l}** (${o(e.p)}${c?`; ${c}`:""})
5
5
 
6
- _Answered by ${o} on ${t.where||"this device"}${m} — a typed decision, no language model.${d}_`}async function Q({prompt:n,material:a="",providers:t={},fetch:s,normalizeEntities:i,id:r="turn",enabled:c=!0}={}){if(c===!1)return null;const l={detect:(t.detect||[]).length>0,decide:(t.decide||[]).length>0},o=B(n,{material:a,providers:l});if(!o)return null;const[{assign:m,describePlan:d},{createExecutor:e},{capabilitySource:u,capabilityRunners:g}]=await Promise.all([import("./plan.js"),import("./plan-executor.js"),import("./capability-providers.js")]),L=o.capability==="detect"?{id:"extract",kind:"detect",title:o.reason,input:{from:"material"},requires:{maxLatencyMs:5e3},fallback:"skip"}:{id:"judge",kind:"decide",title:o.reason,input:{from:"material"},questions:o.question,requires:{maxLatencyMs:5e3},fallback:"skip"};let b;try{b=m({id:`fast-${r}`,origin:"chat",goal:n,steps:[L]},{capability:u(t)})}catch{return null}if(b.unassignable.length||b.steps[0].assigned?.skipped)return null;const k=e({runners:g({fetch:s,normalizeEntities:i})});let y;try{y=await k.run(b,{goal:n,material:o.text})}catch{return null}const p=y.steps[0];if(p.status!=="done"||!p.output)return null;const h=Math.round(p.cost?.ms||0),f=d(y);if(o.capability==="detect"){const{entities:S,models:v,where:N,provider:O}=p.output;return{capability:"detect",content:`${G(o,S,{models:v,ms:h,where:N})}
7
- _Plan: ${f}_`,provider:O,models:v,ms:h,reason:o.reason,plan:f,entities:S}}const{answers:w,models:$,where:C,provider:D,calibrated:x}=p.output,E=H(o,w,{models:$,ms:h,where:C,calibrated:x});return E?{capability:"decide",content:`${E}
8
- _Plan: ${f}_`,provider:D,models:$,ms:h,reason:o.reason,plan:f,answers:w,calibrated:x}:null}export{F as decideQuestionFor,B as fastPathFor,H as renderDecideAnswer,G as renderDetectAnswer,Q as runFastPath,z as splitPrompt};
6
+ _Answered by ${a} on ${t.where||"this device"}${p} — a typed decision, no language model.${m}_`}async function Y({prompt:i,material:r="",providers:t={},fetch:s,normalizeEntities:e,id:o="turn",enabled:l=!0}={}){if(l===!1)return null;const c={detect:(t.detect||[]).length>0,decide:(t.decide||[]).length>0},a=K(i,{material:r,providers:c});if(!a)return null;const[{assign:p,describePlan:m},{createExecutor:n},{capabilitySource:u,capabilityRunners:g}]=await Promise.all([import("./plan.js"),import("./plan-executor.js"),import("./capability-providers.js")]),C=a.capability==="detect"?{id:"extract",kind:"detect",title:a.reason,input:{from:"material"},requires:{maxLatencyMs:5e3},fallback:"skip"}:{id:"judge",kind:"decide",title:a.reason,input:{from:"material"},questions:a.question,requires:{maxLatencyMs:5e3},fallback:"skip"};let b;try{b=p({id:`fast-${o}`,origin:"chat",goal:i,steps:[C]},{capability:u(t)})}catch{return null}if(b.unassignable.length||b.steps[0].assigned?.skipped)return null;const O=n({runners:g({fetch:s,normalizeEntities:e})});let y;try{y=await O.run(b,{goal:i,material:a.text})}catch{return null}const d=y.steps[0];if(d.status!=="done"||!d.output)return null;const h=Math.round(d.cost?.ms||0),f=m(y);if(a.capability==="detect"){const{entities:S,models:I,where:N,provider:D}=d.output;return{capability:"detect",content:`${V(a,S,{models:I,ms:h,where:N})}
7
+ _Plan: ${f}_`,provider:D,models:I,ms:h,reason:a.reason,plan:f,entities:S}}const{answers:w,models:$,where:L,provider:R,calibrated:x}=d.output,E=W(a,w,{models:$,ms:h,where:L,calibrated:x});return E?{capability:"decide",content:`${E}
8
+ _Plan: ${f}_`,provider:R,models:$,ms:h,reason:a.reason,plan:f,answers:w,calibrated:x}:null}export{X as choiceQuestionFor,F as decideQuestionFor,K as fastPathFor,W as renderDecideAnswer,V as renderDetectAnswer,Y as runFastPath,J as splitPrompt};
package/feature-map.js CHANGED
@@ -1 +1 @@
1
- const s=["chat","privacy","notes","knowledge","meetings","voice","automation","sync","runtime","browser"],t=[{id:"chat.streaming-turn",surface:"chat",title:"Streaming turns",what:"A turn streams into the thread through its tool rounds, with a stop.",shared:["turn-loop.js","tool-round.js"]},{id:"chat.toolset",surface:"chat",title:"Per-turn toolset",what:"The tools a turn may call, chosen per target and policy.",shared:["toolset.js","tool-dispatch.js"]},{id:"chat.slash-skills",surface:"chat",title:"Skills as /commands",what:"The user’s skills and the packages the bridge found, offered as slash commands in every composer.",shared:["slash-commands.js","skill-vars.js"]},{id:"chat.slash-builtins",surface:"chat",title:"Built-in /commands",what:"/search and /history as commands, not tools the model may or may not call.",shared:["slash-commands.js"]},{id:"chat.suggestions",surface:"chat",title:"Empty-chat suggestions",what:"Prompt suggestions on an empty thread, from the page or the recent history.",shared:[]},{id:"chat.attachments",surface:"chat",title:"Attachments",what:"Text, PDF and by-reference files attached to a turn.",shared:["context-attachments.js","attached-paths.js","pdf-layout.js"]},{id:"chat.html-artifacts",surface:"chat",title:"HTML artifacts",what:"An HTML reply rendered in a sandbox, never in the panel.",shared:[]},{id:"chat.diagram-artifacts",surface:"chat",title:"Diagram artifacts",what:"A mermaid block becomes a Diagram | Code card with zoom and copy.",shared:[]},{id:"chat.model-routing",surface:"chat",title:"Auto model routing",what:"An Auto target picks a candidate per message and fails over on error.",shared:["model-candidates.js","route-strategies.js","failover.js"]},{id:"chat.history-rag",surface:"chat",title:"History in the turn",what:"Past chats, notes and meetings retrieved into a turn automatically, not only on request.",shared:["sources-retrieval.js","text-search.js"]},{id:"chat.history-search-tool",surface:"chat",title:"history_search tool",what:"The model searches the local history and reads one record in full.",shared:["sources.js"]},{id:"chat.sideline",surface:"chat",title:"Sideline",what:"A side conversation beside the thread, on the same context.",shared:["sideline.js"]},{id:"chat.fast-path",surface:"chat",title:"Fast path",what:"A turn answered without the model when a local answer exists.",shared:["fast-path.js"]},{id:"chat.capability-tools",surface:"chat",title:"decide / rerank tools",what:"The model hands a judgement or an ordering to a small local model mid-turn.",shared:["capability-tools.js","capability-providers.js"]},{id:"chat.presence",surface:"chat",title:"Situational presence",what:"What the client knows about the moment (time, place, page) stated to the model as facts.",shared:["presence.js"]},{id:"chat.usage",surface:"chat",title:"Usage meter",what:"Tokens and cost per turn and per day.",shared:["usage.js","usage-pricing.js"]},{id:"chat.web-search",surface:"chat",title:"Web search",what:"Web search as a tool, client-side or through the gateway.",shared:["web-search.js","web-search-tool.js"]},{id:"chat.weather",surface:"chat",title:"Weather",what:"Weather as a tool.",shared:["weather.js","weather-tool.js"]},{id:"chat.event-log",surface:"chat",title:"Event log",what:"What happened in a turn, in order, with where the time went.",shared:["event.js","trajectory.js"]},{id:"chat.teams",surface:"chat",title:"Agent teams",what:"Several agents on one task with a board, a plan and a trail.",shared:["team.js","team-run.js"]},{id:"chat.mcp",surface:"chat",title:"MCP servers",what:"MCP servers as tools.",shared:["mcp-client.js","mcp-manager.js"]},{id:"chat.mcp-oauth",surface:"chat",title:"MCP sign-in",what:"Signing in to an MCP server that asks for OAuth.",shared:["mcp-oauth.js","mcp-signin.js"]},{id:"chat.omni-search",surface:"chat",title:"Omni search",what:"One palette searching notes, chats and meetings at once.",shared:["omni.js"]},{id:"chat.memory",surface:"chat",title:"Memory",what:"Facts remembered across conversations, and the tool that writes them.",shared:["memory.js","memory-tool.js"]},{id:"chat.tool-result-shield",surface:"chat",title:"Tool-result shield",what:"A tool result is redacted before the model sees it.",shared:["tool-result.js"]},{id:"chat.read-aloud",surface:"chat",title:"Read aloud",what:"A reply spoken as it streams.",shared:["speak-stream.js"]},{id:"chat.structured-output",surface:"chat",title:"Typed answers",what:"A model call that expects a shape goes through one schema.",shared:["structured.js"]},{id:"chat.media-transcript",surface:"chat",title:"Video transcripts",what:"“Summarise this video” from a caption track.",shared:["media-transcript.js"]},{id:"privacy.redaction",surface:"privacy",title:"On-device redaction",what:"PII redacted before a cloud model and restored on the way back.",shared:["redaction-tokens.js","redaction-dictionary.js"]},{id:"privacy.redaction-preview",surface:"privacy",title:"Show what the model sees",what:"The redacted text, by type, before it leaves.",shared:[]},{id:"privacy.access-log",surface:"privacy",title:"Access log",what:"What left this device, on the record.",shared:["observability.js"]},{id:"privacy.vault",surface:"privacy",title:"Vault",what:"Records kept encrypted at rest.",shared:["vault.js"]},{id:"privacy.encrypted-backup",surface:"privacy",title:"Encrypted backup",what:"A backup sealed with the user’s key.",shared:["backup-envelope.js"]},{id:"notes.editor",surface:"notes",title:"Live-preview editor",what:"The note editor with regions, follow-tail and rich paste.",shared:[]},{id:"notes.cowriter",surface:"notes",title:"Co-writer",what:"A writer swarm working the note, routed per section.",shared:["cowriter.js","cowriter-router.js"]},{id:"notes.fact-check",surface:"notes",title:"Fact check",what:"Claims in a note checked against sources.",shared:["cowriter-factcheck.js"]},{id:"notes.research",surface:"notes",title:"Note research",what:"Research gathered for a note from the web and the history.",shared:["note-research.js"]},{id:"notes.graph",surface:"notes",title:"Note graph",what:"Links and mentions between notes as a graph.",shared:["note-graph.js"]},{id:"notes.tags",surface:"notes",title:"Tags",what:"Tags on notes, with tag queries in search.",shared:["tags.js"]},{id:"knowledge.briefs",surface:"knowledge",title:"Briefs",what:"Briefs read with first-class citations.",shared:["knowledge.js"]},{id:"knowledge.brief-curation",surface:"knowledge",title:"Brief curation",what:"Briefs derived from the sources — the curator.",shared:["knowledge-derive.js","synthesis.js"]},{id:"knowledge.topics",surface:"knowledge",title:"Topics",what:"Topics extracted from chats, notes and meetings, and the index they build.",shared:[]},{id:"knowledge.corpus",surface:"knowledge",title:"Corpus overview",what:"What the local corpus holds, by kind and by time.",shared:[]},{id:"meetings.live-transcript",surface:"meetings",title:"Live transcript",what:"A meeting transcribed as it happens, kept as a record.",shared:["meeting-shape.js","meeting-text.js"]},{id:"meetings.charts",surface:"meetings",title:"Meeting charts",what:"Who spoke, how much, when.",shared:[]},{id:"meetings.insights",surface:"meetings",title:"Meeting insights",what:"Decisions, actions and the moments that need you, from the transcript.",shared:["meeting-insights.js","meeting-analyzers.js"]},{id:"meetings.monitors",surface:"meetings",title:"Monitors",what:"A profile watching meetings for what matters to it.",shared:["monitor-profile.js"]},{id:"meetings.transcript-import",surface:"meetings",title:"Transcript import",what:"A transcript pasted from Zoom, Teams or Meet becomes a meeting record.",shared:[]},{id:"meetings.voice-commands",surface:"meetings",title:"Spoken commands",what:"Commands spoken during a meeting, matched from the transcript.",shared:["voice-intents.js"]},{id:"voice.dictation",surface:"voice",title:"Dictation",what:"Speak into any composer.",shared:["voice-vad.js"]},{id:"voice.mode",surface:"voice",title:"Voice mode",what:"A spoken conversation with barge-in.",shared:["voice-loop.js"]},{id:"voice.tts",surface:"voice",title:"Speech",what:"Text to speech with the chosen voice, including the user’s own.",shared:["voice-speaker.js","voice-models.js"]},{id:"automation.jobs",surface:"automation",title:"Jobs",what:"Scheduled and triggered work that runs without a turn.",shared:["job.js","schedule.js"]},{id:"automation.text-triggers",surface:"automation",title:"Text triggers",what:"A phrase arriving anywhere, matched against the user’s jobs.",shared:[]},{id:"automation.alert-sound",surface:"automation",title:"Timer sound",what:"A timer that goes off makes a sound, not only a notification.",shared:[]},{id:"automation.widgets",surface:"automation",title:"Widgets",what:"Small HTML plugins the user or an agent wrote, hosted in a frame.",shared:["widget.js"]},{id:"automation.projects",surface:"automation",title:"Projects",what:"A folder an agent works in, with its runs.",shared:["project.js","project-run.js"]},{id:"automation.skills",surface:"automation",title:"Skills",what:"Skills written by the user or found on the machine.",shared:["skill-manifest.js","skill-runtime.js","skill-sources.js"]},{id:"automation.recipes",surface:"automation",title:"Recipes",what:"Saved multi-step prompts.",shared:["recipe.js"]},{id:"automation.channels",surface:"automation",title:"Channels",what:"Telegram and WhatsApp surfaces to the agents.",shared:[]},{id:"automation.channel-pairing-qr",surface:"automation",title:"Pairing QR",what:"The channel pairing link as a QR code, read from another device.",shared:[]},{id:"sync.auto-backup",surface:"sync",title:"Auto backup",what:"A backup written on a schedule.",shared:["backup-records.js"]},{id:"sync.warm",surface:"sync",title:"Warm sync",what:"Records pulled from and pushed to the gateway.",shared:["sync-plan.js"]},{id:"sync.prefs",surface:"sync",title:"Settings travel",what:"Every setting shared between the clients, live.",shared:["client-prefs.js"]},{id:"sync.drive",surface:"sync",title:"Google Drive backup",what:"Backups to and from the user’s Drive.",shared:[]},{id:"runtime.license",surface:"runtime",title:"Licence",what:"Pro and Team verified offline against the signed token.",shared:["entitlement.js"]},{id:"runtime.free-caps",surface:"runtime",title:"Free caps",what:"The Free limits on the workspace surfaces, asked the same way everywhere.",shared:["entitlement.js"]},{id:"runtime.managed",surface:"runtime",title:"Managed mode",what:"The organisation’s configuration, pushed by IT.",shared:[]},{id:"runtime.updates",surface:"runtime",title:"Updates",what:"The client, the gateway and the bridge know when a newer version exists.",shared:[]},{id:"runtime.bridge-health",surface:"runtime",title:"Runtime health",what:"The bridge and the gateway watched, with what to do when one is down.",shared:[]},{id:"runtime.local-pairing",surface:"runtime",title:"Local pairing",what:"This client paired with the local servers by token or pin.",shared:[]},{id:"runtime.model-roles",surface:"runtime",title:"What runs where",what:"Every model in use by job, where it runs, a jump to swap it.",shared:["model-roles.js"]},{id:"browser.page-actions",surface:"browser",title:"Page actions",what:"The agent acts on the open page.",shared:[]},{id:"browser.page-tools",surface:"browser",title:"Page tools",what:"The open page read, matched and calibrated as a tool.",shared:[]},{id:"browser.canvas",surface:"browser",title:"Canvas adapters",what:"Web apps (docs, sheets, whiteboards) driven through their canvas.",shared:[]},{id:"browser.in-browser-model",surface:"browser",title:"In-browser model",what:"A model run in the browser on WebGPU.",shared:[]},{id:"browser.floating-launcher",surface:"browser",title:"Floating launcher",what:"The button on web pages that opens the panel.",shared:[]}];function r(e){return e?t.filter(a=>a.surface===e):t.slice()}function i(){return t.map(e=>e.id)}export{t as FEATURES,s as SURFACES,i as featureIds,r as listFeatures};
1
+ const s=["chat","privacy","notes","knowledge","meetings","voice","automation","sync","runtime","browser"],t=[{id:"chat.streaming-turn",surface:"chat",title:"Streaming turns",what:"A turn streams into the thread through its tool rounds, with a stop.",shared:["turn-loop.js","tool-round.js"]},{id:"chat.toolset",surface:"chat",title:"Per-turn toolset",what:"The tools a turn may call, chosen per target and policy.",shared:["toolset.js","tool-dispatch.js"]},{id:"chat.slash-skills",surface:"chat",title:"Skills as /commands",what:"The user’s skills and the packages the bridge found, offered as slash commands in every composer.",shared:["slash-commands.js","skill-vars.js"]},{id:"chat.slash-builtins",surface:"chat",title:"Built-in /commands",what:"/search and /history as commands, not tools the model may or may not call.",shared:["slash-commands.js"]},{id:"chat.suggestions",surface:"chat",title:"Empty-chat suggestions",what:"Prompt suggestions on an empty thread, from the page or the recent history.",shared:[]},{id:"chat.attachments",surface:"chat",title:"Attachments",what:"Text, PDF and by-reference files attached to a turn.",shared:["context-attachments.js","attached-paths.js","pdf-layout.js"]},{id:"chat.html-artifacts",surface:"chat",title:"HTML artifacts",what:"An HTML reply rendered in a sandbox, never in the panel.",shared:[]},{id:"chat.diagram-artifacts",surface:"chat",title:"Diagram artifacts",what:"A mermaid block becomes a Diagram | Code card with zoom and copy.",shared:[]},{id:"chat.model-routing",surface:"chat",title:"Auto model routing",what:"An Auto target picks a candidate per message and fails over on error.",shared:["model-candidates.js","route-strategies.js","route-decider.js","failover.js"]},{id:"chat.history-rag",surface:"chat",title:"History in the turn",what:"Past chats, notes and meetings retrieved into a turn automatically, not only on request.",shared:["sources-retrieval.js","text-search.js"]},{id:"chat.history-search-tool",surface:"chat",title:"history_search tool",what:"The model searches the local history and reads one record in full.",shared:["sources.js"]},{id:"chat.sideline",surface:"chat",title:"Sideline",what:"A side conversation beside the thread, on the same context.",shared:["sideline.js"]},{id:"chat.fast-path",surface:"chat",title:"Fast path",what:"A turn answered without the model when a local answer exists.",shared:["fast-path.js"]},{id:"chat.capability-tools",surface:"chat",title:"decide / rerank tools",what:"The model hands a judgement or an ordering to a small local model mid-turn.",shared:["capability-tools.js","capability-providers.js"]},{id:"chat.presence",surface:"chat",title:"Situational presence",what:"What the client knows about the moment (time, place, page) stated to the model as facts.",shared:["presence.js"]},{id:"chat.usage",surface:"chat",title:"Usage meter",what:"Tokens and cost per turn and per day.",shared:["usage.js","usage-pricing.js"]},{id:"chat.web-search",surface:"chat",title:"Web search",what:"Web search as a tool, client-side or through the gateway.",shared:["web-search.js","web-search-tool.js"]},{id:"chat.weather",surface:"chat",title:"Weather",what:"Weather as a tool.",shared:["weather.js","weather-tool.js"]},{id:"chat.event-log",surface:"chat",title:"Event log",what:"What happened in a turn, in order, with where the time went.",shared:["event.js","trajectory.js"]},{id:"chat.teams",surface:"chat",title:"Agent teams",what:"Several agents on one task with a board, a plan and a trail.",shared:["team.js","team-run.js"]},{id:"chat.mcp",surface:"chat",title:"MCP servers",what:"MCP servers as tools.",shared:["mcp-client.js","mcp-manager.js"]},{id:"chat.mcp-oauth",surface:"chat",title:"MCP sign-in",what:"Signing in to an MCP server that asks for OAuth.",shared:["mcp-oauth.js","mcp-signin.js"]},{id:"chat.omni-search",surface:"chat",title:"Omni search",what:"One palette searching notes, chats and meetings at once.",shared:["omni.js"]},{id:"chat.memory",surface:"chat",title:"Memory",what:"Facts remembered across conversations, and the tool that writes them.",shared:["memory.js","memory-tool.js"]},{id:"chat.tool-result-shield",surface:"chat",title:"Tool-result shield",what:"A tool result is redacted before the model sees it.",shared:["tool-result.js"]},{id:"chat.read-aloud",surface:"chat",title:"Read aloud",what:"A reply spoken as it streams.",shared:["speak-stream.js"]},{id:"chat.structured-output",surface:"chat",title:"Typed answers",what:"A model call that expects a shape goes through one schema.",shared:["structured.js"]},{id:"chat.media-transcript",surface:"chat",title:"Video transcripts",what:"“Summarise this video” from a caption track.",shared:["media-transcript.js"]},{id:"privacy.redaction",surface:"privacy",title:"On-device redaction",what:"PII redacted before a cloud model and restored on the way back.",shared:["redaction-tokens.js","redaction-dictionary.js"]},{id:"privacy.redaction-preview",surface:"privacy",title:"Show what the model sees",what:"The redacted text, by type, before it leaves.",shared:[]},{id:"privacy.access-log",surface:"privacy",title:"Access log",what:"What left this device, on the record.",shared:["observability.js"]},{id:"privacy.vault",surface:"privacy",title:"Vault",what:"Records kept encrypted at rest.",shared:["vault.js"]},{id:"privacy.encrypted-backup",surface:"privacy",title:"Encrypted backup",what:"A backup sealed with the user’s key.",shared:["backup-envelope.js"]},{id:"notes.editor",surface:"notes",title:"Live-preview editor",what:"The note editor with regions, follow-tail and rich paste.",shared:[]},{id:"notes.images",surface:"notes",title:"Images in a note",what:"A picture pasted or dropped into a note, stored beside it and placed by reference.",shared:["note-images.js"]},{id:"notes.cowriter",surface:"notes",title:"Co-writer",what:"A writer swarm working the note, routed per section.",shared:["cowriter.js","cowriter-router.js"]},{id:"notes.fact-check",surface:"notes",title:"Fact check",what:"Claims in a note checked against sources.",shared:["cowriter-factcheck.js"]},{id:"notes.research",surface:"notes",title:"Note research",what:"Research gathered for a note from the web and the history.",shared:["note-research.js"]},{id:"notes.graph",surface:"notes",title:"Note graph",what:"Links and mentions between notes as a graph.",shared:["note-graph.js"]},{id:"notes.tags",surface:"notes",title:"Tags",what:"Tags on notes, with tag queries in search.",shared:["tags.js"]},{id:"knowledge.briefs",surface:"knowledge",title:"Briefs",what:"Briefs read with first-class citations.",shared:["knowledge.js"]},{id:"knowledge.brief-curation",surface:"knowledge",title:"Brief curation",what:"Briefs derived from the sources — the curator.",shared:["knowledge-derive.js","synthesis.js"]},{id:"knowledge.topics",surface:"knowledge",title:"Topics",what:"Topics extracted from chats, notes and meetings, and the index they build.",shared:[]},{id:"knowledge.corpus",surface:"knowledge",title:"Corpus overview",what:"What the local corpus holds, by kind and by time.",shared:[]},{id:"meetings.live-transcript",surface:"meetings",title:"Live transcript",what:"A meeting transcribed as it happens, kept as a record.",shared:["meeting-shape.js","meeting-text.js"]},{id:"meetings.charts",surface:"meetings",title:"Meeting charts",what:"Who spoke, how much, when.",shared:[]},{id:"meetings.insights",surface:"meetings",title:"Meeting insights",what:"Decisions, actions and the moments that need you, from the transcript.",shared:["meeting-insights.js","meeting-analyzers.js"]},{id:"meetings.monitors",surface:"meetings",title:"Monitors",what:"A profile watching meetings for what matters to it.",shared:["monitor-profile.js"]},{id:"meetings.transcript-import",surface:"meetings",title:"Transcript import",what:"A transcript pasted from Zoom, Teams or Meet becomes a meeting record.",shared:[]},{id:"meetings.speaker-names",surface:"meetings",title:"Speaker names",what:"Who “Speaker 1” is: named in the transcript or by typing “Speaker 1 is Sarah” in the chat, applied on every read and to every later line.",shared:["meeting-speakers.js","meeting-speakers-typed.js"]},{id:"meetings.voice-commands",surface:"meetings",title:"Spoken commands",what:"Commands spoken during a meeting, matched from the transcript.",shared:["voice-intents.js"]},{id:"meetings.audio-scribe",surface:"meetings",title:"Audio scribe",what:"A meeting with no captions, a desktop app, a playing video or a conversation in the room, transcribed locally from what is playing and the microphone as separate channels — a mic held by one person is You, everything else is diarized.",shared:["voice-channels.js","voice-scribe.js"]},{id:"voice.dictation",surface:"voice",title:"Dictation",what:"Speak into any composer.",shared:["voice-vad.js"]},{id:"voice.mode",surface:"voice",title:"Voice mode",what:"A spoken conversation with barge-in.",shared:["voice-loop.js"]},{id:"voice.tts",surface:"voice",title:"Speech",what:"Text to speech with the chosen voice, including the user’s own.",shared:["voice-speaker.js","voice-models.js"]},{id:"automation.jobs",surface:"automation",title:"Jobs",what:"Scheduled and triggered work that runs without a turn.",shared:["job.js","schedule.js"]},{id:"automation.text-triggers",surface:"automation",title:"Text triggers",what:"A phrase arriving anywhere, matched against the user’s jobs.",shared:[]},{id:"automation.alert-sound",surface:"automation",title:"Timer sound",what:"A timer that goes off makes a sound, not only a notification.",shared:[]},{id:"automation.widgets",surface:"automation",title:"Widgets",what:"Small HTML plugins the user or an agent wrote, hosted in a frame.",shared:["widget.js"]},{id:"automation.projects",surface:"automation",title:"Projects",what:"A folder an agent works in, with its runs.",shared:["project.js","project-run.js"]},{id:"automation.skills",surface:"automation",title:"Skills",what:"Skills written by the user or found on the machine.",shared:["skill-manifest.js","skill-runtime.js","skill-sources.js"]},{id:"automation.recipes",surface:"automation",title:"Recipes",what:"Saved multi-step prompts.",shared:["recipe.js"]},{id:"automation.channels",surface:"automation",title:"Channels",what:"Telegram and WhatsApp surfaces to the agents.",shared:[]},{id:"automation.channel-pairing-qr",surface:"automation",title:"Pairing QR",what:"The channel pairing link as a QR code, read from another device.",shared:[]},{id:"sync.auto-backup",surface:"sync",title:"Auto backup",what:"A backup written on a schedule.",shared:["backup-records.js"]},{id:"sync.warm",surface:"sync",title:"Warm sync",what:"Records pulled from and pushed to the gateway.",shared:["sync-plan.js"]},{id:"sync.prefs",surface:"sync",title:"Settings travel",what:"Every setting shared between the clients, live.",shared:["client-prefs.js"]},{id:"sync.drive",surface:"sync",title:"Google Drive backup",what:"Backups to and from the user’s Drive.",shared:[]},{id:"runtime.model-place",surface:"runtime",title:"One model place",what:"Every model of every type — chat, vision, embeddings, speech, entity recognition, decisions, ranking — added by type and runtime, listed in one place with where it runs and which jobs may use it.",shared:["model-roles.js","capability-uses.js","model-entries.js"]},{id:"runtime.model-fusion",surface:"runtime",title:"Model fusion",what:"Several models as one — a union for recall (the entity detector with companions), a draft + target for speed (a server drafting with a small model or the model’s MTP head), a fallback for reliability (the next member answers when one is down) — shown with their members in the model place.",shared:["model-fusion.js"]},{id:"runtime.license",surface:"runtime",title:"Licence",what:"Pro and Team verified offline against the signed token.",shared:["entitlement.js"]},{id:"runtime.free-caps",surface:"runtime",title:"Free caps",what:"The Free limits on the workspace surfaces, asked the same way everywhere.",shared:["entitlement.js"]},{id:"runtime.managed",surface:"runtime",title:"Managed mode",what:"The organisation’s configuration, pushed by IT.",shared:[]},{id:"runtime.updates",surface:"runtime",title:"Updates",what:"The client, the gateway and the bridge know when a newer version exists.",shared:[]},{id:"runtime.bridge-health",surface:"runtime",title:"Runtime health",what:"The bridge and the gateway watched, with what to do when one is down.",shared:[]},{id:"runtime.local-pairing",surface:"runtime",title:"Local pairing",what:"This client paired with the local servers by token or pin.",shared:[]},{id:"runtime.model-roles",surface:"runtime",title:"What runs where",what:"Every model in use by job, where it runs, a jump to swap it.",shared:["model-roles.js"]},{id:"browser.page-actions",surface:"browser",title:"Page actions",what:"The agent acts on the open page.",shared:[]},{id:"browser.page-tools",surface:"browser",title:"Page tools",what:"The open page read, matched and calibrated as a tool.",shared:[]},{id:"browser.canvas",surface:"browser",title:"Canvas adapters",what:"Web apps (docs, sheets, whiteboards) driven through their canvas.",shared:[]},{id:"browser.in-browser-model",surface:"browser",title:"In-browser model",what:"A model run in the browser on WebGPU.",shared:[]},{id:"browser.floating-launcher",surface:"browser",title:"Floating launcher",what:"The button on web pages that opens the panel.",shared:[]}];function r(e){return e?t.filter(a=>a.surface===e):t.slice()}function i(){return t.map(e=>e.id)}export{t as FEATURES,s as SURFACES,i as featureIds,r as listFeatures};
@@ -0,0 +1 @@
1
+ const n=Object.freeze({claude:{label:"Claude Code",vendor:"Anthropic",hosts:["api.anthropic.com"],repoint:"limited",how:"ANTHROPIC_BASE_URL (+ ANTHROPIC_AUTH_TOKEN) to an Anthropic-compatible endpoint — this gateway’s /v1/messages qualifies",defaultModel:"cloud"},codex:{label:"Codex",vendor:"OpenAI",hosts:["api.openai.com","chatgpt.com"],repoint:"limited",how:"OPENAI_BASE_URL, or a model_provider in ~/.codex/config.toml pointing at an OpenAI-compatible endpoint",defaultModel:"cloud"},antigravity:{label:"Antigravity",vendor:"Google",hosts:["*.googleapis.com"],repoint:"no",how:"",defaultModel:"cloud"},kiro:{label:"Kiro",vendor:"AWS",hosts:["*.amazonaws.com"],repoint:"no",how:"",defaultModel:"cloud"},copilot:{label:"GitHub Copilot",vendor:"GitHub",hosts:["api.githubcopilot.com","*.github.com"],repoint:"no",how:"",defaultModel:"cloud"},deepseek:{label:"DeepSeek Harness",vendor:"DeepSeek",hosts:["api.deepseek.com"],repoint:"limited",how:"its base URL setting, to an OpenAI-compatible endpoint",defaultModel:"cloud"},opencode:{label:"OpenCode",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — any OpenAI-compatible endpoint, Ollama, LM Studio, or this gateway",defaultModel:"configurable"},pi:{label:"Pi",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — any OpenAI-compatible endpoint, or this gateway",defaultModel:"configurable"},hermes:{label:"Hermes",vendor:null,hosts:[],repoint:"yes",how:"a provider in its config — a local model is a first-class choice",defaultModel:"configurable"}}),a=t=>String(t||"").toLowerCase().replace(/[^a-z]/g,""),i={claudecode:"claude",githubcopilot:"copilot",copilotcli:"copilot",deepseekharness:"deepseek",gemini:"antigravity",geminicli:"antigravity"};function s(t){const o=a(t);if(n[o])return{id:o,...n[o]};if(i[o])return{id:i[o],...n[i[o]]};const e=Object.entries(n).find(([l,r])=>o.includes(l)||o.includes(a(r.label)));return e?{id:e[0],...e[1]}:null}function d(t,{repointed:o=null}={}){const e=s(t);return e?o?{egress:"configurable",where:`a coding agent · model at ${o}`,note:`Re-pointed by you; ${e.how||"its own setting"}.`}:e.repoint==="yes"?{egress:"configurable",where:"a coding agent · model of your choosing",note:`Its model is a setting of its own — ${e.how}. Until you set one, whatever it defaults to.`}:e.repoint==="limited"?{egress:"internet",where:`a coding agent · model at ${e.vendor}`,note:`The conversation goes to ${e.vendor} with your own login. It can be re-pointed: ${e.how}.`}:{egress:"internet",where:`a coding agent · model at ${e.vendor}`,note:`The conversation goes to ${e.vendor} with your own login; this agent cannot be pointed elsewhere.`}:{egress:"internet",where:"a coding agent · its own model, elsewhere",note:"No card for this agent — assume its model is a vendor’s until you know otherwise."}}export{n as HARNESS_CARDS,s as harnessCard,d as harnessEgress};