@chatpanel/events 0.290.0 → 0.329.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/agent-card-view.js +1 -1
  2. package/agent-permission.js +2 -2
  3. package/agent-session-open.js +1 -0
  4. package/agent-thread.js +5 -0
  5. package/attached-paths.js +1 -1
  6. package/browser-relay.js +1 -1
  7. package/client-prefs.js +1 -1
  8. package/clock.js +1 -0
  9. package/compaction.js +4 -4
  10. package/context-select.js +2 -0
  11. package/context-window.js +1 -1
  12. package/dialect-a2a.js +1 -1
  13. package/dialect-claude.js +1 -1
  14. package/digest.js +7 -0
  15. package/entitlement.js +1 -1
  16. package/fetched.js +2 -2
  17. package/find-tool.js +1 -1
  18. package/harness-cards.js +1 -1
  19. package/history-search.js +6 -6
  20. package/identity.js +1 -0
  21. package/index.js +1 -1
  22. package/kokoro-text.js +1 -1
  23. package/link-connect.js +1 -1
  24. package/link-protocol.js +1 -1
  25. package/link-routes.js +2 -0
  26. package/link-sync.js +5 -0
  27. package/memory.js +2 -2
  28. package/model-candidates.js +1 -1
  29. package/note-merge.js +9 -9
  30. package/note-tool.js +2 -2
  31. package/own-instructions.js +5 -0
  32. package/package.json +25 -1
  33. package/prefetch.js +4 -2
  34. package/provider-presets.js +1 -1
  35. package/research.js +7 -7
  36. package/retrieval-plan.js +1 -0
  37. package/sandbox-policy.js +1 -1
  38. package/search-modes.js +6 -6
  39. package/service-standby.js +1 -0
  40. package/settings-registry.js +1 -1
  41. package/stitch.js +16 -14
  42. package/thread-send.js +1 -0
  43. package/tool-group-data.js +1 -1
  44. package/tool-hints.js +4 -4
  45. package/tool-hub.js +4 -4
  46. package/tool-need.js +3 -3
  47. package/tool-result.js +2 -2
  48. package/turn-loop.js +4 -4
  49. package/vault.js +1 -1
  50. package/voice-intents.js +2 -2
  51. package/voice-sample.js +1 -1
  52. package/weather-tool.js +10 -1
  53. package/weather.js +2 -2
