@chatpanel/events 0.114.0 → 0.115.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/find-tool.js +1 -1
- package/package.json +1 -1
- package/presence.js +3 -3
- package/tool-need.js +3 -3
package/find-tool.js
CHANGED
|
@@ -1 +1 @@
|
|
|
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:
|
|
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. A search returns excerpts, not the record: before reporting details (action items, decisions, who said what) read the full record by its id — each result names the action.";function c(e,{all:t=null,rank:s=void 0}={}){return a({name:n,description:r,resident:o,inner:e,remote:!1,all:t,rank:s})}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.
|
|
3
|
+
"version": "0.115.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",
|
package/presence.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{approxTokens as g}from"./sources-retrieval.js";const w=350,O=60,u=6;function
|
|
2
|
-
`);return{text:c,lines:a.map(({kind:l,text:h,tokens:
|
|
3
|
-
`),M=new Set(k.map(s=>s.kind));for(const s of h)!M.has(s.kind)&&r[s.kind]!=null&&(y[s.kind]=r[s.kind]);return{text:b,lines:k.map(({kind:s,text:f,tokens:$})=>({kind:s,text:f,tokens:$})),omitted:c,tokens:g(b),state:y,unchanged:!1}}function
|
|
1
|
+
import{approxTokens as g}from"./sources-retrieval.js";const w=350,O=60,u=6;function q(e,t=[]){const n=new Set;for(const i of e?.specs||[]){const o=i?.name||i?.function?.name;if(!o)continue;n.add(o);const a=(i.parameters||i.function?.parameters||i.input_schema||null)?.properties?.action?.enum;if(Array.isArray(a))for(const c of a)typeof c=="string"&&n.add(`${o}:${c}`)}for(const i of t||[])i&&n.add(String(i));return n}function m(e,t=O){const n=String(e||"").replace(/\s+/g," ").trim();return n.length>t?n.slice(0,t-1).trimEnd()+"…":n}function d(e){const t=Math.max(0,Math.floor(Number(e)||0));return t<20?String(t):`${Math.floor(t/10)*10}+`}function T(e){const t=Math.max(0,Math.floor((Number(e)||0)/6e4));return t<10?`${t} min`:`~${Math.floor(t/5)*5} min`}function D(e){const t=Math.max(0,Math.floor((Number(e)||0)/6e4));return t<1?"just now":t<10?`${t} min ago`:`~${Math.floor(t/5)*5} min ago`}function A(e){try{return new URL(e).hostname.replace(/^www\./,"")}catch{return""}}function x(e){const t=new Date(Number(e)||0);return Number.isFinite(t.getTime())&&t.getTime()>0?t.toISOString().slice(0,10):""}const _=[{kind:"meeting",priority:1,via:["find:meeting_live_transcript","meeting_live_transcript"],applies:e=>!!e.meeting,key:e=>`${e.meeting.id||""}|${m(e.meeting.title)}|${e.meeting.platform||""}`,render:(e,t)=>{const n=e.meeting,i=[];return n.platform&&i.push(String(n.platform)),n.startedAt&&i.push(`${T(t-n.startedAt)} in`),Number(n.segments)>0&&i.push(`${d(n.segments)} captions`),n.lastCaptionAt&&i.push(`last ${D(t-n.lastCaptionAt)}`),n.hasSummary&&i.push("running summary kept"),`Live meeting: "${m(n.title||"Meeting")}"${i.length?` (${i.join(", ")})`:""} — read with find {"action":"meeting_live_transcript"} (args.sinceMinutes for the recent part). Not included here.`}},{kind:"page",priority:2,via:["page:read_page","read_page"],applies:e=>!!e.page&&(e.page.title||e.page.url),key:e=>`${A(e.page.url)}|${m(e.page.title)}`,render:e=>{const t=e.page,n=A(t.url);return`Active tab: "${m(t.title||n||"page")}"${n?` (${n})`:""} — read with page {"action":"read_page"} (args.query on a long page). Not included here. A question about something this conversation has not mentioned ("it", "this", a name, a headline) is most likely about this tab: read it before searching history or the web.`}},{kind:"fetched",priority:3,via:["source"],applies:e=>Array.isArray(e.fetched)&&e.fetched.length>0,key:e=>e.fetched.map(t=>t.id).join(","),render:e=>`Already fetched in this conversation: ${e.fetched.slice(0,u).map(n=>`${n.id} ${m(n.title,40)} (${n.agoText||"earlier"})`).join("; ")} — read one with source {"id":"<id>"} (args.query for a part); do not fetch the same thing again.`},{kind:"sidelines",priority:3,via:["find:history_search","find","history_search"],applies:e=>Array.isArray(e.sidelines)&&e.sidelines.length>0,key:e=>e.sidelines.map(t=>`${t.index}:${t.folded?"f":"o"}`).join(","),render:e=>{const t=e.sidelines.slice(0,u).map(i=>{const o=i.folded?"folded back":"open";return`#${i.index||"?"} "${m(i.title||"sideline",40)}" (${o})`}),n=e.sidelines.length>u?`, +${e.sidelines.length-u} more`:"";return`Sidelines of this thread: ${t.join("; ")}${n} — a sideline is a chat; find {"action":"history_search"} reads one.`}},{kind:"teams",priority:4,via:["team"],applies:e=>Array.isArray(e.teams)&&e.teams.length>0,key:e=>e.teams.map(t=>typeof t=="string"?t:t?.name).filter(Boolean).join(","),render:e=>{const t=e.teams.map(o=>typeof o=="string"?o:o?.name).filter(Boolean),n=t.slice(0,u).join(", "),i=t.length>u?`, +${t.length-u} more`:"";return`Teams & agents you can run: ${n}${i} — team {"action":"run","name":…}; {"action":"describe"} for how.`}},{kind:"notes",priority:5,via:["find:history_search","find","history_search"],applies:e=>e.notes&&Number(e.notes.count)>0,key:e=>d(e.notes.count),render:e=>{const t=(e.notes.recent||[]).slice(0,3).map(n=>`"${m(typeof n=="string"?n:n?.title,40)}"`).filter(n=>n!=='""');return`Notes: ${d(e.notes.count)}${t.length?` (recent: ${t.join(", ")})`:""} — find {"action":"history_search","args":{"query":…}} searches them.`}},{kind:"meetings",priority:6,via:["find:history_list_meetings","history_list_meetings"],applies:e=>e.meetings&&Number(e.meetings.count)>0,key:e=>`${d(e.meetings.count)}|${m(e.meetings.latest?.title,40)}`,render:e=>{const t=e.meetings.latest,n=t?` (latest: "${m(t.title,40)}"${x(t.date)?` ${x(t.date)}`:""})`:"";return`Past meetings: ${d(e.meetings.count)}${n} — find {"action":"history_list_meetings"}.`}},{kind:"skills",priority:7,via:["skill_open"],applies:e=>e.skills&&Number(e.skills.count)>0,key:e=>d(e.skills.count),render:e=>{const t=(e.skills.top||[]).slice(0,3).map(n=>typeof n=="string"?n:n?.name).filter(Boolean);return`Skills: ${d(e.skills.count)}${t.length?` (e.g. ${t.join(", ")})`:""} — skill_open {"name":…} loads one.`}},{kind:"memory",priority:8,via:["memory"],applies:e=>e.memory&&Number(e.memory.count)>0,key:e=>d(e.memory.count),render:e=>`Memory: ${d(e.memory.count)} durable facts about the user — memory {"action":"list"}.`},{kind:"chats",priority:9,via:["find:history_search","find","history_search"],applies:e=>e.chats&&Number(e.chats.count)>0,key:e=>d(e.chats.count),render:e=>`Past chats: ${d(e.chats.count)} — find {"action":"history_search","args":{"scope":"chats"}}.`}],K=Object.freeze(_.map(e=>e.kind)),S="Around this turn (NOT included — read what the question needs, one call):",v="Changed since your last turn:",B={meeting:"Live meeting ended — the transcript is now in past meetings.",page:"Active tab: none readable now.",sidelines:"Sidelines of this thread: none open now."};function N(e,t,n){const i=[],o=[];for(const r of _){if(!r.applies(e))continue;if(!r.via.some(c=>t.has(c))){o.push({kind:r.kind,why:"no reader armed"});continue}const a=`- ${r.render(e,n)}`;i.push({kind:r.kind,priority:r.priority,text:a,key:r.key(e),tokens:g(a)})}return{lines:i,omitted:o}}function E(e,t,n,i){let o=g(e)+t.reduce((a,c)=>a+c.tokens+1,0);const r=[...t];for(;o>n&&r.length>1;){let a=0;for(let l=1;l<r.length;l++)r[l].priority>r[a].priority&&(a=l);const[c]=r.splice(a,1);i.push({kind:c.kind,why:"over budget"}),o-=c.tokens+1}return r}const j=e=>e instanceof Set?e:new Set(Array.isArray(e)?e:[]);function C({facts:e={},reach:t=new Set,budget:n=w,now:i=Date.now()}={}){const{lines:o,omitted:r}=N(e||{},j(t),i);if(!o.length)return{text:"",lines:[],omitted:r,tokens:0,state:{}};const a=E(S,o,n,r),c=[S,...a.map(l=>l.text)].join(`
|
|
2
|
+
`);return{text:c,lines:a.map(({kind:l,text:h,tokens:p})=>({kind:l,text:h,tokens:p})),omitted:r,tokens:g(c),state:Object.fromEntries(a.map(l=>[l.kind,l.key]))}}function P({facts:e={},reach:t=new Set,previous:n=null,budget:i=w,now:o=Date.now()}={}){const r=n&&typeof n=="object"?n:null;if(!r||!Object.keys(r).length)return C({facts:e,reach:t,budget:i,now:o});const{lines:a,omitted:c}=N(e||{},j(t),o),l=new Map(a.map(s=>[s.kind,s])),h=a.filter(s=>r[s.kind]!==s.key),p=[];for(const s of Object.keys(r)){if(l.has(s))continue;const f=_.find($=>$.kind===s);p.push({kind:s,priority:f?f.priority:99,text:`- ${B[s]||`${s}: no longer available.`}`,tokens:0}),p[p.length-1].tokens=g(p[p.length-1].text)}const y=Object.fromEntries(a.map(s=>[s.kind,s.key]));if(!h.length&&!p.length)return{text:"",lines:[],omitted:c,tokens:0,state:y,unchanged:!0};const k=E(v,[...h,...p],i,c),b=[v,...k.map(s=>s.text)].join(`
|
|
3
|
+
`),M=new Set(k.map(s=>s.kind));for(const s of h)!M.has(s.kind)&&r[s.kind]!=null&&(y[s.kind]=r[s.kind]);return{text:b,lines:k.map(({kind:s,text:f,tokens:$})=>({kind:s,text:f,tokens:$})),omitted:c,tokens:g(b),state:y,unchanged:!1}}function R(e,t){const n=String(t||"").trim(),i=Array.isArray(e)?e:[];if(!n)return i;let o=-1;for(let r=i.length-1;r>=0;r--)if(i[r]?.role==="user"){o=r;break}return o<0?i:i.map((r,a)=>a===o?{...r,presence:n}:r)}import{presenceBlock as G}from"./context-attachments.js";export{w as PRESENCE_BUDGET_TOKENS,K as PRESENCE_KINDS,G as presenceBlock,P as presenceDelta,C as presenceFor,q as reachOf,d as roundCount,T as roundMinutes,R as withPresence};
|
package/tool-need.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{signalsFrom as
|
|
2
|
-
`));return
|
|
3
|
-
`));if(!
|
|
1
|
+
import{signalsFrom as A}from"./router.js";const x=new Set(["hi","hii","hiya","hey","heya","hello","helo","yo","sup","howdy","greetings","good","morning","afternoon","evening","night","day","thanks","thank","thankyou","thx","tnx","ty","cheers","appreciated","ok","okay","k","kk","got","sounds","perfect","great","cool","nice","awesome","lol","haha","hah","hehe","nvm","yep","yeah","yes","no","nope","sure","bye","goodbye","later","ya","cya","ciao","welcome","worries","problem","np","please","there","again","all","everyone","team","friend","mate","buddy","you","u","so","much","very","well","and","a","the"]),R=6;function E(t){const o=String(t||"").toLowerCase().replace(/[^\p{L}\s']/gu," ").split(/\s+/).filter(Boolean);return!o.length||o.length>R?!1:o.every(i=>x.has(i))}function _({request:t=null,signals:o=null,attachments:i=[],explicit:c=!1}={}){if(c)return{tools:!0,why:"the turn asked for tools"};if((i||[]).some(a=>a&&!a.auto))return{tools:!0,why:"the turn carries an attachment"};const h=String(t?.text??(t?.messages||[]).map(a=>a?.content||"").join(`
|
|
2
|
+
`));return E(h)?(o||A(t||{})).smalltalk?{tools:!1,why:"a greeting — nothing to look up"}:{tools:!0,why:"the request may need something fetched"}:{tools:!0,why:"the request may need something fetched"}}const j=Object.freeze([["web",/\b(search|google|look ?up|latest|current|recent|today|this (week|month|year)|news|price|prices|pricing|cost of|quote|stock|market|website|url|online|web|docs?umentation|release notes|changelog|versions?)\b/i],["history",/\b(our (meeting|call|notes?|chats?|conversation)|what (did|was) (we|i)|we (decided|agreed|discussed|said)|in (my|our) (notes?|meetings?|history|chats?)|past (chats?|meetings?|notes?)|earlier (meeting|conversation|chat|note)|transcript|standup|retro)\b/i],["data",/\b(attached|attachment|this (page|document|file|pdf|spreadsheet|sheet)|the (document|file|pdf|spreadsheet) (above|provided|attached))\b/i]]);function q(t,{held:o=null}={}){const i=String(t||"");if(!i.trim())return[];const c=j.filter(([,s])=>s.test(i)).map(([s])=>s);if(!o)return c;const h=new Set((Array.isArray(o)?o:[]).map(s=>String(s).toLowerCase()));return c.filter(s=>h.has(s)||s==="history"&&h.has("data"))}const b=Object.freeze(["page","data","mcp","memory","note","team","sideline","skills","widgets","recipes"]),f=Object.freeze(["data","mcp","memory"]),w="page_read",y=/\b(this|the|current|open|active|that|my) (page|tab|site|website|article|post|thread|document|doc|file|pdf|sheet|spreadsheet|form|canvas|board|diagram|screen|window|video|table|cell|button|field|link|image)\b|\bon (the|this) (page|screen|tab)\b|\bhere\b|\bthis\b(?!\s+(morning|afternoon|evening|week|weekend|month|year|time|is (a|the|my))\b)|\bthese\b|\bthose\b/i,k=/\b(click|tap|press|type|fill|enter|select|scroll|drag|draw|paint|sketch|navigate|go to|open|close|submit|upload|download|play|pause|screenshot|inspect|read (the|this)|zoom|highlight|copy|paste|log ?in|sign ?in|sign ?up|checkout|add to cart|search (on|in) (the|this)|watch|browse)\b/i,L=/\b(build|make|create|write|generate|draft|code|design|implement|prototype)\b[^.?!]{0,40}\b(app|widget|tool|timer|calculator|tracker|checklist|game|dashboard|form|page|site|script|component|converter|counter|scoreboard|clock|note|dice)\b|\b(widget|app)\b/i,O=/\b(run|use|ask|start|save|create|make|set ?up|open|launch|kick ?off|assign|delegate)\b[^.?!]{0,30}\b(team|teams|agent|agents|skill|skills|recipe|recipes|sideline|project)\b|\b(the|my|our|this|that)\s+(\w+[\s-]+)?(team|agent|skill|recipe|sideline|project)\b|\bask (the|our|my) \w+ (to|for)\b|\b(executive|breakout|workflow)\b|remember this|save (this|that) as|^\s*\//i,v=/\b(summar\w*|analy\w*|review|edit|rewrite|fix|refactor|debug|translate|convert|extract|compare|explain (this|that|the)|proofread|format|organi[sz]e|plan)\b/i,G=300;function F({request:t=null,signals:o=null,attachments:i=[],explicit:c=!1,stable:h=!1,ambient:s=null}={}){const a=n=>({tools:!0,tier:"full",groups:new Set(b),why:n});if(h)return a("a warm process keeps one tool set");const d=_({request:t,signals:o,attachments:i,explicit:c});if(!d.tools)return{tools:!1,tier:"none",groups:new Set,why:d.why};if(c)return a(d.why);if((i||[]).some(n=>n&&!n.auto))return a("the turn carries an attachment");const r=String(t?.text??(t?.messages||[]).map(n=>n?.content||"").join(`
|
|
3
|
+
`));if(!r.trim())return a("no text to read");if(r.length>G||/```/.test(r))return a("a long or code-bearing request");const g=y.test(r)||k.test(r)||v.test(r),u=O.test(r),m=L.test(r),S=v.test(r),p=!!s?.page;if(!g&&!u&&!m){const n=new Set(f);return p&&n.add(w),{tools:!0,tier:"light",groups:n,why:p?"a lookup, asked from a readable tab — the user's data, the web, and a reader for the tab":"a lookup — the user's data and the web are enough"}}const e=new Set(f),l=[];return g&&(e.add("page"),e.add("note"),l.push(k.test(r)?"the request asks to act":y.test(r)?"the request refers to the page or to something in view":"the request is work, not a lookup")),(S||u)&&e.add("skills"),u&&(e.add("team"),e.add("sideline"),e.add("recipes"),e.add("note"),l.push("the request names a team, skill, recipe or command")),m&&(e.add("widgets"),e.add("note"),l.push("the request asks to make something")),p&&!e.has("page")&&e.add(w),b.every(n=>e.has(n))?a(l.join("; ")):{tools:!0,tier:"task",groups:e,why:l.join("; ")}}export{F as equipmentFor,q as grantsNeededFor,_ as toolNeedFor};
|