@chatpanel/events 0.111.0 → 0.111.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,16 +1,20 @@
1
- import{makeSourceStore as h,manifestText as l,readSource as d,approxTokens as p}from"./sources-retrieval.js";function g(t){const e=String(t||"").trim();return e?`<presence>
2
- ${e}
3
- </presence>`:""}function f(t){let e=t.content||"";const i=(t.attachments||[]).filter(s=>s.kind!=="image");if(i.length){const s=i.map(n=>{const a=`[${n.kind||"context"}] ${n.title||n.url||""}`.trim();return`<context source="${(n.url||n.title||"").replace(/"/g,"")}">
4
- # ${a}
5
- ${n.text||""}
6
- </context>`}).join(`
1
+ import{makeSourceStore as h,manifestText as l,readSource as d,approxTokens as p}from"./sources-retrieval.js";function g(n){const t=String(n||"").trim();return t?`<presence>
2
+ ${t}
3
+ </presence>`:""}function f(n){let t=n.content||"";const i=(n.attachments||[]).filter(e=>e.kind!=="image"),o=i.filter(e=>e.kind==="prefetch"),c=i.filter(e=>e.kind!=="prefetch"),s=e=>{const r=`[${e.kind||"context"}] ${e.title||e.url||""}`.trim();return`<context source="${(e.url||e.title||"").replace(/"/g,"")}">
4
+ # ${r}
5
+ ${e.text||""}
6
+ </context>`};if(o.length&&(t=`${o.map(s).join(`
7
7
 
8
- `);e=e?`${e}
8
+ `)}
9
9
 
10
- ${s}`:s}const r=g(t.presence);return r&&(e=e?`${e}
10
+ ${t}`.trim()),c.length){const e=c.map(s).join(`
11
11
 