package/memory.js CHANGED
@@ -1,2 +1,2 @@
1
- const ae=1,k=Object.freeze({identity:{label:"Identity",ambient:!0,hint:"Who the user is — name, role, pronouns, language, timezone."},preference:{label:"Preference",ambient:!0,hint:"How they want things done — tone, format, defaults, things never to do."},project:{label:"Project",ambient:!1,hint:"Ongoing work, goals and constraints not derivable from the material itself."},fact:{label:"Fact",ambient:!1,hint:"A durable fact about their world — systems, teams, environments, conventions."},reference:{label:"Reference",ambient:!1,hint:"A pointer to something external — a URL, a dashboard, a ticket, a doc."}}),O=Object.freeze(Object.keys(k)),F=Object.freeze(O.filter(e=>k[e].ambient)),S=280,v=3,U=200,R=1200;class $ extends Error{constructor(r){super(r),this.name="MemoryError"}}function _(e={},{now:r=0,newId:s=null}={}){const o=f(e.text);if(o.length<v)throw new $("a memory needs text");if(o.length>S)throw new $(`a memory must be at most ${S} characters — save longer material as a note`);const t=k[e.kind]?e.kind:"fact",a=Number(e.createdAt)||Number(r)||0;return{id:String(e.id||(s?s():"")||""),v:1,text:o,kind:t,scope:String(e.scope||"global"),key:y(o),slot:f(e.slot).toLowerCase()||P(o),tags:[...new Set((e.tags||[]).map(n=>f(n).toLowerCase()).filter(Boolean))].slice(0,8),pinned:!!e.pinned,source:{via:String(e.source?.via||"user"),surface:String(e.source?.surface||""),ref:String(e.source?.ref||""),agent:String(e.source?.agent||"")},confidence:ie(e.confidence==null?1:Number(e.confidence)),createdAt:a,updatedAt:Number(e.updatedAt)||a,usedAt:Number(e.usedAt)||0,useCount:Math.max(0,Math.floor(Number(e.useCount)||0)),expiresAt:e.expiresAt?Number(e.expiresAt):null,history:(e.history||[]).slice(-5).map(n=>({text:f(n.text),at:Number(n.at)||0}))}}function ce(e){try{return _(e,{now:e?.createdAt||1}),!!e?.id}catch{return!1}}function y(e){const r=f(e).toLowerCase().replace(/[^\p{L}\p{N}\s]/gu," ").split(/\s+/).filter(s=>s&&!z.has(s));return[...new Set(r)].sort().join(" ")}const z=new Set(["a","an","the","i","im","me","my","mine","we","our","us","you","your","is","am","are","was","were","be","been","being","do","does","did","to","of","in","on","at","for","with","and","or","that","this","it","please","always","usually","generally","really","just","very","so","remember","note","noting","user","prefer","prefers","preferred","like","likes"]);function P(e){const r=f(e).toLowerCase().replace(/^the\s+/,"");if(/^(?:goes by|name is|is called|called)\b/.test(r))return"name";if(/^pronouns\b/.test(r))return"pronouns";const s=/^(?:my\s+|their\s+)?([\p{L}\p{N}][\p{L}\p{N} '-]{0,28}?)\s+(?:is|are|was|were)\b/u.exec(r);if(!s)return"";const o=s[1].split(/\s+/).filter(t=>!z.has(t)).join(" ");return o.length>=3?o:""}function j(e,r){const s=new Set(y(e).split(" ").filter(Boolean)),o=new Set(y(r).split(" ").filter(Boolean));if(!s.size||!o.size)return 0;let t=0;for(const a of s)o.has(a)&&(t+=1);return t/(s.size+o.size-t)}function W(e,r){const s=new Set(y(e).split(" ").filter(Boolean)),o=new Set(y(r).split(" ").filter(Boolean));if(!s.size||!o.size)return 0;let t=0;for(const a of s)o.has(a)&&(t+=1);return t/Math.min(s.size,o.size)}const K=.8,V=[{re:/^(?:please\s+)?(?:remember|memorize|memorise)(?:\s+that|\s+this)?[:,]?\s+(.+)$/i,kind:"fact"},{re:/^(?:please\s+)?(?:keep in mind|bear in mind|don'?t forget|do not forget)(?:\s+that)?[:,]?\s+(.+)$/i,kind:"fact"},{re:/^(?:please\s+)?(?:make a note|note)(?:\s+that|\s+of)[:,]?\s+(.+)$/i,kind:"fact"},{re:/^(?:from now on|going forward|in future|in the future|henceforth)[:,]?\s+(.+)$/i,kind:"preference"},{re:/^(?:call me|i go by|refer to me as)\s+(.+)$/i,kind:"identity",rebuild:e=>`Goes by ${x(e[1])}`},{re:/^my name(?:'s| is)\s+(.+)$/i,kind:"identity",rebuild:e=>`Name is ${x(e[1])}`},{re:/^(?:always|never)\s+(.+)$/i,kind:"preference",rebuild:(e,r)=>N(r)}],I=/^(?:(?:no|nope|yes|yeah|yep|ok|okay|sure|well|and|also|just|so|oh|hey|actually|then|but)[,.!]?\s+){1,3}/i,L=/^(?:please\s+)?(?:remember|memorize|memorise|save|note|keep)\s+(?:it|this|that)(?:\s+(?:for me|please))?\s*[.!]*$/i,H=[{re:/^i (?:prefer|like|want|need)\s+(.+)$/i,kind:"preference",confidence:.7},{re:/^i (?:hate|dislike|don'?t like|do not like|can'?t stand)\s+(.+)$/i,kind:"preference",confidence:.7},{re:/^i(?:'m| am)(?: a| an| the)?\s+(.+)$/i,kind:"identity",confidence:.6},{re:/^i (?:work|working) (?:on|at|with)\s+(.+)$/i,kind:"project",confidence:.6},{re:/^i(?:'m| am) (?:working|building|writing) (?:on\s+)?(.+)$/i,kind:"project",confidence:.6},{re:/^(?:we|our team|my team) (?:use|uses|are using|run|runs|deploy|deploys)\s+(.+)$/i,kind:"fact",confidence:.6},{re:/^my (?:\w+\s){0,2}?(?:is|are)\s+(.+)$/i,kind:"fact",confidence:.55}],G=[/^(?:please\s+)?forget(?:\s+that|\s+about)?[:,]?\s+(.+)$/i,/^(?:please\s+)?(?:stop remembering|no longer remember|un-?remember)[:,]?\s+(.+)$/i],q=/(?:^|\s)(?:do|does|did|can|could|would|will|what|when|where|who|why|how|are|is)\s+(?:you|i|we|it)\b/i,X=/\b(?:can'?t|cannot|don'?t|do not|couldn'?t|never|didn'?t)\s+(?:seem to\s+)?(?:remember|recall|forget)\b/i;function le(e,{maxCandidates:r=3,includeReveals:s=!0,previous:o=""}={}){const t=[],n=String(e||"").replace(/```[\s\S]*?```/g," ").replace(/`[^`]*`/g," ");for(const i of B(n)){if(t.length>=r)break;if(i.length<v||X.test(i))continue;let h=!1;for(const l of G){const u=l.exec(i);if(!u)continue;const p=E(x(u[1]));p.length>=v&&(t.push({op:"forget",text:p,kind:"fact",confidence:1,explicit:!0,trigger:"forget"}),h=!0);break}if(h||q.test(i))continue;const d=i.replace(I,"");if(L.test(d)){const l=B(String(o||"").replace(/```[\s\S]*?```/g," ")).map(u=>u.trim()).find(u=>u.length>=v&&!L.test(u.replace(I,"")));l&&t.push({op:"remember",text:E(N(x(l))),kind:"fact",confidence:1,explicit:!0,trigger:"command"});continue}for(const{re:l,kind:u,rebuild:p}of V){const g=l.exec(d);if(!g)continue;const b=E(p?p(g,d):N(x(g[1])));b.length>=v&&(t.push({op:"remember",text:b,kind:u,confidence:1,explicit:!0,trigger:"command"}),h=!0);break}if(!(h||!s))for(const{re:l,kind:u,confidence:p}of H){if(!l.test(i))continue;const g=E(N(i));g.split(/\s+/).length>=3&&t.push({op:"remember",text:g,kind:u,confidence:p,explicit:!1,trigger:"reveal"});break}}return t.slice(0,r)}function de(e,r,{now:s=0,newId:o=null}={}){const t=_(r,{now:s,newId:o}),a=(e||[]).filter(i=>i&&i.scope===t.scope),n=t.slot&&a.find(i=>i.slot===t.slot)||a.find(i=>i.key===t.key)||a.find(i=>i.kind===t.kind&&j(i.text,t.text)>=K);return n?f(n.text).toLowerCase()===t.text.toLowerCase()?{action:"duplicate",record:{...n,updatedAt:Number(s)||n.updatedAt,useCount:n.useCount+1},replaces:n}:{action:"update",record:{...n,text:t.text,key:t.key,slot:t.slot,kind:t.kind,tags:t.tags.length?t.tags:n.tags,confidence:t.confidence,source:t.source,updatedAt:Number(s)||n.updatedAt,history:[...n.history,{text:n.text,at:n.updatedAt}].slice(-5)},replaces:n}:{action:"create",record:t,replaces:null}}function ue(e,r,{limit:s=5}={}){const o=f(r);if(!o)return[];const t=(e||[]).filter(n=>n.id===o);if(t.length)return t;const a=y(o);return(e||[]).map(n=>({m:n,s:n.key===a?1:Math.max(j(n.text,o),W(o,n.text))})).filter(n=>n.s>=.5).sort((n,i)=>i.s-n.s).slice(0,s).map(n=>n.m)}const Z=/\b(?:(?:i|we|user|they)\s+(?:live|lives|stay|stays|reside|resides|am based|are based|is based|am located|are located|is located|moved|have moved)\s+(?:in|at|near|to|around|outside)|(?:i'?m|i am|we'?re|we are|user is|they are|they'?re)\s+(?:from|based in|located in|living in|in the)\b|(?:my|our|user'?s|their)\s+(?:home|home ?town|city|town|address|location|zip|postcode|neighbou?rhood|area)\b|\blives?\s+(?:in|at|near)|\bhome is\b)/i,J=/\b(?:how far|how long (?:does it take |will it take |would it take |is the (?:drive|flight|ride|walk) )?to (?:get|drive|walk|fly|reach|go)|distance (?:to|from)|drive to|driving to|commute|directions? to|route to|get(?:ting)? to|near(?:by| me| here)|(?:around|from|over) (?:here|me)|close to me|in my area|local (?:time|news|weather|restaurants?|shops?|stores?|events?)|where i (?:am|live)|(?:rain|snow|weather|sunny|cold|hot|warm|windy) here)\b|^\s*(?:what(?:'s| is) the |how(?:'s| is) the )?(?:weather|forecast|temperature|sunset|sunrise)\b/i,Q=/\bfrom\s+(?!here\b|home\b|me\b|my\b|where\b)[\p{L}]/iu;function ee(e){return Z.test(String(e?.text||""))}function te(e){const r=String(e||"");return J.test(r)&&!Q.test(r)}function fe(e,{text:r="",scopes:s=["global"],kinds:o=null,now:t=0,limit:a=24,maxChars:n=R,includeAmbient:i=!0,ambientKinds:h=F}={}){const d=new Set(s.length?s:["global"]),l=new Set(y(r).split(" ").filter(Boolean)),u=te(r),g=(e||[]).filter(c=>c&&c.text).filter(c=>d.has(c.scope)).filter(c=>!o||o.includes(c.kind)).filter(c=>!c.expiresAt||!t||c.expiresAt>t).map(c=>{const A=new Set(c.key.split(" ").filter(Boolean));let M=0;for(const Y of A)l.has(Y)&&(M+=1);const m=Math.max(A.size?M/A.size:0,u&&ee(c)?1:0),w=i&&h.includes(c.kind)&&k[c.kind]?.ambient&&A.size<=re,T=t&&c.updatedAt?Math.max(0,1-(t-c.updatedAt)/oe):0,D=Math.min(1,c.useCount/10);return{m:c,keep:c.pinned||w||m>0,score:(c.pinned?100:0)+(w?10:0)+m*8+T+D}}),b=[];let C=0;for(const{m:c,keep:A,score:M}of g.filter(m=>m.keep).sort((m,w)=>w.score-m.score)){if(b.length>=a)break;if(b.some(w=>ne(w,c)))continue;const m=c.text.length+c.kind.length+6;if(C+m>n&&b.length)break;C+=m,b.push(c)}return b}const re=14;function ne(e,r){const s=new Set(String(e?.key||"").split(" ").filter(Boolean)),o=new Set(String(r?.key||"").split(" ").filter(Boolean));if(!s.size||!o.size)return!1;const[t,a]=s.size<=o.size?[s,o]:[o,s];let n=0;for(const i of t)a.has(i)&&(n+=1);return n/t.size>=.7}const oe=365*24*60*60*1e3;function he(e,{heading:r="What you already know about this user",maxChars:s=R}={}){const o=(e||[]).filter(n=>n&&n.text);if(!o.length)return"";const t=[];let a=0;for(const n of o){const i=`- (${n.kind}) ${n.text}`;if(a+i.length>s&&t.length)break;a+=i.length+1,t.push(i)}return[`## ${r}`,"Saved by the user in ChatPanel and true across conversations, agents and devices.","Apply them without being asked and without announcing them.",...t,"If the user states something durable about themselves, their preferences or their work, save it with the `memory` tool. If they correct one of these, update it — do not just agree."].join(`
2
- `)}function me(e,r,{now:s=0}={}){const o=new Set(r||[]);return(e||[]).map(t=>o.has(t.id)?{...t,usedAt:Number(s)||t.usedAt,useCount:t.useCount+1}:t)}function pe(e,{now:r=0,max:s=U}={}){const o=(e||[]).filter(Boolean),t=r?o.filter(i=>i.expiresAt&&i.expiresAt<=r):[];let a=t.length?o.filter(i=>!t.includes(i)):o;const n=[...t];if(a.length>s){const i=d=>(d.pinned?3:0)+(k[d.kind]?.ambient?1:0),h=[...a].sort((d,l)=>i(l)-i(d)||l.useCount-d.useCount||(l.usedAt||l.updatedAt)-(d.usedAt||d.updatedAt));n.push(...h.slice(s)),a=h.slice(0,s)}return{kept:a,dropped:n}}const ge=Object.freeze({name:"memory",description:'Save, update or remove a durable fact about the USER in ChatPanel — carried into every future conversation, on every model and agent. Use it the moment they state a standing preference ("always be terse"), an identity fact ("call me Alex"), or a constraint about their work that will still be true next week. Do NOT use it for one-off task details, anything already obvious from the conversation, or content that belongs in a note. Keep each memory one short self-contained sentence. Use `forget` when the user says something is no longer true, and `list` to see what is already stored before adding.',parameters:{type:"object",properties:{action:{type:"string",enum:["remember","forget","list"],description:"What to do."},text:{type:"string",description:`The fact, as one short sentence written in the third person ("Prefers terse answers"). Max ${S} characters. Required for remember; for forget, the memory to drop (its text or id).`},kind:{type:"string",enum:O,description:O.map(e=>`${e}: ${k[e].hint}`).join(" ")},tags:{type:"array",items:{type:"string"},description:"Optional short tags for grouping."}},required:["action"]}});function be(){return"`memory` saves something durable the user says about themselves, how they want to be helped, or their ongoing work — never task details or transient state — and you say in a short clause what you saved."}const se=Object.freeze({});function ye(e){let r=e;for(let s=Number(r?.v)||1;s<1;s+=1){const o=se[s];if(!o)throw new $(`no upcaster from memory v${s}`);r=o(r)}return r}const f=e=>String(e??"").replace(/\s+/g," ").trim(),ie=e=>Number.isFinite(e)?Math.min(1,Math.max(0,e)):1,x=e=>f(e).replace(/[.,;:!]+$/,""),E=e=>e.length>S?`${e.slice(0,S-1).trimEnd()}…`:e,N=e=>{const r=x(e);return r&&r[0].toUpperCase()+r.slice(1)};function B(e){return String(e||"").split(/\n+/).flatMap(r=>f(r).replace(/^[-*+•]\s*|^\d+[.)]\s*/,"").split(/(?<=[.!?])\s+(?=[A-Z"'])/)).map(f).filter(Boolean)}export{F as AMBIENT_KINDS,re as AMBIENT_MAX_WORDS,R as DEFAULT_BLOCK_CHARS,U as DEFAULT_MAX_MEMORIES,S as MAX_MEMORY_CHARS,k as MEMORY_KINDS,O as MEMORY_KIND_NAMES,ge as MEMORY_TOOL_SPEC,se as MEMORY_UPCASTERS,ae as MEMORY_VERSION,v as MIN_MEMORY_CHARS,$ as MemoryError,K as SAME_FACT,le as candidatesFrom,W as containment,ce as isValidMemory,me as markUsed,ue as matchForForget,he as memoryBlock,y as memoryKey,be as memoryToolSystem,te as needsWhere,_ as normalizeMemory,pe as pruneMemories,fe as recall,de as reconcile,ne as sameMemory,ee as saysWhere,j as similarity,P as slotOf,ye as upcastMemory};
1
+ const ae=1,k=Object.freeze({identity:{label:"Identity",ambient:!0,hint:"Who the user is — name, role, pronouns, language, timezone."},preference:{label:"Preference",ambient:!0,hint:"How they want things done — tone, format, defaults, things never to do."},project:{label:"Project",ambient:!1,hint:"Ongoing work, goals and constraints not derivable from the material itself."},fact:{label:"Fact",ambient:!1,hint:"A durable fact about their world — systems, teams, environments, conventions."},reference:{label:"Reference",ambient:!1,hint:"A pointer to something external — a URL, a dashboard, a ticket, a doc."}}),O=Object.freeze(Object.keys(k)),F=Object.freeze(O.filter(e=>k[e].ambient)),S=280,v=3,U=200,R=1200;class $ extends Error{constructor(r){super(r),this.name="MemoryError"}}function _(e={},{now:r=0,newId:s=null}={}){const o=f(e.text);if(o.length<v)throw new $("a memory needs text");if(o.length>S)throw new $(`a memory must be at most ${S} characters — save longer material as a note`);const t=k[e.kind]?e.kind:"fact",a=Number(e.createdAt)||Number(r)||0;return{id:String(e.id||(s?s():"")||""),v:1,text:o,kind:t,scope:String(e.scope||"global"),key:y(o),slot:f(e.slot).toLowerCase()||W(o),tags:[...new Set((e.tags||[]).map(n=>f(n).toLowerCase()).filter(Boolean))].slice(0,8),pinned:!!e.pinned,source:{via:String(e.source?.via||"user"),surface:String(e.source?.surface||""),ref:String(e.source?.ref||""),agent:String(e.source?.agent||"")},confidence:ie(e.confidence==null?1:Number(e.confidence)),createdAt:a,updatedAt:Number(e.updatedAt)||a,usedAt:Number(e.usedAt)||0,useCount:Math.max(0,Math.floor(Number(e.useCount)||0)),expiresAt:e.expiresAt?Number(e.expiresAt):null,history:(e.history||[]).slice(-5).map(n=>({text:f(n.text),at:Number(n.at)||0}))}}function ce(e){try{return _(e,{now:e?.createdAt||1}),!!e?.id}catch{return!1}}function y(e){const r=f(e).toLowerCase().replace(/[^\p{L}\p{N}\s]/gu," ").split(/\s+/).filter(s=>s&&!z.has(s));return[...new Set(r)].sort().join(" ")}const z=new Set(["a","an","the","i","im","me","my","mine","we","our","us","you","your","is","am","are","was","were","be","been","being","do","does","did","to","of","in","on","at","for","with","and","or","that","this","it","please","always","usually","generally","really","just","very","so","remember","note","noting","user","prefer","prefers","preferred","like","likes"]);function W(e){const r=f(e).toLowerCase().replace(/^the\s+/,"");if(/^(?:goes by|name is|is called|called)\b/.test(r))return"name";if(/^pronouns\b/.test(r))return"pronouns";const s=/^(?:my\s+|their\s+)?([\p{L}\p{N}][\p{L}\p{N} '-]{0,28}?)\s+(?:is|are|was|were)\b/u.exec(r);if(!s)return"";const o=s[1].split(/\s+/).filter(t=>!z.has(t)).join(" ");return o.length>=3?o:""}function j(e,r){const s=new Set(y(e).split(" ").filter(Boolean)),o=new Set(y(r).split(" ").filter(Boolean));if(!s.size||!o.size)return 0;let t=0;for(const a of s)o.has(a)&&(t+=1);return t/(s.size+o.size-t)}function K(e,r){const s=new Set(y(e).split(" ").filter(Boolean)),o=new Set(y(r).split(" ").filter(Boolean));if(!s.size||!o.size)return 0;let t=0;for(const a of s)o.has(a)&&(t+=1);return t/Math.min(s.size,o.size)}const P=.8,V=[{re:/^(?:please\s+)?(?:remember|memorize|memorise)(?:\s+that|\s+this)?[:,]?\s+(.+)$/i,kind:"fact"},{re:/^(?:please\s+)?(?:keep in mind|bear in mind|don'?t forget|do not forget)(?:\s+that)?[:,]?\s+(.+)$/i,kind:"fact"},{re:/^(?:please\s+)?(?:make a note|note)(?:\s+that|\s+of)[:,]?\s+(.+)$/i,kind:"fact"},{re:/^(?:from now on|going forward|in future|in the future|henceforth)[:,]?\s+(.+)$/i,kind:"preference"},{re:/^(?:call me|i go by|refer to me as)\s+(.+)$/i,kind:"identity",rebuild:e=>`Goes by ${x(e[1])}`},{re:/^my name(?:'s| is)\s+(.+)$/i,kind:"identity",rebuild:e=>`Name is ${x(e[1])}`},{re:/^(?:always|never)\s+(.+)$/i,kind:"preference",rebuild:(e,r)=>N(r)}],I=/^(?:(?:no|nope|yes|yeah|yep|ok|okay|sure|well|and|also|just|so|oh|hey|actually|then|but)[,.!]?\s+){1,3}/i,L=/^(?:please\s+)?(?:remember|memorize|memorise|save|note|keep)\s+(?:it|this|that)(?:\s+(?:for me|please))?\s*[.!]*$/i,H=[{re:/^i (?:prefer|like|want|need)\s+(.+)$/i,kind:"preference",confidence:.7},{re:/^i (?:hate|dislike|don'?t like|do not like|can'?t stand)\s+(.+)$/i,kind:"preference",confidence:.7},{re:/^i(?:'m| am)(?: a| an| the)?\s+(.+)$/i,kind:"identity",confidence:.6},{re:/^i (?:work|working) (?:on|at|with)\s+(.+)$/i,kind:"project",confidence:.6},{re:/^i(?:'m| am) (?:working|building|writing) (?:on\s+)?(.+)$/i,kind:"project",confidence:.6},{re:/^(?:we|our team|my team) (?:use|uses|are using|run|runs|deploy|deploys)\s+(.+)$/i,kind:"fact",confidence:.6},{re:/^my (?:\w+\s){0,2}?(?:is|are)\s+(.+)$/i,kind:"fact",confidence:.55}],G=[/^(?:please\s+)?forget(?:\s+that|\s+about)?[:,]?\s+(.+)$/i,/^(?:please\s+)?(?:stop remembering|no longer remember|un-?remember)[:,]?\s+(.+)$/i],q=/(?:^|\s)(?:do|does|did|can|could|would|will|what|when|where|who|why|how|are|is)\s+(?:you|i|we|it)\b/i,X=/\b(?:can'?t|cannot|don'?t|do not|couldn'?t|never|didn'?t)\s+(?:seem to\s+)?(?:remember|recall|forget)\b/i;function le(e,{maxCandidates:r=3,includeReveals:s=!0,previous:o=""}={}){const t=[],n=String(e||"").replace(/```[\s\S]*?```/g," ").replace(/`[^`]*`/g," ");for(const i of B(n)){if(t.length>=r)break;if(i.length<v||X.test(i))continue;let h=!1;for(const l of G){const u=l.exec(i);if(!u)continue;const p=E(x(u[1]));p.length>=v&&(t.push({op:"forget",text:p,kind:"fact",confidence:1,explicit:!0,trigger:"forget"}),h=!0);break}if(h||q.test(i))continue;const d=i.replace(I,"");if(L.test(d)){const l=B(String(o||"").replace(/```[\s\S]*?```/g," ")).map(u=>u.trim()).find(u=>u.length>=v&&!L.test(u.replace(I,"")));l&&t.push({op:"remember",text:E(N(x(l))),kind:"fact",confidence:1,explicit:!0,trigger:"command"});continue}for(const{re:l,kind:u,rebuild:p}of V){const g=l.exec(d);if(!g)continue;const b=E(p?p(g,d):N(x(g[1])));b.length>=v&&(t.push({op:"remember",text:b,kind:u,confidence:1,explicit:!0,trigger:"command"}),h=!0);break}if(!(h||!s))for(const{re:l,kind:u,confidence:p}of H){if(!l.test(i))continue;const g=E(N(i));g.split(/\s+/).length>=3&&t.push({op:"remember",text:g,kind:u,confidence:p,explicit:!1,trigger:"reveal"});break}}return t.slice(0,r)}function de(e,r,{now:s=0,newId:o=null}={}){const t=_(r,{now:s,newId:o}),a=(e||[]).filter(i=>i&&i.scope===t.scope),n=t.slot&&a.find(i=>i.slot===t.slot)||a.find(i=>i.key===t.key)||a.find(i=>i.kind===t.kind&&j(i.text,t.text)>=P);return n?f(n.text).toLowerCase()===t.text.toLowerCase()?{action:"duplicate",record:{...n,updatedAt:Number(s)||n.updatedAt,useCount:n.useCount+1},replaces:n}:{action:"update",record:{...n,text:t.text,key:t.key,slot:t.slot,kind:t.kind,tags:t.tags.length?t.tags:n.tags,confidence:t.confidence,source:t.source,updatedAt:Number(s)||n.updatedAt,history:[...n.history,{text:n.text,at:n.updatedAt}].slice(-5)},replaces:n}:{action:"create",record:t,replaces:null}}function ue(e,r,{limit:s=5}={}){const o=f(r);if(!o)return[];const t=(e||[]).filter(n=>n.id===o);if(t.length)return t;const a=y(o);return(e||[]).map(n=>({m:n,s:n.key===a?1:Math.max(j(n.text,o),K(o,n.text))})).filter(n=>n.s>=.5).sort((n,i)=>i.s-n.s).slice(0,s).map(n=>n.m)}const Z=/\b(?:(?:i|we|user|they)\s+(?:live|lives|stay|stays|reside|resides|am based|are based|is based|am located|are located|is located|moved|have moved)\s+(?:in|at|near|to|around|outside)|(?:i'?m|i am|we'?re|we are|user is|they are|they'?re)\s+(?:from|based in|located in|living in|in the)\b|(?:my|our|user'?s|their)\s+(?:home|home ?town|city|town|address|location|zip|postcode|neighbou?rhood|area)\b|\blives?\s+(?:in|at|near)|\bhome is\b)/i,J=/\b(?:how far|how long (?:does it take |will it take |would it take |is the (?:drive|flight|ride|walk) )?to (?:get|drive|walk|fly|reach|go)|distance (?:to|from)|drive to|driving to|commute|directions? to|route to|get(?:ting)? to|near(?:by| me| here)|(?:around|from|over) (?:here|me)|close to me|in my area|local (?:time|news|weather|restaurants?|shops?|stores?|events?)|where i (?:am|live)|(?:rain|snow|weather|sunny|cold|hot|warm|windy) here)\b|^\s*(?:what(?:'s| is) the |how(?:'s| is) the )?(?:weather|forecast|temperature|sunset|sunrise)\b/i,Q=/\bfrom\s+(?!here\b|home\b|me\b|my\b|where\b)[\p{L}]/iu;function ee(e){return Z.test(String(e?.text||""))}function te(e){const r=String(e||"");return J.test(r)&&!Q.test(r)}function fe(e,{text:r="",scopes:s=["global"],kinds:o=null,now:t=0,limit:a=24,maxChars:n=R,includeAmbient:i=!0,ambientKinds:h=F}={}){const d=new Set(s.length?s:["global"]),l=new Set(y(r).split(" ").filter(Boolean)),u=te(r),g=(e||[]).filter(c=>c&&c.text).filter(c=>d.has(c.scope)).filter(c=>!o||o.includes(c.kind)).filter(c=>!c.expiresAt||!t||c.expiresAt>t).map(c=>{const A=new Set(c.key.split(" ").filter(Boolean));let M=0;for(const Y of A)l.has(Y)&&(M+=1);const m=Math.max(A.size?M/A.size:0,u&&ee(c)?1:0),w=i&&h.includes(c.kind)&&k[c.kind]?.ambient&&A.size<=re,T=t&&c.updatedAt?Math.max(0,1-(t-c.updatedAt)/oe):0,D=Math.min(1,c.useCount/10);return{m:c,keep:c.pinned||w||m>0,score:(c.pinned?100:0)+(w?10:0)+m*8+T+D}}),b=[];let C=0;for(const{m:c,keep:A,score:M}of g.filter(m=>m.keep).sort((m,w)=>w.score-m.score)){if(b.length>=a)break;if(b.some(w=>ne(w,c)))continue;const m=c.text.length+c.kind.length+6;if(C+m>n&&b.length)break;C+=m,b.push(c)}return b}const re=14;function ne(e,r){const s=new Set(String(e?.key||"").split(" ").filter(Boolean)),o=new Set(String(r?.key||"").split(" ").filter(Boolean));if(!s.size||!o.size)return!1;const[t,a]=s.size<=o.size?[s,o]:[o,s];let n=0;for(const i of t)a.has(i)&&(n+=1);return n/t.size>=.7}const oe=365*24*60*60*1e3;function he(e,{heading:r="What you already know about this user",maxChars:s=R}={}){const o=(e||[]).filter(n=>n&&n.text);if(!o.length)return"";const t=[];let a=0;for(const n of o){const i=`- (${n.kind}) ${n.text}`;if(a+i.length>s&&t.length)break;a+=i.length+1,t.push(i)}return[`## ${r}`,"Saved by the user in Chap and true across conversations, agents and devices.","Apply them without being asked and without announcing them.",...t,"If the user states something durable about themselves, their preferences or their work, save it with the `memory` tool. If they correct one of these, update it — do not just agree."].join(`
2
+ `)}function me(e,r,{now:s=0}={}){const o=new Set(r||[]);return(e||[]).map(t=>o.has(t.id)?{...t,usedAt:Number(s)||t.usedAt,useCount:t.useCount+1}:t)}function pe(e,{now:r=0,max:s=U}={}){const o=(e||[]).filter(Boolean),t=r?o.filter(i=>i.expiresAt&&i.expiresAt<=r):[];let a=t.length?o.filter(i=>!t.includes(i)):o;const n=[...t];if(a.length>s){const i=d=>(d.pinned?3:0)+(k[d.kind]?.ambient?1:0),h=[...a].sort((d,l)=>i(l)-i(d)||l.useCount-d.useCount||(l.usedAt||l.updatedAt)-(d.usedAt||d.updatedAt));n.push(...h.slice(s)),a=h.slice(0,s)}return{kept:a,dropped:n}}const ge=Object.freeze({name:"memory",description:'Save, update or remove a durable fact about the USER in Chap — carried into every future conversation, on every model and agent. Use it the moment they state a standing preference ("always be terse"), an identity fact ("call me Alex"), or a constraint about their work that will still be true next week. Do NOT use it for one-off task details, anything already obvious from the conversation, or content that belongs in a note. Keep each memory one short self-contained sentence. Use `forget` when the user says something is no longer true, and `list` to see what is already stored before adding.',parameters:{type:"object",properties:{action:{type:"string",enum:["remember","forget","list"],description:"What to do."},text:{type:"string",description:`The fact, as one short sentence written in the third person ("Prefers terse answers"). Max ${S} characters. Required for remember; for forget, the memory to drop (its text or id).`},kind:{type:"string",enum:O,description:O.map(e=>`${e}: ${k[e].hint}`).join(" ")},tags:{type:"array",items:{type:"string"},description:"Optional short tags for grouping."}},required:["action"]}});function be(){return"`memory` saves something durable the user says about themselves, how they want to be helped, or their ongoing work — never task details or transient state — and you say in a short clause what you saved."}const se=Object.freeze({});function ye(e){let r=e;for(let s=Number(r?.v)||1;s<1;s+=1){const o=se[s];if(!o)throw new $(`no upcaster from memory v${s}`);r=o(r)}return r}const f=e=>String(e??"").replace(/\s+/g," ").trim(),ie=e=>Number.isFinite(e)?Math.min(1,Math.max(0,e)):1,x=e=>f(e).replace(/[.,;:!]+$/,""),E=e=>e.length>S?`${e.slice(0,S-1).trimEnd()}…`:e,N=e=>{const r=x(e);return r&&r[0].toUpperCase()+r.slice(1)};function B(e){return String(e||"").split(/\n+/).flatMap(r=>f(r).replace(/^[-*+•]\s*|^\d+[.)]\s*/,"").split(/(?<=[.!?])\s+(?=[A-Z"'])/)).map(f).filter(Boolean)}export{F as AMBIENT_KINDS,re as AMBIENT_MAX_WORDS,R as DEFAULT_BLOCK_CHARS,U as DEFAULT_MAX_MEMORIES,S as MAX_MEMORY_CHARS,k as MEMORY_KINDS,O as MEMORY_KIND_NAMES,ge as MEMORY_TOOL_SPEC,se as MEMORY_UPCASTERS,ae as MEMORY_VERSION,v as MIN_MEMORY_CHARS,$ as MemoryError,P as SAME_FACT,le as candidatesFrom,K as containment,ce as isValidMemory,me as markUsed,ue as matchForForget,he as memoryBlock,y as memoryKey,be as memoryToolSystem,te as needsWhere,_ as normalizeMemory,pe as pruneMemories,fe as recall,de as reconcile,ne as sameMemory,ee as saysWhere,j as similarity,W as slotOf,ye as upcastMemory};
@@ -1 +1 @@
1
- import{classifySource as R}from"./sources.js";import{defineModel as A}from"./router.js";import{windowOf as S}from"./context-window.js";const L=/^(ollama|lm-?studio|llama[-.]?cpp|llamafile|localai|local|vllm|mlx|mlx-lm|koboldcpp|jan|gpt4all|textgen|oobabooga)$/i;function b(e){const n=String(e||"").trim(),t=n.indexOf("/");return t>0&&L.test(n.slice(0,t))?"device":"any"}function g(e,n=null){if(e&&c.includes(e.reach))return e.reach;if(e?.provider_type==="agent"||e?.owned_by==="chatpanel-bridge"||n?.type==="agent"){const a=String(e?.id||""),o=e?.model||(a.includes("/")?a.slice(a.indexOf("/")+1):"");return b(o)}const i=String(n?.baseUrl||"");return i?p({baseUrl:i}):"any"}function p(e){if(e.kind==="bridge")return b(e.model);if(e.gatewayModel)return g(e);if(e.gateway){const i=String(e.model||""),a=(Array.isArray(e.modelOptions)?e.modelOptions:[]).find(o=>o&&typeof o=="object"&&o.id===i);return a?g(a):"any"}if(e.kind==="webllm")return"device";const n=String(e.baseUrl||e.url||"");if(/^https?:\/\/(localhost|127\.0\.0\.1|\[::1\]|0\.0\.0\.0)(:|\/|$)/i.test(n))return"device";const t=R(n);return t.internal&&t.matched!=="unparseable"?"trusted":"any"}const I=Object.freeze([{id:"tools",label:"Tools",hint:"Can call functions — needed for page actions, search and MCP."},{id:"vision",label:"Vision",hint:"Can read images and screenshots."},{id:"reasoning",label:"Reasoning",hint:"Thinks before answering — worth the wait on hard tasks."},{id:"long-context",label:"Long context",hint:"Handles large documents and long meetings."},{id:"coding",label:"Coding",hint:"Strong at writing and refactoring code."},{id:"json",label:"Structured output",hint:"Reliably returns valid JSON."},{id:"speech-in",label:"Speech in",hint:"Takes audio as input — a meeting, a voice note."},{id:"speech-out",label:"Speech out",hint:"Speaks its answer."},{id:"audio",label:"Audio",hint:"Understands audio content beyond speech — music, sounds."},{id:"image-out",label:"Image out",hint:"Generates images."}]);function E(e){const n=String(e.model||"").toLowerCase(),t=new Set(["json"]);return(e.kind==="bridge"||e.model)&&t.add("tools"),/gpt-4|gpt-5|claude|gemini|vision|vl\b|llava|pixtral/.test(n)&&t.add("vision"),/o1|o3|r1|reason|think|opus|sonnet|deepseek-r/.test(n)&&t.add("reasoning"),/200k|1m\b|long|gemini|claude|gpt-4\.1|gpt-5/.test(n)&&t.add("long-context"),/code|coder|codex|deepseek|qwen|opus|sonnet/.test(n)&&t.add("coding"),e.kind==="bridge"&&(t.add("coding"),t.add("reasoning")),[...t]}const y=[/localhost|127\.0\.0\.1|ollama|lm.?studio/i,/anthropic|openai\.com|api\.deepseek|googleapis|x\.ai/i,/(^|\W)bridge(\W|$)/i,/openrouter|huggingface|together|groq|fireworks|nvidia|replicate/i],k=1e3;function _(e,n){const t=`${e.baseUrl||e.url||""} ${e.name||""} ${n||e.kind||""}`;for(let i=0;i<y.length;i++)if(y[i].test(t))return k+i*10;return k+50}function w(e){const n=`${e.model||""} ${e.name||""}`.toLowerCase(),t=Number(/(\d+(?:\.\d+)?)\s*b\b/.exec(n)?.[1]);return Number.isFinite(t)?t>=60?.85:t>=20?.6:.3:/instant|mini|nano|tiny|lite|-small\b|haiku/.test(n)?.3:/opus|gpt-5|o1|o3|\bpro\b|ultra|deepseek-r|thinking/.test(n)?.9:/sonnet|gpt-4|flash|gemini|deepseek|qwen|mistral|codestral/.test(n)?.6:e.kind==="bridge"?.8:.5}function x(e,n){const t=e==="device"?1500:700,i=Number.isFinite(n)?n:.5;return Math.round(t*(.6+i))}function M(e,n){if(n==="device")return 0;const t=String(e.model||"").toLowerCase();return/opus|gpt-4|pro\b/.test(t)?5:/sonnet|mini|flash|haiku/.test(t)?1:2}function m(e){if(e==null||e===""||typeof e=="boolean")return null;const n=Number(e);return Number.isFinite(n)?n:null}function f(e,n={},{declared:t=!1}={}){if(!n||typeof n!="object")return e;const i={...e},a=m(n.providerRank);a!==null&&(i.providerRank=a,i.orderPinned=!0),Array.isArray(n.capabilities)&&(i.capabilities=[...n.capabilities]);for(const o of["costPer1k","latencyMs","quality","window"]){const l=m(n[o]);l!==null&&(i[o]=l)}if(typeof n.available=="boolean"&&(i.available=n.available),n.reach&&c.includes(n.reach)){const o=c.includes(e.reachDetected)?e.reachDetected:e.reach;i.reachDetected=o,s[n.reach]>s[e.reach]?i.reach=n.reach:t&&s[n.reach]<s[o]&&s[n.reach]>=s[v]&&(i.reach=n.reach,i.reachDeclared=!0)}return i}import{DEFAULT_MIN_CALLS as O,cardOverride as D}from"./model-ledger.js";import{cardOverride as V}from"./model-ledger.js";function H(e,n,{minCalls:t=O,jobKind:i=null,userOverride:a=null}={}){const{override:o,observed:l}=D(n,{minCalls:t,jobKind:i});let r=f(e,o);const u=new Set(n?.capabilities?.withdrawn||[]);return u.size&&Array.isArray(r.capabilities)&&(r={...r,capabilities:r.capabilities.filter(d=>!u.has(d))},l.push("capabilities")),a&&(r=f(r,a,{declared:!0})),{...r,observed:l}}const s={device:0,trusted:1,any:2},c=["device","trusted","any"],v="trusted";function N(e){const n=c.indexOf(e);return n<0?[...c]:c.slice(Math.min(n,s[v]))}function P(e,n){return!c.includes(n)||!c.includes(e)?!1:s[n]<s[e]}const C=Object.freeze([{id:"device",label:"On this device",hint:"The words never leave this machine."},{id:"trusted",label:"My machine/network",hint:"Your own machine, your own network, or a service your organisation runs and controls."},{id:"any",label:"Third party",hint:"Someone else’s service."}]),h=e=>C.find(n=>n.id===e)?.label||String(e||""),q='How far a request travels to reach it. ChatPanel reads this from the address, so a coding agent that answers from its vendor comes out as a third party — and you can say otherwise: further out to hold it at arm’s length, or "My machine/network" when your organisation’s own controls put it inside yours. That is your word rather than a detection, and the row says so. "On this device" is never offered: it means the words never leave this machine, which is a fact we detect rather than a level of trust anyone can grant.';function U(e){return N(e).map(n=>{const t=P(e,n);return{value:n,label:n===e?`${h(n)} (detected)`:t?`${h(n)} (you declare)`:h(n),detected:n===e,declares:t,hint:t?`ChatPanel detects ${h(e)}. Choose this only if it really is inside your machine or network — content from an internal source will then be allowed to reach it.`:C.find(i=>i.id===n)?.hint||""}})}function z(e,n=null){const t=p(e||{});return!n||typeof n!="object"||!n.reach?t:f({reach:t,reachDetected:t},n,{declared:!0}).reach}function B(e,n,{override:t=null,health:i=null}={}){if(!e||!e.model&&n!=="bridge"&&e.kind!=="bridge")return null;const a=e.id||e.name||e.model;if(!a)return null;const o=[e.name,e.model&&e.model!==e.name?e.model:null].filter(Boolean).join(" · ")||[e.bridgeAgent,e.model].filter(Boolean).join(" · ")||n||e.kind||String(a),l=n||e.kind,r=p(l==="bridge"?{...e,kind:"bridge"}:e),u={id:a,label:o,model:e.model||"",reach:r,reachDetected:r,classUsed:r==="device"?"L":l==="bridge"?"A":"C",capabilities:E({...e,kind:l}),window:S({...e,kind:l,reach:r}),costPer1k:M(e,r),latencyMs:x(r,w({...e,kind:l})),quality:w({...e,kind:l}),providerRank:_(e,l),available:e.enabled!==!1},d=f(u,t||{},{declared:!0});return e.enabled===!1&&(d.available=!1),m(t?.latencyMs)===null&&(d.latencyMs=x(r,d.quality)),A({...d,available:d.available&&(i?i.available!==!1:!0),rateLimited:!!i?.rateLimited})}export{O as DEFAULT_MIN_CALLS,I as KNOWN_CAPABILITIES,C as REACH_CHOICES,v as REACH_DECLARABLE_FLOOR,q as REACH_HELP,s as REACH_RANK,b as agentModelReach,H as applyCard,f as applyOverride,E as capabilitiesOf,V as cardOverride,M as costOf,B as inferCandidate,x as latencyOf,m as numericOverride,_ as providerRankOf,w as qualityOf,N as reachChoicesFor,z as reachFor,P as reachIsDeclaration,h as reachLabel,p as reachOf,g as reachOfGatewayModel,U as reachOptionsFor};
1
+ import{classifySource as A}from"./sources.js";import{defineModel as C}from"./router.js";import{windowOf as S}from"./context-window.js";const L=/^(ollama|lm-?studio|llama[-.]?cpp|llamafile|localai|local|vllm|mlx|mlx-lm|koboldcpp|jan|gpt4all|textgen|oobabooga)$/i;function b(e){const n=String(e||"").trim(),t=n.indexOf("/");return t>0&&L.test(n.slice(0,t))?"device":"any"}function g(e,n=null){if(e&&c.includes(e.reach))return e.reach;if(E(e)||n?.type==="agent"){const a=String(e?.id||""),o=e?.model||(a.includes("/")?a.slice(a.indexOf("/")+1):"");return b(o)}const i=String(n?.baseUrl||"");return i?p({baseUrl:i}):"any"}function E(e){return e?.provider_type==="agent"||e?.api==="agent"||e?.owned_by==="chatpanel-bridge"}function p(e){if(e.kind==="bridge")return b(e.model);if(e.gatewayModel)return g(e);if(e.gateway){const i=String(e.model||""),a=(Array.isArray(e.modelOptions)?e.modelOptions:[]).find(o=>o&&typeof o=="object"&&o.id===i);return a?g(a):"any"}if(e.kind==="webllm")return"device";const n=String(e.baseUrl||e.url||"");if(/^https?:\/\/(localhost|127\.0\.0\.1|\[::1\]|0\.0\.0\.0)(:|\/|$)/i.test(n))return"device";const t=A(n);return t.internal&&t.matched!=="unparseable"?"trusted":"any"}const H=Object.freeze([{id:"tools",label:"Tools",hint:"Can call functions — needed for page actions, search and MCP."},{id:"vision",label:"Vision",hint:"Can read images and screenshots."},{id:"reasoning",label:"Reasoning",hint:"Thinks before answering — worth the wait on hard tasks."},{id:"long-context",label:"Long context",hint:"Handles large documents and long meetings."},{id:"coding",label:"Coding",hint:"Strong at writing and refactoring code."},{id:"json",label:"Structured output",hint:"Reliably returns valid JSON."},{id:"speech-in",label:"Speech in",hint:"Takes audio as input — a meeting, a voice note."},{id:"speech-out",label:"Speech out",hint:"Speaks its answer."},{id:"audio",label:"Audio",hint:"Understands audio content beyond speech — music, sounds."},{id:"image-out",label:"Image out",hint:"Generates images."}]);function _(e){const n=String(e.model||"").toLowerCase(),t=new Set(["json"]);return(e.kind==="bridge"||e.model)&&t.add("tools"),/gpt-4|gpt-5|claude|gemini|vision|vl\b|llava|pixtral/.test(n)&&t.add("vision"),/o1|o3|r1|reason|think|opus|sonnet|deepseek-r/.test(n)&&t.add("reasoning"),/200k|1m\b|long|gemini|claude|gpt-4\.1|gpt-5/.test(n)&&t.add("long-context"),/code|coder|codex|deepseek|qwen|opus|sonnet/.test(n)&&t.add("coding"),e.kind==="bridge"&&(t.add("coding"),t.add("reasoning")),[...t]}const y=[/localhost|127\.0\.0\.1|ollama|lm.?studio/i,/anthropic|openai\.com|api\.deepseek|googleapis|x\.ai/i,/(^|\W)bridge(\W|$)/i,/openrouter|huggingface|together|groq|fireworks|nvidia|replicate/i],w=1e3;function M(e,n){const t=`${e.baseUrl||e.url||""} ${e.name||""} ${n||e.kind||""}`;for(let i=0;i<y.length;i++)if(y[i].test(t))return w+i*10;return w+50}function k(e){const n=`${e.model||""} ${e.name||""}`.toLowerCase(),t=Number(/(\d+(?:\.\d+)?)\s*b\b/.exec(n)?.[1]);return Number.isFinite(t)?t>=60?.85:t>=20?.6:.3:/instant|mini|nano|tiny|lite|-small\b|haiku/.test(n)?.3:/opus|gpt-5|o1|o3|\bpro\b|ultra|deepseek-r|thinking/.test(n)?.9:/sonnet|gpt-4|flash|gemini|deepseek|qwen|mistral|codestral/.test(n)?.6:e.kind==="bridge"?.8:.5}function x(e,n){const t=e==="device"?1500:700,i=Number.isFinite(n)?n:.5;return Math.round(t*(.6+i))}function D(e,n){if(n==="device")return 0;const t=String(e.model||"").toLowerCase();return/opus|gpt-4|pro\b/.test(t)?5:/sonnet|mini|flash|haiku/.test(t)?1:2}function m(e){if(e==null||e===""||typeof e=="boolean")return null;const n=Number(e);return Number.isFinite(n)?n:null}function f(e,n={},{declared:t=!1}={}){if(!n||typeof n!="object")return e;const i={...e},a=m(n.providerRank);a!==null&&(i.providerRank=a,i.orderPinned=!0),Array.isArray(n.capabilities)&&(i.capabilities=[...n.capabilities]);for(const o of["costPer1k","latencyMs","quality","window"]){const s=m(n[o]);s!==null&&(i[o]=s)}if(typeof n.available=="boolean"&&(i.available=n.available),n.reach&&c.includes(n.reach)){const o=c.includes(e.reachDetected)?e.reachDetected:e.reach;i.reachDetected=o,l[n.reach]>l[e.reach]?i.reach=n.reach:t&&l[n.reach]<l[o]&&l[n.reach]>=l[v]&&(i.reach=n.reach,i.reachDeclared=!0)}return i}import{DEFAULT_MIN_CALLS as O,cardOverride as N}from"./model-ledger.js";import{cardOverride as W}from"./model-ledger.js";function q(e,n,{minCalls:t=O,jobKind:i=null,userOverride:a=null}={}){const{override:o,observed:s}=N(n,{minCalls:t,jobKind:i});let r=f(e,o);const u=new Set(n?.capabilities?.withdrawn||[]);return u.size&&Array.isArray(r.capabilities)&&(r={...r,capabilities:r.capabilities.filter(d=>!u.has(d))},s.push("capabilities")),a&&(r=f(r,a,{declared:!0})),{...r,observed:s}}const l={device:0,trusted:1,any:2},c=["device","trusted","any"],v="trusted";function $(e){const n=c.indexOf(e);return n<0?[...c]:c.slice(Math.min(n,l[v]))}function j(e,n){return!c.includes(n)||!c.includes(e)?!1:l[n]<l[e]}const R=Object.freeze([{id:"device",label:"On this device",hint:"The words never leave this machine."},{id:"trusted",label:"My machine/network",hint:"Your own machine, your own network, or a service your organisation runs and controls."},{id:"any",label:"Third party",hint:"Someone else’s service."}]),h=e=>R.find(n=>n.id===e)?.label||String(e||""),U='How far a request travels to reach it. Chap reads this from the address, so a coding agent that answers from its vendor comes out as a third party — and you can say otherwise: further out to hold it at arm’s length, or "My machine/network" when your organisation’s own controls put it inside yours. That is your word rather than a detection, and the row says so. "On this device" is never offered: it means the words never leave this machine, which is a fact we detect rather than a level of trust anyone can grant.';function z(e){return $(e).map(n=>{const t=j(e,n);return{value:n,label:n===e?`${h(n)} (detected)`:t?`${h(n)} (you declare)`:h(n),detected:n===e,declares:t,hint:t?`Chap detects ${h(e)}. Choose this only if it really is inside your machine or network — content from an internal source will then be allowed to reach it.`:R.find(i=>i.id===n)?.hint||""}})}function B(e,n=null){const t=p(e||{});return!n||typeof n!="object"||!n.reach?t:f({reach:t,reachDetected:t},n,{declared:!0}).reach}function G(e,n,{override:t=null,health:i=null}={}){if(!e||!e.model&&n!=="bridge"&&e.kind!=="bridge")return null;const a=e.id||e.name||e.model;if(!a)return null;const o=[e.name,e.model&&e.model!==e.name?e.model:null].filter(Boolean).join(" · ")||[e.bridgeAgent,e.model].filter(Boolean).join(" · ")||n||e.kind||String(a),s=n||e.kind,r=p(s==="bridge"?{...e,kind:"bridge"}:e),u={id:a,label:o,model:e.model||"",reach:r,reachDetected:r,classUsed:r==="device"?"L":s==="bridge"?"A":"C",capabilities:_({...e,kind:s}),window:S({...e,kind:s,reach:r}),costPer1k:D(e,r),latencyMs:x(r,k({...e,kind:s})),quality:k({...e,kind:s}),providerRank:M(e,s),available:e.enabled!==!1},d=f(u,t||{},{declared:!0});return e.enabled===!1&&(d.available=!1),m(t?.latencyMs)===null&&(d.latencyMs=x(r,d.quality)),C({...d,available:d.available&&(i?i.available!==!1:!0),rateLimited:!!i?.rateLimited})}export{O as DEFAULT_MIN_CALLS,H as KNOWN_CAPABILITIES,R as REACH_CHOICES,v as REACH_DECLARABLE_FLOOR,U as REACH_HELP,l as REACH_RANK,b as agentModelReach,q as applyCard,f as applyOverride,_ as capabilitiesOf,W as cardOverride,D as costOf,G as inferCandidate,E as isGatewayAgentRow,x as latencyOf,m as numericOverride,M as providerRankOf,k as qualityOf,$ as reachChoicesFor,B as reachFor,j as reachIsDeclaration,h as reachLabel,p as reachOf,g as reachOfGatewayModel,z as reachOptionsFor};
package/note-merge.js CHANGED
@@ -1,13 +1,13 @@
1
- const j="<!-- conflict:start -->",y="<!-- conflict:other -->",C="<!-- conflict:end -->",w=/<!-- conflict:start -->\n([\s\S]*?)\n<!-- conflict:other -->\n([\s\S]*?)\n<!-- conflict:end -->/g,_=4e3;function S(e){const r=String(e??"").replace(/\r\n?/g,`
1
+ const $="<!-- conflict:start -->",j="<!-- conflict:other -->",C="<!-- conflict:end -->",w=/<!-- conflict:start -->\n([\s\S]*?)\n<!-- conflict:other -->\n([\s\S]*?)\n<!-- conflict:end -->/g,v=4e3;function S(t){const s=String(t??"").replace(/\r\n?/g,`
2
2
  `).split(`
3
- `),c=[];let t=[],n=null;const l=()=>{t.length&&(c.push(t.join(`
4
- `)),t=[])};for(const o of r){const i=/^\s*(`{3,}|~{3,})/.exec(o);if(n){t.push(o),i&&i[1][0]===n[0]&&i[1].length>=n.length&&(n=null,l());continue}if(i){l(),n=i[1],t.push(o);continue}if(!o.trim()){l();continue}/^\s*(?:[-*+]|\d+[.)])\s+/.test(o)&&t.length&&l(),t.push(o)}return l(),c}const $=/^\s*(?:[-*+]|\d+[.)])\s+/,g=e=>e.reduce((r,c,t)=>t===0?c:`${r}${$.test(c)&&$.test(e[t-1])?`
3
+ `),o=[];let e=[],n=null;const r=()=>{e.length&&(o.push(e.join(`
4
+ `)),e=[])};for(const c of s){const i=/^\s*(`{3,}|~{3,})/.exec(c);if(n){e.push(c),i&&i[1][0]===n[0]&&i[1].length>=n.length&&(n=null,r());continue}if(i){r(),n=i[1],e.push(c);continue}if(!c.trim()){r();continue}/^\s*(?:[-*+]|\d+[.)])\s+/.test(c)&&e.length&&r(),e.push(c)}return r(),o}const y=/^\s*(?:[-*+]|\d+[.)])\s+/,g=t=>t.reduce((s,o,e)=>e===0?o:`${s}${y.test(o)&&y.test(t[e-1])?`
5
5
  `:`
6
6
 
7
- `}${c}`,"");function k(e,r){const c=e.length,t=r.length,n=Array.from({length:c+1},()=>new Uint32Array(t+1));for(let f=c-1;f>=0;f--)for(let h=t-1;h>=0;h--)n[f][h]=e[f]===r[h]?n[f+1][h+1]+1:Math.max(n[f+1][h],n[f][h+1]);const l=[];let o=0,i=0;for(;o<c&&i<t;)e[o]===r[i]?(l.push([o,i]),o++,i++):n[o+1][i]>=n[o][i+1]?o++:i++;return l}const A=(e,r)=>`${j}
8
- ${g(e)}
9
- ${y}
10
- ${g(r)}
11
- ${C}`;function N({base:e=null,ours:r="",theirs:c=""}={}){const t=String(r??""),n=String(c??"");if(t===n)return{markdown:t,conflicts:0,clean:!0};if(e!=null&&String(e)===t)return{markdown:n,conflicts:0,clean:!0};if(e!=null&&String(e)===n)return{markdown:t,conflicts:0,clean:!0};const l=S(t),o=S(n);return l.length>4e3||o.length>4e3?{markdown:A(l,o),conflicts:1,clean:!1}:e==null?I(l,o):L(S(e),l,o)}function I(e,r){const c=[];let t=0,n=0,l=0;for(const[o,i]of[...k(e,r),[e.length,r.length]]){const f=e.slice(n,o),h=r.slice(l,i);f.length&&h.length?(c.push(A(f,h)),t++):c.push(...f,...h),o<e.length&&c.push(e[o]),n=o+1,l=i+1}return{markdown:g(c),conflicts:t,clean:t===0}}function M(e,r){const c=[];let t=0,n=0;for(const[l,o]of[...k(e,r),[e.length,r.length]])(l>t||o>n)&&c.push({s:t,e:l,xs:n,xe:o}),t=l+1,n=o+1;return c}function L(e,r,c){const t=[...M(e,r).map(s=>({...s,side:"o"})),...M(e,c).map(s=>({...s,side:"t"}))].sort((s,u)=>s.s-u.s||s.e-u.e||(s.side==="o"?-1:1)),n=[];for(const s of t){const u=n[n.length-1];u&&(s.s<u.e||s.s===u.e&&s.s===s.e&&u.s===u.e)?(u.e=Math.max(u.e,s.e),u[s.side].push(s)):n.push({s:s.s,e:s.e,o:s.side==="o"?[s]:[],t:s.side==="t"?[s]:[]})}const l=(s,u,a,p)=>{const d=[];let m=u;for(const x of s)d.push(...e.slice(m,x.s),...p.slice(x.xs,x.xe)),m=x.e;return d.push(...e.slice(m,a)),d},o=(s,u)=>s.length===u.length&&s.every((a,p)=>a===u[p]),i=[];let f=0,h=0;for(const s of n){i.push(...e.slice(h,s.s));const u=l(s.o,s.s,s.e,r),a=l(s.t,s.s,s.e,c);s.t.length?s.o.length?o(u,a)?i.push(...u):s.s===s.e?i.push(...u,...a.filter(p=>!u.includes(p))):(i.push(A(u,a)),f++):i.push(...a):i.push(...u),h=s.e}return i.push(...e.slice(h)),{markdown:g(i),conflicts:f,clean:f===0}}function K(e){return[...String(e??"").matchAll(w)].map((r,c)=>({index:c,ours:r[1],theirs:r[2]}))}function T(e,r,c="ours"){let t=-1;return String(e??"").replace(w,(n,l,o)=>(t++,t!==r?n:c==="theirs"?o:c==="both"?`${l}
7
+ `}${o}`,"");function k(t,s){const o=t.length,e=s.length,n=Array.from({length:o+1},()=>new Uint32Array(e+1));for(let f=o-1;f>=0;f--)for(let a=e-1;a>=0;a--)n[f][a]=t[f]===s[a]?n[f+1][a+1]+1:Math.max(n[f+1][a],n[f][a+1]);const r=[];let c=0,i=0;for(;c<o&&i<e;)t[c]===s[i]?(r.push([c,i]),c++,i++):n[c+1][i]>=n[c][i+1]?c++:i++;return r}const A=(t,s)=>`${$}
8
+ ${g(t)}
9
+ ${j}
10
+ ${g(s)}
11
+ ${C}`;function N({base:t=null,ours:s="",theirs:o=""}={}){const e=String(s??""),n=String(o??"");if(e===n)return{markdown:e,conflicts:0,clean:!0};if(t!=null&&String(t)===e)return{markdown:n,conflicts:0,clean:!0};if(t!=null&&String(t)===n)return{markdown:e,conflicts:0,clean:!0};const r=S(e),c=S(n);return r.length>4e3||c.length>4e3?{markdown:A(r,c),conflicts:1,clean:!1}:t==null?L(r,c):I(S(t),r,c)}function L(t,s){const o=[];let e=0,n=0,r=0;for(const[c,i]of[...k(t,s),[t.length,s.length]]){const f=t.slice(n,c),a=s.slice(r,i);f.length&&a.length?(o.push(A(f,a)),e++):o.push(...f,...a),c<t.length&&o.push(t[c]),n=c+1,r=i+1}return{markdown:g(o),conflicts:e,clean:e===0}}function M(t,s){const o=[];let e=0,n=0;for(const[r,c]of[...k(t,s),[t.length,s.length]])(r>e||c>n)&&o.push({s:e,e:r,xs:n,xe:c}),e=r+1,n=c+1;return o}function I(t,s,o){const e=[...M(t,s).map(l=>({...l,side:"o"})),...M(t,o).map(l=>({...l,side:"t"}))].sort((l,u)=>l.s-u.s||l.e-u.e||(l.side==="o"?-1:1)),n=[];for(const l of e){const u=n[n.length-1];u&&(l.s<u.e||l.s===u.e&&l.s===l.e&&u.s===u.e)?(u.e=Math.max(u.e,l.e),u[l.side].push(l)):n.push({s:l.s,e:l.e,o:l.side==="o"?[l]:[],t:l.side==="t"?[l]:[]})}const r=(l,u,d,h)=>{const m=[];let x=u;for(const p of l)m.push(...t.slice(x,p.s),...h.slice(p.xs,p.xe)),x=p.e;return m.push(...t.slice(x,d)),m},c=(l,u)=>l.length===u.length&&l.every((d,h)=>d===u[h]),i=[];let f=0,a=0;for(const l of n){i.push(...t.slice(a,l.s));const u=r(l.o,l.s,l.e,s),d=r(l.t,l.s,l.e,o);l.t.length?l.o.length?c(u,d)?i.push(...u):l.s===l.e?i.push(...u,...d.filter(h=>!u.includes(h))):(i.push(A(u,d)),f++):i.push(...d):i.push(...u),a=l.e}return i.push(...t.slice(a)),{markdown:g(i),conflicts:f,clean:f===0}}function T(t,s,o,e){const n=(r,c)=>JSON.stringify(r??null)===JSON.stringify(c??null);return n(s,o)?s:t!==void 0&&n(t,s)?o:t!==void 0&&n(t,o)||e?s:o}function _(t,s,o){const e=Array.isArray(s)?s:[],n=Array.isArray(o)?o:[];if(!Array.isArray(t))return[...new Set([...n,...e])];const r=new Set(t.filter(c=>!e.includes(c)||!n.includes(c)));return[...new Set([...n,...e])].filter(c=>!r.has(c)||!t.includes(c))}function K({base:t=null,ours:s,theirs:o,now:e=0}={}){const n=u=>Number(u?.updatedAt)||0,r=n(s)>n(o),c=r?s:o,i=r?o:s,f=u=>String(u?.body?.markdown??""),a=t?N({base:String(t.markdown??""),ours:f(s),theirs:f(o)}):{markdown:f(c),conflicts:0};return{record:{...i,...c,title:T(t?t.title:void 0,s?.title,o?.title,r),tags:_(t?t.tags:void 0,s?.tags,o?.tags),body:{...i?.body||{},...c?.body||{},markdown:a.markdown},meta:{...i?.meta||{},...c?.meta||{}},updatedAt:Math.max(n(s),n(o),Number(e)||0)},conflicts:a.conflicts}}function D(t){return[...String(t??"").matchAll(w)].map((s,o)=>({index:o,ours:s[1],theirs:s[2]}))}function E(t,s,o="ours"){let e=-1;return String(t??"").replace(w,(n,r,c)=>(e++,e!==s?n:o==="theirs"?c:o==="both"?`${r}
12
12
 
13
- ${o}`:l))}function v({ours:e=null,theirs:r=null,base:c=null}={}){const t={text:String(e?.text??""),at:Number(e?.updatedAt)||0},n={text:String(r?.text??""),at:Number(r?.updatedAt)||0},l={text:n.text};if(t.text===n.text)return c?.text===n.text?null:{text:t.text,updatedAt:Math.max(t.at,n.at),base:l,conflicts:0};if(c&&typeof c.text=="string"){const o=N({base:c.text,ours:t.text,theirs:n.text});return{text:o.markdown,updatedAt:Math.max(t.at,n.at),base:l,conflicts:o.conflicts}}return n.at>t.at?{text:n.text,updatedAt:n.at,base:l,conflicts:0}:{text:t.text,updatedAt:t.at,base:l,conflicts:0}}export{_ as MAX_BLOCKS,K as conflictsIn,N as mergeNote,T as resolveConflict,S as splitBlocks,v as syncNote};
13
+ ${c}`:r))}function J({ours:t=null,theirs:s=null,base:o=null}={}){const e={text:String(t?.text??""),at:Number(t?.updatedAt)||0},n={text:String(s?.text??""),at:Number(s?.updatedAt)||0},r={text:n.text};if(e.text===n.text)return o?.text===n.text?null:{text:e.text,updatedAt:Math.max(e.at,n.at),base:r,conflicts:0};if(o&&typeof o.text=="string"){const c=N({base:o.text,ours:e.text,theirs:n.text});return{text:c.markdown,updatedAt:Math.max(e.at,n.at),base:r,conflicts:c.conflicts}}return n.at>e.at?{text:n.text,updatedAt:n.at,base:r,conflicts:0}:{text:e.text,updatedAt:e.at,base:r,conflicts:0}}export{v as MAX_BLOCKS,D as conflictsIn,N as mergeNote,K as mergeNoteRecords,E as resolveConflict,S as splitBlocks,J as syncNote};
package/note-tool.js CHANGED
@@ -1,3 +1,3 @@
1
- const N=[{name:"note",description:"WRITE to the user's ChatPanel notes: create a new note, append to one, or revise one. Use this when the user asks you to save, note down, write up or record something — do NOT try to drive the Notes page with browser tools, and do not hand back text for them to copy. To FIND or READ notes use `find`; this tool only writes. Every write asks the user to confirm, so say what you are saving in your reply.",parameters:{type:"object",properties:{action:{type:"string",enum:["create","append","update"],description:"create a new note, append to the end of one, or revise one."},id:{type:"string",description:"The note to change. Required for append and update; get it from `find`."},title:{type:"string",description:"Title. Used by create, and by update when renaming."},body:{type:"string",description:"Markdown body. The whole note for create/update; use `text` to append."},text:{type:"string",description:"Markdown to add to the end of an existing note (append)."},tags:{type:"array",items:{type:"string"},description:"Optional tags."}},required:["action"]}}],o=(a,y={})=>JSON.stringify({ok:!1,error:a,...y});function S({store:a,confirm:y,onWrote:h=()=>{},agentLabel:s="AI",needsConfirm:w=!0,now:u=Date.now}={}){return async function(b,d={}){if(b!=="note")return o(`Unknown tool "${b}".`);const e=String(d.action||"").trim();if(!["create","append","update"].includes(e))return o(`Unknown action "${e}".`,{actions:["create","append","update"]});const c=String(d.title||"").trim(),i=String(d.body??""),p=String(d.text??"");let t=null;if(e!=="create"){const r=String(d.id||"").trim();if(!r)return o(`"${e}" needs the note's id. Use \`find\` to look it up.`);if(t=await a.getNote(r),!t)return o(`No note with id "${r}".`);if(e==="append"&&!p.trim())return o('"append" needs `text`.');if(e==="update"&&!i.trim()&&!c)return o('"update" needs a `body` or a `title`.')}else if(!i.trim()&&!c)return o('"create" needs a `title` or a `body`.');const g=(r,l=60)=>{const n=String(r||"").replace(/\s+/g," ").trim();return n.length>l?`${n.slice(0,l)}…`:n},m=e==="create"?`Create a note “${g(c||i)}”`:e==="append"?`Add ${p.length} characters to your note “${g(t.title||"Untitled")}”`:`Rewrite your note “${g(t.title||"Untitled")}” (the current version is kept)`;if(w&&await y(m)==="deny")return o("The user DECLINED this note write. Do not retry it — stop and ask the user how to proceed.");try{if(e==="create"){const n=await a.createNote({title:c,body:i,attribution:[{by:s,at:u(),from:0,to:i.length}]});return h(n.id,e),JSON.stringify({ok:!0,id:n.id,title:n.title,chars:(n.body||"").length})}if(e==="append"){const n=String(t.body||""),f=n?`${n.replace(/\s+$/,"")}
1
+ const N=[{name:"note",description:"WRITE to the user's Chap notes: create a new note, append to one, or revise one. Use this when the user asks you to save, note down, write up or record something — do NOT try to drive the Notes page with browser tools, and do not hand back text for them to copy. To FIND or READ notes use `find`; this tool only writes. Every write asks the user to confirm, so say what you are saving in your reply.",parameters:{type:"object",properties:{action:{type:"string",enum:["create","append","update"],description:"create a new note, append to the end of one, or revise one."},id:{type:"string",description:"The note to change. Required for append and update; get it from `find`."},title:{type:"string",description:"Title. Used by create, and by update when renaming."},body:{type:"string",description:"Markdown body. The whole note for create/update; use `text` to append."},text:{type:"string",description:"Markdown to add to the end of an existing note (append)."},tags:{type:"array",items:{type:"string"},description:"Optional tags."}},required:["action"]}}],o=(a,l={})=>JSON.stringify({ok:!1,error:a,...l});function S({store:a,confirm:l,onWrote:h=()=>{},agentLabel:s="AI",needsConfirm:w=!0,now:u=Date.now}={}){return async function(b,d={}){if(b!=="note")return o(`Unknown tool "${b}".`);const e=String(d.action||"").trim();if(!["create","append","update"].includes(e))return o(`Unknown action "${e}".`,{actions:["create","append","update"]});const c=String(d.title||"").trim(),i=String(d.body??""),p=String(d.text??"");let t=null;if(e!=="create"){const r=String(d.id||"").trim();if(!r)return o(`"${e}" needs the note's id. Use \`find\` to look it up.`);if(t=await a.getNote(r),!t)return o(`No note with id "${r}".`);if(e==="append"&&!p.trim())return o('"append" needs `text`.');if(e==="update"&&!i.trim()&&!c)return o('"update" needs a `body` or a `title`.')}else if(!i.trim()&&!c)return o('"create" needs a `title` or a `body`.');const g=(r,y=60)=>{const n=String(r||"").replace(/\s+/g," ").trim();return n.length>y?`${n.slice(0,y)}…`:n},m=e==="create"?`Create a note “${g(c||i)}”`:e==="append"?`Add ${p.length} characters to your note “${g(t.title||"Untitled")}”`:`Rewrite your note “${g(t.title||"Untitled")}” (the current version is kept)`;if(w&&await l(m)==="deny")return o("The user DECLINED this note write. Do not retry it — stop and ask the user how to proceed.");try{if(e==="create"){const n=await a.createNote({title:c,body:i,attribution:[{by:s,at:u(),from:0,to:i.length}]});return h(n.id,e),JSON.stringify({ok:!0,id:n.id,title:n.title,chars:(n.body||"").length})}if(e==="append"){const n=String(t.body||""),f=n?`${n.replace(/\s+$/,"")}
2
2
 
3
- ${p}`:p,k=await a.saveNote({...t,body:f,attribution:[...t.attribution||[],{by:s,at:u(),from:n.length,to:f.length}]});return h(t.id,e),JSON.stringify({ok:!0,id:t.id,title:k?.title,chars:f.length,added:p.length})}const r=String(t.body||""),l=await a.saveNote({...t,title:c||t.title,body:i||r,versions:[...t.versions||[],{body:r,attribution:t.attribution||[],at:u(),by:s,label:`before ${s} revised it`}],attribution:[{by:s,at:u(),from:0,to:(i||r).length}]});return h(t.id,e),JSON.stringify({ok:!0,id:t.id,title:l?.title,chars:(i||r).length,previousVersionKept:!0})}catch(r){return o(String(r?.message||r))}}}export{N as NOTE_TOOL_SPECS,S as makeNoteToolExecutor};
3
+ ${p}`:p,k=await a.saveNote({...t,body:f,attribution:[...t.attribution||[],{by:s,at:u(),from:n.length,to:f.length}]});return h(t.id,e),JSON.stringify({ok:!0,id:t.id,title:k?.title,chars:f.length,added:p.length})}const r=String(t.body||""),y=await a.saveNote({...t,title:c||t.title,body:i||r,versions:[...t.versions||[],{body:r,attribution:t.attribution||[],at:u(),by:s,label:`before ${s} revised it`}],attribution:[{by:s,at:u(),from:0,to:(i||r).length}]});return h(t.id,e),JSON.stringify({ok:!0,id:t.id,title:y?.title,chars:(i||r).length,previousVersionKept:!0})}catch(r){return o(String(r?.message||r))}}}export{N as NOTE_TOOL_SPECS,S as makeNoteToolExecutor};
@@ -0,0 +1,5 @@
1
+ const y=[{head:/^#{1,3}\s*(?:How the user wants answers|What you already know about this user)\s*$/i,body:/^(?:Saved by the user in Chap|-\s*\(|Apply them without)/i},{head:/^#{1,3}\s*Now\s*$/i,body:/^Today's date is /i},{head:/^#{1,3}\s*Sources\s*$/i,body:/^Cite these sources inline/i},{head:/^#{1,3}\s*Tools\s*$/i,body:/^(?:Everything below is reached through ONE tool|You can call tools\.)/i}],h=[/^Chap renders your reply: /,/^Source citation policy:$/],p=/\[… ?\d[\d,]* characters left out to fit the on-device model ?…\]/g,w=/(?:#{1,3}\s*(?:How the user wants answers|What you already know about this user)\s+(?:Saved by|-\s*\(|Apply them)|#{1,3}\s*Now\s+Today's date|#{1,3}\s*Sources\s+Cite these sources|#{1,3}\s*Tools\s+(?:Everything below is reached|You can call tools)|Chap renders your reply: |Source citation policy: )[\s\S]*?(?=\s(?:User|Assistant|You|Chap|Me):\s|$)/g;function m(u){const n=String(u??"");if(!n)return n;const e=n.replace(p,"").split(`
2
+ `),r=[];for(let s=0;s<e.length;s++){const i=/^(\s*[A-Za-z][\w .·-]{0,40}:)\s+(\S.*)$/.exec(e[s]),a=i&&(/^#{1,3}\s/.test(i[2])||h.some(o=>o.test(i[2])))?i[1]:"",c=(a?i[2]:e[s]).trim(),d=(e.slice(s+1).find(o=>o.trim())||"").trim(),l=y.some(o=>o.head.test(c)&&o.body.test(d));if(!l&&!h.some(o=>o.test(c))){r.push(e[s]);continue}a&&r.push(a.trim());let t=s+1;if(l)for(;t<e.length&&!e[t].trim();)t++;for(;t<e.length&&e[t].trim()&&!/^#{1,6}\s/.test(e[t].trim());)t++;s=t-1}return r.join(`
3
+ `).replace(w,"").replace(/[ \t]{2,}/g," ").replace(/\n{3,}/g,`
4
+
5
+ `).trim()}export{m as withoutOwnInstructions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.290.0",
3
+ "version": "0.329.0",
4
4
  "description": "The canonical ChatPanel event-log and capability contracts — typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -17,6 +17,8 @@
17
17
  "./a2a-task.js": "./a2a-task.js",
18
18
  "./agent-dialects.js": "./agent-dialects.js",
19
19
  "./agent-portability.js": "./agent-portability.js",
20
+ "./agent-session-open.js": "./agent-session-open.js",
21
+ "./agent-thread.js": "./agent-thread.js",
20
22
  "./attribution.js": "./attribution.js",
21
23
  "./backup-envelope.js": "./backup-envelope.js",
22
24
  "./blob-envelope.js": "./blob-envelope.js",
@@ -32,6 +34,7 @@
32
34
  "./capability-adapters.js": "./capability-adapters.js",
33
35
  "./open-decision.js": "./open-decision.js",
34
36
  "./runtime-in-process.js": "./runtime-in-process.js",
37
+ "./service-standby.js": "./service-standby.js",
35
38
  "./capability-providers.js": "./capability-providers.js",
36
39
  "./capability-tools.js": "./capability-tools.js",
37
40
  "./fast-path.js": "./fast-path.js",
@@ -125,6 +128,8 @@
125
128
  "./stitch.js": "./stitch.js",
126
129
  "./note-merge.js": "./note-merge.js",
127
130
  "./link-connect.js": "./link-connect.js",
131
+ "./link-sync.js": "./link-sync.js",
132
+ "./link-routes.js": "./link-routes.js",
128
133
  "./qr.js": "./qr.js",
129
134
  "./record-entities.js": "./record-entities.js",
130
135
  "./decide-by-model.js": "./decide-by-model.js",
@@ -191,6 +196,7 @@
191
196
  "./sync-plan.js": "./sync-plan.js",
192
197
  "./synthesis.js": "./synthesis.js",
193
198
  "./tags.js": "./tags.js",
199
+ "./thread-send.js": "./thread-send.js",
194
200
  "./team-board.js": "./team-board.js",
195
201
  "./board-tool.js": "./board-tool.js",
196
202
  "./team-cache.js": "./team-cache.js",
@@ -265,6 +271,7 @@
265
271
  "./kokoro-text.js": "./kokoro-text.js",
266
272
  "./weather-tool.js": "./weather-tool.js",
267
273
  "./weather.js": "./weather.js",
274
+ "./clock.js": "./clock.js",
268
275
  "./web-search-tool.js": "./web-search-tool.js",
269
276
  "./web-search.js": "./web-search.js",
270
277
  "./widget.js": "./widget.js",
@@ -275,6 +282,11 @@
275
282
  "./fetched.js": "./fetched.js",
276
283
  "./context-window.js": "./context-window.js",
277
284
  "./compaction.js": "./compaction.js",
285
+ "./context-select.js": "./context-select.js",
286
+ "./own-instructions.js": "./own-instructions.js",
287
+ "./digest.js": "./digest.js",
288
+ "./retrieval-plan.js": "./retrieval-plan.js",
289
+ "./identity.js": "./identity.js",
278
290
  "./site-policy.js": "./site-policy.js",
279
291
  "./read-document.js": "./read-document.js",
280
292
  "./serp-anchors.js": "./serp-anchors.js",
@@ -297,6 +309,8 @@
297
309
  "a2a-task.js",
298
310
  "agent-dialects.js",
299
311
  "agent-portability.js",
312
+ "agent-session-open.js",
313
+ "agent-thread.js",
300
314
  "attribution.js",
301
315
  "backup-envelope.js",
302
316
  "blob-envelope.js",
@@ -312,6 +326,7 @@
312
326
  "capability-adapters.js",
313
327
  "open-decision.js",
314
328
  "runtime-in-process.js",
329
+ "service-standby.js",
315
330
  "capability-providers.js",
316
331
  "capability-tools.js",
317
332
  "fast-path.js",
@@ -406,6 +421,8 @@
406
421
  "stitch.js",
407
422
  "note-merge.js",
408
423
  "link-connect.js",
424
+ "link-sync.js",
425
+ "link-routes.js",
409
426
  "qr.js",
410
427
  "record-entities.js",
411
428
  "decide-by-model.js",
@@ -433,6 +450,11 @@
433
450
  "fetched.js",
434
451
  "context-window.js",
435
452
  "compaction.js",
453
+ "context-select.js",
454
+ "own-instructions.js",
455
+ "digest.js",
456
+ "retrieval-plan.js",
457
+ "identity.js",
436
458
  "promotion.js",
437
459
  "queue.js",
438
460
  "reach.js",
@@ -479,6 +501,7 @@
479
501
  "sync-plan.js",
480
502
  "synthesis.js",
481
503
  "tags.js",
504
+ "thread-send.js",
482
505
  "team-board.js",
483
506
  "board-tool.js",
484
507
  "team-cache.js",
@@ -553,6 +576,7 @@
553
576
  "kokoro-text.js",
554
577
  "weather-tool.js",
555
578
  "weather.js",
579
+ "clock.js",
556
580
  "web-search-tool.js",
557
581
  "web-search.js",
558
582
  "widget.js",
package/prefetch.js CHANGED
@@ -1,3 +1,5 @@
1
- import{researchAsk as m,runResearch as v}from"./web-research.js";import{frontPagesAskedAbout as F}from"./site-pages.js";const k=/(\bhow(?:'s| is| was|s) (?:the )?(?:weather|forecast|temperature)\b|\bwhat(?:'s| is|s) (?:the )?(?:weather|forecast|temperature)\b|\b(?:weather|forecast|temperature) (?:in|for|at|around|near)\b|\bis it (?:raining|snowing|hot|cold|warm|sunny|cloudy|windy)\b|\b(?:will|does) it (?:rain|snow)\b|\bhow (?:hot|cold|warm|humid|windy) is it\b|^\s*(?:weather|forecast)\b|\b(?:weather|forecast)\s*\??\s*$)/i,B=/\b(right now|now|today|tonight|this (?:morning|afternoon|evening|weekend|week)|tomorrow|currently|at the moment|these days|later)\b/gi,I=new Set(["here","there","home","outside","my location","my area","my city","where i am","it","that"]),y=8;function f(e){return String(e||"").replace(B," ").replace(/[?!.,;:]+$/g,"").replace(/^\s*(the|in|at|for|around|near|of)\s+/i,"").replace(/\s+/g," ").trim()}const $=/\b(how|what|what's|whats|is|are|was|will|do|does|can|should|why|when|the|a|an|tell|me|there|here|it|like|about)\b/i;function g(e){const t=e.toLowerCase();return t.length>=2&&t.length<=60&&!I.has(t)&&!$.test(t)&&!/^(weather|forecast|temperature)$/.test(t)&&/[\p{L}]/u.test(t)&&t.split(/\s+/).length<=5}function S(e){const t=String(e||"").trim();return!k.test(t)||b(t)||/\b(?:api|app|apps|service|widget|feature|code|bug|model|tool|component|test|tests|data|endpoint|sdk|library|module|page|screen)\b/i.test(t)?!1:t.split(/\s+/).length<=12}function b(e){const t=String(e||"").trim();if(!k.test(t))return"";let n=/\b(?:in|at|for|around|near)\s+([^?!.;]+?)(?:\s+(?:right now|now|today|tonight|tomorrow|currently|this \w+))*\s*[?!.]*$/i.exec(t);return n&&g(f(n[1]))||(n=/^(?:what(?:'s| is) the\s+)?([\p{L}][\p{L}\s,.'-]{1,60}?)\s+(?:weather|forecast|temperature)\b/iu.exec(t),n&&g(f(n[1])))||(n=/\b(?:weather|forecast|temperature)\s*[:\-]?\s+([\p{L}][\p{L}\s,.'-]{1,60}?)\s*[?!.]*$/iu.exec(t),n&&g(f(n[1])))?f(n[1]):""}const L=/\b(summari[sz]e|explain|try|again|retry|do|make|write|show|tell|open|read|find|search|help|stop|continue|go|list|give|send|run|check|fix|thanks|thank|yes|no|please|this|that|my|page|note|file|meeting|chat|sounds?|good|great|nice|cool|fine|perfect|awesome|sure|nothing|else|ok|okay|yeah|yep|nope|bye|hello|hi|hey|time|traffic|news|story|joke|stock|price)\b/i,H=/^(?:(?:okay|ok|alright|all right|great|cool|thanks|thank you|fine|good|and|also|then|so|now|actually|well|um+|uh+|hmm+|oh|no|wait)(?:[\s,.!—-]+|$))+/i,M=/^(?:(?:i(?: want| wanted| would like|'d like) to know|i'm wondering|i wonder|(?:can|could) you (?:tell|check) (?:me)?|tell me)\s+)/i,E=/^(?:(?:how|what) about|(?:how|what)(?:'s| is|s) it(?: like)?(?: in| at| for| around| near)?|(?:in|at|for|around|near))\b[\s,]*/i;function _(e,t){if(!t||t.kind!=="weather")return"";const n=String(e||"").trim().replace(/[?!.]+$/,"").trim(),o=n.replace(H,"").trim().replace(M,"").trim();if(!o||o.split(/\s+/).length>y)return"";const s=E.test(o)||o!==n&&/^(?:and|also)\b/i.test(n),r=f(o.replace(E,"").replace(/^(?:like\s+)?(?:in|at|for|around|near)\s+/i,""));return!r||/\d/.test(r)||!s&&r.split(/\s+/).length>2||!g(r)||L.test(r)?"":r}const w="([\\p{L}$][\\p{L}\\p{N}.&'-]*(?:\\s+[\\p{L}][\\p{L}\\p{N}.&'-]*){0,3})",U=[new RegExp(`\\b(?:share price|stock price|stock quote|ticker)\\s+(?:of|for)\\s+${w}`,"iu"),{question:!0,re:new RegExp(`\\b(?:stock|stocks|shares?)\\s+(?:of|for|in)\\s+${w}`,"iu")},new RegExp(`\\b${w}(?:'s)?\\s+(?:stock|shares)\\s+(?:price|doing|trading|today|now|performance|performing|up|down|quote)\\b`,"iu"),new RegExp(`\\b${w}(?:'s)?\\s+(?:share price|stock price|stock quote)\\b`,"iu"),new RegExp(`^\\s*${w}(?:'s)?\\s+(?:stock|shares)\\s*\\??\\s*$`,"iu"),new RegExp(`\\b(?:how|where)(?:'s| is| are)\\s+${w}\\s+(?:stock\\s+|shares\\s+)?trading\\b`,"iu"),new RegExp(`\\bwhat(?:'s| is| are)\\s+${w}\\s+trading at\\b`,"iu"),/\$([A-Z]{1,5})\b/u],J=/^(?:the|a|an|my|our|your|this|that|it|its|their|market|stock market|markets|price|prices|today|now|company|companies|how|what|is|are|doing|of|for|in|weather|forecast|news|time|date|temperature|rain|you|me|us|them|those|these)$/i,K=/^(?:how|what|what's|whats|where|is|are|was|the|a|an|can|could|you|tell|me|about|of|for|in|and|also|so|now|then|please|check|show|give|get)$/i,G=/\s+(?:stock|stocks|shares?|price|prices|doing|trading|today|now|right now|currently|at the moment|this (?:morning|afternoon|week)|lately|so far)\b.*$/i;function j(e){const t=e.toLowerCase();return t.length>=1&&t.length<=40&&!J.test(t)&&!$.test(t)&&/^[\p{L}]/u.test(t)&&t.split(/\s+/).length<=4}function Y(e){const t=e.split(/\s+/).filter(Boolean);for(;t.length>1&&K.test(t[0]);)t.shift();return t.join(" ")}function A(e){return String(e||"").replace(/[?!.,;:]+$/g,"").replace(G,"").replace(/(?:\s+(?:at|on|up|down|for me|please))+$/i,"").replace(/^\s*(?:the|shares? of|stock of)\s+/i,"").replace(/'s$/i,"").replace(/\s+(?:corp(?:oration)?|inc|co|company|ltd)\.?$/i,t=>t).replace(/\s+/g," ").trim()}function R(e){const t=String(e||"").trim(),n=/\?\s*$/.test(t)||/^\s*(?:(?:hey|hi|ok|okay|so|and|now)[\s,]+)*(?:how|what|where|is|are|can|could|would|will|tell|check|show|give|get|find|look up|please)\b/i.test(t);for(const o of U){const s=o instanceof RegExp?o:o.re;if(o.question&&!n)continue;const r=s.exec(t);if(!r)continue;const l=Y(A(r[1]));if(j(l))return l}return""}function C(e,t){if(!t||t.kind!=="stock")return"";let n=String(e||"").trim().replace(/[?!.]+$/,"").trim();if(!n||n.split(/\s+/).length>y)return"";n=n.replace(/^(?:(?:okay|ok|fine|good|great|thanks|thank you|cool|alright|all right|that'?s (?:fine|good|great|ok|okay))[\s,.!—-]*)+/i,"").trim();const o=/^(?:(?:and|also|then|so|now)[\s,]+)*(?:how about|what about)\b/i.test(n)||/^(?:and|also)[\s,]+/i.test(n);n=n.replace(/^(?:(?:and|also|then|so|now)[\s,]+)*(?:(?:how|what) about\b)?[\s,]*/i,"").trim();const s=A(n);return!s||!o&&(s.split(/\s+/).length>2||!/[?]\s*$/.test(String(e))&&s.split(/\s+/).length>1)||!j(s)||L.test(s)?"":s}const O=new RegExp("(?<![\\p{L}\\p{N}'])\\p{L}(?:[ \\t.,\\-–]{1,3}\\p{L}(?![\\p{L}\\p{N}'])){2,}","gu");function N(e){return String(e||"").replace(O,t=>t.replace(/[^\p{L}]/gu,"").toLowerCase())}function X(e){return[...String(e||"").matchAll(O)].map(t=>t[0].replace(/[^\p{L}]/gu,"").toLowerCase())}const z=/\b(?:tell me (?:more |everything |all |something )?about|what do you know about|do you know (?:anything )?about|who(?:'s| is| was| are)|look up|lookup|search (?:the web |online |the internet |google )?for|search up|google|find (?:out )?(?:info(?:rmation)?|details|more|anything|something|everything) (?:on|about)|(?:info|information|background|details) (?:on|about)|research)\s+(.+)$/i,V=/[.?!;:,()](?=\s|$)|\s(?:uh|um|umm|er|erm|hmm|like|actually|i mean|sorry|the (?:first |last |sur|family )?name|his|her|their|its|it's|it is|spelled|spelt|and (?:tell|give|find|show|let|search|look)|then|please|for me|on the web|online|on google|from the web|if you can|thanks|thank you)\b/i,Z=/^(?:it|this|that|these|those|him|her|them|me|you|yourself|us|he|she|they|we|i|my|our|your|his|their|here|there|on|in|at|to|for|with|from|going|coming|speaking|talking|calling|joining|what|how|why|when|where|which|the weather|weather)\b/i,Q=/^(?:my|our|your|this|that|today'?s|yesterday'?s|last|next|latest|recent)\b/i,ee=/^(?:the|a|an)\b/i,te=6;function x(e){const n=(String(e||"").split(V)[0]||"").replace(/\s+/g," ").replace(/^["'“‘]+|["'”’]+$/g,"").trim(),o=n.split(" ").filter(Boolean);return!o.length||o.length>te||!new RegExp("\\p{L}","u").test(n)||Z.test(n)?"":n}function ne(e){const t=z.exec(N(e));return t?x(t[1]):""}const se=[[/\b(?:last|sur|family|second) ?name\b|\bsurname\b/i,e=>e.length-1],[/\bfirst name\b|\bgiven name\b/i,()=>0]],oe=/\b(?:it(?:'s| is)|spelled|spelt|should be|is actually|actually|but|name is)\s+["'“‘]?([\p{L}][\p{L}'-]{1,40})["'”’]?\s*[.!?]*\s*$/iu,re=/\b(?:no|nope|not|wrong|incorrect|misspel\w*|spell\w*|typo|name|actually|i meant|i mean)\b/i;function ae(e,t){const n=e.toLowerCase(),o=t.toLowerCase(),s=Array.from({length:o.length+1},(r,l)=>l);for(let r=1;r<=n.length;r++){let l=s[0];s[0]=r;for(let a=1;a<=o.length;a++){const h=s[a];s[a]=Math.min(s[a]+1,s[a-1]+1,l+(n[r-1]===o[a-1]?0:1)),l=h}}return s[o.length]}function ie(e,t){return new RegExp("^\\p{Lu}","u").test(t)?e.charAt(0).toUpperCase()+e.slice(1):e}function D(e,t){const n=String(t||"").trim();if(!n)return null;const o=String(e||""),s=X(o),r=N(o);let l=s.at(-1)||"";if(!l&&re.test(r)&&(l=oe.exec(r)?.[1]||""),!l||l.length<2)return null;const a=n.split(/\s+/);let h=-1;for(const[c,i]of se)if(c.test(r)){h=i(a);break}if(h<0){let c=1/0;a.forEach((i,p)=>{const d=ae(i,l)/Math.max(i.length,l.length);d<c&&(c=d,h=p)}),c>.6&&(h=a.length===1?0:-1)}if(h<0)return null;const u=a[h];return u.toLowerCase()===l.toLowerCase()?{subject:n,replaced:""}:(a[h]=ie(l,a.find(c=>new RegExp("^\\p{Lu}","u").test(c))||u),{subject:a.join(" "),replaced:u})}const ce=/\b(?:search|look|google|check|find|try)\b[^.?!]{0,30}\b(?:web|online|internet|google|up|again|it|him|her|them)\b|\blook(?:ing)? (?:it|that|him|her|them)? ?up\b/i,T=/\b(?:web|online|internet|google)\b/i;function le(e,t){if(!t||t.kind!=="lookup"||!t.subject)return null;const n=D(e,t.subject),o=/\b(?:not|wrong|isn'?t|incorrect|nope)\b/i.test(e);return!n&&!o&&!ce.test(e)?null:{subject:n?.subject||t.subject,replaced:n?.replaced||"",corrected:!!n||o,web:T.test(e)}}function W(e,t){const n=ne(e);if(n){const s=D(e.slice(e.toLowerCase().indexOf(n.toLowerCase())+n.length),n);return{kind:"lookup",subject:s?.subject||n,replaced:s?.replaced||"",corrected:!!s?.replaced,web:T.test(e)}}const o=le(e,t);return o?{kind:"lookup",...o}:null}function P(e){return Q.test(e)||/@|\d{5,}/.test(e)||!new RegExp("\\p{L}{2,}","u").test(e)?!1:!ee.test(e)||new RegExp("\\s\\p{Lu}","u").test(e)}const he=/\b(?:news|headlines|stories)\s+(?:on|about|from|in|for|regarding|around)\s+(.+)$/i,ue=/\bwhat(?:'s| is| are)\s+(?:new|happening|going on|the latest|the news)\s+(?:with|in|on|at|around|from)\s+(.+)$/i,pe=/^(?:(?:can|could) you (?:tell|give) me |tell me |give me |show me )?(?:the |any |some )?(?:latest |recent |top |today'?s |breaking )?(.{2,60}?)\s+news(?:\s+(?:today|this (?:morning|week|evening)|right now|lately|these days))?\s*[?.!]*$/i,fe=/^(?:(?:can|could) you (?:tell|give) me |tell me |give me |show me |what(?:'s| is| are) )?(?:the |any )?(?:latest |top |today'?s |breaking )?(?:news|headlines)(?:\s+(?:today|this (?:morning|week|evening)|right now))?\s*[?.!]*$/i,q=/\s+(?:today|tonight|this (?:morning|week|evening|year)|right now|lately|these days|recently|now)$/i;function we(e){const t=String(e||"").trim();if(!t||F(t).length)return null;if(fe.test(t))return{subject:""};const n=he.exec(t)||pe.exec(t),o=n?null:ue.exec(t),s=n||o;if(!s)return null;const r=x(s[1].replace(/[?.!]+$/,"").replace(q,"")).replace(q,"");return o&&r.split(/\s+/).length>4||!r||!P(r)||/^(?:the )?(?:weather|stock|stocks|market)$/i.test(r)?null:{subject:r}}function ye(e){return/^\s*No (?:history matches|web results)\b/.test(String(e||""))}function de(e,t){const n=b(e)||_(e,t);if(n)return{kind:"weather",subject:n};if(S(e))return{kind:"weather",subject:"here"};const o=R(e)||C(e,t);if(o)return{kind:"stock",subject:o};const s=W(String(e||""),t);if(s)return s;const r=m(e,{previous:t});return r?{kind:"research",subject:r.subject,research:r}:null}function $e(e){const t=(Array.isArray(e)?e:[]).filter(s=>s&&!s.pending&&(s.role==="user"||s.role==="assistant")),n=[];for(let s=0;s<t.length;s++)t[s].role==="user"&&n.push(s);if(n.length<2)return null;let o=null;for(let s=0;s<n.length-1;s++){const r=t[n[s]],l=t[n[s]+1]?.role==="assistant"?t[n[s]+1]:null,a=(r.attachments||[]).find(c=>c?.kind==="prefetch"),h=typeof r.content=="string"?r.content:"";o=de(h,o)||(a?{kind:a.prefetch,...a.research?{research:a.research}:{}}:null)||((l?.steps||[]).some(c=>c?.input?.action==="weather"||c?.tool==="weather")?{kind:"weather"}:null)}return o}function Se({text:e="",previous:t=null,reach:n=new Set,lookup:o=!1,research:s=!1,now:r=Date.now()}={}){const l=n instanceof Set?n:new Set(Array.isArray(n)?n:[]),a=[],h=l.has("find:weather"),u=l.has("weather");if(h||u){const i=b(e)||_(e,t),p=i||(S(e)?"here":"");p&&a.push({kind:"weather",tool:h?"find":"weather",input:h?{action:"weather",args:{location:p}}:{location:p},label:i?`Weather — ${i}`:"Weather — near you"})}const c=l.has("find:web_search");if(!a.length&&(c||l.has("web_search"))){const i=R(e)||C(e,t);if(i){const p=`${i} stock price today`;a.push({kind:"stock",tool:c?"find":"web_search",input:c?{action:"web_search",args:{query:p}}:{query:p},label:`Stock — ${i}`})}}if(!a.length&&(c||l.has("web_search"))){const i=we(e);if(i){const p=i.subject?`${i.subject} news today`:"top news today";a.push({kind:"news",tool:c?"find":"web_search",input:c?{action:"web_search",args:{query:p}}:{query:p},label:i.subject?`News — ${i.subject}`:"News — today",subject:i.subject})}}if(s&&!a.length&&(c||l.has("web_search"))){const i=m(e,{previous:t,now:r});if(i){const p=c?"find":"web_search";a.push({kind:"research",tool:p,input:p==="find"?{action:"web_search",args:{query:i.queries[0]}}:{query:i.queries[0]},label:`Research — ${i.subject}`,subject:i.subject,research:i})}}return o&&!a.length&&a.push(...ge(e,t,l)),a}function ge(e,t,n){const o=W(String(e||""),t);if(!o)return[];const{subject:s}=o,r=o.corrected?`The user corrected the name: it is "${s}"${o.replaced?`, not "${o.replaced}"`:""} — use this spelling; earlier answers in this chat were about the wrong name.`:"",l=c=>n.has(`find:${c}`)?{tool:"find",input:i=>({action:c,args:i})}:n.has(c)?{tool:c,input:i=>i}:null,a=[],h=l("history_search"),u=l("web_search");return h&&!o.web&&a.push({kind:"lookup",tool:h.tool,input:h.input({query:s}),label:`Library — ${s}`,subject:s,note:r}),u&&(o.web||P(s))&&a.push({kind:"lookup",tool:u.tool,input:u.input({query:s}),label:`Web — ${s}`,subject:s,note:r,fallback:a.length>0}),a}function be(e,t,{now:n=Date.now()}={}){if(e.kind==="research"){const l=String(t||""),{question:a,domain:h,subject:u,slots:c}=e.research||{};return{id:`prefetch_research_${n}`,kind:"prefetch",prefetch:"research",subject:e.subject||u||"",research:{question:a,domain:h,subject:u,slots:c},title:e.label,text:l,chars:l.length}}const o=e.kind==="stock"?`do not call ${e.tool} or any search tool again for the same company. Say the price and change it gives; if it gives none, say you could not find a current price — never estimate one.`:e.kind==="lookup"?`if it is about someone or something else, or found nothing, search again with DIFFERENT words (another spelling, the other source — library or web) — never the same query.${e.note?` ${e.note}`:""}`:`do not call ${e.tool} or any weather/search tool again for the same place.`,r=`(ALREADY ${e.kind==="lookup"?`SEARCHED for "${e.subject}"`:"FETCHED"} for the question below, with ${e.tool}. Answer from this; ${o})
1
+ import{researchAsk as j,runResearch as V}from"./web-research.js";import{frontPagesAskedAbout as Z}from"./site-pages.js";import{weatherFromSearch as ee}from"./weather-tool.js";const R=/(\bhow(?:'s| is| was|s) (?:the )?(?:weather|forecast|temperature)\b|\bwhat(?:'s| is|s) (?:the )?(?:weather|forecast|temperature)\b|\b(?:weather|forecast|temperature) (?:in|for|at|around|near)\b|\bis it (?:raining|snowing|hot|cold|warm|sunny|cloudy|windy)\b|\b(?:will|does) it (?:rain|snow)\b|\bhow (?:hot|cold|warm|humid|windy) is it\b|^\s*(?:weather|forecast)\b|\b(?:weather|forecast)\s*\??\s*$)/i,te=/\b(right now|now|today|tonight|this (?:morning|afternoon|evening|weekend|week)|tomorrow|currently|at the moment|these days|later)\b/gi,ne=new Set(["here","there","home","outside","my location","my area","my city","where i am","it","that"]),O=8,E="(?:page|tab|article|post|thread|discussion|story|site|website|doc|document|comments?|content|piece|blog(?: post)?|paper|video|readme|pdf)",se=new RegExp(`\\b(?:this|current|the current|the open|open|that)\\s+${E}\\b`,"i"),oe=new RegExp(`^\\s*(?:(?:can you |could you |please )?(?:summari[sz]e|tl;?\\s?dr|recap|give me the gist|what are the key (?:points|takeaways))(?:\\s+(?:it|this|that|here|(?:the|this)\\s+${E}(?:\\s+and\\s+(?:the\\s+)?${E})?))?|what(?:'s| is| are)? (?:people|they|folks|commenters) (?:saying|think(?:ing)?)(?: here| about (?:it|this))?)\\s*[?.!]*\\s*$`,"i"),re=/\b(?:my|our|your|the|this|that|last|today'?s|yesterday'?s)\s+(?:meeting|chat|conversation|call|standup|notes?|email|inbox|calendar|day|week|transcript|thread with)\b|https?:\/\//i,ae=/^\s*(?:(?:please|pls|can you|could you|just|ok,?|no,?)\s+)*(?:use (?:the )?(?:web|internet)(?: search)?|use web ?search|search (?:the )?(?:web|internet|online)|web ?search(?: it)?|google(?: it| that)?|look (?:it |that )?up(?: online| on the web)?|check (?:the web|online)|try (?:the )?(?:web|internet|a web search|web search)|search (?:it|that|again|online))\b(?:\s+(?:for|about)\s+(.+?))?(?:,?\s+(?:please|pls|thanks|instead|now|then))*\s*[?.!]*\s*$/i;function ie(e){const t=ae.exec(String(e||""));if(!t)return null;const n=String(t[1]||"").trim();return n?{query:n}:{}}const ce=/\b(?:weather|forecast|temperature|rain|snow)\b/i,he=/\b(?:rest of (?:the|this) (?:week|weekend|month)|(?:this|next|coming) (?:week|weekend)|(?:the|this) weekend|week ahead|the week|next (?:few|several|couple of) days|coming days|(?:5|7|10|14)[- ]?days?|extended|long[- ]range|two[- ]weeks?)\b/i,le=/\b(?:i|we) (?:asked|said|wrote|told|searched|talked|discussed|mentioned|looked up|checked)\b|\b(?:did|have|had) (?:i|we)\b|\bhow (?:many|often) (?:times )?(?:i|we|did|have)\b|\bhow many times\b|\bmy (?:chats?|notes?|history|meetings?|conversations?|questions?|searches)\b|\blast time (?:i|we)\b/i,ue=/\b(?:find out more|find (?:out )?more|more (?:info|information|details)|look into (?:it|that|this)|dig (?:deeper|into (?:it|that))|get more details?|find (?:it|that) out|check (?:on )?(?:it|that) (?:again|online)|search (?:for )?more|look (?:it|that) up|find (?:the )?(?:rest|full|whole)(?: of it| forecast)?)\b/i,pe=/^\s*(?:yes|yeah|yep|yup|sure|ok(?:ay)?|k|please(?: do)?|go ahead|go for it|do it|yes please|sure thing|absolutely|of course|ok look|look|search|please search|search it)(?:[\s,.!]+(?:please|thanks|thank you|go ahead|do it|look|search|yes))*[\s.!]*$/i,de=/\b(?:search the web|web search|search online|search for|look (?:it|that|this) up|look up|check online|find (?:it|that|out|more))\b/i,we=/(?:web search for|search the web for|search (?:online )?for|look up|look for)\s+(?:the\s+)?(.{3,160}?)(?:\s*[?.!]|$)/i;function fe(e){const t=String(e||"").split(/\n+/).map(s=>s.trim()).filter(Boolean).slice(-3).join(" ");if(de.test(t)&&/\?/.test(t)){const s=(we.exec(t)?.[1]||"").replace(/\s+for me$/i,"").trim();if(s)return s}const n=/\b(?:searching(?: the web| online)? for|looking up|checking(?: the web| online)? for)\s+(?:the\s+)?(.{3,160}?)(?:\.\.\.|…|[.!?]|$)/i.exec(t);return n?n[1].trim():""}const A=/^\s*(?:(?:no|nope|actually|but|well|sorry)\b[,.!]?\s*)?(?:i|we) (?:asked|said|meant|wanted)\b/i,N=/\b(?:did|when|how (?:many|often)|earlier|before|yesterday|last (?:time|week|month)|ago|previously|other day)\b/i;function ge(e){const t=String(e||"");if(!A.test(t)||N.test(t))return"";const n=t.replace(A,"").replace(/^\s*(?:for|about)\s+/i,"").replace(/[.;]\s+(?:and|also)\s+/gi," and ").replace(/,?\s+not\s+[^.?!]*/i,"").trim();return/^(?:the\s+)?(?:weather|forecast|temperature)\b/i.test(n)?`what is ${/^the\s/i.test(n)?"":"the "}${n}`:""}function be(e){const t=String(e||"");return A.test(t)&&!N.test(t)?!1:le.test(t)}const ke=/^\s*(?:and|what about|how about|now|no,?|ok,?|same for)\b[^?.!]{0,30}[?.!]*\s*$/i;function C(e){const t=String(e||"").trim();return!t||t.length>300||re.test(t)?null:se.test(t)||oe.test(t)?{}:null}function g(e){return String(e||"").replace(te," ").replace(/[?!.,;:]+$/g,"").replace(/^\s*(the|in|at|for|around|near|of)\s+/i,"").replace(/\s+/g," ").trim()}const P=/\b(how|what|what's|whats|is|are|was|will|do|does|can|should|why|when|the|a|an|tell|me|there|here|it|like|about)\b/i;function m(e){const t=e.toLowerCase();return t.length>=2&&t.length<=60&&!ne.has(t)&&!P.test(t)&&!/^(weather|forecast|temperature)$/.test(t)&&/^[\p{L}]/u.test(t)&&t.split(/\s+/).length<=5}function W(e){const t=String(e||"").trim();return!R.test(t)||y(t)||/\b(?:api|app|apps|service|widget|feature|code|bug|model|tool|component|test|tests|data|endpoint|sdk|library|module|page|screen)\b/i.test(t)?!1:t.split(/\s+/).length<=12}const me=/\s+(?:for|over|during|through|in|this|next|and)?\s*(?:the\s+)?(?:rest of (?:the|this) (?:week|weekend|day|month)|next (?:few|several|couple of|\d+) days|(?:this|next|coming) (?:week|weekend|month|few days)|the (?:weekend|week(?: ahead)?|coming days)|week ahead|\d+[- ]days?(?: forecast)?)\b/gi;function y(e){const t=String(e||"").trim();if(!R.test(t))return"";const n=t.replace(me,"").trim();let s=/\b(?:in|at|for|around|near)\s+([^?!.;]+?)(?:\s+(?:right now|now|today|tonight|tomorrow|currently|this \w+))*\s*[?!.]*$/i.exec(n);return s&&m(g(s[1]))||(s=/^(?:what(?:'s| is) the\s+)?([\p{L}][\p{L}\s,.'-]{1,60}?)\s+(?:weather|forecast|temperature)\b/iu.exec(n),s&&m(g(s[1])))||(s=/\b(?:weather|forecast|temperature)\s*[:\-]?\s+([\p{L}][\p{L}\s,.'-]{1,60}?)\s*[?!.]*$/iu.exec(n),s&&m(g(s[1])))?g(s[1]):""}const T=/\b(summari[sz]e|explain|try|again|retry|do|make|write|show|tell|open|read|find|search|help|stop|continue|go|list|give|send|run|check|fix|thanks|thank|yes|no|please|this|that|my|page|note|file|meeting|chat|sounds?|good|great|nice|cool|fine|perfect|awesome|sure|nothing|else|ok|okay|yeah|yep|nope|bye|hello|hi|hey|time|traffic|news|story|joke|stock|price|you|yourself|him|her|them|us)\b/i,ye=/^(?:(?:okay|ok|alright|all right|great|cool|thanks|thank you|fine|good|and|also|then|so|now|actually|well|um+|uh+|hmm+|oh|no|wait)(?:[\s,.!—-]+|$))+/i,$e=/^(?:(?:i(?: want| wanted| would like|'d like) to know|i'm wondering|i wonder|(?:can|could) you (?:tell|check) (?:me)?|tell me)\s+)/i,x=/^(?:(?:how|what) about|(?:how|what)(?:'s| is|s) it(?: like)?(?: in| at| for| around| near)?|(?:in|at|for|around|near))\b[\s,]*/i;function F(e,t){if(!t||t.kind!=="weather")return"";const n=String(e||"").trim().replace(/[?!.]+$/,"").trim(),s=n.replace(ye,"").trim().replace($e,"").trim();if(!s||s.split(/\s+/).length>O)return"";const o=x.test(s)||s!==n&&/^(?:and|also)\b/i.test(n),r=g(s.replace(x,"").replace(/^(?:like\s+)?(?:in|at|for|around|near)\s+/i,""));return!r||/\d/.test(r)||!o&&r.split(/\s+/).length>2||!m(r)||T.test(r)?"":r}const b="([\\p{L}$][\\p{L}\\p{N}.&'-]*(?:\\s+[\\p{L}][\\p{L}\\p{N}.&'-]*){0,3})",Se=[new RegExp(`\\b(?:share price|stock price|stock quote|ticker)\\s+(?:of|for)\\s+${b}`,"iu"),{question:!0,re:new RegExp(`\\b(?:stock|stocks|shares?)\\s+(?:of|for|in)\\s+${b}`,"iu")},new RegExp(`\\b${b}(?:'s)?\\s+(?:stock|shares)\\s+(?:price|doing|trading|today|now|performance|performing|up|down|quote)\\b`,"iu"),new RegExp(`\\b${b}(?:'s)?\\s+(?:share price|stock price|stock quote)\\b`,"iu"),new RegExp(`^\\s*${b}(?:'s)?\\s+(?:stock|shares)\\s*\\??\\s*$`,"iu"),new RegExp(`\\b(?:how|where)(?:'s| is| are)\\s+${b}\\s+(?:stock\\s+|shares\\s+)?trading\\b`,"iu"),new RegExp(`\\bwhat(?:'s| is| are)\\s+${b}\\s+trading at\\b`,"iu"),/\$([A-Z]{1,5})\b/u],_e=/^(?:the|a|an|my|our|your|this|that|it|its|their|market|stock market|markets|price|prices|today|now|company|companies|how|what|is|are|doing|of|for|in|weather|forecast|news|time|date|temperature|rain|you|me|us|them|those|these)$/i,Ee=/^(?:how|what|what's|whats|where|is|are|was|the|a|an|can|could|you|tell|me|about|of|for|in|and|also|so|now|then|please|check|show|give|get)$/i,Ae=/\s+(?:stock|stocks|shares?|price|prices|doing|trading|today|now|right now|currently|at the moment|this (?:morning|afternoon|week)|lately|so far)\b.*$/i;function q(e){const t=e.toLowerCase();return t.length>=1&&t.length<=40&&!_e.test(t)&&!P.test(t)&&/^[\p{L}]/u.test(t)&&t.split(/\s+/).length<=4}function Le(e){const t=e.split(/\s+/).filter(Boolean);for(;t.length>1&&Ee.test(t[0]);)t.shift();return t.join(" ")}function D(e){return String(e||"").replace(/[?!.,;:]+$/g,"").replace(Ae,"").replace(/(?:\s+(?:at|on|up|down|for me|please))+$/i,"").replace(/^\s*(?:the|shares? of|stock of)\s+/i,"").replace(/'s$/i,"").replace(/\s+(?:corp(?:oration)?|inc|co|company|ltd)\.?$/i,t=>t).replace(/\s+/g," ").trim()}function v(e){const t=String(e||"").trim(),n=/\?\s*$/.test(t)||/^\s*(?:(?:hey|hi|ok|okay|so|and|now)[\s,]+)*(?:how|what|where|is|are|can|could|would|will|tell|check|show|give|get|find|look up|please)\b/i.test(t);for(const s of Se){const o=s instanceof RegExp?s:s.re;if(s.question&&!n)continue;const r=o.exec(t);if(!r)continue;const l=Le(D(r[1]));if(q(l))return l}return""}function I(e,t){if(!t||t.kind!=="stock")return"";let n=String(e||"").trim().replace(/[?!.]+$/,"").trim();if(!n||n.split(/\s+/).length>O)return"";n=n.replace(/^(?:(?:okay|ok|fine|good|great|thanks|thank you|cool|alright|all right|that'?s (?:fine|good|great|ok|okay))[\s,.!—-]*)+/i,"").trim();const s=/^(?:(?:and|also|then|so|now)[\s,]+)*(?:how about|what about)\b/i.test(n)||/^(?:and|also)[\s,]+/i.test(n);n=n.replace(/^(?:(?:and|also|then|so|now)[\s,]+)*(?:(?:how|what) about\b)?[\s,]*/i,"").trim();const o=D(n);return!o||!s&&(o.split(/\s+/).length>2||!/[?]\s*$/.test(String(e))&&o.split(/\s+/).length>1)||!q(o)||T.test(o)?"":o}const B=new RegExp("(?<![\\p{L}\\p{N}'])\\p{L}(?:[ \\t.,\\-–]{1,3}\\p{L}(?![\\p{L}\\p{N}'])){2,}","gu");function H(e){return String(e||"").replace(B,t=>t.replace(/[^\p{L}]/gu,"").toLowerCase())}function je(e){return[...String(e||"").matchAll(B)].map(t=>t[0].replace(/[^\p{L}]/gu,"").toLowerCase())}const Re=/\b(?:tell me (?:more |everything |all |something )?about|what do you know about|do you know (?:anything )?about|who(?:'s| is| was| are)|look up|lookup|search (?:the web |online |the internet |google )?for|search up|google|find (?:out )?(?:info(?:rmation)?|details|more|anything|something|everything) (?:on|about)|(?:info|information|background|details) (?:on|about)|research)\s+(.+)$/i,Oe=/[.?!;:,()](?=\s|$)|\s(?:uh|um|umm|er|erm|hmm|like|actually|i mean|sorry|the (?:first |last |sur|family )?name|his|her|their|its|it's|it is|spelled|spelt|and (?:tell|give|find|show|let|search|look)|then|please|for me|on the web|online|on google|from the web|if you can|thanks|thank you)\b/i,Ne=/^(?:it|this|that|these|those|him|her|them|me|you|yourself|us|he|she|they|we|i|my|our|your|his|their|here|there|on|in|at|to|for|with|from|going|coming|speaking|talking|calling|joining|what|how|why|when|where|which|the weather|weather)\b/i,Ce=/^(?:my|our|your|this|that|today'?s|yesterday'?s|last|next|latest|recent)\b/i,Pe=/^(?:the|a|an)\b/i,We=6;function M(e){const n=(String(e||"").split(Oe)[0]||"").replace(/\s+/g," ").replace(/^["'“‘]+|["'”’]+$/g,"").trim(),s=n.split(" ").filter(Boolean);return!s.length||s.length>We||!new RegExp("\\p{L}","u").test(n)||Ne.test(n)?"":n}function Te(e){const t=Re.exec(H(e));return t?M(t[1]):""}const xe=[[/\b(?:last|sur|family|second) ?name\b|\bsurname\b/i,e=>e.length-1],[/\bfirst name\b|\bgiven name\b/i,()=>0]],Fe=/\b(?:it(?:'s| is)|spelled|spelt|should be|is actually|actually|but|name is)\s+["'“‘]?([\p{L}][\p{L}'-]{1,40})["'”’]?\s*[.!?]*\s*$/iu,qe=/\b(?:no|nope|not|wrong|incorrect|misspel\w*|spell\w*|typo|name|actually|i meant|i mean)\b/i;function De(e,t){const n=e.toLowerCase(),s=t.toLowerCase(),o=Array.from({length:s.length+1},(r,l)=>l);for(let r=1;r<=n.length;r++){let l=o[0];o[0]=r;for(let c=1;c<=s.length;c++){const u=o[c];o[c]=Math.min(o[c]+1,o[c-1]+1,l+(n[r-1]===s[c-1]?0:1)),l=u}}return o[s.length]}function ve(e,t){return new RegExp("^\\p{Lu}","u").test(t)?e.charAt(0).toUpperCase()+e.slice(1):e}function U(e,t){const n=String(t||"").trim();if(!n)return null;const s=String(e||""),o=je(s),r=H(s);let l=o.at(-1)||"";if(!l&&qe.test(r)&&(l=Fe.exec(r)?.[1]||""),!l||l.length<2)return null;const c=n.split(/\s+/);let u=-1;for(const[a,d]of xe)if(a.test(r)){u=d(c);break}if(u<0){let a=1/0;c.forEach((d,k)=>{const f=De(d,l)/Math.max(d.length,l.length);f<a&&(a=f,u=k)}),a>.6&&(u=c.length===1?0:-1)}if(u<0)return null;const i=c[u];return i.toLowerCase()===l.toLowerCase()?{subject:n,replaced:""}:(c[u]=ve(l,c.find(a=>new RegExp("^\\p{Lu}","u").test(a))||i),{subject:c.join(" "),replaced:i})}const Ie=/\b(?:search|look|google|check|find|try)\b[^.?!]{0,30}\b(?:web|online|internet|google|up|again|it|him|her|them)\b|\blook(?:ing)? (?:it|that|him|her|them)? ?up\b/i,G=/\b(?:web|online|internet|google)\b/i;function Be(e,t){if(!t||t.kind!=="lookup"||!t.subject)return null;const n=U(e,t.subject),s=/\b(?:not|wrong|isn'?t|incorrect|nope)\b/i.test(e);return!n&&!s&&!Ie.test(e)?null:{subject:n?.subject||t.subject,replaced:n?.replaced||"",corrected:!!n||s,web:G.test(e)}}function K(e,t){const n=Te(e);if(n){const o=U(e.slice(e.toLowerCase().indexOf(n.toLowerCase())+n.length),n);return{kind:"lookup",subject:o?.subject||n,replaced:o?.replaced||"",corrected:!!o?.replaced,web:G.test(e)}}const s=Be(e,t);return s?{kind:"lookup",...s}:null}function J(e){return Ce.test(e)||/@|\d{5,}/.test(e)||!new RegExp("\\p{L}{2,}","u").test(e)?!1:!Pe.test(e)||new RegExp("\\s\\p{Lu}","u").test(e)}const He=/\b(?:news|headlines|stories)\s+(?:on|about|from|in|for|regarding|around)\s+(.+)$/i,Me=/\bwhat(?:'s| is| are)\s+(?:new|happening|going on|the latest|the news)\s+(?:with|in|on|at|around|from)\s+(.+)$/i,Ue=/^(?:(?:can|could) you (?:tell|give) me |tell me |give me |show me )?(?:the |any |some )?(?:latest |recent |top |today'?s |breaking )?(.{2,60}?)\s+news(?:\s+(?:today|this (?:morning|week|evening)|right now|lately|these days))?\s*[?.!]*$/i,Ge=/^(?:(?:can|could) you (?:tell|give) me |tell me |give me |show me |what(?:'s| is| are) )?(?:the |any )?(?:latest |top |today'?s |breaking )?(?:news|headlines)(?:\s+(?:today|this (?:morning|week|evening)|right now))?\s*[?.!]*$/i,Y=/\s+(?:today|tonight|this (?:morning|week|evening|year)|right now|lately|these days|recently|now)$/i;function Ke(e){const t=String(e||"").trim();if(!t||Z(t).length)return null;if(Ge.test(t))return{subject:""};const n=He.exec(t)||Ue.exec(t),s=n?null:Me.exec(t),o=n||s;if(!o)return null;const r=M(o[1].replace(/[?.!]+$/,"").replace(Y,"")).replace(Y,"");return s&&r.split(/\s+/).length>4||!r||!J(r)||/^(?:the )?(?:weather|stock|stocks|market)$/i.test(r)?null:{subject:r}}function Ze(e){return/^\s*No (?:history matches|web results)\b/.test(String(e||""))}const Je=/^\s*(?:(?:and|also|ok(?:ay)?|so|then)[,\s]+)?(?:(?:what|how) about|how(?:'s|’s| is| will| does)?(?: it| the weather| things)?(?: be| look(?:ing)?)?|is it|and|for)?\s*(?:(?:right )?now|currently|today|tonight|tomorrow(?: morning| afternoon| evening| night)?|(?:a |the )?day after tomorrow|later(?: today| tonight)?|(?:this|next|the) (?:morning|afternoon|evening|night|weekend|week)|(?:the )?rest of (?:the|this) week|(?:on |this |next )?(?:mon|tues|wednes|thurs|fri|satur|sun)day|outside|out there)\s*[?!.]*\s*$/i;function z(e,t){return!t||t.kind!=="weather"?"":Je.test(String(e||""))?String(t.subject||"here"):""}function Ye(e,t){const n=y(e)||z(e,t)||F(e,t);if(n)return{kind:"weather",subject:n};if(W(e))return{kind:"weather",subject:"here"};const s=v(e)||I(e,t);if(s)return{kind:"stock",subject:s};const o=K(String(e||""),t);if(o)return o;const r=j(e,{previous:t});return r?{kind:"research",subject:r.subject,research:r}:null}function et(e){const t=(Array.isArray(e)?e:[]).filter(o=>o&&!o.pending&&(o.role==="user"||o.role==="assistant")),n=[];for(let o=0;o<t.length;o++)t[o].role==="user"&&n.push(o);if(n.length<2)return null;let s=null;for(let o=0;o<n.length-1;o++){const r=t[n[o]],l=t[n[o]+1]?.role==="assistant"?t[n[o]+1]:null,c=(r.attachments||[]).find(a=>a?.kind==="prefetch"),u=typeof r.content=="string"?r.content:"";s=Ye(u,s)||(c?{kind:c.prefetch,...c.research?{research:c.research}:{}}:null)||((l?.steps||[]).some(a=>a?.input?.action==="weather"||a?.tool==="weather")?{kind:"weather"}:null)}return s}function tt({text:e="",previous:t=null,previousText:n="",previousAnswer:s="",reach:o=new Set,lookup:r=!1,research:l=!1,page:c=!1,now:u=Date.now()}={}){const i=o instanceof Set?o:new Set(Array.isArray(o)?o:[]),a=[];if(be(e))return r?X(e,t,i):[];const d=pe.test(String(e||""))?fe(s):"",k=String(e||"").trim().split(/\s+/).length,f=ie(e)||(d?{query:d}:null)||(ue.test(String(e||""))&&k<=14?{}:null);if(f&&(i.has("find:web_search")||i.has("web_search"))){const h=f.query||String(n||"").trim();if(h){const p=i.has("find:web_search");return[{kind:"web",tool:p?"find":"web_search",input:p?{action:"web_search",args:{query:h}}:{query:h},label:`Web — ${h.slice(0,60)}`,subject:h,...ce.test(h)?{weather:!0}:{}}]}}if(c&&(i.has("page:read_page")||i.has("read_page"))&&C(e)){const h=i.has("page:read_page"),p=ke.test(e)&&C(n)?String(n).trim():"";return[{kind:"page",tool:h?"page":"read_page",input:h?{action:"read_page",args:{}}:{},label:"This page",...p?{ask:p}:{}}]}const $=i.has("find:weather"),Q=i.has("weather");if($||Q){e=ge(e)||e;const h=y(e)?"":z(e,t),p=y(e)||(h?h!=="here"?h:"":F(e,t)),S=p||(W(e)||h?"here":"");if(S&&(a.push({kind:"weather",tool:$?"find":"weather",input:$?{action:"weather",args:{location:S}}:{location:S},label:p?`Weather — ${p}`:"Weather — near you"}),p&&he.test(String(e||""))&&(i.has("find:web_search")||i.has("web_search")))){const _=`${p} 10 day weather forecast`,L=i.has("find:web_search");a.push({kind:"web",tool:L?"find":"web_search",input:L?{action:"web_search",args:{query:_}}:{query:_},label:`Web — ${p} extended forecast`,subject:_,weather:!0})}}const w=i.has("find:web_search");if(!a.length&&(w||i.has("web_search"))){const h=v(e)||I(e,t);if(h){const p=`${h} stock price today`;a.push({kind:"stock",tool:w?"find":"web_search",input:w?{action:"web_search",args:{query:p}}:{query:p},label:`Stock — ${h}`})}}if(!a.length&&(w||i.has("web_search"))){const h=Ke(e);if(h){const p=h.subject?`${h.subject} news today`:"top news today";a.push({kind:"news",tool:w?"find":"web_search",input:w?{action:"web_search",args:{query:p}}:{query:p},label:h.subject?`News — ${h.subject}`:"News — today",subject:h.subject})}}if(l&&!a.length&&(w||i.has("web_search"))){const h=j(e,{previous:t,now:u});if(h){const p=w?"find":"web_search";a.push({kind:"research",tool:p,input:p==="find"?{action:"web_search",args:{query:h.queries[0]}}:{query:h.queries[0]},label:`Research — ${h.subject}`,subject:h.subject,research:h})}}return r&&!a.length&&a.push(...X(e,t,i)),a}function X(e,t,n){const s=K(String(e||""),t);if(!s)return[];const{subject:o}=s,r=s.corrected?`The user corrected the name: it is "${o}"${s.replaced?`, not "${s.replaced}"`:""} — use this spelling; earlier answers in this chat were about the wrong name.`:"",l=a=>n.has(`find:${a}`)?{tool:"find",input:d=>({action:a,args:d})}:n.has(a)?{tool:a,input:d=>d}:null,c=[],u=l("history_search"),i=l("web_search");return u&&!s.web&&c.push({kind:"lookup",tool:u.tool,input:u.input({query:o}),label:`Library — ${o}`,subject:o,note:r}),i&&(s.web||J(o))&&c.push({kind:"lookup",tool:i.tool,input:i.input({query:o}),label:`Web — ${o}`,subject:o,note:r,fallback:c.length>0}),c}function nt(e=[]){const t=Array.isArray(e)?e:[];for(let n=t.length-1;n>=0;n--)if(t[n]?.role==="user")return(t[n].attachments||[]).some(s=>s?.kind==="prefetch"&&String(s.text||"").trim());return!1}function ze(e,t,{now:n=Date.now()}={}){if(e.kind==="web"&&e.weather&&(t=ee(t)||t),e.kind==="research"){const c=String(t||""),{question:u,domain:i,subject:a,slots:d}=e.research||{};return{id:`prefetch_research_${n}`,kind:"prefetch",prefetch:"research",subject:e.subject||a||"",research:{question:u,domain:i,subject:a,slots:d},title:e.label,text:c,chars:c.length}}const s=e.kind==="page"?"this is the page they mean.":e.kind==="web"?`these are web results for "${String(e.subject||"").slice(0,80)}" — answer from them; search again only with different words.`:e.kind==="stock"?`do not call ${e.tool} or any search tool again for the same company. Say the price and change it gives; if it gives none, say you could not find a current price — never estimate one.`:e.kind==="lookup"?`if it is about someone or something else, or found nothing, search again with DIFFERENT words (another spelling, the other source — library or web) — never the same query.${e.note?` ${e.note}`:""}`:`do not call ${e.tool} or any weather/search tool again for the same place.`,o=e.kind==="lookup"||e.kind==="web"?`SEARCHED for "${e.subject}"`:e.kind==="page"?"READ the page the user has open":"FETCHED",r=e.kind==="page"&&e.ask?`
2
2
 
3
- ${String(t||"")}`;return{id:`prefetch_${e.kind}${e.kind==="lookup"?`_${e.input?.action||e.tool}`:""}_${n}`,kind:"prefetch",prefetch:e.kind,...e.subject?{subject:e.subject}:{},title:e.label,text:r,chars:r.length}}async function Le(e,{execute:t,until:n=null,now:o=()=>Date.now(),onActivity:s=()=>{},read:r=null,rerank:l=null}={}){const a=o(),h=u=>{try{s({type:"tool",name:"research",prefetched:!0,...u})}catch{}};h({phase:"start",input:e.input,summary:e.label});try{const{text:u,result:c}=await v(e,{execute:t,until:n,now:o,read:r,rerank:l,onProgress:d=>h({phase:"progress",summary:`${e.label} — ${d.label}`})});if(!u)return h({phase:"done",status:"skipped",summary:e.label,ms:o()-a}),{attachment:null,text:"",result:c,note:"",status:"skipped"};const i=c.stats,p=`${i.searches} search${i.searches===1?"":"es"} · ${i.sites} site${i.sites===1?"":"s"} · ${(i.ms/1e3).toFixed(1)} s`;return h({phase:"done",status:"ok",summary:`${e.label} — ${p}`,ms:o()-a}),{attachment:be(e,u,{now:o()}),text:u,result:c,note:p,status:"ok"}}catch(u){const c=`error: ${String(u?.message||u).slice(0,80)}`;return h({phase:"done",status:c,summary:e.label,ms:o()-a}),{attachment:null,text:"",result:null,note:"",status:c}}}export{D as correctedSubject,N as joinSpelled,le as lookupFollowup,ne as lookupSubject,we as newsAsk,be as prefetchAttachment,ye as prefetchMissed,Se as prefetchPlan,$e as previousAsk,Le as runResearchItem,C as stockFollowupSubject,R as stockSubject,_ as weatherFollowupPlace,S as weatherHere,b as weatherPlace};
3
+ The question about this page: ${e.ask.slice(0,200)}`:"",l=`(ALREADY ${o} for the question below, with ${e.tool}. Answer from this; ${s})
4
+
5
+ ${String(t||"")}${r}`;return{id:`prefetch_${e.kind}${e.kind==="lookup"?`_${e.input?.action||e.tool}`:""}_${n}`,kind:"prefetch",prefetch:e.kind,...e.subject?{subject:e.subject}:{},title:e.label,text:l,chars:l.length}}async function st(e,{execute:t,until:n=null,now:s=()=>Date.now(),onActivity:o=()=>{},read:r=null,rerank:l=null}={}){const c=s(),u=i=>{try{o({type:"tool",name:"research",prefetched:!0,...i})}catch{}};u({phase:"start",input:e.input,summary:e.label});try{const{text:i,result:a}=await V(e,{execute:t,until:n,now:s,read:r,rerank:l,onProgress:f=>u({phase:"progress",summary:`${e.label} — ${f.label}`})});if(!i)return u({phase:"done",status:"skipped",summary:e.label,ms:s()-c}),{attachment:null,text:"",result:a,note:"",status:"skipped"};const d=a.stats,k=`${d.searches} search${d.searches===1?"":"es"} · ${d.sites} site${d.sites===1?"":"s"} · ${(d.ms/1e3).toFixed(1)} s`;return u({phase:"done",status:"ok",summary:`${e.label} — ${k}`,ms:s()-c}),{attachment:ze(e,i,{now:s()}),text:i,result:a,note:k,status:"ok"}}catch(i){const a=`error: ${String(i?.message||i).slice(0,80)}`;return u({phase:"done",status:a,summary:e.label,ms:s()-c}),{attachment:null,text:"",result:null,note:"",status:a}}}export{be as aboutOwnPast,nt as answeredByPrefetch,U as correctedSubject,H as joinSpelled,Be as lookupFollowup,Te as lookupSubject,Ke as newsAsk,fe as offeredSearch,C as pageAsk,ze as prefetchAttachment,Ze as prefetchMissed,tt as prefetchPlan,et as previousAsk,ge as restatedWeather,st as runResearchItem,I as stockFollowupSubject,v as stockSubject,F as weatherFollowupPlace,z as weatherFollowupWhen,W as weatherHere,y as weatherPlace,ie as webRedoAsk};
@@ -1 +1 @@
1
- const t=[{id:"custom",name:"Custom / self-hosted",kind:"openai",baseUrl:"",authMode:"apiKey",custom:!0},{id:"openai",name:"OpenAI",kind:"openai",baseUrl:"https://api.openai.com/v1",authMode:"apiKey",keyUrl:"https://platform.openai.com/api-keys",docsUrl:"https://platform.openai.com/docs/api-reference"},{id:"anthropic",name:"Anthropic",kind:"anthropic",baseUrl:"https://api.anthropic.com",authMode:"apiKey",keyUrl:"https://console.anthropic.com/settings/keys",docsUrl:"https://docs.anthropic.com/en/api/overview"},{id:"openrouter",name:"OpenRouter",kind:"openai",baseUrl:"https://openrouter.ai/api/v1",authMode:"openrouter",keyUrl:"https://openrouter.ai/settings/keys",docsUrl:"https://openrouter.ai/docs/quickstart",defaultHeaders:{"HTTP-Referer":"https://chatpanel.net"},note:"ChatPanel adds HTTP-Referer so OpenRouter can attribute traffic. You can edit or remove it in Advanced request options."},{id:"huggingface-api-key",name:"Hugging Face Router",kind:"openai",baseUrl:"https://router.huggingface.co/v1",authMode:"apiKey",keyUrl:"https://huggingface.co/settings/tokens",docsUrl:"https://huggingface.co/docs/inference-providers/en/index",note:"Use API key with a fine-grained HF token that has Inference Providers permission, or switch Method to OAuth: Hugging Face and connect. A 401 HTML page usually means the wrong auth method or token."},{id:"gemini-api-key",name:"Google AI Studio · Gemini",kind:"openai",baseUrl:"https://generativelanguage.googleapis.com/v1beta/openai",authMode:"apiKey",keyUrl:"https://aistudio.google.com/apikey",docsUrl:"https://ai.google.dev/gemini-api/docs/openai"},{id:"nvidia",name:"NVIDIA NIM",kind:"openai",baseUrl:"https://integrate.api.nvidia.com/v1",authMode:"apiKey",keyUrl:"https://build.nvidia.com/settings/api-keys",docsUrl:"https://docs.nvidia.com/ai-workbench/user-guide/latest/how-to/integrations/nvidia-integrations.html#integration-endpoint",note:"NVIDIA endpoint API keys may require phone verification."},{id:"groq",name:"Groq",kind:"openai",baseUrl:"https://api.groq.com/openai/v1",authMode:"apiKey",keyUrl:"https://console.groq.com/keys",docsUrl:"https://console.groq.com/docs/openai"},{id:"vercel-ai-gateway",name:"Vercel AI Gateway",kind:"openai",baseUrl:"https://ai-gateway.vercel.sh/v1",authMode:"apiKey",signupUrl:"https://vercel.com/signup",docsUrl:"https://vercel.com/docs/ai-gateway",note:"Use a Vercel AI Gateway API key. Model IDs are provider-prefixed, for example anthropic/claude-sonnet-4.6."},{id:"opencode-zen",name:"OpenCode Zen",kind:"openai",baseUrl:"https://opencode.ai/zen/v1",authMode:"apiKey",signupUrl:"https://opencode.ai/zen",docsUrl:"https://opencode.ai/docs/zen/",note:"ChatPanel uses the OpenAI-compatible chat completions path. Use OpenCode Zen model IDs such as opencode/deepseek-v4-flash-free."},{id:"cohere",name:"Cohere",kind:"openai",baseUrl:"https://api.cohere.ai/compatibility/v1",authMode:"apiKey",keyUrl:"https://dashboard.cohere.com/api-keys",docsUrl:"https://docs.cohere.com/docs/compatibility-api"},{id:"together",name:"Together AI",kind:"openai",baseUrl:"https://api.together.ai/v1",authMode:"apiKey",keyUrl:"https://api.together.ai/settings/api-keys",docsUrl:"https://docs.together.ai/docs/openai-api-compatibility"},{id:"mistral",name:"Mistral · La Plateforme",kind:"openai",baseUrl:"https://api.mistral.ai/v1",authMode:"apiKey",keyUrl:"https://console.mistral.ai/api-keys",docsUrl:"https://docs.mistral.ai/api"},{id:"mistral-codestral",name:"Mistral · Codestral",kind:"openai",baseUrl:"https://api.mistral.ai/v1",authMode:"apiKey",keyUrl:"https://console.mistral.ai/api-keys",docsUrl:"https://docs.mistral.ai/api",note:"Codestral model IDs are available through the regular Mistral API."},{id:"xai",name:"xAI",kind:"openai",baseUrl:"https://api.x.ai/v1",authMode:"apiKey",keyUrl:"https://console.x.ai/team/default/api-keys",docsUrl:"https://docs.x.ai/docs/api-reference"},{id:"deepinfra",name:"DeepInfra",kind:"openai",baseUrl:"https://api.deepinfra.com/v1/openai",authMode:"apiKey",keyUrl:"https://deepinfra.com/dash/api_keys",docsUrl:"https://deepinfra.com/docs/openai_api",note:"Model listing may work without proving chat auth. If chat returns “Missing captcha token”, add a DeepInfra API key and click Test."},{id:"fireworks",name:"Fireworks AI",kind:"openai",baseUrl:"https://api.fireworks.ai/inference/v1",authMode:"apiKey",keyUrl:"https://fireworks.ai/account/api-keys",docsUrl:"https://docs.fireworks.ai/api-reference/introduction"},{id:"cerebras",name:"Cerebras",kind:"openai",baseUrl:"https://api.cerebras.ai/v1",authMode:"apiKey",keyUrl:"https://cloud.cerebras.ai",docsUrl:"https://inference-docs.cerebras.ai/resources/openai"},{id:"github-models",name:"GitHub Models",kind:"openai",baseUrl:"https://models.github.ai/inference",authMode:"apiKey",keyUrl:"https://github.com/settings/personal-access-tokens",docsUrl:"https://docs.github.com/en/rest/models/inference",defaultHeaders:{Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2026-03-10"},note:"Use a GitHub token with models:read. Model listing may differ from generic OpenAI-compatible /models endpoints."},{id:"cloudflare-workers-ai",name:"Cloudflare Workers AI",kind:"openai",baseUrl:"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1",authMode:"apiKey",keyUrl:"https://dash.cloudflare.com/profile/api-tokens",docsUrl:"https://developers.cloudflare.com/workers-ai/configuration/open-ai-compatibility/",note:"Replace {account_id} in Base URL with your Cloudflare account ID."},{id:"ollama",name:"Local · Ollama",kind:"openai",baseUrl:"http://localhost:11434/v1",authMode:"apiKey",docsUrl:"https://github.com/ollama/ollama/blob/main/docs/openai.md"},{id:"lmstudio",name:"Local · LM Studio",kind:"openai",baseUrl:"http://localhost:1234/v1",authMode:"apiKey",docsUrl:"https://lmstudio.ai/docs/app/api/endpoints/openai"},{id:"llamacpp",name:"Local · llama.cpp",kind:"openai",baseUrl:"http://localhost:8080/v1",authMode:"apiKey",docsUrl:"https://github.com/ggml-org/llama.cpp/tree/master/tools/server"},{id:"vllm",name:"Local · vLLM",kind:"openai",baseUrl:"http://localhost:8000/v1",authMode:"apiKey",docsUrl:"https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html"},{id:"webllm",name:"In-browser · WebLLM (WebGPU)",kind:"webllm",baseUrl:"",authMode:"apiKey",model:"Llama-3.2-1B-Instruct-q4f16_1-MLC",docsUrl:"https://llm.mlc.ai/docs/",note:"Runs 100% in your browser on WebGPU — no API key, no server, works offline after a one-time download. Pick any model from the catalog; bigger models give better answers."}],s=new Set(["ollama","lmstudio","llamacpp","vllm","webllm"]),p={custom:{mark:"+",color:"#64748b"},openai:{mark:"AI",color:"#10a37f"},anthropic:{mark:"A",color:"#d97757"},openrouter:{mark:"OR",color:"#6467f2"},"huggingface-api-key":{mark:"HF",color:"#ff9d00"},"gemini-api-key":{mark:"G",color:"#1a73e8"},nvidia:{mark:"N",color:"#76b900"},groq:{mark:"GQ",color:"#f55036"},"vercel-ai-gateway":{mark:"▲",color:"#111317"},"opencode-zen":{mark:"Z",color:"#3b82f6"},cohere:{mark:"C",color:"#ff7759"},together:{mark:"T",color:"#0f6fff"},mistral:{mark:"M",color:"#fa520f"},"mistral-codestral":{mark:"MC",color:"#fa520f"},xai:{mark:"X",color:"#111317"},deepinfra:{mark:"DI",color:"#4f46e5"},fireworks:{mark:"F",color:"#5019c5"},cerebras:{mark:"CB",color:"#ff6b35"},"github-models":{mark:"GH",color:"#2b3137"},"cloudflare-workers-ai":{mark:"CF",color:"#f6821f"},ollama:{mark:"OL",color:"#0b0d12"},lmstudio:{mark:"LM",color:"#2563eb"},llamacpp:{mark:"LC",color:"#6b7280"},vllm:{mark:"VL",color:"#0ea5e9"},webllm:{mark:"WL",color:"#7c3aed"}},d=new Set(["openai","anthropic","huggingface-api-key","gemini-api-key","nvidia","vercel-ai-gateway","mistral","mistral-codestral","xai","github-models","cloudflare-workers-ai","openrouter","groq","cohere","cerebras","ollama"]);function m(e){return{...p[e]||{mark:String(e||"?").replace(/[^a-z0-9]/gi,"").charAt(0).toUpperCase()||"?",color:"#64748b"},logo:d.has(e)?`assets/providers/${e}.svg`:null}}const n={claude:{mark:"CC",color:"#d97757",logo:"assets/providers/anthropic.svg"},codex:{mark:"CX",color:"#10a37f",logo:"assets/providers/openai.svg"},antigravity:{mark:"AG",color:"#1a73e8"},pi:{mark:"PI",color:"#8b5cf6"},opencode:{mark:"OC",color:"#0ea5e9"},kiro:{mark:"KI",color:"#a855f7"},copilot:{mark:"GH",color:"#24292f"},deepseek:{mark:"DS",color:"#4d6bfe"},custom:{mark:"BYO",color:"#64748b"}};function h(e){return{logo:null,...n[e]||n.custom}}function l(e){return String(e||"").trim().replace(/\/+$/,"")}function u(){const e=t.filter(r=>r.custom),o=t.filter(r=>s.has(r.id)),a=t.filter(r=>!r.custom&&!s.has(r.id)).sort((r,c)=>r.name.localeCompare(c.name));return[...e,...a,...o]}function i(e){return t.find(o=>o.id===e)||null}function k(e={}){if(e.providerPreset){const a=i(e.providerPreset);if(a&&!a.custom)return a}if(e.kind==="webllm")return i("webllm");const o=l(e.baseUrl);return o&&t.find(a=>!a.custom&&l(a.baseUrl)===o&&(!e.kind||a.kind===e.kind))||null}function g(e={}){const o=i(e.providerPreset);return!o||o.custom?{...e,providerPreset:"custom"}:{...e,providerPreset:o.id,name:o.name,kind:o.kind,baseUrl:o.baseUrl,authMode:o.authMode,...o.model&&!e.model?{model:o.model}:{},headers:{...o.defaultHeaders||{},...e.headers||{}}}}export{t as API_PROVIDER_PRESETS,h as agentBrand,g as applyProviderPreset,u as orderedProviderPresets,m as providerBrand,i as providerPresetById,k as providerPresetForEndpoint};
1
+ const r=[{id:"custom",name:"Custom / self-hosted",kind:"openai",baseUrl:"",authMode:"apiKey",custom:!0},{id:"openai",name:"OpenAI",kind:"openai",baseUrl:"https://api.openai.com/v1",authMode:"apiKey",keyUrl:"https://platform.openai.com/api-keys",docsUrl:"https://platform.openai.com/docs/api-reference"},{id:"anthropic",name:"Anthropic",kind:"anthropic",baseUrl:"https://api.anthropic.com",authMode:"apiKey",keyUrl:"https://console.anthropic.com/settings/keys",docsUrl:"https://docs.anthropic.com/en/api/overview"},{id:"openrouter",name:"OpenRouter",kind:"openai",baseUrl:"https://openrouter.ai/api/v1",authMode:"openrouter",keyUrl:"https://openrouter.ai/settings/keys",docsUrl:"https://openrouter.ai/docs/quickstart",defaultHeaders:{"HTTP-Referer":"https://chatpanel.net"},note:"Chap adds HTTP-Referer so OpenRouter can attribute traffic. You can edit or remove it in Advanced request options."},{id:"huggingface-api-key",name:"Hugging Face Router",kind:"openai",baseUrl:"https://router.huggingface.co/v1",authMode:"apiKey",keyUrl:"https://huggingface.co/settings/tokens",docsUrl:"https://huggingface.co/docs/inference-providers/en/index",note:"Use API key with a fine-grained HF token that has Inference Providers permission, or switch Method to OAuth: Hugging Face and connect. A 401 HTML page usually means the wrong auth method or token."},{id:"gemini-api-key",name:"Google AI Studio · Gemini",kind:"openai",baseUrl:"https://generativelanguage.googleapis.com/v1beta/openai",authMode:"apiKey",keyUrl:"https://aistudio.google.com/apikey",docsUrl:"https://ai.google.dev/gemini-api/docs/openai"},{id:"nvidia",name:"NVIDIA NIM",kind:"openai",baseUrl:"https://integrate.api.nvidia.com/v1",authMode:"apiKey",keyUrl:"https://build.nvidia.com/settings/api-keys",docsUrl:"https://docs.nvidia.com/ai-workbench/user-guide/latest/how-to/integrations/nvidia-integrations.html#integration-endpoint",note:"NVIDIA endpoint API keys may require phone verification."},{id:"groq",name:"Groq",kind:"openai",baseUrl:"https://api.groq.com/openai/v1",authMode:"apiKey",keyUrl:"https://console.groq.com/keys",docsUrl:"https://console.groq.com/docs/openai"},{id:"vercel-ai-gateway",name:"Vercel AI Gateway",kind:"openai",baseUrl:"https://ai-gateway.vercel.sh/v1",authMode:"apiKey",signupUrl:"https://vercel.com/signup",docsUrl:"https://vercel.com/docs/ai-gateway",note:"Use a Vercel AI Gateway API key. Model IDs are provider-prefixed, for example anthropic/claude-sonnet-4.6."},{id:"opencode-zen",name:"OpenCode Zen",kind:"openai",baseUrl:"https://opencode.ai/zen/v1",authMode:"apiKey",signupUrl:"https://opencode.ai/zen",docsUrl:"https://opencode.ai/docs/zen/",note:"Chap uses the OpenAI-compatible chat completions path. Use OpenCode Zen model IDs such as opencode/deepseek-v4-flash-free."},{id:"cohere",name:"Cohere",kind:"openai",baseUrl:"https://api.cohere.ai/compatibility/v1",authMode:"apiKey",keyUrl:"https://dashboard.cohere.com/api-keys",docsUrl:"https://docs.cohere.com/docs/compatibility-api"},{id:"together",name:"Together AI",kind:"openai",baseUrl:"https://api.together.ai/v1",authMode:"apiKey",keyUrl:"https://api.together.ai/settings/api-keys",docsUrl:"https://docs.together.ai/docs/openai-api-compatibility"},{id:"mistral",name:"Mistral · La Plateforme",kind:"openai",baseUrl:"https://api.mistral.ai/v1",authMode:"apiKey",keyUrl:"https://console.mistral.ai/api-keys",docsUrl:"https://docs.mistral.ai/api"},{id:"mistral-codestral",name:"Mistral · Codestral",kind:"openai",baseUrl:"https://api.mistral.ai/v1",authMode:"apiKey",keyUrl:"https://console.mistral.ai/api-keys",docsUrl:"https://docs.mistral.ai/api",note:"Codestral model IDs are available through the regular Mistral API."},{id:"xai",name:"xAI",kind:"openai",baseUrl:"https://api.x.ai/v1",authMode:"apiKey",keyUrl:"https://console.x.ai/team/default/api-keys",docsUrl:"https://docs.x.ai/docs/api-reference"},{id:"deepinfra",name:"DeepInfra",kind:"openai",baseUrl:"https://api.deepinfra.com/v1/openai",authMode:"apiKey",keyUrl:"https://deepinfra.com/dash/api_keys",docsUrl:"https://deepinfra.com/docs/openai_api",note:"Model listing may work without proving chat auth. If chat returns “Missing captcha token”, add a DeepInfra API key and click Test."},{id:"fireworks",name:"Fireworks AI",kind:"openai",baseUrl:"https://api.fireworks.ai/inference/v1",authMode:"apiKey",keyUrl:"https://fireworks.ai/account/api-keys",docsUrl:"https://docs.fireworks.ai/api-reference/introduction"},{id:"cerebras",name:"Cerebras",kind:"openai",baseUrl:"https://api.cerebras.ai/v1",authMode:"apiKey",keyUrl:"https://cloud.cerebras.ai",docsUrl:"https://inference-docs.cerebras.ai/resources/openai"},{id:"github-models",name:"GitHub Models",kind:"openai",baseUrl:"https://models.github.ai/inference",authMode:"apiKey",keyUrl:"https://github.com/settings/personal-access-tokens",docsUrl:"https://docs.github.com/en/rest/models/inference",defaultHeaders:{Accept:"application/vnd.github+json","X-GitHub-Api-Version":"2026-03-10"},note:"Use a GitHub token with models:read. Model listing may differ from generic OpenAI-compatible /models endpoints."},{id:"cloudflare-workers-ai",name:"Cloudflare Workers AI",kind:"openai",baseUrl:"https://api.cloudflare.com/client/v4/accounts/{account_id}/ai/v1",authMode:"apiKey",keyUrl:"https://dash.cloudflare.com/profile/api-tokens",docsUrl:"https://developers.cloudflare.com/workers-ai/configuration/open-ai-compatibility/",note:"Replace {account_id} in Base URL with your Cloudflare account ID."},{id:"ollama",name:"Local · Ollama",kind:"openai",baseUrl:"http://localhost:11434/v1",authMode:"apiKey",docsUrl:"https://github.com/ollama/ollama/blob/main/docs/openai.md"},{id:"lmstudio",name:"Local · LM Studio",kind:"openai",baseUrl:"http://localhost:1234/v1",authMode:"apiKey",docsUrl:"https://lmstudio.ai/docs/app/api/endpoints/openai"},{id:"llamacpp",name:"Local · llama.cpp",kind:"openai",baseUrl:"http://localhost:8080/v1",authMode:"apiKey",docsUrl:"https://github.com/ggml-org/llama.cpp/tree/master/tools/server"},{id:"vllm",name:"Local · vLLM",kind:"openai",baseUrl:"http://localhost:8000/v1",authMode:"apiKey",docsUrl:"https://docs.vllm.ai/en/latest/serving/openai_compatible_server.html"},{id:"apple",name:"Local · Apple on-device (Mac)",kind:"openai",baseUrl:"http://127.0.0.1:8895/v1",authMode:"apiKey",model:"apple-on-device",window:4096,docsUrl:"https://developer.apple.com/documentation/foundationmodels",note:"Apple Intelligence on this Mac: macOS 26 on Apple Silicon, with Apple Intelligence turned on. Start it first in Settings › Runtime › Apple on-device — the gateway runs it. No key. Text only; 4,096 tokens at a time, and a longer chat is trimmed to fit."},{id:"webllm",name:"In-browser · WebLLM (WebGPU)",kind:"webllm",baseUrl:"",authMode:"apiKey",model:"Llama-3.2-1B-Instruct-q4f16_1-MLC",docsUrl:"https://llm.mlc.ai/docs/",note:"Runs 100% in your browser on WebGPU — no API key, no server, works offline after a one-time download. Pick any model from the catalog; bigger models give better answers."}],s=new Set(["ollama","lmstudio","llamacpp","vllm","apple","webllm"]),p={custom:{mark:"+",color:"#64748b"},openai:{mark:"AI",color:"#10a37f"},anthropic:{mark:"A",color:"#d97757"},openrouter:{mark:"OR",color:"#6467f2"},"huggingface-api-key":{mark:"HF",color:"#ff9d00"},"gemini-api-key":{mark:"G",color:"#1a73e8"},nvidia:{mark:"N",color:"#76b900"},groq:{mark:"GQ",color:"#f55036"},"vercel-ai-gateway":{mark:"▲",color:"#111317"},"opencode-zen":{mark:"Z",color:"#3b82f6"},cohere:{mark:"C",color:"#ff7759"},together:{mark:"T",color:"#0f6fff"},mistral:{mark:"M",color:"#fa520f"},"mistral-codestral":{mark:"MC",color:"#fa520f"},xai:{mark:"X",color:"#111317"},deepinfra:{mark:"DI",color:"#4f46e5"},fireworks:{mark:"F",color:"#5019c5"},cerebras:{mark:"CB",color:"#ff6b35"},"github-models":{mark:"GH",color:"#2b3137"},"cloudflare-workers-ai":{mark:"CF",color:"#f6821f"},ollama:{mark:"OL",color:"#0b0d12"},lmstudio:{mark:"LM",color:"#2563eb"},llamacpp:{mark:"LC",color:"#6b7280"},vllm:{mark:"VL",color:"#0ea5e9"},apple:{mark:"Ap",color:"#1d1d1f"},webllm:{mark:"WL",color:"#7c3aed"}},d=new Set(["openai","anthropic","huggingface-api-key","gemini-api-key","nvidia","vercel-ai-gateway","mistral","mistral-codestral","xai","github-models","cloudflare-workers-ai","openrouter","groq","cohere","cerebras","ollama"]);function u(e){return{...p[e]||{mark:String(e||"?").replace(/[^a-z0-9]/gi,"").charAt(0).toUpperCase()||"?",color:"#64748b"},logo:d.has(e)?`assets/providers/${e}.svg`:null}}const n={claude:{mark:"CC",color:"#d97757",logo:"assets/providers/anthropic.svg"},codex:{mark:"CX",color:"#10a37f",logo:"assets/providers/openai.svg"},antigravity:{mark:"AG",color:"#1a73e8"},pi:{mark:"PI",color:"#8b5cf6"},opencode:{mark:"OC",color:"#0ea5e9"},kiro:{mark:"KI",color:"#a855f7"},copilot:{mark:"GH",color:"#24292f"},deepseek:{mark:"DS",color:"#4d6bfe"},custom:{mark:"BYO",color:"#64748b"}};function k(e){return{logo:null,...n[e]||n.custom}}function l(e){return String(e||"").trim().replace(/\/+$/,"")}function f(){const e=r.filter(t=>t.custom),o=r.filter(t=>s.has(t.id)),a=r.filter(t=>!t.custom&&!s.has(t.id)).sort((t,c)=>t.name.localeCompare(c.name));return[...e,...a,...o]}function i(e){return r.find(o=>o.id===e)||null}function m(e={}){if(e.providerPreset){const a=i(e.providerPreset);if(a&&!a.custom)return a}if(e.kind==="webllm")return i("webllm");const o=l(e.baseUrl);return o&&r.find(a=>!a.custom&&l(a.baseUrl)===o&&(!e.kind||a.kind===e.kind))||null}function g(e){if(!e||typeof e!="object")return e;const o=m(e);if(!o)return e;const a={};return o.window&&!(Number(e.window||e.contextLength||e.contextWindow)>0)&&(a.window=o.window),o.toolCalls&&e.toolCalls===void 0&&(a.toolCalls=o.toolCalls),Object.keys(a).length?{...e,...a}:e}function b(e={}){const o=i(e.providerPreset);return!o||o.custom?{...e,providerPreset:"custom"}:{...e,providerPreset:o.id,name:o.name,kind:o.kind,baseUrl:o.baseUrl,authMode:o.authMode,...o.model&&!e.model?{model:o.model}:{},headers:{...o.defaultHeaders||{},...e.headers||{}}}}const h=Object.freeze({8891:"vLLM",8892:"vLLM (Metal, Apple Silicon)",8893:"llama.cpp",8894:"MLX",8895:"Apple on-device"});function y(e){let o;try{o=new URL(String(e||""))}catch{return null}if(!/^(?:127\.0\.0\.1|localhost|\[::1\])$/i.test(o.hostname))return null;const a=h[Number(o.port)];return a?{port:Number(o.port),label:a}:null}export{r as API_PROVIDER_PRESETS,h as RUNTIME_CHAT_PORTS,k as agentBrand,b as applyProviderPreset,f as orderedProviderPresets,g as presetFacts,u as providerBrand,i as providerPresetById,m as providerPresetForEndpoint,y as runtimeServiceAt};