12
- ${r}`:r),e}function k(t){return t.filter(e=>e.role==="user"||e.role==="assistant").map(e=>({role:e.role,content:f(e)}))}function m(t){return(t.attachments||[]).filter(e=>e.kind==="image"&&e.dataUrl)}function $(t,e){return t.filter(i=>i.role==="user"||i.role==="assistant").map(i=>{const r=f(i),s=i.role==="user"?m(i):[];if(s.length===0)return{role:i.role,content:r};if(e==="anthropic"){const a=[];for(const c of s){const o=/^data:([^;]+);base64,(.+)$/s.exec(c.dataUrl);o&&a.push({type:"image",source:{type:"base64",media_type:o[1],data:o[2]}})}return r&&a.push({type:"text",text:r}),{role:"user",content:a.length?a:r}}const n=[];r&&n.push({type:"text",text:r});for(const a of s)n.push({type:"image_url",image_url:{url:a.dataUrl}});return{role:"user",content:n.length?n:r}})}function S(t,e,{minTokens:i=700}={}){if(!e?.specs?.length)return null;const r=[];for(const c of t||[])for(const o of c?.attachments||[])o?.kind==="image"||!o?.text||o.kind!=="prefetch"&&r.push(o);if(!r.length)return null;const s=h(r.map(c=>({kind:c.kind||"context",title:c.title,url:c.url,text:c.text})));if(s.tokens<i)return null;const n=new Map(r.map((c,o)=>[c,s.entries[o]?.id]));return{messages:(t||[]).map(c=>c?.attachments?.some(o=>n.get(o))?{...c,attachments:c.attachments.map(o=>{const u=n.get(o);return u?{...o,text:`(not included — read with \`source\`: id ${u}, ~${p(o.text)} tokens)`}:o})}:c),store:s}}const x={name:"source",description:"Read an attached source (a page, tab, selection or file the user attached). Their content is NOT in the conversation — read what you need from here.",parameters:{type:"object",properties:{id:{type:"string",description:"The source id from the manifest, e.g. page-1."},query:{type:"string",description:"What you are looking for. A large source returns the matching sections rather than its first page."}},required:["id"]}};function T(t,e){const i={...x},r=[t?.system,`${l(e)}
12
+ `);t=t?`${t}
13
+
14
+ ${e}`:e}const a=g(n.presence);return a&&(t=t?`${t}
15
+
16
+ ${a}`:a),t}function k(n){return n.filter(t=>t.role==="user"||t.role==="assistant").map(t=>({role:t.role,content:f(t)}))}function m(n){return(n.attachments||[]).filter(t=>t.kind==="image"&&t.dataUrl)}function $(n,t){return n.filter(i=>i.role==="user"||i.role==="assistant").map(i=>{const o=f(i),c=i.role==="user"?m(i):[];if(c.length===0)return{role:i.role,content:o};if(t==="anthropic"){const a=[];for(const e of c){const r=/^data:([^;]+);base64,(.+)$/s.exec(e.dataUrl);r&&a.push({type:"image",source:{type:"base64",media_type:r[1],data:r[2]}})}return o&&a.push({type:"text",text:o}),{role:"user",content:a.length?a:o}}const s=[];o&&s.push({type:"text",text:o});for(const a of c)s.push({type:"image_url",image_url:{url:a.dataUrl}});return{role:"user",content:s.length?s:o}})}function S(n,t,{minTokens:i=700}={}){if(!t?.specs?.length)return null;const o=[];for(const e of n||[])for(const r of e?.attachments||[])r?.kind==="image"||!r?.text||r.kind!=="prefetch"&&o.push(r);if(!o.length)return null;const c=h(o.map(e=>({kind:e.kind||"context",title:e.title,url:e.url,text:e.text})));if(c.tokens<i)return null;const s=new Map(o.map((e,r)=>[e,c.entries[r]?.id]));return{messages:(n||[]).map(e=>e?.attachments?.some(r=>s.get(r))?{...e,attachments:e.attachments.map(r=>{const u=s.get(r);return u?{...r,text:`(not included — read with \`source\`: id ${u}, ~${p(r.text)} tokens)`}:r})}:e),store:c}}const x={name:"source",description:"Read an attached source (a page, tab, selection or file the user attached). Their content is NOT in the conversation — read what you need from here.",parameters:{type:"object",properties:{id:{type:"string",description:"The source id from the manifest, e.g. page-1."},query:{type:"string",description:"What you are looking for. A large source returns the matching sections rather than its first page."}},required:["id"]}};function T(n,t){const i={...x},o=[n?.system,`${l(t)}
13
17
 
14
18
  Their content is NOT in this conversation. Call \`source\` with an id — and a query when the source is large — to read what you need.`].filter(Boolean).join(`
15
19
 
16
- `);return{...t,specs:[...t?.specs||[],i],system:r,systemParts:{...t?.systemParts||{},source:p(l(e))},execute:async(s,n,a)=>s==="source"?JSON.stringify(d(e,typeof n=="string"?JSON.parse(n||"{}"):n||{})):t.execute(s,n,a)}}export{x as SOURCE_TOOL_SPEC,S as deferAttachedSources,m as imageAttachmentsOf,g as presenceBlock,f as renderContent,k as toChatMessages,$ as toMultimodalMessages,T as withSourceTool};
20
+ `);return{...n,specs:[...n?.specs||[],i],system:o,systemParts:{...n?.systemParts||{},source:p(l(t))},execute:async(c,s,a)=>c==="source"?JSON.stringify(d(t,typeof s=="string"?JSON.parse(s||"{}"):s||{})):n.execute(c,s,a)}}export{x as SOURCE_TOOL_SPEC,S as deferAttachedSources,m as imageAttachmentsOf,g as presenceBlock,f as renderContent,k as toChatMessages,$ as toMultimodalMessages,T as withSourceTool};
package/find-tool.js CHANGED
@@ -1 +1 @@
1
- import{makeDispatchProvider as n}from"./tool-dispatch.js";const a="find",r='Search and read the user\'s own saved data (past chats, notes, meetings) and the web. Pass an `action` and put that action\'s own arguments inside `args`, e.g. {"action":"history_search","args":{"query":"pricing"}}. Unsure of an action\'s arguments? {"action":"describe","args":{"tool":"<action>"}} returns its full schema. Use this when the answer plausibly depends on something the user already has; do not call it for greetings or general knowledge.',o="You HAVE access to the user's own ChatPanel data — past chats, notes, meeting transcripts and summaries — through `find`, plus the web. For anything they discussed or wrote, call `find` FIRST and answer from it; never say you cannot access their meetings, notes or history. For anything current — weather, prices, news — use `find` (actions `weather`, `web_search`), not a search tool of your own; the user sees `find` calls as steps.";function c(e,{all:s=null,rank:t=void 0}={}){return n({name:a,description:r,resident:o,inner:e,remote:!1,all:s,rank:t})}export{r as FIND_DESCRIPTION,o as FIND_RESIDENT,a as FIND_TOOL_NAME,c as findDispatchProvider};
1
+ import{makeDispatchProvider as a}from"./tool-dispatch.js";const n="find",r='Search and read the user\'s own saved data (past chats, notes, meetings) and the web. Pass an `action` and put that action\'s own arguments inside `args`, e.g. {"action":"history_search","args":{"query":"pricing"}}. Unsure of an action\'s arguments? {"action":"describe","args":{"tool":"<action>"}} returns its full schema. Use this when the answer plausibly depends on something the user already has; do not call it for greetings or general knowledge.',o="You HAVE access to the user's own ChatPanel data — past chats, notes, meeting transcripts and summaries — through `find`, plus the web. For anything they discussed or wrote, call `find` FIRST and answer from it; never say you cannot access their meetings, notes or history. For anything current — weather, prices, news — use `find` (actions `weather`, `web_search`), not a search tool of your own; the user sees `find` calls as steps. A [prefetch] block in the message IS that call, already made: answer from it, no call.";function c(e,{all:s=null,rank:t=void 0}={}){return a({name:n,description:r,resident:o,inner:e,remote:!1,all:s,rank:t})}export{r as FIND_DESCRIPTION,o as FIND_RESIDENT,n as FIND_TOOL_NAME,c as findDispatchProvider};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chatpanel/events",
3
- "version": "0.111.0",
3
+ "version": "0.111.1",
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",
package/prefetch.js CHANGED
@@ -1,3 +1,3 @@
1
- const w=/(\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,u=/\b(right now|now|today|tonight|this (?:morning|afternoon|evening|weekend|week)|tomorrow|currently|at the moment|these days|later)\b/gi,f=new Set(["here","there","home","outside","my location","my area","my city","where i am","it","that"]),p=8;function o(n){return String(n||"").replace(u," ").replace(/[?!.,;:]+$/g,"").replace(/^\s*(the|in|at|for|around|near|of)\s+/i,"").replace(/\s+/g," ").trim()}const d=/\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 i(n){const e=n.toLowerCase();return e.length>=2&&e.length<=60&&!f.has(e)&&!d.test(e)&&!/^(weather|forecast|temperature)$/.test(e)&&/[\p{L}]/u.test(e)&&e.split(/\s+/).length<=5}function b(n){const e=String(n||"").trim();if(!w.test(e))return"";let t=/\b(?:in|at|for|around|near)\s+([^?!.;]+?)(?:\s+(?:right now|now|today|tonight|tomorrow|currently|this \w+))*\s*[?!.]*$/i.exec(e);return t&&i(o(t[1]))||(t=/^(?:what(?:'s| is) the\s+)?([\p{L}][\p{L}\s,.'-]{1,60}?)\s+(?:weather|forecast|temperature)\b/iu.exec(e),t&&i(o(t[1])))||(t=/\b(?:weather|forecast|temperature)\s*[:\-]?\s+([\p{L}][\p{L}\s,.'-]{1,60}?)\s*[?!.]*$/iu.exec(e),t&&i(o(t[1])))?o(t[1]):""}const m=/\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)\b/i,c=/^(?:(?:and|also|ok|okay|now|then|so)[\s,]*)*(?:what about|how about|how(?:'s| is|s) it(?: like)?|what(?:'s| is|s) it(?: like)?|how(?:'s| is|s)|what(?:'s| is|s))\b[\s,]*/i;function g(n,e){if(!e||e.kind!=="weather")return"";let t=String(n||"").trim().replace(/[?!.]+$/,"").trim();if(!t||t.split(/\s+/).length>p)return"";const a=c.test(t)||/^(?:and|also|ok|okay|now|then|so)[\s,]+(?:in|at|for|around|near)\s+/i.test(t)||/^(?:in|at|for|around|near)\s+/i.test(t);t=t.replace(c,"").replace(/^(?:(?:and|also|ok|okay|now|then|so)[\s,]*)*/i,"").replace(/^(?:like\s+)?(?:in|at|for|around|near)\s+/i,"").trim();const r=o(t);return!r||!a&&r.split(/\s+/).length>2||!i(r)||m.test(r)?"":r}function y({text:n="",previous:e=null,reach:t=new Set}={}){const a=t instanceof Set?t:new Set(Array.isArray(t)?t:[]),r=[],h=a.has("find:weather"),l=a.has("weather");if(h||l){const s=b(n)||g(n,e);s&&r.push({kind:"weather",tool:h?"find":"weather",input:h?{action:"weather",args:{location:s}}:{location:s},label:`Weather — ${s}`})}return r}function k(n,e,{now:t=Date.now()}={}){const a=`(Fetched before this turn with ${n.tool}, for this question. Answer from it; do not call ${n.tool} again for the same place.)
1
+ const w=/(\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,u=/\b(right now|now|today|tonight|this (?:morning|afternoon|evening|weekend|week)|tomorrow|currently|at the moment|these days|later)\b/gi,f=new Set(["here","there","home","outside","my location","my area","my city","where i am","it","that"]),p=8;function o(n){return String(n||"").replace(u," ").replace(/[?!.,;:]+$/g,"").replace(/^\s*(the|in|at|for|around|near|of)\s+/i,"").replace(/\s+/g," ").trim()}const d=/\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 i(n){const t=n.toLowerCase();return t.length>=2&&t.length<=60&&!f.has(t)&&!d.test(t)&&!/^(weather|forecast|temperature)$/.test(t)&&/[\p{L}]/u.test(t)&&t.split(/\s+/).length<=5}function b(n){const t=String(n||"").trim();if(!w.test(t))return"";let e=/\b(?:in|at|for|around|near)\s+([^?!.;]+?)(?:\s+(?:right now|now|today|tonight|tomorrow|currently|this \w+))*\s*[?!.]*$/i.exec(t);return e&&i(o(e[1]))||(e=/^(?:what(?:'s| is) the\s+)?([\p{L}][\p{L}\s,.'-]{1,60}?)\s+(?:weather|forecast|temperature)\b/iu.exec(t),e&&i(o(e[1])))||(e=/\b(?:weather|forecast|temperature)\s*[:\-]?\s+([\p{L}][\p{L}\s,.'-]{1,60}?)\s*[?!.]*$/iu.exec(t),e&&i(o(e[1])))?o(e[1]):""}const m=/\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)\b/i,l=/^(?:(?:and|also|ok|okay|now|then|so)[\s,]*)*(?:what about|how about|how(?:'s| is|s) it(?: like)?|what(?:'s| is|s) it(?: like)?|how(?:'s| is|s)|what(?:'s| is|s))\b[\s,]*/i;function g(n,t){if(!t||t.kind!=="weather")return"";let e=String(n||"").trim().replace(/[?!.]+$/,"").trim();if(!e||e.split(/\s+/).length>p)return"";const a=l.test(e)||/^(?:and|also|ok|okay|now|then|so)[\s,]+(?:in|at|for|around|near)\s+/i.test(e)||/^(?:in|at|for|around|near)\s+/i.test(e);e=e.replace(l,"").replace(/^(?:(?:and|also|ok|okay|now|then|so)[\s,]*)*/i,"").replace(/^(?:like\s+)?(?:in|at|for|around|near)\s+/i,"").trim();const r=o(e);return!r||!a&&r.split(/\s+/).length>2||!i(r)||m.test(r)?"":r}function y({text:n="",previous:t=null,reach:e=new Set}={}){const a=e instanceof Set?e:new Set(Array.isArray(e)?e:[]),r=[],h=a.has("find:weather"),c=a.has("weather");if(h||c){const s=b(n)||g(n,t);s&&r.push({kind:"weather",tool:h?"find":"weather",input:h?{action:"weather",args:{location:s}}:{location:s},label:`Weather — ${s}`})}return r}function k(n,t,{now:e=Date.now()}={}){const a=`(ALREADY FETCHED for the question below, with ${n.tool}. Answer from this; do not call ${n.tool} or any weather/search tool again for the same place.)
2
2
 
3
- ${String(e||"")}`;return{id:`prefetch_${n.kind}_${t}`,kind:"prefetch",prefetch:n.kind,title:n.label,text:a,chars:a.length}}export{k as prefetchAttachment,y as prefetchPlan,g as weatherFollowupPlace,b as weatherPlace};
3
+ ${String(t||"")}`;return{id:`prefetch_${n.kind}_${e}`,kind:"prefetch",prefetch:n.kind,title:n.label,text:a,chars:a.length}}export{k as prefetchAttachment,y as prefetchPlan,g as weatherFollowupPlace,b as weatherPlace};